Egy szimulátor mindig hazudik egy kicsit. Nem rosszindulatból — egyszerűen elnéz dolgokat, amiket a valódi szilícium nem. A CLI-CPU mögött 250+ C# teszt és egy teljes cocotb regressziós csomag áll: a referencia-szimulátor zölden futott, a Verilator RTL-szimuláció zölden futott, a Fibonacci(20) végponttól végpontig 6765-öt adott. Papíron kész volt.
Aztán fogtam egy Alinx A7-Lite kártyát egy Xilinx XC7A200T FPGA-val, és kiderült, mit jelent valójában a „kész".
A szimuláció megmondja, hogy a logikád helyes. A hardver megmondja, hogy a logikád valódi.
Mit akartam látni
A cél egyetlen, szándékosan unalmas dolog volt: egy C#-ban írt függvény fusson le natívan, valódi hardveren, JIT, interpreter és operációs rendszer nélkül — és írja ki az eredményt egy soros porton. Ez a CLI-CPU „hello world"-je.
C# (samples/PureMath, Math.FibonacciIterative)
↓ dotnet build (Roslyn)
.dll (CIL bytecode)
↓ TCliCpuLinker
app.t0 (40 byte: 8 header + 32 kód)
↓ openFPGALoader (config-flash @ 0xC00000)
IS25LP128 flash
↓ (FPGA üzem közben olvassa)
cilcpu_core (Fetch → Decode → Microcode → StackCache → ALU)
↓ core_halt, return_value = 6765
decimal_printer → uart_tx (115200 8N1)
↓
"6765\r\n" a soros porton
A teljes láncban egyetlen sornyi C kód vagy firmware sincs. A C# függvény CIL bytecode-ja közvetlenül a szilíciumon fut. Ez a vízió lényege — és pontosan ez tette a bring-upot izgalmassá.
Három bug állt a szilícium és köztem
A „papíron kész" és a „villog a LED, jön a 6765" között három hiba húzódott meg. Mindhárom olyan, amit a szimuláció elnéz, a valódi eszköz viszont nem.
1. A szimulátor megengedőbb, mint a szintézis
Az első igazi Vivado-szintézis három Verilog-szabálysértést dobott ki, amit a Verilator évek óta elnézett:
- Kettős part-select —
BOOT_ARG_COUNT[7:0][4:0], amit a Verilator értelmezett, a szintézer viszont visszautasít. - Hiányzó
begin/endhat többutasításos function-ben — a Verilog-2001 megköveteli, a sim-fordító nem panaszkodott. - BRAM-inferencia: az SRAM-blokkot úgy kellett átírni, hogy a Vivado tisztán 4× RAMB36E1-et ismerjen fel — egy halott kombinációs olvasási ágat, egy rosszul elhelyezett busz-multiplexert és egy async-reset-et kellett kiszedni belőle.
Tanulság: a sim-szintű zöld teszt szükséges, de nem elégséges. A szintézer egy második, szigorúbb lektor — és érdemes minél hamarabb futtatni.
2. Az osztó, ami nem fért bele az órajelbe
A szintézis lefutott, de a timing nem zárt: WNS = −66 ns 50 MHz-en. A kritikus út 329 logikai szint volt, 287 darab CARRY4 egyetlen láncon. A bűnös: a tisztán kombinációs ALU 32-bites előjeles osztása (DIV / REM), amit a szintézer egy 32 szintű kivonó-láncként göngyölített ki.
Itt nem volt felületi javítás — a gyökeret kellett orvosolni. Az egyciklusos kombinációs osztó helyébe egy szekvenciális, 1 bit/ciklus restoring osztó került (~34 ciklus, külön ST_DIV_WAIT állapottal a core-ban, megőrizve a C# osztás-szemantikát: 0 felé csonkítás, a maradék előjele az osztandóé). Az eredmény nem csak timing-zárás, hanem jelentősen kisebb chip is lett:
| Erőforrás | Kombinációs | Iteratív | Változás |
|---|---|---|---|
| Slice LUT | 5 722 | 3 559 | −37,8% |
| CARRY4 | 869 | 302 | −65,2% |
| Slice FF | 1 354 | 1 564 | +15,5% |
A végső build WNS = +2,797 ns margóval zárt 50 MHz-en, nulla bukó endpoint-tal. Klasszikus hardver-trade-off: néhány extra flip-flop és néhány ciklus latencia cserébe a kombinációs robbanásért.
3. A flash, ami nem akart négysávosan beszélni
A legalattomosabb bug a legvégére maradt. A bitstream betöltve, a flash felprogramozva, KEY2 megnyomva — és a soros porton 3\r\n jelent meg. Ez a TRAP_INVALID_OPCODE trap kódja: a core szemetet olvasott a kódmemóriából.
A nyom a flash-hez vezetett. A core a 0x6B Quad Output Read paranccsal olvassa a programot az ISSI IS25LP128 flashből — ehhez a flash QE (Quad Enable) bitjének 1-nek kell lennie. Csakhogy ennek a flash-nek a QE bitje gyárilag 0, az A7-Lite MODE-lábai nincsenek SPIx4-re kötve, így az FPGA startup ROM-ja sem állítja be, és az openFPGALoader --enable-quad sem ismeri ezt a variánst. Négysávos parancs, egysávos flash → tiszta szemét.
A megoldás megint a gyökérnél: a cilcpu_qspi_controller reset után egy WREN (0x06) + WRSR (0x01, 0x40) szekvenciával maga állítja perzisztensen 1-re a flash Status Register QE bitjét. Egy QE_INIT_ENABLE paraméter mögé tettem: a szimulációban 0 (a meglévő tesztek viselkedése változatlan marad), a valódi hardveren 1.
begin/end a szintézernek számított, a timing a valódi órajelnek, a flash QE-bit pedig egy fizikai chip gyári alapállapotának. A szimuláció a logikát ellenőrzi — a hardver a feltételezéseket.
A pillanat
Reset (KEY1), majd start (KEY2). A soros terminál (COM3, 115200 8N1) hat bájtot mutatott:
36 37 36 35 0D 0A = "6765\r\n" = FibonacciIterative(20) = 6765 ✓
Egy C#-ban írt függvény lefordult CIL bytecode-dá, áthaladt a saját linkeremen, leszállt egy flash chipre, és egy általam tervezett processzor — valódi szilíciumon, ~1,1 ms alatt — kiszámolta a helyes választ. Ez a CLI-CPU első igazi életjele a szimuláción túl.
Miért éri meg az FPGA
Ezt a három bugot meg lehetett volna találni a chip legyártása után is. Az viszont drasztikusan másképp néz ki:
| Hol bukik el a hiba | Költség | Iterációs idő |
|---|---|---|
| Szimuláció | ~0 € | másodpercek |
| FPGA | ~0 € (a kártya megvan) | percek (újraflashelés) |
| ASIC tape-out | $1300+ (MPW shuttle) | hónapok |
Ez az F2.7 fázis tétje: nincs tape-out FPGA-validáció nélkül. A flash QE-bug egy néhány soros RTL-javítás volt FPGA-n. Ugyanez egy legyártott chipen egy halott die és egy elveszett shuttle-kör. Az FPGA az a hely, ahol a feltételezések ingyen omlanak össze.
Egy core — és a nagyobb kép
Ez egyetlen Nano core volt, egyetlen kártyán. A CLI-CPU víziója ennél nagyságrendekkel nagyobb: sok kicsi, független core egyetlen chipben, hardveres mailbox-okkal összekötve — a „Cognitive Fabric". A mostani futás ennek a víziónak az első, kézzelfogható alapköve: nem egy diagram, nem egy szimuláció, hanem működő szilícium.
A teljes toolchain működik: C# → CIL-T0 → bitstream → flash → core → UART. Ez a lánc az, ami eddig csak a fejemben és a tesztekben létezett — most egy fizikai eszközön zár be.
Nyílt forráskód
Az RTL, a szimulátor, a linker és a teljes tesztcsomag publikusan elérhető. A bring-up runbook is benne van a repóban.
A szimuláció megmondja, hogy igazad lehet. A hardver megmondja, hogy igazad van. 2026. május 23-án a CLI-CPU átlépte ezt a határt.