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}