code wiki / (root) / nx_emu_mips64.nx

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}