nx_emu_mips64.nx source
↩ module page · 126 lines · 6605 B
1// nx_emu_mips64.nx -- sovereign MIPS64 (n64, big-endian) interpreter (NX-EMU).
2// Flat 32 GPRs (r0==zero), BIG-ENDIAN, DELAY SLOTS (PC/nPC model like SPARC).
3// Decode/execute pure NishiLang per the MIPS64 ISA -- NO qemu (qemu-mips64 =
4// differential BENCHMARK that must agree). Resolves the earlier "inconclusive"
5// run-proof (that was a qemu-harness ABI artifact; here Nishi carries it).
6//
7// Forms: R-type opcode0 (funct): OR 0x25 / DADDU 0x2d / DSUBU 0x2f / AND 0x24 /
8// XOR 0x26 / DMUL(R6) funct 0x1c sa 2 / JR 0x08 / JALR 0x09 / SLL 0x00 (nop) /
9// SYSCALL 0x0c / DSLL 0x38 / DSRL 0x3a / DSRA 0x3b. I-type: ADDIU 0x09 /
10// DADDIU 0x19 / ORI 0x0d / LUI 0x0f / LD 0x37 / SD 0x3f. J-type: J 0x02 /
11// JAL 0x03 (link r31=pc+8). n64 syscalls v0=num,a0..=args: exit=5058.
12//
13// license_tier: ORIGINAL
14
15import "nx_syscalls_x86_64.nx"
16const MI_MAGIC_200000000: i64 = 200000000
17
18const MI_GUEST_SIZE: i64 = 16777216
19const MI_SYS_READ: i64 = 5000
20const MI_SYS_WRITE: i64 = 5001
21const MI_SYS_EXIT: i64 = 5058
22const MI_SYS_EXITG: i64 = 5205
23const MIE_UNSUPPORTED: i64 = -1
24const MIE_FAULT: i64 = -3
25
26func mi_g_ld(mem: *u8, va: i64, width: i64) -> i64 { // big-endian
27 var v: i64 = 0
28 var i: i64 = 0
29 while i < width { v = (v << 8) | (mem[va + i] & 0xff); i = i + 1 }
30 return v
31}
32func mi_g_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 {
33 var i: i64 = 0
34 while i < width { mem[va + (width - 1 - i)] = (val >> (i * 8)) & 0xff; i = i + 1 }
35 return 0
36}
37func mi_sx16(x: i64) -> i64 { if (x & 0x8000) != 0 { return x - 0x10000 } return x }
38func mi_rd(r: *i64, n: i64) -> i64 { if n == 0 { return 0 } return r[n] }
39func mi_wr(r: *i64, n: i64, v: i64) -> i64 { if n != 0 { r[n] = v } return 0 }
40
41func emu_mips64_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 {
42 let r: *i64 = sys_mmap(32 * 8) as *i64
43 var i: i64 = 0
44 while i < 32 { r[i] = 0; i = i + 1 }
45 r[29] = sp0 // $sp = $29
46 var pc: i64 = entry
47 var npc: i64 = entry + 4
48 var steps: i64 = 0
49 var halted: i64 = 0
50 var result: i64 = MIE_FAULT
51 while halted == 0 && steps < MI_MAGIC_200000000 {
52 if pc < 0 { halted = 1; result = MIE_FAULT }
53 if pc + 4 > mem_size { halted = 1; result = MIE_FAULT }
54 if halted == 0 {
55 let w: i64 = mi_g_ld(mem, pc, 4)
56 let opc: i64 = (w >> 26) & 0x3F
57 let rs: i64 = (w >> 21) & 0x1F
58 let rt: i64 = (w >> 16) & 0x1F
59 let rd: i64 = (w >> 11) & 0x1F
60 let sa: i64 = (w >> 6) & 0x1F
61 let fn: i64 = w & 0x3F
62 var next_pc: i64 = npc
63 var next_npc: i64 = npc + 4
64 var handled: i64 = 0
65
66 if opc == 0 { // SPECIAL (R-type)
67 if fn == 0x25 { handled = 1; mi_wr(r, rd, mi_rd(r, rs) | mi_rd(r, rt)) } // OR / move
68 if fn == 0x2d { handled = 1; mi_wr(r, rd, mi_rd(r, rs) + mi_rd(r, rt)) } // DADDU
69 if fn == 0x2f { handled = 1; mi_wr(r, rd, mi_rd(r, rs) - mi_rd(r, rt)) } // DSUBU
70 if fn == 0x24 { handled = 1; mi_wr(r, rd, mi_rd(r, rs) & mi_rd(r, rt)) } // AND
71 if fn == 0x26 { handled = 1; mi_wr(r, rd, mi_rd(r, rs) ^ mi_rd(r, rt)) } // XOR
72 if fn == 0x1c { if sa == 2 { handled = 1; mi_wr(r, rd, mi_rd(r, rs) * mi_rd(r, rt)) } } // DMUL (R6)
73 if fn == 0x38 { handled = 1; mi_wr(r, rd, mi_rd(r, rt) << sa) } // DSLL
74 if fn == 0x3a { handled = 1; mi_wr(r, rd, mi_rd(r, rt) >> sa) } // DSRL
75 if fn == 0x3b { handled = 1; mi_wr(r, rd, mi_rd(r, rt) >> sa) } // DSRA
76 if fn == 0x00 { handled = 1; mi_wr(r, rd, mi_rd(r, rt) << sa) } // SLL (nop=0)
77 if fn == 0x08 { handled = 1; next_npc = mi_rd(r, rs) } // JR
78 if fn == 0x09 { handled = 1; mi_wr(r, rd, pc + 8); next_npc = mi_rd(r, rs) } // JALR
79 if fn == 0x0c { // SYSCALL
80 handled = 1
81 let nr: i64 = mi_rd(r, 2) // v0
82 if nr == MI_SYS_EXIT { result = mi_rd(r, 4) & 0xff; halted = 1 }
83 if nr == MI_SYS_EXITG { result = mi_rd(r, 4) & 0xff; halted = 1 }
84 if nr == MI_SYS_WRITE { mi_wr(r, 2, sys_write(mi_rd(r, 4), ((mem as i64) + mi_rd(r, 5)) as *u8, mi_rd(r, 6))) }
85 if nr == MI_SYS_READ { mi_wr(r, 2, sys_read(mi_rd(r, 4), ((mem as i64) + mi_rd(r, 5)) as *u8, mi_rd(r, 6))) }
86 }
87 }
88 if opc == 0x09 { handled = 1; mi_wr(r, rt, mi_rd(r, rs) + mi_sx16(w & 0xFFFF)) } // ADDIU
89 if opc == 0x19 { handled = 1; mi_wr(r, rt, mi_rd(r, rs) + mi_sx16(w & 0xFFFF)) } // DADDIU
90 if opc == 0x0d { handled = 1; mi_wr(r, rt, mi_rd(r, rs) | (w & 0xFFFF)) } // ORI
91 if opc == 0x0f { handled = 1; mi_wr(r, rt, mi_sx16(w & 0xFFFF) << 16) } // LUI
92 if opc == 0x37 { handled = 1; mi_wr(r, rt, mi_g_ld(mem, mi_rd(r, rs) + mi_sx16(w & 0xFFFF), 8)) } // LD
93 if opc == 0x3f { handled = 1; mi_g_st(mem, mi_rd(r, rs) + mi_sx16(w & 0xFFFF), 8, mi_rd(r, rt)) } // SD
94 if opc == 0x02 { handled = 1; next_npc = (pc & 0xF0000000) | ((w & 0x3FFFFFF) << 2) } // J
95 if opc == 0x03 { handled = 1; mi_wr(r, 31, pc + 8); next_npc = (pc & 0xF0000000) | ((w & 0x3FFFFFF) << 2) } // JAL
96
97 if handled == 0 { result = MIE_UNSUPPORTED; halted = 1 }
98 pc = next_pc
99 npc = next_npc
100 steps = steps + 1
101 }
102 }
103 return result
104}
105
106func emu_mips64_load_elf(buf: *u8, len: i64) -> i64 {
107 if len < 64 { return MIE_FAULT }
108 let e_entry: i64 = mi_g_ld(buf, 24, 8)
109 let e_phoff: i64 = mi_g_ld(buf, 32, 8)
110 let e_phnum: i64 = mi_g_ld(buf, 56, 2)
111 let e_phent: i64 = mi_g_ld(buf, 54, 2)
112 let mem: *u8 = sys_mmap(MI_GUEST_SIZE)
113 var idx: i64 = 0
114 while idx < e_phnum {
115 let ph: i64 = e_phoff + idx * e_phent
116 if mi_g_ld(buf, ph, 4) == 1 {
117 let p_off: i64 = mi_g_ld(buf, ph + 8, 8)
118 let p_va: i64 = mi_g_ld(buf, ph + 16, 8)
119 let p_fs: i64 = mi_g_ld(buf, ph + 32, 8)
120 var k: i64 = 0
121 while k < p_fs { if (p_va + k) < MI_GUEST_SIZE { mem[p_va + k] = buf[p_off + k] }; k = k + 1 }
122 }
123 idx = idx + 1
124 }
125 return emu_mips64_run_mem(mem, MI_GUEST_SIZE, e_entry, 0x00F00000)
126}