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}