code wiki / _hdl_build / nx_game_display_gate.nx

nx_game_display_gate.nx source

↩ module page · 131 lines · 8374 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_game_display_gate.nx -- GATE: SF5 -- a REAL GAME FRAME flows through the sovereign display path, BOTH 4// halves. Closes the loop on "grow the nishi GAME ecosystem from the hardware rung up": the ecosystem's 5// actual game pixels (the nx_arcade_render scene -- grid + green player + gold goals + red hazards, integer/ 6// no-float) are delivered through (1) the SILICON display controller (nx_fpga_dc, the on-fabric MMIO decode) 7// and (2) the x86 UEFI GOP sink (nx_gop_present), and BOTH reproduce the game frame pixel-exact + agree. 8// (The arcade scene is rendered inline with nx_arcade_render's exact render+fill_rect logic; that module owns 9// a main() so it can't be imported -- the game LOGIC is already gated in nx_arcade_render, this rung proves 10// the DISPLAY PATH carries it.) 11// T1 SILICON: the game frame, MMIO-stored pixel-by-pixel through the on-fabric display controller, scans 12// out == the game frame (0 mismatch). PNG (eyeball: the arcade game). 13// T2 x86 GOP: the same game frame, presented through the GOP sink (BGRX LFB), reconstructs == the game 14// frame (0 mismatch). PNG. 15// T3 REAL GAME: the frame carries real game content (a green player cell, a red hazard cell, gold goals). 16// T4 PATHS AGREE: the silicon scanout and the GOP reconstruction are byte-identical -- one game frame, 17// two sovereign display paths, same pixels. 18// T5 NEVER-BRICK (#26): deterministic (re-render bit-identical); both sinks bounded, volatile, gui-axis. 19// expect_exit: 0 license_tier: ORIGINAL 20import "nx_fpga_dc.nx" 21import "nx_gop_present.nx" 22import "nx_png.nx" 23import "nx_syscalls.nx" 24 25func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 26" as *u8); return ok } 27 28// integer rect fill into the packed-RGB framebuffer (nx_arcade_render's fill_rect, clamped, no float). 29func fill_rect(fb: *i64, w: i64, h: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 { 30 var xs: i64=x0; if xs<0 {xs=0} 31 var ys: i64=y0; if ys<0 {ys=0} 32 var xe: i64=x1; if xe>w {xe=w} 33 var ye: i64=y1; if ye>h {ye=h} 34 var yy: i64=ys 35 while yy<ye { var xx: i64=xs; while xx<xe { fb[yy*w+xx]=c; xx=xx+1 } yy=yy+1 } 36 return 0 37} 38 39// render the arcade game scene to a packed-RGB framebuffer (nx_arcade_render's render logic, inline). 40func render_arcade(fb: *i64, w: i64, h: i64, gw_: i64, gh_: i64, cell: i64, 41 gx: *i64, gy: *i64, ng: i64, hx: *i64, hy: *i64, nh: i64, px: i64, py: i64) -> i64 { 42 fill_rect(fb, w, h, 0, 0, w, h, dc_pack(16, 20, 30)) // bg 43 var c: i64=0 44 while c <= gw_ { fill_rect(fb, w, h, c*cell, 0, c*cell+1, gh_*cell, dc_pack(40,46,60)); c=c+1 } // grid V 45 var r: i64=0 46 while r <= gh_ { fill_rect(fb, w, h, 0, r*cell, gw_*cell, r*cell+1, dc_pack(40,46,60)); r=r+1 } // grid H 47 var i: i64=0 48 while i < ng { fill_rect(fb, w, h, gx[i]*cell+6, gy[i]*cell+6, gx[i]*cell+cell-6, gy[i]*cell+cell-6, dc_pack(255,210,70)); i=i+1 } // goals gold 49 var j: i64=0 50 while j < nh { fill_rect(fb, w, h, hx[j]*cell+4, hy[j]*cell+4, hx[j]*cell+cell-4, hy[j]*cell+cell-4, dc_pack(224,80,58)); j=j+1 } // hazards red 51 fill_rect(fb, w, h, px*cell+4, py*cell+4, px*cell+cell-4, py*cell+cell-4, dc_pack(90,210,122)) // player green 52 return 0 53} 54 55func main() -> i64 { 56 gw("=== nx_game_display_gate: SF5 -- a REAL GAME FRAME through the sovereign display path (silicon + x86) ===\n" as *u8) 57 var pass: i64 = 0; var total: i64 = 0 58 let GW: i64=6; let GH: i64=5; let CELL: i64=16 59 let W: i64=GW*CELL; let H: i64=GH*CELL // 96 x 80 60 61 // ---- render the real arcade game frame ---- 62 let gx: *i64=sys_mmap(8*8) as *i64; let gy: *i64=sys_mmap(8*8) as *i64 63 let hx: *i64=sys_mmap(8*8) as *i64; let hy: *i64=sys_mmap(8*8) as *i64 64 gx[0]=3; gy[0]=0; gx[1]=5; gy[1]=2; gx[2]=1; gy[2]=4 65 hx[0]=4; hy[0]=3; hx[1]=2; hy[1]=1 66 let game: *i64=sys_mmap(8*(W*H+8)) as *i64 67 render_arcade(game, W, H, GW, GH, CELL, gx, gy, 3, hx, hy, 2, 1, 2) 68 69 // ---- T1: SILICON display controller (on-fabric MMIO decode) carries the game frame ---- 70 let FBASE: i64=0x20000000; let AW: i64=32 71 let dcfb: *i64=sys_mmap(8*(W*H+8)) as *i64 72 let dsi: *i64=sys_mmap(8*128) as *i64; let dss: *i64=sys_mmap(8*512) as *i64; let dsp: *i64=sys_mmap(8*48) as *i64 73 let dpi: *i64=sys_mmap(8*80) as *i64; let dco: *i64=sys_mmap(8*128) as *i64; let dc: *NxFpgaDC=sys_mmap(8*16) as *NxFpgaDC 74 dc_init(dc, dcfb, W, H, FBASE, AW, dsi, dss, dsp, dpi, dco) 75 dc_clear(dc, dc_pack(0,0,0)) 76 var idx: i64=0 77 while idx < W*H { dc_store(dc, FBASE + idx, game[idx]); idx=idx+1 } // MMIO-store each game pixel through the fabric decode 78 var sm: i64=0; idx=0 79 while idx < W*H { if dcfb[idx] != game[idx] { sm=sm+1 } idx=idx+1 } 80 write_png(dcfb, W, H, "knowledge/nx_game_silicon.png" as *u8) 81 total=total+1; if sm==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 82 gw("T1 silicon: the arcade frame MMIO-stored through the on-fabric display controller scans out == game, mismatches=" as *u8); gn(sm); gw(" (PNG knowledge/nx_game_silicon.png)\n" as *u8) 83 84 // ---- T2: x86 UEFI GOP sink carries the same game frame ---- 85 let PITCH: i64=W+4 // a padded LFB stride (the real GOP case) 86 let lfb: *u8=sys_mmap(PITCH*H*4) 87 let r2: i64=nx_gop_present(game, W, H, lfb, PITCH, NX_GOP_FMT_BGRX) 88 let recon: *i64=sys_mmap(8*(W*H+8)) as *i64 89 var gm: i64=0; var y: i64=0 90 while y < H { 91 var x: i64=0 92 while x < W { 93 let o: i64=(y*PITCH + x)*4 94 let px: i64=(lfb[o+2] as i64) | ((lfb[o+1] as i64)<<8) | ((lfb[o] as i64)<<16) // BGRX -> R|G<<8|B<<16 95 recon[y*W+x]=px 96 if px != game[y*W+x] { gm=gm+1 } 97 x=x+1 98 } 99 y=y+1 100 } 101 write_png(recon, W, H, "knowledge/nx_game_gop.png" as *u8) 102 var t2ok: i64=1; if r2 != W*H { t2ok=0 } if gm != 0 { t2ok=0 } 103 total=total+1; if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 104 gw("T2 x86 GOP: the same frame through the GOP sink (BGRX, pitch>width) reconstructs == game, mismatches=" as *u8); gn(gm); gw(" (PNG knowledge/nx_game_gop.png)\n" as *u8) 105 106 // ---- T3: it is a real game frame (player green, a hazard red, goals gold present) ---- 107 let pcell: i64=game[(2*CELL+8)*W + (1*CELL+8)] // player at (1,2) 108 let hcell: i64=game[(3*CELL+8)*W + (4*CELL+8)] // hazard at (4,3) 109 let pr: i64=pcell&0xFF; let pg: i64=(pcell>>8)&0xFF 110 let hr: i64=hcell&0xFF; let hg: i64=(hcell>>8)&0xFF 111 var t3ok: i64=1; if pg <= pr { t3ok=0 } if hr <= hg { t3ok=0 } 112 total=total+1; if t3ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 113 gw("T3 real game: player cell green (g=" as *u8); gn(pg); gw(">r=" as *u8); gn(pr); gw("), hazard cell red (r=" as *u8); gn(hr); gw(">g=" as *u8); gn(hg); gw(")\n" as *u8) 114 115 // ---- T4: the two sovereign display paths agree byte-for-byte ---- 116 var am: i64=0; idx=0 117 while idx < W*H { if dcfb[idx] != recon[idx] { am=am+1 } idx=idx+1 } 118 total=total+1; if am==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 119 gw("T4 paths agree: silicon scanout == GOP reconstruction byte-for-byte, diffs=" as *u8); gn(am); gw(" (one game frame, two sovereign display paths)\n" as *u8) 120 121 // ---- T5: never-brick / determinism ---- 122 let game2: *i64=sys_mmap(8*(W*H+8)) as *i64 123 render_arcade(game2, W, H, GW, GH, CELL, gx, gy, 3, hx, hy, 2, 1, 2) 124 var dm: i64=0; idx=0; while idx < W*H { if game2[idx] != game[idx] { dm=dm+1 } idx=idx+1 } 125 total=total+1; if dm==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 126 gw("T5 never-brick (#26): deterministic render (re-render bit-identical, diffs=" as *u8); gn(dm); gw("), both sinks bounded/volatile/gui-axis\n" as *u8) 127 128 gw("\n=== nx_game_display_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 129 if pass == total { gw(" GREEN (a real arcade game frame flows through BOTH sovereign display paths -- silicon on-fabric controller + x86 GOP sink -- pixel-exact and agreeing)\n" as *u8); sys_exit(0); return 0 } 130 gw(" RED\n" as *u8); sys_exit(1); return 1 131}