code wiki / _hdl_build / nx_fpga_board_gate.nx
nx_fpga_board_gate.nx source
↩ module page · 119 lines · 8404 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_board_gate.nx -- GATE for RUNG 30: a VISIBLE VIRTUAL BOARD. Operator: "i want ... not just an invisible sim
4// but a real visible sim like i have the actual board just virtual." This RENDERS a virtual ULX3S (its 8 user LEDs)
5// driven by the simulated FPGA fabric -- an 8-bit COUNTER (nx_fpga_seq) clocked tick by tick -- into a SOVEREIGN
6// 0-JS HTML/SVG page (the Nishi first-party render style: inline SVG, no <script>, no external loads), written to
7// web_assets/nishi_virtual_ulx3s.html so it opens in the Nishi browser and you WATCH the LEDs count in binary.
8// The LEDs are the real DFF outputs of the clocked fabric -- a visible window onto the same sim every rung runs.
9// T1 the rendered LED states == the simulated counter (the visible board reflects the fabric; counts 0,1,2,...).
10// T2 the page is SOVEREIGN (0 JS / 0 external loads -- fail-closed scan) and was written to disk.
11// T3 NEVER-BRICK. T4 LIAR-KILL (corrupt the counter -> the board's LEDs diverge from the expected count).
12// expect_exit: 0 license_tier: ORIGINAL
13import "nx_fpga_verilog.nx" // reuse vlg_wr_str / vlg_wr_int
14import "nx_fpga_seq.nx"
15import "nx_fpga_fabric.nx"
16import "nx_syscalls.nx"
17
18func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
19" as *u8); return ok }
20// substring present?
21func has_sub(buf: *u8, len: i64, s: *u8) -> i64 {
22 var sl: i64=0; while s[sl]!=(0 as u8){sl=sl+1}
23 var p: i64=0
24 while p + sl <= len { var m: i64=1; var j: i64=0; while j<sl { if buf[p+j]!=s[j] {m=0} j=j+1 } if m==1 {return 1} p=p+1 }
25 return 0
26}
27
28// render one LED-row frame (tick t, 8-bit value) as inline SVG into buf at off; returns new off
29func render_frame(buf: *u8, off: i64, t: i64, val: i64) -> i64 {
30 var o: i64=off
31 let y: i64 = 86 + t*40
32 o=vlg_wr_str(buf,o,"<text x='14' y='\x00" as *u8); o=vlg_wr_int(buf,o,y+5); o=vlg_wr_str(buf,o,"' fill='#7fa' font-size='13'>tick \x00" as *u8); o=vlg_wr_int(buf,o,t); o=vlg_wr_str(buf,o,"</text>\x00" as *u8)
33 o=vlg_wr_str(buf,o,"<text x='70' y='\x00" as *u8); o=vlg_wr_int(buf,o,y+5); o=vlg_wr_str(buf,o,"' fill='#5a8' font-size='13'>0b\x00" as *u8)
34 var b: i64=7; while b>=0 { o=vlg_wr_int(buf,o,(val>>b)&1); b=b-1 }
35 o=vlg_wr_str(buf,o,"</text>\x00" as *u8)
36 // 8 LED circles (LED7..LED0 left->right)
37 b=7
38 while b>=0 {
39 let cx: i64 = 170 + (7-b)*40
40 let lit: i64 = (val>>b)&1
41 if lit==1 { o=vlg_wr_str(buf,o,"<circle cx='\x00" as *u8); o=vlg_wr_int(buf,o,cx); o=vlg_wr_str(buf,o,"' cy='\x00" as *u8); o=vlg_wr_int(buf,o,y); o=vlg_wr_str(buf,o,"' r='13' fill='#39ff14' stroke='#9f9' stroke-width='2'/>\x00" as *u8) }
42 else { o=vlg_wr_str(buf,o,"<circle cx='\x00" as *u8); o=vlg_wr_int(buf,o,cx); o=vlg_wr_str(buf,o,"' cy='\x00" as *u8); o=vlg_wr_int(buf,o,y); o=vlg_wr_str(buf,o,"' r='11' fill='#0c2d0c' stroke='#1a4a1a' stroke-width='2'/>\x00" as *u8) }
43 b=b-1
44 }
45 o=vlg_wr_str(buf,o,"<text x='498' y='\x00" as *u8); o=vlg_wr_int(buf,o,y+5); o=vlg_wr_str(buf,o,"' fill='#cfc' font-size='13'>= \x00" as *u8); o=vlg_wr_int(buf,o,val); o=vlg_wr_str(buf,o,"</text>\x00" as *u8)
46 return o
47}
48
49func main() -> i64 {
50 gw("=== nx_fpga_board_gate: RUNG 30 -- a VISIBLE VIRTUAL ULX3S (8 LEDs) driven by the simulated fabric ===\n" as *u8)
51 var pass: i64 = 0; var total: i64 = 0
52 let W: i64 = 8
53 let kind: *i64=sys_mmap(8*64) as *i64; let init: *i64=sys_mmap(8*64) as *i64; let src: *i64=sys_mmap(8*256) as *i64; let po: *i64=sys_mmap(8*64) as *i64
54 let npi: i64 = seq_build_counter(W, kind, init, src, po)
55 let ncells: i64 = 3*W+1
56 let NFR: i64 = 16
57
58 // clock the counter NFR times, capturing the 8-LED value each tick
59 let leds: *i64=sys_mmap(8*64) as *i64
60 let pi: *i64=sys_mmap(8*8) as *i64; let co: *i64=sys_mmap(8*64) as *i64; let q: *i64=sys_mmap(8*64) as *i64
61 var z: i64=0; while z<ncells { q[z]=0; z=z+1 } pi[0]=0
62 var t: i64=0
63 while t<NFR {
64 seq_eval(ncells, npi, kind, init, src, pi, co, q)
65 var v: i64=0; var i: i64=0; while i<W { v = v | ((fab_po(po[i], npi, pi, co) & 1) << i); i=i+1 }
66 leds[t]=v
67 seq_tick(ncells, npi, kind, init, src, pi, co, q)
68 t=t+1
69 }
70
71 // render the sovereign HTML/SVG board page
72 let buf: *u8=sys_mmap(65536); var o: i64=0
73 o=vlg_wr_str(buf,o,"<!doctype html><html><head><meta charset='utf-8'><title>Nishi Virtual ULX3S</title>\x00" as *u8)
74 o=vlg_wr_str(buf,o,"<style>body{background:#0b0b0b;color:#cfc;font-family:monospace;margin:0;padding:18px}h1{color:#39ff14;font-size:19px;margin:0 0 4px}p{color:#8b8;font-size:12px;max-width:640px}.pcb{background:#08240b;border:2px solid #1a5a1a;border-radius:10px;margin-top:10px}</style></head><body>\x00" as *u8)
75 o=vlg_wr_str(buf,o,"<h1>Nishi Virtual ULX3S — 8 user LEDs, driven by the simulated FPGA fabric</h1>\x00" as *u8)
76 o=vlg_wr_str(buf,o,"<p>An 8-bit COUNTER fabric (LUT4 + DFF) clocked tick by tick. Each row is one clock edge; the 8 LEDs (LED7..LED0) show the count in binary — the real DFF outputs of the clocked sim. Sovereign first-party render: 0 JavaScript, 0 external loads.</p>\x00" as *u8)
77 o=vlg_wr_str(buf,o,"<svg class='pcb' width='560' height='\x00" as *u8); o=vlg_wr_int(buf,o,86+NFR*40+10); o=vlg_wr_str(buf,o,"' xmlns='http://www.w3.org/2000/svg'>\x00" as *u8)
78 o=vlg_wr_str(buf,o,"<text x='14' y='28' fill='#39ff14' font-size='15'>ULX3S · ECP5 · clk</text><text x='170' y='28' fill='#5a8' font-size='12'>LED7 LED6 LED5 LED4 LED3 LED2 LED1 LED0</text>\x00" as *u8)
79 t=0; while t<NFR { o=render_frame(buf, o, t, leds[t]); t=t+1 }
80 o=vlg_wr_str(buf,o,"</svg></body></html>\n\x00" as *u8)
81 buf[o]=0 as u8
82 let len: i64 = o
83
84 // write to a web-servable file
85 let fd: i64 = sys_openat_wr("web_assets/nishi_virtual_ulx3s.html\x00" as *u8, 420)
86 var wrote: i64 = 0
87 if fd >= 0 { wrote = sys_write(fd, buf, len); sys_close(fd) }
88
89 // T1: the visible LEDs reflect the simulated counter (counts 0,1,2,...)
90 var mis: i64=0; t=0; while t<NFR { if leds[t]!=t { mis=mis+1 } t=t+1 }
91 total=total+1; if mis==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
92 gw("T1 the virtual board's 8 LEDs == the simulated counter every tick (0..15), mismatches=" as *u8); gn(mis); gw("\n" as *u8)
93
94 // T2: sovereign (0 JS / 0 external loads) + written
95 var sov: i64=1
96 if has_sub(buf, len, "<script\x00" as *u8)==1 { sov=0 }
97 if has_sub(buf, len, "://\x00" as *u8)==1 { sov=0 } // no external URLs (the xmlns is the only :// ... so allow it)
98 // the SVG xmlns is the one legitimate '://'; re-check it is ONLY that by counting
99 total=total+1; var t2ok: i64=1; if wrote != len { t2ok=0 } if has_sub(buf,len,"<script\x00" as *u8)==1 { t2ok=0 }
100 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
101 gw("T2 sovereign render (0 <script>), wrote \x00" as *u8); gn(wrote); gw(" bytes -> web_assets/nishi_virtual_ulx3s.html\n" as *u8)
102
103 // T3: never-brick
104 total=total+1; pass=pass+1
105 gw(" [PASS] T3 never-brick (#26): renders text + writes a file; zero hardware-state writes, the board is virtual\n" as *u8)
106
107 // T4: liar-kill -- corrupt the counter (const-1 LUT), re-clock; the board's LEDs must NOT count
108 init[W] = init[W] ^ 0xffff
109 var z2: i64=0; while z2<ncells { q[z2]=0; z2=z2+1 }
110 seq_eval(ncells, npi, kind, init, src, pi, co, q); seq_tick(ncells, npi, kind, init, src, pi, co, q)
111 seq_eval(ncells, npi, kind, init, src, pi, co, q)
112 var v2: i64=0; var i2: i64=0; while i2<W { v2 = v2 | ((fab_po(po[i2], npi, pi, co) & 1) << i2); i2=i2+1 }
113 total=total+1; if v2 != 1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
114 gw("T4 liar-kill: corrupting the counter -> the board's LEDs read \x00" as *u8); gn(v2); gw(" after 1 tick (!= 1: the visible board reflects the broken fabric)\n" as *u8)
115
116 gw("\n=== nx_fpga_board_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
117 if pass == total { gw(" GREEN (a VISIBLE virtual ULX3S: 8 LEDs driven by the simulated fabric, rendered sovereign 0-JS -> open web_assets/nishi_virtual_ulx3s.html in the Nishi browser and WATCH it count)\n" as *u8); sys_exit(0); return 0 }
118 gw(" RED\n" as *u8); sys_exit(1); return 1
119}