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 &mdash; 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 &mdash; 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 &middot; ECP5 &middot; 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}