code wiki / (root) / nx_x86_dos_gate.nx

nx_x86_dos_gate.nx source

↩ module page · 79 lines · 3955 B

1// nx_x86_dos_gate.nx -- R1.1: run a REAL DOS .COM on the sovereign x86 emulator. Hello-World program: 2// B4 09 MOV AH,09h (DOS print-string function) 3// BA 0B 01 MOV DX,0x010B (offset of the $-terminated string) 4// CD 21 INT 21h -> prints "Hello, World!" into the console buffer 5// B4 4C MOV AH,4Ch (terminate) 6// CD 21 INT 21h -> sets the exit flag -> emulator halts 7// 0x10B: "Hello, World!$" 8// Proves 8-bit reg moves (B0+r) + INT (CD) + the HLE DOS INT 21h handler -> an actual program produces output. 9import "nx_syscalls.nx" 10import "nx_x86.nx" 11import "nx_gate_verdict.nx" 12 13func 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 } 14func g_pn(v: i64) -> i64 { 15 let b: *u8 = sys_mmap(28) 16 var x: i64 = v 17 if x < 0 { b[0] = 45 as u8; sys_write(1, b, 1); x = 0 - x } 18 if x == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 } 19 var d: i64 = 0 20 var y: i64 = x 21 while y > 0 { d = d + 1; y = y / 10 } 22 var i: i64 = d - 1 23 y = x 24 while i >= 0 { b[i] = (48 + (y % 10)) as u8; y = y / 10; i = i - 1 } 25 sys_write(1, b, d) 26 return 0 27} 28func g_check(name: *u8, cond: i64) -> i64 { 29 if cond == 1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } 30 g_puts(name); g_puts("\n" as *u8) 31 return cond 32} 33 34func main() -> i64 { 35 g_puts("nx_x86 DOS gate (a real .COM: INT 21h Hello-World on the sovereign emulator)\n" as *u8) 36 var pass: i64 = 0 37 var total: i64 = 0 38 39 let base: i64 = sys_mmap(131072) as i64 40 x86_reset(base) 41 // code 42 x86_load(base, 256, 180); x86_load(base, 257, 9) // MOV AH,09 43 x86_load(base, 258, 186); x86_load(base, 259, 11); x86_load(base, 260, 1) // MOV DX,0x010B 44 x86_load(base, 261, 205); x86_load(base, 262, 33) // INT 21h 45 x86_load(base, 263, 180); x86_load(base, 264, 76) // MOV AH,4Ch 46 x86_load(base, 265, 205); x86_load(base, 266, 33) // INT 21h 47 // string "Hello, World!$" at 0x10B (267) 48 x86_load(base, 267, 72); x86_load(base, 268, 101); x86_load(base, 269, 108); x86_load(base, 270, 108) 49 x86_load(base, 271, 111); x86_load(base, 272, 44); x86_load(base, 273, 32); x86_load(base, 274, 87) 50 x86_load(base, 275, 111); x86_load(base, 276, 114); x86_load(base, 277, 108); x86_load(base, 278, 100) 51 x86_load(base, 279, 33); x86_load(base, 280, 36) 52 53 x86_run(base, 500) 54 55 let clen: i64 = x86_con_len(base) 56 g_puts(" [output] '" as *u8) 57 sys_write(1, (base + O_CON) as *u8, clen) 58 g_puts("' (len=" as *u8); g_pn(clen); g_puts(")\n" as *u8) 59 60 pass = pass + g_check("console length == 13" as *u8, clen == 13); total = total + 1 61 let want: *u8 = "Hello, World!" as *u8 62 var ok: i64 = 1 63 var i: i64 = 0 64 while i < 13 { if x86_con_byte(base, i) != (want[i] as i64) { ok = 0 } i = i + 1 } 65 pass = pass + g_check("console bytes == 'Hello, World!'" as *u8, ok); total = total + 1 66 // AH=4Ch path must have written 0x4C into AH (high byte of AX) before exit 67 pass = pass + g_check("AH == 0x4C at exit (8-bit reg move worked)" as *u8, ((x86_reg(base, 0) >> 8) & 0xff) == 76); total = total + 1 68 69 g_puts("---- x86 DOS gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 70 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 71 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 72 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 73 let ctr__dry: *i64 = gv_ctr() 74 ctr__dry[0] = pass 75 ctr__dry[1] = total 76 let rc__dry: i64 = gv_verdict("X86-DOS-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 77 sys_exit(rc__dry) 78 return rc__dry 79}