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}