code wiki / (root) / nx_x86_modrm_gate.nx

nx_x86_modrm_gate.nx source

↩ module page · 76 lines · 4636 B

1// nx_x86_modrm_gate.nx -- R1.0b: ModR/M + memory operands. Program round-trips a value through memory via 2// [disp16] and [BX], does a memory-operand ADD, and a register-direct ModR/M MOV; checks both registers and 3// the actual memory contents. Proves the 16-bit addressing core that real DOS programs depend on. 4// B8 34 12 MOV AX,0x1234 5// 89 06 00 02 MOV [0x200],AX (mod00 rm6 disp16 store) 6// 8B 1E 00 02 MOV BX,[0x200] (mod00 rm6 disp16 load) -> BX=0x1234 7// 03 1E 00 02 ADD BX,[0x200] (memory-operand add) -> BX=0x2468 8// 89 1E 02 02 MOV [0x202],BX -> mem[0x202]=0x2468 9// 89 D9 MOV CX,BX (mod11 register-direct) -> CX=0x2468 10// BB 00 03 MOV BX,0x300 11// 89 07 MOV [BX],AX (mod00 rm7 [BX] store) -> mem[0x300]=0x1234 12// 8B 17 MOV DX,[BX] (mod00 rm7 [BX] load) -> DX=0x1234 13// F4 HLT 14import "nx_syscalls.nx" 15import "nx_x86.nx" 16import "nx_gate_verdict.nx" 17 18func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 19func g_pn(v: i64) -> i64 { 20 let b: *u8 = sys_mmap(28) 21 var x: i64 = v 22 if x < 0 { b[0] = 45 as u8; sys_write(1, b, 1); x = 0 - x } 23 if x == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 } 24 var d: i64 = 0 25 var y: i64 = x 26 while y > 0 { d = d + 1; y = y / 10 } 27 var i: i64 = d - 1 28 y = x 29 while i >= 0 { b[i] = (48 + (y % 10)) as u8; y = y / 10; i = i - 1 } 30 sys_write(1, b, d) 31 return 0 32} 33func g_check(name: *u8, cond: i64) -> i64 { 34 if cond == 1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } 35 g_puts(name); g_puts("\n" as *u8) 36 return cond 37} 38 39func main() -> i64 { 40 g_puts("nx_x86 ModR/M gate (memory operands + 16-bit addressing)\n" as *u8) 41 var pass: i64 = 0 42 var total: i64 = 0 43 44 let base: i64 = sys_mmap(131072) as i64 45 x86_reset(base) 46 x86_load(base, 256, 184); x86_load(base, 257, 52); x86_load(base, 258, 18) // MOV AX,0x1234 47 x86_load(base, 259, 137); x86_load(base, 260, 6); x86_load(base, 261, 0); x86_load(base, 262, 2) // MOV [0x200],AX 48 x86_load(base, 263, 139); x86_load(base, 264, 30); x86_load(base, 265, 0); x86_load(base, 266, 2) // MOV BX,[0x200] 49 x86_load(base, 267, 3); x86_load(base, 268, 30); x86_load(base, 269, 0); x86_load(base, 270, 2) // ADD BX,[0x200] 50 x86_load(base, 271, 137); x86_load(base, 272, 30); x86_load(base, 273, 2); x86_load(base, 274, 2) // MOV [0x202],BX 51 x86_load(base, 275, 137); x86_load(base, 276, 217) // MOV CX,BX 52 x86_load(base, 277, 187); x86_load(base, 278, 0); x86_load(base, 279, 3) // MOV BX,0x300 53 x86_load(base, 280, 137); x86_load(base, 281, 7) // MOV [BX],AX 54 x86_load(base, 282, 139); x86_load(base, 283, 23) // MOV DX,[BX] 55 x86_load(base, 284, 244) // HLT 56 x86_run(base, 100) 57 58 pass = pass + g_check("AX == 0x1234" as *u8, x86_reg(base, 0) == 4660); total = total + 1 59 pass = pass + g_check("BX == 0x300 (re-set after the math)" as *u8, x86_reg(base, 3) == 768); total = total + 1 60 pass = pass + g_check("CX == 0x2468 (register-direct MOV CX,BX)" as *u8, x86_reg(base, 1) == 9320); total = total + 1 61 pass = pass + g_check("DX == 0x1234 (MOV DX,[BX])" as *u8, x86_reg(base, 2) == 4660); total = total + 1 62 pass = pass + g_check("mem[0x200] == 0x1234 ([disp16] store)" as *u8, x86_peek16(base, 512) == 4660); total = total + 1 63 pass = pass + g_check("mem[0x202] == 0x2468 (memory-operand ADD result)" as *u8, x86_peek16(base, 514) == 9320); total = total + 1 64 pass = pass + g_check("mem[0x300] == 0x1234 ([BX] store)" as *u8, x86_peek16(base, 768) == 4660); total = total + 1 65 66 g_puts("---- x86 modrm gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 67 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 68 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 69 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 70 let ctr__dry: *i64 = gv_ctr() 71 ctr__dry[0] = pass 72 ctr__dry[1] = total 73 let rc__dry: i64 = gv_verdict("X86-MODRM-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 74 sys_exit(rc__dry) 75 return rc__dry 76}