code wiki / _hdl_build / nx_fpga_regfile_gate.nx

nx_fpga_regfile_gate.nx source

↩ module page · 112 lines · 6884 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_regfile_gate.nx -- GATE for RUNG 10: a REGISTER FILE on the sequential fabric. Proves the core CPU 4// storage: addressed clocked write + addressed read, x0 hardwired 0, write is CLOCK-EDGE triggered, state HOLDS. 5// T1 ROUNDTRIP+x0 -- write reg1/2/3, read each back; reg0 (x0) always reads 0. 6// T2 HOLD -- an idle clock (we=0) leaves all registers unchanged. 7// T3 CLOCK-EDGE -- staging a write (we=1) but NOT ticking leaves the old value; the value updates only on TICK. 8// T4 SCALES -- an R=8 register file round-trips. 9// T5 NEVER-BRICK -- deterministic; bounded; x0 invariant. 10// T6 LIAR-KILL -- corrupt a write-decode LUT -> a write lands wrong. 11// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL 12import "nx_fpga_regfile.nx" 13import "nx_syscalls.nx" 14 15func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 16" as *u8); return ok } 17 18func main() -> i64 { 19 gw("=== nx_fpga_regfile_gate: RUNG 10 -- a REGISTER FILE on the sequential fabric (CPU storage) ===\n" as *u8) 20 var pass: i64 = 0; var total: i64 = 0 21 22 let kind: *i64 = sys_mmap(8 * 320) as *i64 23 let init: *i64 = sys_mmap(8 * 320) as *i64 24 let src: *i64 = sys_mmap(8 * 1300) as *i64 25 let po: *i64 = sys_mmap(8 * 40) as *i64 26 let q: *i64 = sys_mmap(8 * 320) as *i64 27 let co: *i64 = sys_mmap(8 * 320) as *i64 28 let pi: *i64 = sys_mmap(8 * 24) as *i64 29 30 // ---- R=4, W=8 ---- 31 let R: i64 = 4; let W: i64 = 8; let AB: i64 = 2 32 let npi: i64 = seq_build_regfile(R, W, AB, kind, init, src, po) 33 let nc: i64 = rf_ncells(R, W) 34 var i: i64 = 0 35 while i < nc { q[i] = 0; i = i + 1 } 36 37 // ---- T1: roundtrip + x0 ---- 38 rf_write(R, W, AB, kind, init, src, pi, co, q, 1, 90) // reg1 = 0x5A 39 rf_write(R, W, AB, kind, init, src, pi, co, q, 2, 231) // reg2 = 0xE7 40 rf_write(R, W, AB, kind, init, src, pi, co, q, 3, 60) // reg3 = 0x3C 41 var t1ok: i64 = 1 42 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 1) != 90 { t1ok = 0 } 43 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 2) != 231 { t1ok = 0 } 44 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 3) != 60 { t1ok = 0 } 45 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 0) != 0 { t1ok = 0 } // x0 46 rf_write(R, W, AB, kind, init, src, pi, co, q, 0, 255) // write x0 -> ignored 47 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 0) != 0 { t1ok = 0 } 48 total=total+1; if t1ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 49 gw("T1 write/read roundtrip (reg1=90 reg2=231 reg3=60) + x0 always 0 (write to x0 ignored)\n" as *u8) 50 51 // ---- T2: hold across an idle clock (we=0) ---- 52 var j: i64 = 0 53 while j < AB { pi[j]=0; pi[AB+j]=0; j=j+1 } 54 i = 0; while i < W { pi[2*AB+i]=0; i=i+1 } 55 pi[2*AB+W] = 0 56 seq_tick(nc, npi, kind, init, src, pi, co, q) // idle tick 57 var t2ok: i64 = 1 58 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 1) != 90 { t2ok = 0 } 59 if rf_read(R, W, AB, kind, init, src, pi, co, q, po, 2) != 231 { t2ok = 0 } 60 total=total+1; if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 61 gw("T2 hold: an idle clock (we=0) leaves registers unchanged\n" as *u8) 62 63 // ---- T3: clock-edge -- stage reg1<-170 with we=1 but DON'T tick; old value until TICK ---- 64 pi[0]=1; pi[1]=0 // raddr = 1 65 pi[AB+0]=1; pi[AB+1]=0 // waddr = 1 66 i = 0; while i < W { pi[2*AB+i] = (170 >> i) & 1; i=i+1 }// wdata = 0xAA 67 pi[2*AB+W] = 1 // we = 1 68 seq_eval(nc, npi, kind, init, src, pi, co, q) // settle, NO latch 69 var staged: i64 = 0 70 i = 0; while i < W { staged = staged | ((fab_po(po[i], npi, pi, co) & 1) << i); i=i+1 } 71 seq_tick(nc, npi, kind, init, src, pi, co, q) // NOW latch 72 let after: i64 = rf_read(R, W, AB, kind, init, src, pi, co, q, po, 1) 73 total=total+1; if staged==90 { if after==170 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) } 74 gw("T3 clock-edge: before tick reg1=" as *u8); gn(staged); gw(" (old 90), after tick reg1=" as *u8); gn(after); gw(" (new 170)\n" as *u8) 75 76 // ---- T4: R=8 round-trips ---- 77 let R8: i64 = 8; let AB3: i64 = 3 78 let npi8: i64 = seq_build_regfile(R8, W, AB3, kind, init, src, po) 79 let nc8: i64 = rf_ncells(R8, W) 80 i = 0; while i < nc8 { q[i] = 0; i = i + 1 } 81 rf_write(R8, W, AB3, kind, init, src, pi, co, q, 5, 200) 82 rf_write(R8, W, AB3, kind, init, src, pi, co, q, 7, 99) 83 var t4ok: i64 = 1 84 if rf_read(R8, W, AB3, kind, init, src, pi, co, q, po, 5) != 200 { t4ok = 0 } 85 if rf_read(R8, W, AB3, kind, init, src, pi, co, q, po, 7) != 99 { t4ok = 0 } 86 if rf_read(R8, W, AB3, kind, init, src, pi, co, q, po, 0) != 0 { t4ok = 0 } 87 if rf_read(R8, W, AB3, kind, init, src, pi, co, q, po, 3) != 0 { t4ok = 0 } // never written 88 total=total+1; if t4ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 89 gw("T4 scales: R=8 register file round-trips (reg5=200 reg7=99, unwritten reg3=0)\n" as *u8) 90 91 // ---- T5: never-brick (deterministic) ---- 92 let npi4: i64 = seq_build_regfile(R, W, AB, kind, init, src, po) 93 i = 0; while i < nc { q[i] = 0; i = i + 1 } 94 rf_write(R, W, AB, kind, init, src, pi, co, q, 2, 123) 95 let d1: i64 = rf_read(R, W, AB, kind, init, src, pi, co, q, po, 2) 96 let d2: i64 = rf_read(R, W, AB, kind, init, src, pi, co, q, po, 2) 97 total=total+1; if d1==d2 { if d1==123 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) } 98 gw("T5 never-brick (#26): deterministic reads, bounded, x0 invariant, zero hw-state writes\n" as *u8) 99 100 // ---- T6: liar-kill -- corrupt the write-decode LUT of reg2 -> write to reg2 lands wrong ---- 101 seq_build_regfile(R, W, AB, kind, init, src, po) 102 init[R*W + 1 + 2] = init[R*W + 1 + 2] ^ 0xffff // wsel_2 LUT (cell R*W+1+2) 103 i = 0; while i < nc { q[i] = 0; i = i + 1 } 104 rf_write(R, W, AB, kind, init, src, pi, co, q, 2, 77) 105 let got: i64 = rf_read(R, W, AB, kind, init, src, pi, co, q, po, 2) 106 total=total+1; if got != 77 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 107 gw("T6 liar-kill: corrupting reg2's write-decode LUT -> write lands wrong (read=" as *u8); gn(got); gw(", expected!=77)\n" as *u8) 108 109 gw("\n=== nx_fpga_regfile_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 110 if pass == total { gw(" GREEN (a clocked register file with addressed read/write + x0=0 runs on the simulated FPGA; CPU storage)\n" as *u8); sys_exit(0); return 0 } 111 gw(" RED\n" as *u8); sys_exit(1); return 1 112}