{"id":11190,"date":"2026-10-23T22:27:06","date_gmt":"2026-10-23T20:27:06","guid":{"rendered":"https:\/\/retrofixer.it\/?page_id=11190"},"modified":"2026-10-23T22:35:08","modified_gmt":"2026-10-23T20:35:08","slug":"rom-creator","status":"publish","type":"page","link":"https:\/\/retrofixer.it\/en\/rom-creator\/","title":{"rendered":"ROM Creator"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"11190\" class=\"elementor elementor-11190\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7700a50 e-con-full e-flex e-con e-parent\" data-id=\"7700a50\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-99da4e6 elementor-widget elementor-widget-html\" data-id=\"99da4e6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n<!--\r\n  RETRO FIXER - ROM Creator: compone piu' immagini in un unico file .bin da scrivere sulla EPROM.\r\n  Progetti salvabili (.romproj, legge anche quelli della vecchia app), spazi vuoti, allineamenti,\r\n  mappa della memoria con i banchi, editor esadecimale, export intero \/ a parti \/ pari-dispari \/ byte-swap.\r\n  Da incollare in un widget \"HTML\" di Elementor. Tutto lo stile e' racchiuso nella classe .rcr.\r\n-->\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\r\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Press+Start+2P&family=VT323&family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\r\n\r\n<style>\r\n.rcr{\r\n  --bg:#0f0c24; --bg2:#171338; --panel:#1d1846; --line:#342c74; --text:#eceaff; --muted:#aaa5d8;\r\n  --c64:#3e31a2; --c64l:#7c70da; --yel:#ffd23f; --grn:#5ad15f; --cya:#3fd8ff; --ora:#f8961e; --red:#f94144; --mag:#e0398a;\r\n  font-family:'Inter',system-ui,-apple-system,Segoe UI,Roboto,sans-serif; color:var(--text); background:var(--bg); line-height:1.55;\r\n  position:relative; padding:44px 0 70px; overflow:clip;\r\n}\r\n.rcr *,.rcr *::before,.rcr *::after{box-sizing:border-box}\r\n.rcr h2,.rcr h3,.rcr h4,.rcr p,.rcr ul,.rcr ol{margin:0;padding:0}\r\n.rcr h2,.rcr h3,.rcr h4{font-family:'Inter',system-ui,sans-serif!important;letter-spacing:0;text-transform:none;font-weight:700}\r\n.rcr a{color:inherit;text-decoration:none}\r\n.rcr button,.rcr input,.rcr select{font:inherit;color:inherit}\r\n.rcr button{cursor:pointer;margin:0!important;height:auto!important;min-height:0!important;text-transform:none!important;letter-spacing:0!important;box-shadow:none}\r\n.rcr input,.rcr select{height:auto!important;margin:0!important;box-shadow:none!important}\r\n.rcr [hidden]{display:none!important}\r\n.rcr .wrap{max-width:1240px;margin:0 auto;padding:0 20px}\r\n.rcr .stripe{height:6px;background:linear-gradient(90deg,var(--red) 0 16.6%,var(--ora) 0 33.3%,var(--yel) 0 50%,var(--grn) 0 66.6%,var(--cya) 0 83.3%,var(--c64l) 0);position:absolute;left:0;right:0;top:0}\r\n.rcr .kicker{display:inline-block;font-family:'Press Start 2P',monospace;font-size:10px;color:var(--yel);letter-spacing:.06em;margin-bottom:12px}\r\n.rcr .h2{font-family:'Press Start 2P',monospace!important;font-size:clamp(17px,2.4vw,26px);line-height:1.45;color:#fff;text-shadow:3px 3px 0 #000;margin-bottom:10px;font-weight:400}\r\n.rcr .h3{font-family:'Press Start 2P',monospace!important;font-size:clamp(12px,1.5vw,15px);line-height:1.5;color:#fff;margin-bottom:8px;font-weight:400}\r\n.rcr .sub{color:var(--muted);font-size:15.5px;max-width:860px}\r\n.rcr .sub b,.rcr p b{color:#fff}\r\n.rcr section{margin-top:52px}\r\n.rcr .head{margin-bottom:16px}\r\n.rcr .panel{background:var(--bg2);border:2px solid var(--line);border-radius:16px;padding:16px}\r\n.rcr .lbl{display:block;font-family:'Press Start 2P',monospace;font-size:9px;color:var(--yel);margin-bottom:9px;letter-spacing:.04em}\r\n.rcr .hint{font-size:12.5px;color:var(--muted)}\r\n\r\n\/* barra progetto *\/\r\n.rcr .top{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:22px}\r\n.rcr .pname{flex:1 1 240px;display:flex;align-items:center;gap:10px;min-width:0}\r\n.rcr .pname span{font-family:'Press Start 2P',monospace;font-size:9px;color:var(--yel);white-space:nowrap}\r\n.rcr .txt{width:100%;min-width:0;background:#0b0920!important;border:2px solid var(--line)!important;border-radius:9px!important;padding:9px 11px!important;color:#fff!important;font-size:14.5px!important;line-height:1.3!important;outline:0}\r\n.rcr .txt:focus{border-color:var(--cya)!important}\r\n.rcr .mono{font-family:'VT323',monospace!important;font-size:20px!important;padding:4px 10px!important}\r\n.rcr .btns{display:flex;flex-wrap:wrap;gap:8px}\r\n.rcr .btn{display:inline-flex!important;align-items:center;justify-content:center;gap:8px;font-family:'Press Start 2P',monospace!important;font-size:9px!important;line-height:1.4!important;padding:11px 13px!important;border-radius:8px!important;border:2px solid var(--line)!important;background:rgba(255,255,255,.05)!important;color:#fff!important;white-space:nowrap}\r\n.rcr .btn .ic{font-family:'Segoe UI Symbol','Apple Color Emoji','Segoe UI Emoji',system-ui,sans-serif!important;font-style:normal;font-size:14px;line-height:1}\r\n.rcr .btn:hover{border-color:var(--c64l)!important}\r\n.rcr .btn.y{background:var(--yel)!important;border-color:var(--yel)!important;color:#231a00!important;box-shadow:0 4px 0 #a07d00}\r\n.rcr .btn.c{background:#123c48!important;border-color:var(--cya)!important}\r\n.rcr .btn.s{padding:8px 10px!important;font-size:8px!important}\r\n.rcr .btn:disabled{opacity:.35;cursor:not-allowed}\r\n.rcr .saved{font-size:12px;color:var(--muted);min-width:0}\r\n.rcr .saved.ok{color:var(--grn)}\r\n.rcr .saved.w{color:var(--ora)}\r\n\r\n\/* layout *\/\r\n.rcr .grid{display:grid;grid-template-columns:minmax(0,350px) minmax(0,1fr);gap:18px;margin-top:16px;align-items:start}\r\n.rcr .col{display:grid;gap:18px;min-width:0}\r\n.rcr .col>*{min-width:0}\r\n\r\n\/* scelta EPROM *\/\r\n.rcr .chips{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px}\r\n.rcr .chip{display:flex!important;flex-direction:column;align-items:flex-start!important;gap:0;padding:6px 8px!important;border-radius:9px!important;border:2px solid var(--line)!important;background:var(--panel)!important;color:#fff!important;line-height:1.1!important;text-align:left!important;min-width:0;overflow:hidden}\r\n.rcr .chip b{font-family:'VT323',monospace!important;font-size:19px;font-weight:400;white-space:nowrap}\r\n.rcr .chip sup{font-family:'Inter',sans-serif;font-size:9px;font-weight:700;color:var(--cya);margin-left:3px;vertical-align:6px;line-height:0}\r\n.rcr .chip small{font-size:10.5px;color:var(--muted);white-space:nowrap}\r\n.rcr .chip:hover{border-color:var(--c64l)!important}\r\n.rcr .chip.on{border-color:var(--yel)!important;background:#2a2350!important}\r\n.rcr .chip.fit small{color:var(--grn)}\r\n.rcr .row2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;margin-top:12px}\r\n.rcr .fld{display:grid;gap:5px;min-width:0}\r\n.rcr .fld>span{font-size:12px;color:var(--muted);font-weight:600}\r\n.rcr .sel{width:100%;min-width:0;background:#0b0920!important;border:2px solid var(--line)!important;border-radius:9px!important;padding:8px 10px!important;color:#fff!important;font-size:14px!important;line-height:1.3!important}\r\n\r\n\/* occupazione *\/\r\n.rcr .sum{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\r\n.rcr .sum div{background:var(--panel);border:2px solid var(--line);border-radius:12px;padding:8px 11px;min-width:0}\r\n.rcr .sum b{display:block;font-family:'VT323',monospace;font-size:27px;line-height:1;color:var(--yel);font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\r\n.rcr .sum span{font-size:11.5px;color:var(--muted)}\r\n.rcr .gauge{height:16px;border:2px solid #000;border-radius:6px;background:#0b0920;overflow:hidden;margin:12px 0 4px;position:relative}\r\n.rcr .gauge i{position:absolute;left:0;top:0;bottom:0;background:repeating-linear-gradient(90deg,var(--grn) 0 6px,#3fa844 6px 8px);transition:width .3s}\r\n.rcr .gauge.over i{background:repeating-linear-gradient(90deg,var(--red) 0 6px,#b52a2c 6px 8px)}\r\n.rcr .msg{margin-top:12px;font-size:13.5px;padding:10px 12px;border-radius:12px;border:2px solid var(--line);background:var(--panel);color:#dcd8f6}\r\n.rcr .msg.warn{background:#2a0c14;border-color:#7a1d33;color:#ffd6e0}\r\n.rcr .msg.ok{background:#11301a;border-color:#2b7a3a;color:#d6ffde}\r\n.rcr .msg b{color:#fff}\r\n.rcr .msg .btn{margin-top:8px!important}\r\n\r\n\/* spazio vuoto *\/\r\n.rcr .tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}\r\n.rcr .tab{padding:6px 10px!important;border-radius:999px!important;border:2px solid var(--line)!important;background:transparent!important;color:var(--muted)!important;font-size:12px!important;font-weight:600!important;line-height:1.2!important}\r\n.rcr .tab:hover{color:#fff!important}\r\n.rcr .tab.on{color:#231a00!important;background:var(--yel)!important;border-color:var(--yel)!important}\r\n.rcr .prev{font-family:'VT323',monospace;font-size:18px;color:var(--cya);margin:8px 0 10px;line-height:1.2}\r\n.rcr .prev.w{color:var(--ora)}\r\n\r\n\/* export *\/\r\n.rcr .opts{display:grid;gap:7px;margin:4px 0 12px}\r\n.rcr .opt{display:flex;gap:9px;align-items:flex-start;font-size:13.5px;color:#dcd8f6;cursor:pointer;line-height:1.35}\r\n.rcr .opt input{margin-top:2px!important;accent-color:var(--yel);width:16px;height:16px!important;flex:none}\r\n.rcr .opt small{display:block;color:var(--muted);font-size:12px}\r\n.rcr .opt.off{opacity:.4;pointer-events:none}\r\n.rcr .crc{font-family:'VT323',monospace;font-size:18px;color:var(--grn);background:#000;border:2px solid #333;border-radius:8px;padding:6px 10px;margin-top:10px;overflow-x:auto;white-space:nowrap}\r\n\r\n\/* drop *\/\r\n.rcr .drop{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;text-align:center;border:3px dashed var(--line);border-radius:16px;padding:22px 16px;background:repeating-linear-gradient(45deg,rgba(255,255,255,.015) 0 10px,transparent 10px 20px);transition:border-color .2s,background .2s;cursor:pointer}\r\n.rcr .drop:hover,.rcr .drop.hot{border-color:var(--yel);background:rgba(255,210,63,.06)}\r\n.rcr .drop .ico{font-size:30px;line-height:1}\r\n.rcr .drop .dt{display:grid;gap:6px}\r\n.rcr .drop b{font-family:'Press Start 2P',monospace;font-size:10px;color:#fff;line-height:1.6}\r\n.rcr .drop p{font-size:13px;color:var(--muted)}\r\n.rcr .drop .btn{margin-top:4px!important}\r\n.rcr .drop input{display:none}\r\n\r\n\/* mappa *\/\r\n.rcr .maphead{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;margin-bottom:10px}\r\n.rcr .maphead .lbl{margin:0}\r\n.rcr .maphead label{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);font-weight:600}\r\n.rcr .maphead select{width:auto}\r\n.rcr .map{position:relative;height:58px;background:#0b0920;border:2px solid #000;border-radius:10px;overflow:hidden}\r\n.rcr .map .free{position:absolute;top:0;bottom:0;background:repeating-linear-gradient(135deg,#151132 0 6px,#1b1640 6px 12px)}\r\n.rcr .map .sg{position:absolute;top:0;bottom:0;border-right:2px solid #000;display:flex;align-items:center;justify-content:center;overflow:hidden;cursor:pointer;color:#0b0920;font-family:'VT323',monospace;font-size:17px;line-height:1;padding:0 3px;white-space:nowrap;transition:filter .15s}\r\n.rcr .map .sg:hover{filter:brightness(1.15)}\r\n.rcr .map .sg.on{box-shadow:inset 0 0 0 3px #fff}\r\n.rcr .map .sg.blank{background-image:repeating-linear-gradient(135deg,rgba(0,0,0,.25) 0 4px,transparent 4px 8px)!important}\r\n.rcr .map .ovr{position:absolute;top:0;bottom:0;background:repeating-linear-gradient(135deg,rgba(249,65,68,.55) 0 6px,rgba(249,65,68,.25) 6px 12px);pointer-events:none}\r\n.rcr .map .end{position:absolute;top:0;bottom:0;width:3px;background:var(--red);box-shadow:0 0 6px var(--red);pointer-events:none}\r\n.rcr .map .bk{position:absolute;top:0;bottom:0;width:0;border-left:2px dashed rgba(255,255,255,.55);pointer-events:none}\r\n.rcr .ruler{position:relative;height:38px;margin-top:4px}\r\n.rcr .ruler span{position:absolute;top:0;transform:translateX(-50%);text-align:center;font-family:'VT323',monospace;font-size:15px;line-height:1;color:var(--muted);white-space:nowrap}\r\n.rcr .ruler span b{display:block;color:var(--cya);font-weight:400;font-size:17px}\r\n.rcr .ruler .a0{transform:none;text-align:left}\r\n.rcr .ruler .a1{transform:translateX(-100%);text-align:right}\r\n.rcr .banks{font-size:12.5px;color:var(--muted);margin-top:4px}\r\n.rcr .banks b{color:#fff}\r\n\r\n\/* lista segmenti *\/\r\n.rcr .list{display:grid;gap:7px;margin-top:14px}\r\n.rcr .empty{text-align:center;color:var(--muted);font-size:14px;padding:18px;border:2px dashed var(--line);border-radius:12px}\r\n.rcr .seg{display:grid;grid-template-columns:26px 10px minmax(0,1fr) auto;gap:9px;align-items:center;background:var(--panel);border:2px solid var(--line);border-radius:11px;padding:7px 9px;transition:border-color .15s,background .15s}\r\n.rcr .seg.on{border-color:var(--yel);background:#2a2350}\r\n.rcr .seg.drag{opacity:.85;border-color:var(--cya);box-shadow:0 8px 20px rgba(0,0,0,.5);position:relative;z-index:3}\r\n.rcr .seg .hd{cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;color:var(--muted);font-size:18px;line-height:1;text-align:center;padding:8px 0}\r\n.rcr .seg .hd:active{cursor:grabbing}\r\n.rcr .seg .sw{width:10px;align-self:stretch;border-radius:4px}\r\n.rcr .seg .bd{min-width:0;cursor:pointer}\r\n.rcr .seg .nm{width:100%;min-width:0;background:transparent!important;border:0!important;border-bottom:1px dashed transparent!important;border-radius:0!important;padding:1px 0!important;font-size:14.5px!important;font-weight:600;color:#fff!important;line-height:1.3!important;outline:0}\r\n.rcr .seg .nm:hover,.rcr .seg .nm:focus{border-bottom-color:#5d58a0!important}\r\n.rcr .seg .mt{display:flex;flex-wrap:wrap;gap:4px 10px;font-size:12px;color:var(--muted);align-items:center}\r\n.rcr .seg .mt .ad{font-family:'VT323',monospace;font-size:17px;color:var(--cya)}\r\n.rcr .seg .mt .ck{font-family:'VT323',monospace;font-size:16px}\r\n.rcr .tag{display:inline-block;font-family:'Press Start 2P',monospace;font-size:7px;padding:3px 6px;border-radius:4px;line-height:1.3}\r\n.rcr .tag.bl{background:#2c2a55;color:#c9c4ff}\r\n.rcr .tag.ns{background:#4a2f0b;color:#ffd08a}\r\n.rcr .tag.md{background:#4a1230;color:#ff9ccc}\r\n.rcr .tag.ov{background:#5a0f12;color:#ffb3b3}\r\n.rcr .seg .ac{display:flex;gap:3px}\r\n.rcr .ib{width:30px;height:30px!important;display:inline-flex!important;align-items:center;justify-content:center;padding:0!important;border-radius:7px!important;border:2px solid transparent!important;background:transparent!important;color:var(--muted)!important;font-size:15px!important;line-height:1!important}\r\n.rcr .ib:hover{color:#fff!important;border-color:var(--line)!important;background:rgba(255,255,255,.04)!important}\r\n.rcr .ib.x:hover{color:var(--red)!important}\r\n.rcr .ib:disabled{opacity:.25;cursor:not-allowed}\r\n\r\n\/* editor esadecimale *\/\r\n.rcr .hxbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:10px}\r\n.rcr .hxbar .grow{flex:1}\r\n.rcr .mini{display:flex;align-items:center;gap:6px}\r\n.rcr .mini span{font-size:12px;color:var(--muted);font-weight:600}\r\n.rcr .mini .txt{width:120px;padding:5px 8px!important}\r\n.rcr .hxt{font-size:13px;color:var(--muted);margin-bottom:8px;min-height:20px}\r\n.rcr .hxt b{color:#fff}\r\n.rcr .hxw{border:2px solid #000;border-radius:12px;background:#08061a;overflow:hidden}\r\n.rcr .hxhd,.rcr .hxrow{display:grid;grid-template-columns:76px minmax(0,auto) minmax(0,1fr);gap:14px;padding:0 12px;white-space:nowrap}\r\n.rcr .hxhd{font-family:'VT323',monospace;font-size:16px;color:var(--yel);background:#15113a;padding-top:4px;padding-bottom:4px;border-bottom:2px solid #000}\r\n.rcr .hx{height:440px;overflow:auto;position:relative;outline:0;overscroll-behavior:contain}\r\n.rcr .hx:focus-visible{box-shadow:inset 0 0 0 2px var(--cya)}\r\n.rcr .hxs{position:relative}\r\n.rcr .hxr{position:absolute;left:0;right:0;top:0}\r\n.rcr .hxrow{height:22px;font-family:'VT323',monospace;font-size:18px;line-height:22px;color:#cfd2ff}\r\n.rcr .hxrow .a{color:var(--muted);border-left:3px solid transparent;padding-left:5px}\r\n.rcr .hxrow .h i,.rcr .hxrow .t i{font-style:normal;cursor:pointer;border-radius:3px}\r\n.rcr .hxrow .h i{display:inline-block;width:2.05ch;text-align:center;margin-right:.55ch}\r\n.rcr .hxrow .h i:nth-child(8n){margin-right:1.4ch}\r\n.rcr .hxrow .t{color:#8f8bc4}\r\n.rcr .hxrow .t i{display:inline-block;width:1ch;text-align:center}\r\n.rcr .hxrow i.p{color:#4a4675}\r\n.rcr .hxrow i.o{color:#ff8a8c}\r\n.rcr .hxrow i.z{color:#7a77b0}\r\n.rcr .hxrow i.f{background:rgba(255,210,63,.15)}\r\n.rcr .hxrow i.c{background:var(--yel);color:#231a00}\r\n.rcr .hxrow i.c.n{background:var(--cya)}\r\n.rcr .hxrow i.e{color:var(--mag)}\r\n.rcr .hxed{display:flex;flex-wrap:wrap;gap:10px;align-items:center;padding:8px 12px;background:#15113a;border-top:2px solid #000;font-family:'VT323',monospace;font-size:18px;color:var(--muted)}\r\n.rcr .hxed b{color:#fff;font-weight:400}\r\n.rcr .hxed .txt{width:64px;text-transform:uppercase}\r\n\r\n\/* testi *\/\r\n.rcr .cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}\r\n.rcr .gcard{display:flex;flex-direction:column;gap:8px;background:var(--panel);border:2px solid var(--line);border-radius:12px;padding:16px}\r\n.rcr .gcard .ico{font-size:26px;line-height:1}\r\n.rcr .gcard h4{font-size:15.5px;color:#fff;line-height:1.3}\r\n.rcr .gcard p{font-size:14px;color:var(--muted)}\r\n.rcr .gcard code,.rcr p code{font-family:'VT323',monospace;font-size:18px;color:var(--grn)}\r\n.rcr a.gcard{transition:border-color .2s,transform .2s}\r\n.rcr a.gcard:hover{border-color:var(--yel);transform:translateY(-3px)}\r\n.rcr a.gcard .go{margin-top:auto;font-family:'Press Start 2P',monospace;font-size:8px;color:var(--yel)}\r\n\r\n.rcr .toast{position:fixed;left:50%;bottom:22px;transform:translateX(-50%) translateY(20px);opacity:0;pointer-events:none;z-index:99999;background:#0b0920;border:2px solid var(--yel);color:#fff;border-radius:10px;padding:10px 16px;font-size:14px;box-shadow:0 10px 30px rgba(0,0,0,.6);transition:opacity .25s,transform .25s;max-width:calc(100vw - 32px)}\r\n.rcr .toast.on{opacity:1;transform:translateX(-50%)}\r\n.rcr .toast.w{border-color:var(--red)}\r\n\r\n@media (min-width:761px){\r\n  .rcr .drop{flex-direction:row;flex-wrap:wrap;text-align:left;padding:14px 18px;gap:6px 14px}\r\n  .rcr .drop .dt{flex:1 1 0;min-width:220px}\r\n  .rcr .drop .dt b{display:block;margin-bottom:2px}\r\n  .rcr .drop .btn{margin-top:0!important}\r\n}\r\n@media (max-width:1024px){.rcr .grid{grid-template-columns:minmax(0,1fr)}.rcr .col.l{grid-template-columns:repeat(2,minmax(0,1fr))}.rcr .cols{grid-template-columns:repeat(2,minmax(0,1fr))}}\r\n@media (max-width:760px){\r\n  .rcr .col.l{grid-template-columns:minmax(0,1fr)}\r\n  .rcr .seg{grid-template-columns:24px 8px minmax(0,1fr)}\r\n  .rcr .seg .ac{grid-column:3;justify-content:flex-start;flex-wrap:wrap}\r\n  .rcr .hxhd,.rcr .hxrow{grid-template-columns:62px minmax(0,auto) minmax(0,1fr);gap:8px;padding:0 6px}\r\n  .rcr .hxrow{font-size:16px}\r\n  .rcr .hx{height:380px}\r\n  .rcr .top .btns{width:100%}\r\n  .rcr .top .btns .btn{flex:1 1 auto}\r\n}\r\n@media (max-width:480px){.rcr{padding:30px 0 50px}.rcr .wrap{padding:0 14px}.rcr .cols{grid-template-columns:minmax(0,1fr)}.rcr .panel{padding:12px}.rcr .chips{grid-template-columns:repeat(2,minmax(0,1fr))}.rcr .hxbar .mini{flex:1 1 100%}.rcr .hxbar .mini .txt{flex:1}}\r\nbody:has(.rcr) .post-views.entry-meta{display:block;margin:0;padding:7px 16px;text-align:center;\r\n  font:12px\/1.4 'Inter',system-ui,sans-serif;color:#aaa5d8;background:#0f0c24;border-top:2px solid #342c74;border-bottom:2px solid #5ad15f}\r\n<\/style>\r\n\r\n<div class=\"rcr\" id=\"rcr\">\r\n  <div class=\"stripe\"><\/div>\r\n  <div class=\"wrap\">\r\n\r\n    <div class=\"head\">\r\n      <span class=\"kicker\">ROM CREATOR<\/span>\r\n      <h2 class=\"h2\">Componi la tua EPROM<\/h2>\r\n      <p class=\"sub\">Trascina qui le immagini ROM (kernal, basic, chargen, cartucce...), mettile nell'ordine che vuoi, aggiungi <b>spazi vuoti<\/b> o <b>allineamenti<\/b> e guarda subito quanto occupano. Quando \u00e8 tutto a posto esporti il <b>file .bin<\/b> pronto da scrivere con il programmatore. Il progetto si salva e si riapre per modificarlo; nulla viene inviato al server, tutto resta nel tuo browser.<\/p>\r\n    <\/div>\r\n\r\n    <!-- ============ BARRA PROGETTO ============ -->\r\n    <div class=\"panel top\">\r\n      <label class=\"pname\"><span>PROGETTO<\/span><input class=\"txt\" id=\"rcrName\" maxlength=\"60\" value=\"Nuovo progetto\" aria-label=\"Nome del progetto\"><\/label>\r\n      <div class=\"btns\">\r\n        <button class=\"btn\" data-a=\"new\" title=\"Svuota e ricomincia\"><i class=\"ic\">\u271a<\/i> NUOVO<\/button>\r\n        <button class=\"btn\" data-a=\"open\" title=\"Apri un file .romproj\"><i class=\"ic\">\ud83d\udcc2<\/i> APRI<\/button>\r\n        <button class=\"btn\" data-a=\"save\" title=\"Scarica il progetto .romproj\"><i class=\"ic\">\ud83d\udcbe<\/i> SALVA<\/button>\r\n        <button class=\"btn s\" data-a=\"undo\" id=\"rcrUndo\" title=\"Annulla (Ctrl+Z)\"><i class=\"ic\">\u21b6<\/i><\/button>\r\n        <button class=\"btn s\" data-a=\"redo\" id=\"rcrRedo\" title=\"Ripeti (Ctrl+Y)\"><i class=\"ic\">\u21b7<\/i><\/button>\r\n        <button class=\"btn y\" data-a=\"export\" title=\"Scarica il file .bin\"><i class=\"ic\">\u2b07<\/i> ESPORTA .BIN<\/button>\r\n      <\/div>\r\n      <input type=\"file\" id=\"rcrOpen\" accept=\".romproj,.json,application\/json\" hidden>\r\n      <span class=\"saved\" id=\"rcrSaved\"><\/span>\r\n    <\/div>\r\n\r\n    <div class=\"grid\">\r\n      <!-- ============ COLONNA SINISTRA ============ -->\r\n      <div class=\"col l\">\r\n        <div class=\"panel\">\r\n          <span class=\"lbl\">1 \u00b7 EPROM DI DESTINAZIONE<\/span>\r\n          <div class=\"chips\" id=\"rcrChips\"><\/div>\r\n          <div class=\"row2\">\r\n            <label class=\"fld\"><span>Byte di riempimento<\/span>\r\n              <select class=\"sel\" id=\"rcrFill\"><option value=\"255\">$FF (vergine)<\/option><option value=\"0\">$00 (zero)<\/option><option value=\"custom\">Altro...<\/option><\/select>\r\n            <\/label>\r\n            <label class=\"fld\" id=\"rcrFillCw\" hidden><span>Valore esadecimale<\/span><input class=\"txt mono\" id=\"rcrFillC\" maxlength=\"2\" value=\"EA\"><\/label>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"panel\">\r\n          <span class=\"lbl\">2 \u00b7 SPAZIO OCCUPATO<\/span>\r\n          <div class=\"sum\">\r\n            <div><b id=\"rcrUsed\">0<\/b><span>Usato<\/span><\/div>\r\n            <div><b id=\"rcrFree\">0<\/b><span>Libero<\/span><\/div>\r\n            <div><b id=\"rcrTot\">0<\/b><span>Capienza EPROM<\/span><\/div>\r\n            <div><b id=\"rcrPct\">0%<\/b><span>Occupazione<\/span><\/div>\r\n          <\/div>\r\n          <div class=\"gauge\" id=\"rcrGauge\"><i><\/i><\/div>\r\n          <div id=\"rcrFit\"><\/div>\r\n        <\/div>\r\n\r\n        <div class=\"panel\">\r\n          <span class=\"lbl\">3 \u00b7 SPAZIO VUOTO<\/span>\r\n          <div class=\"tabs\" id=\"rcrBlTabs\">\r\n            <button class=\"tab on\" data-bm=\"size\">Dimensione<\/button>\r\n            <button class=\"tab\" data-bm=\"to\">Fino all'indirizzo<\/button>\r\n            <button class=\"tab\" data-bm=\"align\">Allinea a blocco<\/button>\r\n          <\/div>\r\n          <div data-bp=\"size\">\r\n            <div class=\"row2\" style=\"margin-top:0\">\r\n              <label class=\"fld\"><span>Grandezza<\/span><select class=\"sel\" id=\"rcrBlSize\"><\/select><\/label>\r\n              <label class=\"fld\" id=\"rcrBlCw\" hidden><span>Byte (dec o $hex)<\/span><input class=\"txt mono\" id=\"rcrBlC\" value=\"$100\"><\/label>\r\n            <\/div>\r\n          <\/div>\r\n          <div data-bp=\"to\" hidden>\r\n            <label class=\"fld\"><span>Il prossimo pezzo deve iniziare a<\/span><input class=\"txt mono\" id=\"rcrBlTo\" value=\"$2000\"><\/label>\r\n          <\/div>\r\n          <div data-bp=\"align\" hidden>\r\n            <label class=\"fld\"><span>Il prossimo pezzo inizia a un multiplo di<\/span><select class=\"sel\" id=\"rcrBlAl\"><\/select><\/label>\r\n          <\/div>\r\n          <div class=\"row2\">\r\n            <label class=\"fld\"><span>Riempito con<\/span><select class=\"sel\" id=\"rcrBlFill\"><option value=\"255\">$FF<\/option><option value=\"0\">$00<\/option><\/select><\/label>\r\n            <label class=\"fld\"><span>&nbsp;<\/span><button class=\"btn c\" data-a=\"blank\"><i class=\"ic\">\u271a<\/i> AGGIUNGI<\/button><\/label>\r\n          <\/div>\r\n          <div class=\"prev\" id=\"rcrBlPrev\"><\/div>\r\n          <p class=\"hint\">Viene inserito dopo il pezzo selezionato (o in fondo). Utile per far partire un'immagine da una locazione precisa o completare un'immagine di misura non standard.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"panel\">\r\n          <span class=\"lbl\">4 \u00b7 ESPORTA<\/span>\r\n          <div class=\"opts\">\r\n            <label class=\"opt\" id=\"rcrOMir\"><input type=\"checkbox\" id=\"rcrMirror\"><span>Ripeti il contenuto fino a riempire l'EPROM<small>Consigliato se usi una EPROM pi\u00f9 grande con una sola immagine: qualunque sia il livello degli indirizzi in pi\u00f9, la macchina legge sempre lo stesso programma.<\/small><\/span><\/label>\r\n            <label class=\"opt\" id=\"rcrOSwap\"><input type=\"checkbox\" id=\"rcrSwap\"><span>Byte-swap (16 bit)<small>Scambia ogni coppia di byte: per 27C800\/160\/322 usate su bus a 16 bit.<\/small><\/span><\/label>\r\n            <label class=\"opt\" id=\"rcrOEo\"><input type=\"checkbox\" id=\"rcrEo\"><span>Dividi in pari \/ dispari<small>Due file, byte pari e byte dispari, per coppie di EPROM da 8 bit su bus a 16 bit (es. Amiga Kickstart).<\/small><\/span><\/label>\r\n          <\/div>\r\n          <button class=\"btn y\" data-a=\"export\" style=\"width:100%\"><i class=\"ic\">\u2b07<\/i> ESPORTA .BIN<\/button>\r\n          <div class=\"crc\" id=\"rcrCrc\">CRC32 \u2014<\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <!-- ============ COLONNA DESTRA ============ -->\r\n      <div class=\"col\">\r\n        <div class=\"drop\" id=\"rcrDrop\" tabindex=\"0\" role=\"button\" aria-label=\"Aggiungi file ROM\">\r\n          <div class=\"ico\">\ud83d\udcbe<\/div>\r\n          <div class=\"dt\"><b>TRASCINA QUI I FILE ROM<\/b>\r\n          <p>.bin .rom .prg .crt ... uno o pi\u00f9 file insieme. Puoi trascinare anche un progetto .romproj per aprirlo.<\/p><\/div>\r\n          <span class=\"btn c\"><i class=\"ic\">\ud83d\udcc1<\/i> SFOGLIA<\/span>\r\n          <input type=\"file\" id=\"rcrFiles\" multiple>\r\n        <\/div>\r\n\r\n        <div class=\"panel\">\r\n          <div class=\"maphead\">\r\n            <span class=\"lbl\">MAPPA DELLA EPROM<\/span>\r\n            <label>Banchi da <select class=\"sel\" id=\"rcrBank\"><\/select><\/label>\r\n          <\/div>\r\n          <div class=\"map\" id=\"rcrMap\"><\/div>\r\n          <div class=\"ruler\" id=\"rcrRuler\"><\/div>\r\n          <p class=\"banks\" id=\"rcrBanks\"><\/p>\r\n          <div class=\"list\" id=\"rcrList\"><\/div>\r\n        <\/div>\r\n\r\n  <!-- ============ EDITOR HEX ============ -->\r\n        <div class=\"panel hxp\">\r\n          <div class=\"hxbar\">\r\n            <span class=\"lbl\" style=\"margin:0\">EDITOR ESADECIMALE<\/span>\r\n            <div class=\"tabs\" id=\"rcrView\" style=\"margin:0\">\r\n              <button class=\"tab on\" data-v=\"seg\">Pezzo selezionato<\/button>\r\n              <button class=\"tab\" data-v=\"all\">EPROM intera<\/button>\r\n            <\/div>\r\n            <span class=\"grow\"><\/span>\r\n            <label class=\"mini\"><span>Vai a<\/span><input class=\"txt mono\" id=\"rcrGo\" placeholder=\"$0000\"><\/label>\r\n            <label class=\"mini\"><span>Cerca<\/span><input class=\"txt mono\" id=\"rcrFind\" placeholder=\"A9 00 o &quot;CBM&quot;\"><button class=\"btn s\" data-a=\"find\" title=\"Trova il successivo\" type=\"button\">\u25b6<\/button><\/label>\r\n          <\/div>\r\n          <p class=\"hxt\" id=\"rcrHxT\"><\/p>\r\n          <div class=\"hxw\">\r\n            <div class=\"hxhd\" id=\"rcrHxHd\"><\/div>\r\n            <div class=\"hx\" id=\"rcrHx\" tabindex=\"0\"><div class=\"hxs\" id=\"rcrHxS\"><div class=\"hxr\" id=\"rcrHxR\"><\/div><\/div><\/div>\r\n            <div class=\"hxed\" id=\"rcrHxEd\"><\/div>\r\n          <\/div>\r\n          <p class=\"hint\" style=\"margin-top:8px\">Clicca un byte e scrivi due cifre esadecimali (frecce, PagSu\/PagGi\u00f9 per muoverti, Ctrl+Z per annullare). Da cellulare usa la casella <b>valore<\/b> sotto la tabella. Nella vista <b>EPROM intera<\/b> vedi il file esattamente come verr\u00e0 scritto, riempimento compreso.<\/p>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- ============ GUIDA ============ -->\r\n    <section>\r\n      <div class=\"head\"><span class=\"kicker\">COME SI USA<\/span><h3 class=\"h3\">Tre passi per una multi-ROM<\/h3><\/div>\r\n      <div class=\"cols\">\r\n        <div class=\"gcard\"><div class=\"ico\">\ud83d\udcd0<\/div><h4>1. Scegli la EPROM<\/h4><p>La capienza decide quante immagini ci stanno. Una <code>27C256<\/code> (32 KB) contiene 4 kernal da 8 KB, una <code>27C512<\/code> ne contiene 8. Sotto i chip vedi in verde quelli in cui il progetto entra.<\/p><\/div>\r\n        <div class=\"gcard\"><div class=\"ico\">\ud83e\udde9<\/div><h4>2. Ordina i pezzi<\/h4><p>Trascina le righe dalla maniglia <b>\u22ee\u22ee<\/b> per cambiare ordine. Con <b>Banchi da<\/b> la mappa mostra a quale combinazione dei piedini di indirizzo alti corrisponde ogni immagine: \u00e8 quella che imposterai con i DIP switch.<\/p><\/div>\r\n        <div class=\"gcard\"><div class=\"ico\">\u26a1<\/div><h4>3. Esporta e scrivi<\/h4><p>Il .bin ha sempre la misura esatta della EPROM; lo spazio che avanza \u00e8 riempito con <code>$FF<\/code>, lo stato di una EPROM cancellata, cos\u00ec la scrittura \u00e8 pi\u00f9 veloce. Controlla il CRC32 dopo la lettura di verifica.<\/p><\/div>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <section>\r\n      <div class=\"head\"><span class=\"kicker\">CONTINUA<\/span><h3 class=\"h3\">Pagine collegate<\/h3><\/div>\r\n      <div class=\"cols\">\r\n        <a class=\"gcard\" href=\"\/rom-e-adattatori\/\"><div class=\"ico\">\ud83d\udd0c<\/div><h4>ROM e adattatori<\/h4><p>Pinout 23xx e 27xx, confronto zoccolo\/EPROM, collegamenti dei piedini e multi-ROM con DIP switch.<\/p><span class=\"go\">APRI \u25b6<\/span><\/a>\r\n        <a class=\"gcard\" href=\"\/guasti-commodore-64\/\"><div class=\"ico\">\ud83e\udd16<\/div><h4>Ripara il tuo C64 con l'AI<\/h4><p>Guida ai guasti di VIC-20, C64 e C128: sintomi, chip sospetti e come verificarli.<\/p><span class=\"go\">APRI \u25b6<\/span><\/a>\r\n        <a class=\"gcard\" href=\"\/dt-flash-codes\/\"><div class=\"ico\">\ud83d\udea8<\/div><h4>Dead Test flash codes<\/h4><p>Il C64 lampeggia? Dal numero di lampeggi risali al chip RAM guasto.<\/p><span class=\"go\">APRI \u25b6<\/span><\/a>\r\n      <\/div>\r\n    <\/section>\r\n\r\n  <\/div>\r\n  <div class=\"toast\" id=\"rcrToast\"><\/div>\r\n<\/div>\r\n\r\n<script>\r\n(function () {\r\n  var root = document.getElementById('rcr'); if (!root || root.getAttribute('data-ok')) return; root.setAttribute('data-ok', 1);\r\n  function $(id) { return document.getElementById(id); }\r\n  var KB = 1024;\r\n  \/* [id, nome, byte, bus]: bus 8 = solo 8 bit, 'b' = 8 o 16 bit col piedino BYTE, 16 = solo 16 bit *\/\r\n  var CHIPS = [\r\n    ['27C16', '2716', 2 * KB, 8], ['27C32', '2732', 4 * KB, 8], ['27C64', '2764', 8 * KB, 8], ['27C128', '27128', 16 * KB, 8],\r\n    ['27C256', '27256', 32 * KB, 8], ['27C512', '27512', 64 * KB, 8], ['27C010', '27C010', 128 * KB, 8], ['27C020', '27C020', 256 * KB, 8],\r\n    ['27C040', '27C040', 512 * KB, 8], ['27C080', '27C080', 1024 * KB, 8], ['27C800', '27C800', 1024 * KB, 'b'], ['27C160', '27C160', 2048 * KB, 'b'],\r\n    ['27C322', '27C322', 4096 * KB, 16]\r\n  ];\r\n  var COLORS = ['#3fd8ff', '#ffd23f', '#5ad15f', '#f8961e', '#e0398a', '#7c70da', '#f94144', '#43aa8b', '#c77dff', '#90be6d', '#ff99c8', '#4cc9f0'];\r\n  var LS = 'rfRomCreator';\r\n\r\n  var P = { name: 'Nuovo progetto', rom: '27C256', fill: 255, segs: [] };\r\n  var sel = null, view = 'seg', cur = 0, nib = -1, bankSize = 0, blMode = 'size', uid = 1;\r\n  var undo = [], redo = [];\r\n\r\n  function chip(id) { for (var i = 0; i < CHIPS.length; i++) if (CHIPS[i][0] === id) return CHIPS[i]; return CHIPS[4]; }\r\n  function romSize() { return chip(P.rom)[2]; }\r\n  function total() { var t = 0; P.segs.forEach(function (s) { t += s.data.length; }); return t; }\r\n  function hex(n, w) { return n.toString(16).toUpperCase().padStart(w || 2, '0'); }\r\n  function hw() { return Math.max(4, (Math.max(romSize(), total()) - 1).toString(16).length); }\r\n  function fmt(n) { if (n >= KB * KB && n % (KB * KB) === 0) return n \/ KB \/ KB + ' MB'; if (n >= KB && n % KB === 0) return n \/ KB + ' KB'; if (n >= KB) return (n \/ KB).toFixed(2).replace('.', ',') + ' KB'; return n + ' B'; }\r\n  function fmtB(n) { return n.toLocaleString('it-IT') + ' byte'; }\r\n  function esc(s) { return String(s).replace(\/[&<>\"]\/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]; }); }\r\n  function mbit(n) { var b = n * 8; return b >= KB * KB ? b \/ KB \/ KB + ' Mbit' : b \/ KB + ' Kbit'; }\r\n  var BUS = { 8: 'Solo 8 bit', b: '8 o 16 bit (piedino BYTE)', 16: 'Solo 16 bit' };\r\n  function pow2(n) { return n > 0 && (n & (n - 1)) === 0; }\r\n  function num(s) { s = String(s).trim().replace(\/\\s+\/g, ''); if (!s) return NaN; var m; if ((m = \/^(\\$|0x|&h)([0-9a-f]+)$\/i.exec(s))) return parseInt(m[2], 16); if ((m = \/^([0-9a-f]+)h$\/i.exec(s))) return parseInt(m[1], 16); if ((m = \/^(\\d+(?:[.,]\\d+)?)\\s*(k|kb)$\/i.exec(s))) return Math.round(parseFloat(m[1].replace(',', '.')) * KB); if (\/^\\d+$\/.test(s)) return parseInt(s, 10); if (\/^[0-9a-f]+$\/i.test(s)) return parseInt(s, 16); return NaN; }\r\n  function toast(t, warn) { var el = $('rcrToast'); el.textContent = t; el.className = 'toast on' + (warn ? ' w' : ''); clearTimeout(toast.t); toast.t = setTimeout(function () { el.className = 'toast'; }, 2600); }\r\n  function color(s) { return COLORS[P.segs.indexOf(s) % COLORS.length]; }\r\n  function segById(id) { for (var i = 0; i < P.segs.length; i++) if (P.segs[i].id === id) return P.segs[i]; return null; }\r\n  function mk(name, type, data, fill) { return { id: 's' + Date.now().toString(36) + (uid++), name: name, type: type, data: data, fill: fill, mod: 0, crc: null }; }\r\n\r\n  var CT = (function () { var t = new Uint32Array(256); for (var n = 0; n < 256; n++) { var c = n; for (var k = 0; k < 8; k++) c = c & 1 ? 0xEDB88320 ^ (c >>> 1) : c >>> 1; t[n] = c >>> 0; } return t; })();\r\n  function crc32(d) { var c = 0xFFFFFFFF; for (var i = 0; i < d.length; i++) c = CT[(c ^ d[i]) & 255] ^ (c >>> 8); return ((c ^ 0xFFFFFFFF) >>> 0); }\r\n  function segCrc(s) { if (s.crc == null) s.crc = crc32(s.data); return s.crc; }\r\n  function b64e(u) { var s = '', C = 0x8000; for (var i = 0; i < u.length; i += C) s += String.fromCharCode.apply(null, u.subarray(i, i + C)); return btoa(s); }\r\n  function b64d(b) { var s = atob(b), u = new Uint8Array(s.length); for (var i = 0; i < s.length; i++) u[i] = s.charCodeAt(i); return u; }\r\n\r\n  \/* ---------- storia (annulla\/ripeti) ---------- *\/\r\n  function snap() { return { segs: P.segs.slice(), names: P.segs.map(function (s) { return s.name; }), rom: P.rom, fill: P.fill, sel: sel }; }\r\n  function restore(st) { P.segs = st.segs.slice(); P.segs.forEach(function (s, i) { s.name = st.names[i]; }); P.rom = st.rom; P.fill = st.fill; sel = st.sel; }\r\n  function act(fn) { var before = snap(); fn(); undo.push({ k: 's', a: before, b: snap() }); if (undo.length > 200) undo.shift(); redo = []; changed(); }\r\n  function doUndo(r) {\r\n    var A = r ? redo : undo, B = r ? undo : redo, h = A.pop(); if (!h) return;\r\n    if (h.k === 's') restore(r ? h.b : h.a);\r\n    else { var s = h.seg; s.data[h.off] = r ? h.nv : h.ov; s.crc = null; s.mod = Math.max(0, (s.mod | 0) + (r ? 1 : -1)); if (P.segs.indexOf(s) >= 0) { sel = s.id; } }\r\n    B.push(h); changed(); if (h.k === 'b') { jumpTo(h); }\r\n  }\r\n  function jumpTo(h) { var o = view === 'all' ? starts()[P.segs.indexOf(h.seg)] + h.off : h.off; if (view === 'seg' && sel !== h.seg.id) return; cur = o; scrollTo(o); drawHex(); }\r\n\r\n  \/* ---------- salvataggio automatico ---------- *\/\r\n  function serialize(compact) {\r\n    return JSON.stringify({ app: 'RetroFixer ROM Creator', v: 2, name: P.name, romType: P.rom, fillType: P.fill,\r\n      segments: P.segs.map(function (s) { return { id: s.id, name: s.name, type: s.type, size: s.data.length, fill: s.fill, mod: s.mod, b64: b64e(s.data) }; }) }, null, compact ? 0 : 1);\r\n  }\r\n  function load(txt) {\r\n    var j = JSON.parse(txt); if (!j || !Array.isArray(j.segments)) throw new Error('formato');\r\n    P.name = j.name || 'Progetto'; P.rom = chip(j.romType).length ? chip(j.romType)[0] : '27C256'; P.fill = typeof j.fillType === 'number' ? j.fillType & 255 : 255;\r\n    P.segs = j.segments.map(function (s) {\r\n      var d = s.b64 != null ? b64d(s.b64) : new Uint8Array(Array.isArray(s.data) ? s.data : Object.keys(s.data || {}).map(function (k) { return s.data[k]; }));\r\n      var o = mk(s.name || 'ROM', s.type === 'blank' ? 'blank' : 'file', d, s.fill != null ? s.fill : (s.type === 'blank' ? d[0] : undefined)); o.mod = s.mod ? (+s.mod || 1) : 0; return o;\r\n    });\r\n    sel = P.segs.length ? P.segs[0].id : null; undo = []; redo = []; cur = 0; nib = -1;\r\n  }\r\n  var saveT;\r\n  function autosave() {\r\n    clearTimeout(saveT); saveT = setTimeout(function () {\r\n      var el = $('rcrSaved');\r\n      try { if (!P.segs.length) localStorage.removeItem(LS); else localStorage.setItem(LS, serialize(true)); el.textContent = P.segs.length ? '\u2714 Salvato nel browser' : ''; el.className = 'saved ok'; }\r\n      catch (e) { el.textContent = '\u26a0 Troppo grande per il salvataggio automatico: usa SALVA'; el.className = 'saved w'; }\r\n    }, 700);\r\n  }\r\n\r\n  \/* ---------- calcoli ---------- *\/\r\n  function starts() { var a = [], o = 0; P.segs.forEach(function (s) { a.push(o); o += s.data.length; }); return a; }\r\n  function locate(o) { var st = starts(); for (var i = P.segs.length - 1; i >= 0; i--) if (o >= st[i]) return o < st[i] + P.segs[i].data.length ? { s: P.segs[i], i: i, off: o - st[i] } : null; return null; }\r\n  function insIndex() { var i = P.segs.findIndex(function (s) { return s.id === sel; }); return i < 0 ? P.segs.length : i + 1; }\r\n  function insOffset() { var i = insIndex(), o = 0; for (var k = 0; k < i; k++) o += P.segs[k].data.length; return o; }\r\n  function content() { var t = total(), u = new Uint8Array(t), o = 0; P.segs.forEach(function (s) { u.set(s.data, o); o += s.data.length; }); return u; }\r\n  function image(u) {\r\n    var R = romSize(), out = new Uint8Array(R); out.fill(P.fill);\r\n    if ($('rcrMirror').checked && u.length && u.length < R) { for (var o = 0; o < R; o += u.length) out.set(u.subarray(0, Math.min(u.length, R - o)), o); }\r\n    else out.set(u.subarray(0, R));\r\n    return out;\r\n  }\r\n\r\n  \/* ---------- disegno ---------- *\/\r\n  function changed() { render(); autosave(); }\r\n  function render() { drawChips(); drawStats(); drawMap(); drawList(); drawBlank(); drawExport(); drawHexAll(); $('rcrUndo').disabled = !undo.length; $('rcrRedo').disabled = !redo.length; if ($('rcrName').value !== P.name) $('rcrName').value = P.name; }\r\n\r\n  function drawChips() {\r\n    var t = total();\r\n    $('rcrChips').innerHTML = CHIPS.map(function (c) { return '<button class=\"chip' + (c[0] === P.rom ? ' on' : '') + (t && c[2] >= t ? ' fit' : '') + '\" data-rom=\"' + c[0] + '\" title=\"' + esc(BUS[c[3]]) + '\"><b>' + c[1] + (c[3] === 8 ? '' : '<sup>' + (c[3] === 16 ? '16' : '8\/16') + '<\/sup>') + '<\/b><small>' + fmt(c[2]) + ' \u00b7 ' + mbit(c[2]) + '<\/small><\/button>'; }).join('');\r\n    var fs = $('rcrFill'); if (P.fill === 255 || P.fill === 0) { fs.value = String(P.fill); $('rcrFillCw').hidden = true; } else { fs.value = 'custom'; $('rcrFillCw').hidden = false; if (document.activeElement !== $('rcrFillC')) $('rcrFillC').value = hex(P.fill); }\r\n  }\r\n\r\n  function drawStats() {\r\n    var t = total(), R = romSize(), over = t > R;\r\n    $('rcrUsed').textContent = fmt(t); $('rcrFree').textContent = over ? '\u2212' + fmt(t - R) : fmt(R - t); $('rcrTot').textContent = fmt(R);\r\n    $('rcrPct').textContent = (t \/ R * 100).toFixed(t && t \/ R < .1 ? 1 : 0).replace('.', ',') + '%';\r\n    $('rcrGauge').className = 'gauge' + (over ? ' over' : ''); $('rcrGauge').firstChild.style.width = Math.min(100, t \/ R * 100) + '%';\r\n    var h = '';\r\n    if (!t) h = '<div class=\"msg\">Aggiungi un file ROM per iniziare: trascinalo nel riquadro o usa <b>SFOGLIA<\/b>.<\/div>';\r\n    else if (over) {\r\n      var fit = CHIPS.filter(function (c) { return c[2] >= t && c[3] !== 16; })[0];\r\n      h = '<div class=\"msg warn\">Il contenuto supera la ' + chip(P.rom)[1] + ' di <b>' + fmt(t - R) + '<\/b>. Togli qualcosa, scegli una EPROM pi\u00f9 grande o esporta in ' + Math.ceil(t \/ R) + ' parti.' + (fit ? '<br><button class=\"btn s y\" data-rom=\"' + fit[0] + '\">USA ' + fit[1] + ' (' + fmt(fit[2]) + ')<\/button>' : '') + '<\/div>';\r\n    } else {\r\n      var small = CHIPS.filter(function (c) { return c[2] >= t && c[3] !== 16; })[0];\r\n      h = '<div class=\"msg ok\">Ci sta! ' + (t === R ? 'La EPROM \u00e8 piena al byte.' : 'Restano <b>' + fmtB(R - t) + '<\/b> riempiti con $' + hex(P.fill) + '.') + (small && small[2] < R ? ' Basterebbe anche una <b>' + small[1] + '<\/b>.' : '') + '<\/div>';\r\n    }\r\n    var bus = chip(P.rom)[3];\r\n    if (bus === 'b') h += '<div class=\"msg\">La <b>' + chip(P.rom)[1] + '<\/b> lavora a 8 o a 16 bit. Per un bus a 8 bit metti il piedino <b>BYTE<\/b> a GND: il piedino <b>Q15\/A-1<\/b> diventa l\\'indirizzo pi\u00f9 basso e la vedi come una memoria da ' + fmt(romSize()) + ' a 8 bit.<\/div>';\r\n    else if (bus === 16) h += '<div class=\"msg warn\">La <b>27C322<\/b> funziona <b>solo a 16 bit<\/b>. Per un computer a 8 bit la pi\u00f9 grande \u00e8 la <b>27C160<\/b> in modalit\u00e0 8 bit (2 MB), oppure la <b>27C080<\/b> (1 MB) che \u00e8 solo a 8 bit.<\/div>';\r\n    $('rcrFit').innerHTML = h;\r\n  }\r\n\r\n  function bankOptions() {\r\n    var R = romSize(), opts = [0], files = P.segs.filter(function (s) { return s.type === 'file'; });\r\n    for (var b = 512; b <= R \/ 2; b *= 2) opts.push(b);\r\n    var auto = 0; if (files.length) { var m = files[0].data.length; if (files.every(function (s) { return s.data.length === m; }) && pow2(m) && m <= R \/ 2 && R \/ m <= 64) auto = m; }\r\n    return { opts: opts, auto: auto };\r\n  }\r\n  function drawMap() {\r\n    var R = romSize(), t = total(), span = Math.max(R, t) || 1, st = starts(), bo = bankOptions();\r\n    var bs = $('rcrBank'), want = bankSize === -1 ? bo.auto : bankSize;\r\n    if (bo.opts.indexOf(want) < 0) want = 0;\r\n    bs.innerHTML = bo.opts.map(function (b) { return '<option value=\"' + b + '\"' + (b === want ? ' selected' : '') + '>' + (b ? fmt(b) : 'nessuno') + (b && b === bo.auto ? ' (auto)' : '') + '<\/option>'; }).join('');\r\n    var h = '';\r\n    P.segs.forEach(function (s, i) {\r\n      var l = st[i] \/ span * 100, w = s.data.length \/ span * 100;\r\n      h += '<div class=\"sg' + (s.type === 'blank' ? ' blank' : '') + (s.id === sel ? ' on' : '') + '\" data-sel=\"' + s.id + '\" style=\"left:' + l + '%;width:' + w + '%;background:' + color(s) + '\" title=\"' + esc(s.name) + ' \u00b7 $' + hex(st[i], hw()) + '\u2013$' + hex(st[i] + s.data.length - 1, hw()) + '\">' + (w > 7 ? esc(s.name.replace(\/\\.[a-z0-9]{1,4}$\/i, '')) : '') + '<\/div>';\r\n    });\r\n    if (t < R) h = '<div class=\"free\" style=\"left:' + (t \/ span * 100) + '%;right:0\"><\/div>' + h;\r\n    if (t > R) h += '<div class=\"ovr\" style=\"left:' + (R \/ span * 100) + '%;right:0\"><\/div><div class=\"end\" style=\"left:calc(' + (R \/ span * 100) + '% - 1px)\"><\/div>';\r\n    var n = want ? R \/ want : 0, lines = Math.log2(n) | 0, low = want ? Math.log2(want) : 0;\r\n    if (n > 1 && n <= 64) for (var k = 1; k < n; k++) h += '<div class=\"bk\" style=\"left:' + (k * want \/ span * 100) + '%\"><\/div>';\r\n    $('rcrMap').innerHTML = h;\r\n    var r = '<span class=\"a0\" style=\"left:0\">$' + hex(0, hw()) + '<\/span><span class=\"a1\" style=\"left:' + (R \/ span * 100) + '%\">$' + hex(R - 1, hw()) + '<\/span>';\r\n    if (n > 1 && n <= 16) { r = ''; for (k = 0; k < n; k++) r += '<span style=\"left:' + ((k + .5) * want \/ span * 100) + '%\"><b>' + k.toString(2).padStart(lines, '0') + '<\/b>' + (n <= 8 ? '$' + hex(k * want, hw()) : '') + '<\/span>'; }\r\n    $('rcrRuler').innerHTML = r;\r\n    var names = []; for (k = 0; k < lines; k++) names.unshift('A' + (low + k));\r\n    $('rcrBanks').innerHTML = n > 1 ? '<b>' + n + ' banchi da ' + fmt(want) + '<\/b> selezionati dai piedini <b>' + names.join(' ') + '<\/b> (in quest\\'ordine nei numeri blu): 0 = GND, 1 = +5V. ' + (n > 16 ? 'Troppi banchi per scriverli tutti, conviene un selettore a microcontrollore.' : '') : 'Scegli la grandezza di un banco per vedere quale combinazione di indirizzi seleziona ogni immagine.';\r\n  }\r\n\r\n  function drawList() {\r\n    var st = starts(), R = romSize(), w = hw();\r\n    if (!P.segs.length) { $('rcrList').innerHTML = '<p class=\"empty\">Nessun pezzo ancora. Trascina qui sopra i file ROM.<\/p>'; return; }\r\n    $('rcrList').innerHTML = P.segs.map(function (s, i) {\r\n      var a = st[i], e = a + s.data.length - 1, tags = '';\r\n      if (s.type === 'blank') tags += '<span class=\"tag bl\">VUOTO $' + hex(s.fill == null ? s.data[0] : s.fill) + '<\/span>';\r\n      else if (!pow2(s.data.length)) tags += '<span class=\"tag ns\">MISURA NON STANDARD<\/span>';\r\n      if (s.mod) tags += '<span class=\"tag md\">MODIFICATO<\/span>';\r\n      if (e >= R) tags += '<span class=\"tag ov\">FUORI EPROM<\/span>';\r\n      return '<div class=\"seg' + (s.id === sel ? ' on' : '') + '\" data-id=\"' + s.id + '\">' +\r\n        '<span class=\"hd\" title=\"Trascina per spostare\">\u22ee\u22ee<\/span><span class=\"sw\" style=\"background:' + color(s) + '\"><\/span>' +\r\n        '<div class=\"bd\" data-sel=\"' + s.id + '\"><input class=\"nm\" value=\"' + esc(s.name) + '\" data-nm=\"' + s.id + '\" aria-label=\"Nome\">' +\r\n        '<div class=\"mt\"><span class=\"ad\">$' + hex(a, w) + '\u2013$' + hex(e, w) + '<\/span><span>' + fmt(s.data.length) + '<\/span>' + (s.type === 'file' ? '<span class=\"ck\">CRC ' + hex(segCrc(s), 8) + '<\/span>' : '') + tags + '<\/div><\/div>' +\r\n        '<div class=\"ac\"><button class=\"ib\" data-up=\"' + s.id + '\" title=\"Su\"' + (i ? '' : ' disabled') + '>\u25b2<\/button><button class=\"ib\" data-dn=\"' + s.id + '\" title=\"Gi\u00f9\"' + (i < P.segs.length - 1 ? '' : ' disabled') + '>\u25bc<\/button>' +\r\n        '<button class=\"ib\" data-dup=\"' + s.id + '\" title=\"Duplica\">\u29c9<\/button><button class=\"ib\" data-sv=\"' + s.id + '\" title=\"Scarica solo questo pezzo\">\u2b07<\/button><button class=\"ib x\" data-del=\"' + s.id + '\" title=\"Elimina\">\u2715<\/button><\/div><\/div>';\r\n    }).join('');\r\n  }\r\n\r\n  function blankSize() {\r\n    var o = insOffset();\r\n    if (blMode === 'size') { var v = $('rcrBlSize').value; return v === 'custom' ? num($('rcrBlC').value) : +v; }\r\n    if (blMode === 'to') { var t = num($('rcrBlTo').value); return isNaN(t) ? NaN : t - o; }\r\n    var al = +$('rcrBlAl').value; return (al - o % al) % al;\r\n  }\r\n  function drawBlank() {\r\n    var R = romSize(), sz = $('rcrBlSize'), al = $('rcrBlAl');\r\n    if (!sz.options.length) {\r\n      var h = ''; [256, 512, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512].forEach(function (v, i) { var b = i < 2 ? v : v * KB; h += '<option value=\"' + b + '\"' + (b === 4 * KB ? ' selected' : '') + '>' + fmt(b) + '<\/option>'; });\r\n      sz.innerHTML = h + '<option value=\"custom\">Personalizzata...<\/option>';\r\n      h = ''; [256, 512, 1 * KB, 2 * KB, 4 * KB, 8 * KB, 16 * KB, 32 * KB, 64 * KB].forEach(function (b) { h += '<option value=\"' + b + '\"' + (b === 8 * KB ? ' selected' : '') + '>' + fmt(b) + '<\/option>'; });\r\n      al.innerHTML = h;\r\n    }\r\n    $('rcrBlCw').hidden = sz.value !== 'custom';\r\n    var n = blankSize(), o = insOffset(), w = hw(), p = $('rcrBlPrev');\r\n    if (isNaN(n) || n < 0) { p.className = 'prev w'; p.textContent = blMode === 'to' ? '\u2715 L\\'indirizzo \u00e8 prima di $' + hex(o, w) + ', dove inizierebbe il vuoto' : '\u2715 Valore non valido'; }\r\n    else if (n === 0) { p.className = 'prev'; p.textContent = '\u2714 Gi\u00e0 allineato a $' + hex(o, w) + ': non serve spazio'; }\r\n    else { p.className = 'prev' + (o + n > R ? ' w' : ''); p.textContent = '\u25b8 ' + fmtB(n) + ' da $' + hex(o, w) + ' a $' + hex(o + n - 1, w) + (o + n > R ? ' (supera la EPROM)' : ''); }\r\n  }\r\n\r\n  function drawExport() {\r\n    var R = romSize(), t = total(), b16 = chip(P.rom)[3] !== 8;\r\n    $('rcrOMir').className = 'opt' + (t && t < R ? '' : ' off');\r\n    $('rcrOSwap').className = 'opt' + (b16 ? '' : ' off'); if (!b16) $('rcrSwap').checked = false;\r\n    if (!t) { $('rcrCrc').textContent = 'CRC32 \u2014'; return; }\r\n    if (t > R) { $('rcrCrc').textContent = 'Contenuto pi\u00f9 grande della EPROM: verranno create ' + Math.ceil(t \/ R) + ' parti'; return; }\r\n    var img = image(content()); if ($('rcrSwap').checked) swap(img);\r\n    var sum = 0; for (var i = 0; i < img.length; i++) sum = (sum + img[i]) & 0xFFFF;\r\n    $('rcrCrc').textContent = 'CRC32 ' + hex(crc32(img), 8) + ' \u00b7 SOMMA $' + hex(sum, 4) + ' \u00b7 ' + fmtB(img.length) + ($('rcrMirror').checked && t < R && R % t ? ' \u00b7 \u26a0 ' + fmt(t) + ' non sta un numero intero di volte: l\\'ultima copia \u00e8 tagliata' : '');\r\n  }\r\n  function swap(u) { for (var i = 0; i + 1 < u.length; i += 2) { var x = u[i]; u[i] = u[i + 1]; u[i + 1] = x; } return u; }\r\n\r\n  \/* ---------- editor esadecimale (virtuale) ---------- *\/\r\n  var ROWH = 22;\r\n  function bpr() { return $('rcrHx').clientWidth < 560 ? 8 : 16; }\r\n  function vlen() { if (view === 'all') return Math.max(romSize(), total()); var s = segById(sel); return s ? s.data.length : 0; }\r\n  function drawHexAll() {\r\n    var s = segById(sel), t = $('rcrHxT');\r\n    if (view === 'seg') t.innerHTML = s ? 'Stai modificando <b>' + esc(s.name) + '<\/b> \u00b7 ' + fmtB(s.data.length) + (s.type === 'blank' ? ' (spazio vuoto)' : '') : 'Seleziona un pezzo dalla lista per vederne il contenuto.';\r\n    else t.innerHTML = 'Immagine completa: <b>' + fmtB(Math.max(romSize(), total())) + '<\/b>. I byte grigi sono il riempimento ($' + hex(P.fill) + '), quelli rossi finiscono oltre la EPROM.';\r\n    var n = bpr(), h = '<span>INDIRIZZO<\/span><span>'; for (var i = 0; i < n; i++) h += '<i style=\"display:inline-block;width:2.05ch;text-align:center;margin-right:' + ((i + 1) % 8 ? '.55ch' : '1.4ch') + ';font-style:normal\">' + hex(i, 1) + '<\/i>'; $('rcrHxHd').innerHTML = h + '<\/span><span>ASCII<\/span>';\r\n    var len = vlen(); if (cur >= len) cur = Math.max(0, len - 1);\r\n    $('rcrHxS').style.height = Math.ceil(len \/ n) * ROWH + 'px';\r\n    fitHex(); drawHex();\r\n  }\r\n  \/* su schermo largo l'editor si allunga fino al fondo della colonna sinistra, cosi' non resta un buco *\/\r\n  function fitHex() {\r\n    var hx = $('rcrHx'), l = root.querySelector('.col.l'), r = root.querySelector('.grid>.col:not(.l)');\r\n    if (window.innerWidth <= 1024) { hx.style.height = ''; return; }\r\n    var cur = hx.clientHeight, diff = l.getBoundingClientRect().bottom - r.getBoundingClientRect().bottom;\r\n    hx.style.height = Math.max(440, Math.min(1100, Math.round((cur + diff) \/ ROWH) * ROWH)) + 'px';\r\n  }\r\n  function drawHex() {\r\n    var hx = $('rcrHx'), n = bpr(), len = vlen(), w = view === 'all' ? hw() : Math.max(4, (len - 1).toString(16).length);\r\n    var first = Math.max(0, Math.floor(hx.scrollTop \/ ROWH) - 4), rows = Math.ceil(hx.clientHeight \/ ROWH) + 8, last = Math.min(Math.ceil(len \/ n), first + rows);\r\n    var st = view === 'all' ? starts() : null, h = '';\r\n    for (var r = first; r < last; r++) {\r\n      var base = r * n, hs = '', ts = '', bc = 'transparent';\r\n      if (view === 'all') { var L0 = locate(base); if (L0) bc = color(L0.s); }\r\n      else { var s0 = segById(sel); if (s0) bc = color(s0); }\r\n      for (var c = 0; c < n; c++) {\r\n        var o = base + c; if (o >= len) break;\r\n        var b = view === 'seg' ? { v: segById(sel).data[o], cls: '' } : (function (o) { var L = locate(o); return L ? { v: L.s.data[L.off], cls: o >= romSize() ? 'o' : '' } : { v: P.fill, cls: 'p' }; })(o);\r\n        var cl = b.cls || (b.v === 0 || b.v === 255 ? 'z' : '');\r\n        if (o === cur) cl += ' c' + (nib >= 0 ? ' n' : '');\r\n        if (fnd && o >= fnd[0] && o < fnd[0] + fnd[1]) cl += ' f';\r\n        hs += '<i data-o=\"' + o + '\" class=\"' + cl + '\">' + (o === cur && nib >= 0 ? hex(nib, 1) + '_' : hex(b.v)) + '<\/i>';\r\n        ts += '<i data-o=\"' + o + '\" class=\"' + cl + '\">' + (b.v >= 32 && b.v < 127 ? esc(String.fromCharCode(b.v)) : '.') + '<\/i>';\r\n      }\r\n      h += '<div class=\"hxrow\" style=\"position:absolute;left:0;right:0;top:' + (r * ROWH) + 'px\"><span class=\"a\" style=\"border-left-color:' + bc + '\">' + hex(base, w) + '<\/span><span class=\"h\">' + hs + '<\/span><span class=\"t\">' + ts + '<\/span><\/div>';\r\n    }\r\n    if (!len) h = '<div style=\"padding:30px;text-align:center;color:#6f68a8;font-family:Inter,sans-serif;font-size:14px\">' + (view === 'seg' ? 'Nessun pezzo selezionato' : 'Progetto vuoto') + '<\/div>';\r\n    $('rcrHxR').innerHTML = h;\r\n    drawEd();\r\n  }\r\n  function curByte() { if (!vlen()) return null; if (view === 'seg') { var s = segById(sel); return { s: s, off: cur, v: s.data[cur] }; } var L = locate(cur); return L ? { s: L.s, off: L.off, v: L.s.data[L.off] } : { s: null, v: P.fill }; }\r\n  function drawEd() {\r\n    var b = curByte(), el = $('rcrHxEd');\r\n    if (!b) { el.innerHTML = '\u2014'; return; }\r\n    var w = view === 'all' ? hw() : 4, ae = document.activeElement && document.activeElement.id === 'rcrVal';\r\n    if (ae) return;\r\n    el.innerHTML = 'OFFSET <b>$' + hex(cur, w) + '<\/b> (' + cur + ')' + (view === 'all' && b.s ? ' \u00b7 ' + esc(b.s.name) + ' +$' + hex(b.off, 4) : '') + (view === 'all' && !b.s ? ' \u00b7 riempimento' : '') +\r\n      ' \u00b7 <b>' + b.v + '<\/b> \u00b7 %' + b.v.toString(2).padStart(8, '0') + ' <label>VALORE $<input class=\"txt mono\" id=\"rcrVal\" maxlength=\"2\" value=\"' + hex(b.v) + '\"' + (b.s ? '' : ' disabled') + '><\/label>';\r\n  }\r\n  function setByte(o, v) {\r\n    var L = view === 'seg' ? { s: segById(sel), off: o } : locate(o); if (!L || !L.s) { toast('Questo \u00e8 riempimento: aggiungi uno spazio vuoto per poterlo modificare', true); return false; }\r\n    var ov = L.s.data[L.off]; if (ov === v) return true;\r\n    L.s.data[L.off] = v; L.s.crc = null; L.s.mod = (L.s.mod | 0) + 1; undo.push({ k: 'b', seg: L.s, off: L.off, ov: ov, nv: v }); redo = [];\r\n    return true;\r\n  }\r\n  function afterEdit() { drawHex(); drawList(); drawExport(); $('rcrUndo').disabled = !undo.length; $('rcrRedo').disabled = true; autosave(); }\r\n  function scrollTo(o) { var hx = $('rcrHx'), y = Math.floor(o \/ bpr()) * ROWH; if (y < hx.scrollTop) hx.scrollTop = y; else if (y + ROWH > hx.scrollTop + hx.clientHeight) hx.scrollTop = y - hx.clientHeight + ROWH * 2; }\r\n  function move(d) { var len = vlen(); if (!len) return; cur = Math.max(0, Math.min(len - 1, cur + d)); nib = -1; scrollTo(cur); drawHex(); }\r\n\r\n  var fnd = null;\r\n  function find() {\r\n    var q = $('rcrFind').value.trim(); if (!q) return; var pat;\r\n    if (q[0] === '\"' || q[0] === \"'\") { var s = q.replace(\/^[\"']|[\"']$\/g, ''); pat = []; for (var i = 0; i < s.length; i++) pat.push(s.charCodeAt(i) & 255); }\r\n    else { var hx = q.replace(\/[\\s$,]\/g, ''); if (!\/^([0-9a-f]{2})+$\/i.test(hx)) { toast('Scrivi byte esadecimali (A9 00) o un testo tra virgolette', true); return; } pat = hx.match(\/..\/g).map(function (x) { return parseInt(x, 16); }); }\r\n    var len = vlen(), get = view === 'seg' ? (function (d) { return function (o) { return d[o]; }; })(segById(sel) ? segById(sel).data : []) : (function (u, f) { return function (o) { return o < u.length ? u[o] : f; }; })(content(), P.fill);\r\n    var from = fnd && fnd[0] === cur ? cur + 1 : cur;\r\n    for (var pass = 0; pass < 2; pass++) {\r\n      for (var o = pass ? 0 : from; o + pat.length <= len; o++) { var k = 0; while (k < pat.length && get(o + k) === pat[k]) k++; if (k === pat.length) { fnd = [o, pat.length]; cur = o; nib = -1; scrollTo(o); drawHex(); return; } }\r\n    }\r\n    fnd = null; drawHex(); toast('Non trovato', true);\r\n  }\r\n\r\n  \/* ---------- azioni ---------- *\/\r\n  function addFiles(list) {\r\n    var arr = [].slice.call(list || []); if (!arr.length) return;\r\n    var proj = arr.filter(function (f) { return \/\\.(romproj|json)$\/i.test(f.name); });\r\n    if (proj.length) { readText(proj[0]); return; }\r\n    Promise.all(arr.map(function (f) { return f.arrayBuffer().then(function (b) { return { n: f.name, d: new Uint8Array(b) }; }); })).then(function (rs) {\r\n      rs = rs.filter(function (r) { return r.d.length; }); if (!rs.length) { toast('File vuoto', true); return; }\r\n      act(function () { var at = insIndex(), ns = rs.map(function (r) { return mk(r.n, 'file', r.d); }); P.segs.splice.apply(P.segs, [at, 0].concat(ns)); sel = ns[ns.length - 1].id; });\r\n      if (view === 'seg') { cur = 0; $('rcrHx').scrollTop = 0; drawHexAll(); }\r\n      toast(rs.length > 1 ? rs.length + ' file aggiunti' : '\u00ab' + rs[0].n + '\u00bb aggiunto (' + fmt(rs[0].d.length) + ')');\r\n    }).catch(function () { toast('Impossibile leggere il file', true); });\r\n  }\r\n  function readText(f) {\r\n    f.text().then(function (t) {\r\n      try { var before = snap(); load(t); undo = [{ k: 's', a: before, b: snap() }]; $('rcrHx').scrollTop = 0; render(); autosave(); toast('Progetto \u00ab' + P.name + '\u00bb aperto'); }\r\n      catch (e) { toast('Questo file non \u00e8 un progetto ROM Creator valido', true); }\r\n    });\r\n  }\r\n  function download(data, name, type) {\r\n    var b = new Blob([data], { type: type || 'application\/octet-stream' }), u = URL.createObjectURL(b), a = document.createElement('a');\r\n    a.href = u; a.download = name; document.body.appendChild(a); a.click(); a.remove(); setTimeout(function () { URL.revokeObjectURL(u); }, 4000);\r\n  }\r\n  function fname() { return (P.name || 'rom').trim().replace(\/[^\\w\\-]+\/g, '_').replace(\/^_+|_+$\/g, '') || 'rom'; }\r\n  function doExport() {\r\n    var t = total(), R = romSize(); if (!t) { toast('Non c\\'\u00e8 niente da esportare', true); return; }\r\n    var u = content(), parts = [], base = fname() + '_' + P.rom;\r\n    if (t > R) { var n = Math.ceil(t \/ R); if (!confirm('Il contenuto (' + fmt(t) + ') non entra in una ' + chip(P.rom)[1] + ' (' + fmt(R) + ').\\nScaricare ' + n + ' file separati?')) return; for (var i = 0; i < n; i++) { var p = new Uint8Array(R); p.fill(P.fill); p.set(u.subarray(i * R, Math.min(t, (i + 1) * R))); parts.push([p, base + '_parte' + (i + 1) + '.bin']); } }\r\n    else parts.push([image(u), base + '.bin']);\r\n    parts.forEach(function (p, k) {\r\n      var d = p[0]; if ($('rcrSwap').checked) swap(d);\r\n      if ($('rcrEo').checked) { var ev = new Uint8Array(d.length >> 1), od = new Uint8Array(d.length >> 1); for (var i = 0; i < ev.length; i++) { ev[i] = d[2 * i]; od[i] = d[2 * i + 1]; } setTimeout(function () { download(ev, p[1].replace('.bin', '_pari.bin')); }, k * 600); setTimeout(function () { download(od, p[1].replace('.bin', '_dispari.bin')); }, k * 600 + 300); }\r\n      else setTimeout(function () { download(d, p[1]); }, k * 400);\r\n    });\r\n    toast('File .bin pronto' + (parts.length > 1 ? ': ' + parts.length + ' parti' : ''));\r\n  }\r\n\r\n  root.addEventListener('click', function (e) {\r\n    var t = e.target, a = t.closest('[data-a]'), q;\r\n    if ((q = t.closest('[data-rom]'))) { var id = q.getAttribute('data-rom'); if (id !== P.rom) act(function () { P.rom = id; }); return; }\r\n    if ((q = t.closest('[data-bm]'))) { blMode = q.getAttribute('data-bm'); [].forEach.call(root.querySelectorAll('[data-bm]'), function (b) { b.classList.toggle('on', b === q); }); [].forEach.call(root.querySelectorAll('[data-bp]'), function (p) { p.hidden = p.getAttribute('data-bp') !== blMode; }); drawBlank(); return; }\r\n    if ((q = t.closest('[data-v]'))) { view = q.getAttribute('data-v'); [].forEach.call(root.querySelectorAll('[data-v]'), function (b) { b.classList.toggle('on', b === q); }); if (view === 'all') { var s = segById(sel); cur = s ? starts()[P.segs.indexOf(s)] : 0; } else cur = 0; nib = -1; fnd = null; drawHexAll(); scrollTo(cur); drawHex(); return; }\r\n    if ((q = t.closest('[data-up],[data-dn]'))) { var up = q.hasAttribute('data-up'), id2 = q.getAttribute(up ? 'data-up' : 'data-dn'); act(function () { var i = P.segs.indexOf(segById(id2)), j = i + (up ? -1 : 1); var x = P.segs.splice(i, 1)[0]; P.segs.splice(j, 0, x); sel = id2; }); return; }\r\n    if ((q = t.closest('[data-dup]'))) { var s1 = segById(q.getAttribute('data-dup')); act(function () { var c = mk(s1.name.replace(\/(\\.[a-z0-9]{1,4})?$\/i, ' (copia)$1'), s1.type, new Uint8Array(s1.data), s1.fill); c.mod = s1.mod; P.segs.splice(P.segs.indexOf(s1) + 1, 0, c); sel = c.id; }); return; }\r\n    if ((q = t.closest('[data-sv]'))) { var s2 = segById(q.getAttribute('data-sv')); download(s2.data, s2.type === 'blank' ? 'vuoto_' + s2.data.length + '.bin' : s2.name.replace(\/(\\.[a-z0-9]{1,4})?$\/i, s2.mod ? '_mod$1' : '$1') || 'pezzo.bin'); return; }\r\n    if ((q = t.closest('[data-del]'))) { var s3 = segById(q.getAttribute('data-del')); act(function () { var i = P.segs.indexOf(s3); P.segs.splice(i, 1); if (sel === s3.id) sel = P.segs.length ? P.segs[Math.min(i, P.segs.length - 1)].id : null; }); toast('\u00ab' + s3.name + '\u00bb eliminato \u00b7 Ctrl+Z per annullare'); return; }\r\n    if ((q = t.closest('[data-sel]')) && !t.closest('input')) { var ns = q.getAttribute('data-sel'); if (ns !== sel) { sel = ns; if (view === 'seg') { cur = 0; nib = -1; fnd = null; $('rcrHx').scrollTop = 0; } else { cur = starts()[P.segs.indexOf(segById(ns))]; scrollTo(cur); } render(); } return; }\r\n    if (t.closest('#rcrDrop')) { $('rcrFiles').click(); return; }\r\n    var hb = t.closest('.hxrow i[data-o]'); if (hb) { cur = +hb.getAttribute('data-o'); nib = -1; drawHex(); $('rcrHx').focus({ preventScroll: true }); return; }\r\n    if (!a) return;\r\n    var k = a.getAttribute('data-a');\r\n    if (k === 'new') { if (P.segs.length && !confirm('Svuotare il progetto? (puoi tornare indietro con Annulla)')) return; act(function () { P.segs = []; sel = null; P.name = 'Nuovo progetto'; }); }\r\n    else if (k === 'open') $('rcrOpen').click();\r\n    else if (k === 'save') { if (!P.segs.length) { toast('Il progetto \u00e8 vuoto', true); return; } download(serialize(false), fname() + '.romproj', 'application\/json'); toast('Progetto salvato'); }\r\n    else if (k === 'export') doExport();\r\n    else if (k === 'undo') doUndo(false);\r\n    else if (k === 'redo') doUndo(true);\r\n    else if (k === 'find') find();\r\n    else if (k === 'blank') {\r\n      var n = blankSize(), f = +$('rcrBlFill').value; if (isNaN(n) || n < 0) { toast('Controlla il valore dello spazio vuoto', true); return; } if (!n) { toast('Gi\u00e0 allineato: nessuno spazio da aggiungere'); return; }\r\n      if (n > 16 * KB * KB) { toast('Spazio troppo grande', true); return; }\r\n      act(function () { var d = new Uint8Array(n); d.fill(f); var s = mk('Spazio vuoto ' + fmt(n), 'blank', d, f); P.segs.splice(insIndex(), 0, s); sel = s.id; });\r\n      toast('Aggiunti ' + fmtB(n) + ' di $' + hex(f));\r\n    }\r\n  });\r\n\r\n  root.addEventListener('change', function (e) {\r\n    var t = e.target;\r\n    if (t.id === 'rcrFiles') { addFiles(t.files); t.value = ''; }\r\n    else if (t.id === 'rcrOpen') { if (t.files[0]) readText(t.files[0]); t.value = ''; }\r\n    else if (t.id === 'rcrFill') { if (t.value === 'custom') { $('rcrFillCw').hidden = false; var v = parseInt($('rcrFillC').value, 16); act(function () { P.fill = isNaN(v) ? 0xEA : v & 255; }); } else act(function () { P.fill = +t.value; }); }\r\n    else if (t.id === 'rcrFillC') { var v2 = parseInt(t.value, 16); if (!isNaN(v2)) act(function () { P.fill = v2 & 255; }); }\r\n    else if (t.id === 'rcrBank') { var b = +t.value; bankSize = b === bankOptions().auto ? -1 : b; drawMap(); }\r\n    else if (t.id === 'rcrBlSize' || t.id === 'rcrBlAl') drawBlank();\r\n    else if (t.id === 'rcrMirror' || t.id === 'rcrSwap' || t.id === 'rcrEo') drawExport();\r\n    else if (t.hasAttribute('data-nm')) { var s = segById(t.getAttribute('data-nm')), nv = t.value.trim() || s.name; if (nv !== s.name) act(function () { s.name = nv; }); }\r\n    else if (t.id === 'rcrName') { P.name = t.value.trim() || 'Nuovo progetto'; autosave(); }\r\n  });\r\n  root.addEventListener('input', function (e) {\r\n    var t = e.target;\r\n    if (t.id === 'rcrBlC' || t.id === 'rcrBlTo') drawBlank();\r\n    else if (t.id === 'rcrName') { P.name = t.value; autosave(); }\r\n    else if (t.id === 'rcrVal' && \/^[0-9a-f]{2}$\/i.test(t.value)) { if (setByte(cur, parseInt(t.value, 16))) { t.blur(); afterEdit(); } }\r\n  });\r\n  root.addEventListener('keydown', function (e) {\r\n    var t = e.target;\r\n    if (t.id === 'rcrGo' && e.key === 'Enter') { var o = num(t.value); if (isNaN(o) || o >= vlen()) { toast('Indirizzo fuori dal campo', true); return; } cur = o; nib = -1; scrollTo(o); drawHex(); }\r\n    else if (t.id === 'rcrFind' && e.key === 'Enter') find();\r\n    else if (t.hasAttribute('data-nm') && e.key === 'Enter') t.blur();\r\n    else if (t.id === 'rcrVal' && e.key === 'Enter') { var v = parseInt(t.value, 16); if (!isNaN(v) && setByte(cur, v & 255)) { t.blur(); afterEdit(); } }\r\n    else if (t.id === 'rcrDrop' && (e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); $('rcrFiles').click(); }\r\n    else if (t.id === 'rcrHx') {\r\n      var n = bpr(), page = Math.floor(t.clientHeight \/ ROWH) * n, k = e.key;\r\n      if (\/^[0-9a-f]$\/i.test(k) && !e.ctrlKey && !e.metaKey && !e.altKey) {\r\n        e.preventDefault(); var d = parseInt(k, 16);\r\n        if (nib < 0) { var b = curByte(); if (!b || !b.s) { toast('Questo \u00e8 riempimento: aggiungi uno spazio vuoto per poterlo modificare', true); return; } nib = d; drawHex(); }\r\n        else { var val = nib * 16 + d; nib = -1; if (setByte(cur, val)) { if (cur < vlen() - 1) { cur++; scrollTo(cur); } afterEdit(); } }\r\n      }\r\n      else if (k === 'ArrowRight') { e.preventDefault(); move(1); } else if (k === 'ArrowLeft') { e.preventDefault(); move(-1); }\r\n      else if (k === 'ArrowDown') { e.preventDefault(); move(n); } else if (k === 'ArrowUp') { e.preventDefault(); move(-n); }\r\n      else if (k === 'PageDown') { e.preventDefault(); move(page); } else if (k === 'PageUp') { e.preventDefault(); move(-page); }\r\n      else if (k === 'Home') { e.preventDefault(); move(e.ctrlKey ? -cur : -(cur % n)); } else if (k === 'End') { e.preventDefault(); move(e.ctrlKey ? vlen() : n - 1 - cur % n); }\r\n      else if (k === 'Escape') { nib = -1; drawHex(); }\r\n    }\r\n  });\r\n  document.addEventListener('keydown', function (e) {\r\n    if (!(e.ctrlKey || e.metaKey) || !root.contains(document.activeElement) && document.activeElement !== document.body) return;\r\n    var tg = document.activeElement; if (tg && \/INPUT|SELECT|TEXTAREA\/.test(tg.tagName)) return;\r\n    var k = e.key.toLowerCase();\r\n    if (k === 'z' && !e.shiftKey) { e.preventDefault(); doUndo(false); } else if (k === 'y' || (k === 'z' && e.shiftKey)) { e.preventDefault(); doUndo(true); }\r\n  });\r\n  $('rcrHx').addEventListener('scroll', function () { if (!drawHex.raf) drawHex.raf = requestAnimationFrame(function () { drawHex.raf = 0; drawHex(); }); });\r\n  var lastBpr = 0; window.addEventListener('resize', function () { var b = bpr(); if (b !== lastBpr) { lastBpr = b; drawHexAll(); } else { fitHex(); drawHex(); } });\r\n\r\n  \/* trascinamento file *\/\r\n  var drop = $('rcrDrop'), dc = 0;\r\n  root.addEventListener('dragenter', function (e) { if (e.dataTransfer && [].indexOf.call(e.dataTransfer.types, 'Files') >= 0) { e.preventDefault(); dc++; drop.classList.add('hot'); } });\r\n  root.addEventListener('dragover', function (e) { if (e.dataTransfer && [].indexOf.call(e.dataTransfer.types, 'Files') >= 0) { e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; } });\r\n  root.addEventListener('dragleave', function () { if (--dc <= 0) { dc = 0; drop.classList.remove('hot'); } });\r\n  root.addEventListener('drop', function (e) { if (!e.dataTransfer || !e.dataTransfer.files.length) return; e.preventDefault(); dc = 0; drop.classList.remove('hot'); addFiles(e.dataTransfer.files); });\r\n\r\n  \/* riordino trascinando la maniglia (mouse e dita) *\/\r\n  var dr = null;\r\n  $('rcrList').addEventListener('pointerdown', function (e) {\r\n    var h = e.target.closest('.hd'); if (!h) return; e.preventDefault();\r\n    var row = h.closest('.seg'); dr = { row: row, id: row.getAttribute('data-id'), y0: e.clientY, pid: e.pointerId };\r\n    row.classList.add('drag'); document.documentElement.style.userSelect = 'none';\r\n  });\r\n  document.addEventListener('pointermove', function (e) {\r\n    if (!dr || e.pointerId !== dr.pid) return; e.preventDefault();\r\n    var list = $('rcrList'), row = dr.row, moved = true;\r\n    function place() { row.style.transform = 'translateY(' + (e.clientY - dr.y0) + 'px)'; }\r\n    place();\r\n    while (moved) {\r\n      moved = false;\r\n      var r = row.getBoundingClientRect(), mid = r.top + r.height \/ 2, prev = row.previousElementSibling, next = row.nextElementSibling, b = r.top - (e.clientY - dr.y0);\r\n      if (prev && mid < prev.getBoundingClientRect().top + prev.offsetHeight \/ 2) { list.insertBefore(row, prev); moved = true; }\r\n      else if (next && mid > next.getBoundingClientRect().top + next.offsetHeight \/ 2) { list.insertBefore(next, row); moved = true; }\r\n      if (moved) { row.style.transform = ''; dr.y0 += row.getBoundingClientRect().top - b; place(); }\r\n    }\r\n  }, { passive: false });\r\n  function endDrag(e) {\r\n    if (!dr || (e && e.pointerId !== dr.pid)) return; document.documentElement.style.userSelect = '';\r\n    var order = [].map.call($('rcrList').children, function (r) { return r.getAttribute('data-id'); }), id = dr.id; dr = null;\r\n    var same = order.every(function (x, i) { return P.segs[i] && P.segs[i].id === x; });\r\n    if (same) { render(); return; }\r\n    act(function () { P.segs = order.map(segById); sel = id; });\r\n  }\r\n  document.addEventListener('pointerup', endDrag); document.addEventListener('pointercancel', endDrag);\r\n\r\n  \/* avvio *\/\r\n  try { var saved = localStorage.getItem(LS); if (saved) { load(saved); $('rcrSaved').textContent = '\u21ba Ripreso l\\'ultimo progetto'; $('rcrSaved').className = 'saved ok'; } } catch (e) { }\r\n  bankSize = -1; lastBpr = bpr(); render();\r\n  window.rcrDebug = { P: P, content: content, image: image, load: load, serialize: serialize, crc32: crc32, add: function (name, bytes) { act(function () { var s = mk(name, 'file', new Uint8Array(bytes)); P.segs.splice(insIndex(), 0, s); sel = s.id; }); } };\r\n})();\r\n<\/script>\r\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>ROM CREATOR Componi la tua EPROM Trascina qui le immagini ROM (kernal, basic, chargen, cartucce&#8230;), mettile nell&#8217;ordine che vuoi, aggiungi spazi vuoti o allineamenti e guarda<span class=\"excerpt-hellip\"> [\u2026]<\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-11190","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/pages\/11190","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/comments?post=11190"}],"version-history":[{"count":7,"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/pages\/11190\/revisions"}],"predecessor-version":[{"id":11200,"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/pages\/11190\/revisions\/11200"}],"wp:attachment":[{"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/media?parent=11190"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/categories?post=11190"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/retrofixer.it\/en\/wp-json\/wp\/v2\/tags?post=11190"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}