code wiki / _hdl_build / nx_emu_x86_segoff_test.nx
nx_emu_x86_segoff_test.nx source
↩ module page · 46 lines · 3490 B
1// nx_emu_x86_segoff_test.nx -- x86 full-system ladder R5 rung-4: REAL-MODE SEGMENT:OFFSET ADDRESSING.
2// Real mode computes a physical address as phys = (segment << 4) + offset (segment*16 + offset).
3// This is how every boot-sector memory access works. KAT covers the canonical boot addresses
4// (0x07C0:0 = 0x7C00 boot load; 0xF000:0xFFF0 = 0xFFFF0 reset vector), a seg:off memory round-trip,
5// and the classic real-mode ALIASING (0000:0410 == 0040:0010 == phys 0x410).
6// HONEST SCOPE: the addressing model; the far-jump that flushes seg:off real mode into 32-bit
7// protected mode = R5 rung-5; full real-mode ISA = ongoing. No hardware writes (Rule 26).
8// expect_exit: 0 license_tier: ORIGINAL
9import "nx_syscalls.nx"
10
11func sg_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func sg_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
13
14// real-mode physical address from a far (segment:offset) pointer.
15func x86_phys(seg: i64, off: i64) -> i64 { return (seg << 4) + off }
16
17func sg_st64(mem: *u8, addr: i64, v: i64) -> i64 { var i: i64=0; while i<8 { mem[addr+i]=((v>>(i*8)) & 0xff) as u8; i=i+1 } return 0 }
18func sg_ld64(mem: *u8, addr: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v = v | ((mem[addr+i] as i64) << (i*8)); i=i+1 } return v }
19
20func main() -> i64 {
21 sg_puts("x86 full-system ladder R5 rung-4: REAL-MODE SEGMENT:OFFSET ADDRESSING\n" as *u8)
22 let mem: *u8 = sys_mmap(1048576)
23 var pass: i64=0
24 var ttl: i64=0
25
26 let a1: i64 = x86_phys(0x07C0, 0x0000)
27 ttl=ttl+1; sg_puts(" T1 0x07C0:0000 -> " as *u8); sg_num(a1); sg_puts(" (want 31744=0x7C00, boot load): " as *u8); if a1==0x7C00 { pass=pass+1; sg_puts("PASS\n" as *u8) } else { sg_puts("FAIL\n" as *u8) }
28
29 let a2: i64 = x86_phys(0xF000, 0xFFF0)
30 ttl=ttl+1; sg_puts(" T2 0xF000:FFF0 -> " as *u8); sg_num(a2); sg_puts(" (want 1048560=0xFFFF0, reset vector): " as *u8); if a2==0xFFFF0 { pass=pass+1; sg_puts("PASS\n" as *u8) } else { sg_puts("FAIL\n" as *u8) }
31
32 let a3: i64 = x86_phys(0x1000, 0x0010)
33 ttl=ttl+1; sg_puts(" T3 0x1000:0010 -> " as *u8); sg_num(a3); sg_puts(" (want 65552=0x10010): " as *u8); if a3==0x10010 { pass=pass+1; sg_puts("PASS\n" as *u8) } else { sg_puts("FAIL\n" as *u8) }
34
35 // seg:off memory round-trip
36 sg_st64(mem, x86_phys(0x0100, 0x0020), 1234)
37 let rt: i64 = sg_ld64(mem, x86_phys(0x0100, 0x0020))
38 ttl=ttl+1; sg_puts(" T4 store/load via 0x0100:0020 = " as *u8); sg_num(rt); sg_puts(" (want 1234): " as *u8); if rt==1234 { pass=pass+1; sg_puts("PASS\n" as *u8) } else { sg_puts("FAIL\n" as *u8) }
39
40 // classic aliasing: 0000:0410 == 0040:0010 == phys 0x410
41 ttl=ttl+1; sg_puts(" T5 alias 0000:0410 == 0040:0010 (both 0x410): " as *u8); if x86_phys(0x0000,0x0410)==x86_phys(0x0040,0x0010) { if x86_phys(0x0000,0x0410)==0x410 { pass=pass+1; sg_puts("PASS\n" as *u8) } else { sg_puts("FAIL\n" as *u8) } } else { sg_puts("FAIL\n" as *u8) }
42
43 sg_puts("X86-SEGOFF-GATE passed " as *u8); sg_num(pass); sg_puts("/" as *u8); sg_num(ttl)
44 if pass==ttl { sg_puts(" verdict=GREEN (real-mode seg:off addressing; far-jump-into-protected = R5 rung-5)\n" as *u8); sys_exit(0); return 0 }
45 sg_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
46}