code wiki / _hdl_build / nx_fpga_counter_gate.nx

nx_fpga_counter_gate.nx source

↩ module page · 99 lines · 4970 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_counter_gate.nx -- GATE for RUNG 10a: the SEQUENTIAL fabric -- a clocked COUNTER (= a program counter) 4// holds state and increments each clock TICK. Proves the fabric now has MEMORY (DFF state) + a CLOCK. 5// T1 W=8 EXHAUSTIVE CYCLE -- 256 ticks: count == tick# (mod 256) at every step (the whole state sequence). 6// T2 WRAPAROUND -- after 2^8 ticks the counter returns to 0. 7// T3 WIDTH-INDEPENDENT -- a 32-bit counter increments correctly over 500 ticks. 8// T4 NEVER-BRICK -- deterministic: same initial state + same ticks -> the same sequence; bounded; no hw write. 9// T5 LIAR-KILL -- corrupt the increment network -> the count progression goes wrong. 10// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL 11import "nx_fpga_seq.nx" 12import "nx_syscalls.nx" 13 14func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 15" as *u8); return ok } 16 17func count_of(q: *i64, width: i64) -> i64 { 18 var s: i64 = 0; var i: i64 = 0 19 while i < width { s = s | ((q[i] & 1) << i); i = i + 1 } 20 return s 21} 22 23func main() -> i64 { 24 gw("=== nx_fpga_counter_gate: RUNG 10a -- the SEQUENTIAL fabric: a clocked counter (program counter) ===\n" as *u8) 25 var pass: i64 = 0; var total: i64 = 0 26 27 let kind: *i64 = sys_mmap(8 * 128) as *i64 28 let init: *i64 = sys_mmap(8 * 128) as *i64 29 let src: *i64 = sys_mmap(8 * 512) as *i64 30 let po: *i64 = sys_mmap(8 * 40) as *i64 31 let q: *i64 = sys_mmap(8 * 128) as *i64 32 let co: *i64 = sys_mmap(8 * 128) as *i64 33 let pi: *i64 = sys_mmap(8 * 8) as *i64 34 35 // ---- T1 + T2: W=8 exhaustive cycle (256 ticks) ---- 36 let W8: i64 = 8 37 let npi8: i64 = seq_build_counter(W8, kind, init, src, po) 38 let nc8: i64 = 3*W8 + 1 39 var i: i64 = 0 40 while i < nc8 { q[i] = 0; i = i + 1 } 41 var bad: i64 = 0 42 var t: i64 = 0 43 while t < 256 { 44 let c: i64 = count_of(q, W8) 45 if c != (t & 255) { bad = bad + 1 } 46 seq_tick(nc8, npi8, kind, init, src, pi, co, q) 47 t = t + 1 48 } 49 let wrap: i64 = count_of(q, W8) 50 total=total+1; if bad==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 51 gw("T1 W=8 counter: 256 ticks, count==tick# every step, wrong=" as *u8); gn(bad); gw("\n" as *u8) 52 total=total+1; if wrap==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 53 gw("T2 wraparound: after 2^8 ticks count returns to " as *u8); gn(wrap); gw(" (expect 0)\n" as *u8) 54 55 // ---- T3: W=32 counter, 500 ticks ---- 56 let W32: i64 = 32 57 let npi32: i64 = seq_build_counter(W32, kind, init, src, po) 58 let nc32: i64 = 3*W32 + 1 59 i = 0 60 while i < nc32 { q[i] = 0; i = i + 1 } 61 var bad3: i64 = 0 62 t = 0 63 while t < 500 { 64 if count_of(q, W32) != t { bad3 = bad3 + 1 } 65 seq_tick(nc32, npi32, kind, init, src, pi, co, q) 66 t = t + 1 67 } 68 total=total+1; if bad3==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 69 gw("T3 W=32 counter: 500 ticks, count==tick#, wrong=" as *u8); gn(bad3); gw("\n" as *u8) 70 71 // ---- T4: never-brick / deterministic -- rebuild W=8, tick 100, twice, same final ---- 72 seq_build_counter(W8, kind, init, src, po) 73 i = 0; while i < nc8 { q[i] = 0; i = i + 1 } 74 t = 0; while t < 100 { seq_tick(nc8, npi8, kind, init, src, pi, co, q); t = t + 1 } 75 let f1: i64 = count_of(q, W8) 76 i = 0; while i < nc8 { q[i] = 0; i = i + 1 } 77 t = 0; while t < 100 { seq_tick(nc8, npi8, kind, init, src, pi, co, q); t = t + 1 } 78 let f2: i64 = count_of(q, W8) 79 total=total+1; if f1==f2 { if f1==(100 & 255) { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) } 80 gw("T4 never-brick (#26): deterministic (two runs of 100 ticks both -> " as *u8); gn(f1); gw("), bounded, zero hw-state writes\n" as *u8) 81 82 // ---- T5: liar-kill -- corrupt the increment SUM cell of bit 0 -> progression breaks ---- 83 seq_build_counter(W8, kind, init, src, po) 84 init[W8 + 1] = init[W8 + 1] ^ 0xffff // incrementer sum cell of bit 0 (cell W+1) 85 i = 0; while i < nc8 { q[i] = 0; i = i + 1 } 86 var liar_wrong: i64 = 0 87 t = 0 88 while t < 32 { 89 if count_of(q, W8) != (t & 255) { liar_wrong = liar_wrong + 1 } 90 seq_tick(nc8, npi8, kind, init, src, pi, co, q) 91 t = t + 1 92 } 93 total=total+1; if liar_wrong > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 94 gw("T5 liar-kill: corrupting the increment network breaks the count in " as *u8); gn(liar_wrong); gw("/32 ticks\n" as *u8) 95 96 gw("\n=== nx_fpga_counter_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 97 if pass == total { gw(" GREEN (the fabric is now SEQUENTIAL: a clocked program-counter holds + increments state on the simulated FPGA; never-brick)\n" as *u8); sys_exit(0); return 0 } 98 gw(" RED\n" as *u8); sys_exit(1); return 1 99}