code wiki / (root) / nx_emu_ppc64le.nx

nx_emu_ppc64le.nx source

↩ module page · 148 lines · 6852 B

1// nx_emu_ppc64le.nx -- sovereign PowerPC64 little-endian interpreter (NX-EMU). 2// Flat 32 GPRs + LR; little-endian data AND instructions (ppc64le stores 3// instruction words LE, so a 4-byte LE fetch yields the standard PPC 4// encoding). No delay slots. Decode/execute pure NishiLang per the Power 5// ISA -- NO qemu (qemu-ppc64le = differential BENCHMARK that must agree). 6// How Nishi CARRIES ppc64le execution. 7// 8// PPC bit numbering is MSB=0; a field at PPC bits [a..b] = std bits 9// [31-b .. 31-a]. RT/RS=(w>>21)&0x1F, RA=(w>>16)&0x1F, RB=(w>>11)&0x1F, 10// XO=(w>>1)&0x3FF, primary opcode=(w>>26)&0x3F. 11// Forms used by the backend (verified via objdump): D addi/li(14); 12// DS ld(58)/std,stdu(62); X add(31/266)/subf(40)/mulld(233)/or-mr(444)/ 13// mfspr-mflr(339)/mtspr-mtlr(467); XL blr(19/16); I bl(18); SC sc(17). 14// 15// license_tier: ORIGINAL 16 17import "nx_syscalls_x86_64.nx" 18const PP_MAGIC_200000000: i64 = 200000000 19 20const PP_GUEST_SIZE: i64 = 16777216 21const PP_SYS_READ: i64 = 3 22const PP_SYS_WRITE: i64 = 4 23const PP_SYS_EXIT: i64 = 1 24const PP_SYS_EXITG: i64 = 234 25const PPE_UNSUPPORTED: i64 = -1 26const PPE_FAULT: i64 = -3 27 28func pp_g_ld(mem: *u8, va: i64, width: i64) -> i64 { // little-endian 29 var v: i64 = 0 30 var i: i64 = 0 31 while i < width { v = v | ((mem[va + i] & 0xff) << (i * 8)); i = i + 1 } 32 return v 33} 34func pp_g_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 { 35 var i: i64 = 0 36 while i < width { mem[va + i] = (val >> (i * 8)) & 0xff; i = i + 1 } 37 return 0 38} 39func pp_sx16(x: i64) -> i64 { if (x & 0x8000) != 0 { return x - 0x10000 } return x } 40 41func emu_ppc64le_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[1] = sp0 // r1 = stack pointer 46 var lr: i64 = 0 47 var pc: i64 = entry 48 var steps: i64 = 0 49 var halted: i64 = 0 50 var result: i64 = PPE_FAULT 51 while halted == 0 && steps < PP_MAGIC_200000000 { 52 if pc < 0 { halted = 1; result = PPE_FAULT } 53 if pc + 4 > mem_size { halted = 1; result = PPE_FAULT } 54 if halted == 0 { 55 let w: i64 = pp_g_ld(mem, pc, 4) 56 let opc: i64 = (w >> 26) & 0x3F 57 let rt: i64 = (w >> 21) & 0x1F // RT or RS 58 let ra: i64 = (w >> 16) & 0x1F 59 let rb: i64 = (w >> 11) & 0x1F 60 var next: i64 = pc + 4 61 var handled: i64 = 0 62 63 if opc == 14 { // addi / li (RA==0 -> 0) 64 handled = 1 65 var base: i64 = 0 66 if ra != 0 { base = r[ra] } 67 r[rt] = base + pp_sx16(w & 0xFFFF) 68 } 69 if opc == 58 { // DS load: ld (XO=0) 70 handled = 1 71 let off: i64 = pp_sx16(w & 0xFFFC) 72 var base: i64 = 0 73 if ra != 0 { base = r[ra] } 74 if (w & 3) == 0 { r[rt] = pp_g_ld(mem, base + off, 8) } // ld 75 } 76 if opc == 62 { // DS store: std (XO=0) / stdu (XO=1) 77 handled = 1 78 let off: i64 = pp_sx16(w & 0xFFFC) 79 var base: i64 = 0 80 if ra != 0 { base = r[ra] } 81 let ea: i64 = base + off 82 pp_g_st(mem, ea, 8, r[rt]) 83 if (w & 3) == 1 { r[ra] = ea } // stdu: update RA 84 } 85 if opc == 31 { // X-form 86 let xo: i64 = (w >> 1) & 0x3FF 87 if xo == 266 { handled = 1; r[rt] = r[ra] + r[rb] } // add 88 if xo == 40 { handled = 1; r[rt] = r[rb] - r[ra] } // subf 89 if xo == 233 { handled = 1; r[rt] = r[ra] * r[rb] } // mulld 90 if xo == 444 { handled = 1; r[ra] = r[rt] | r[rb] } // or / mr (dest=RA) 91 if xo == 28 { handled = 1; r[ra] = r[rt] & r[rb] } // and 92 if xo == 316 { handled = 1; r[ra] = r[rt] ^ r[rb] } // xor 93 if xo == 339 { handled = 1; r[rt] = lr } // mfspr (mflr) 94 if xo == 467 { handled = 1; lr = r[rt] } // mtspr (mtlr) 95 if xo == 489 { handled = 1; let d: i64 = r[rb]; if d != 0 { r[rt] = r[ra] / d } } // divd 96 if xo == 824 { handled = 1; r[rt] = r[ra] } // (srawi-ish stub) 97 } 98 if opc == 19 { // XL-form: blr (bclr) 99 let xo: i64 = (w >> 1) & 0x3FF 100 if xo == 16 { handled = 1; next = lr } // blr (return) 101 } 102 if opc == 18 { // I-form: b / bl 103 handled = 1 104 var li: i64 = (w >> 2) & 0xFFFFFF 105 if (li & 0x800000) != 0 { li = li - 0x1000000 } 106 if (w & 1) == 1 { lr = pc + 4 } // LK 107 next = pc + (li << 2) 108 } 109 if opc == 24 { handled = 1; r[ra] = r[rt] | (w & 0xFFFF) } // ori (nop = ori 0,0,0) 110 if opc == 25 { handled = 1; r[ra] = r[rt] | ((w & 0xFFFF) << 16) } // oris 111 if opc == 17 { // sc (syscall) r0=num, args r3.. 112 handled = 1 113 let nr: i64 = r[0] 114 if nr == PP_SYS_EXIT { result = r[3] & 0xff; halted = 1 } 115 if nr == PP_SYS_EXITG { result = r[3] & 0xff; halted = 1 } 116 if nr == PP_SYS_WRITE { r[3] = sys_write(r[3], ((mem as i64) + r[4]) as *u8, r[5]) } 117 if nr == PP_SYS_READ { r[3] = sys_read(r[3], ((mem as i64) + r[4]) as *u8, r[5]) } 118 } 119 120 if handled == 0 { result = PPE_UNSUPPORTED; halted = 1 } 121 pc = next 122 steps = steps + 1 123 } 124 } 125 return result 126} 127 128func emu_ppc64le_load_elf(buf: *u8, len: i64) -> i64 { 129 if len < 64 { return PPE_FAULT } 130 let e_entry: i64 = pp_g_ld(buf, 24, 8) 131 let e_phoff: i64 = pp_g_ld(buf, 32, 8) 132 let e_phnum: i64 = pp_g_ld(buf, 56, 2) 133 let e_phent: i64 = pp_g_ld(buf, 54, 2) 134 let mem: *u8 = sys_mmap(PP_GUEST_SIZE) 135 var idx: i64 = 0 136 while idx < e_phnum { 137 let ph: i64 = e_phoff + idx * e_phent 138 if pp_g_ld(buf, ph, 4) == 1 { 139 let p_off: i64 = pp_g_ld(buf, ph + 8, 8) 140 let p_va: i64 = pp_g_ld(buf, ph + 16, 8) 141 let p_fs: i64 = pp_g_ld(buf, ph + 32, 8) 142 var k: i64 = 0 143 while k < p_fs { if (p_va + k) < PP_GUEST_SIZE { mem[p_va + k] = buf[p_off + k] }; k = k + 1 } 144 } 145 idx = idx + 1 146 } 147 return emu_ppc64le_run_mem(mem, PP_GUEST_SIZE, e_entry, 0x00F00000) 148}