nx_emu_sparc64.nx source
↩ module page · 497 lines · 23914 B
1// nx_emu_sparc64.nx -- sovereign SPARC V9 (sparc64) interpreter (NX-EMU).
2// Fourth architecture, the hardest: REGISTER WINDOWS + DELAY SLOTS +
3// BIG-ENDIAN. Decode/execute is pure NishiLang per the SPARC V9 ISA
4// (the spec is the oracle) -- NO qemu. qemu-sparc64 is only the
5// differential BENCHMARK that must agree. This is how Nishi CARRIES
6// sparc64 execution (operator: "nishi ecosystem must carry; externals
7// = benchmarks only").
8//
9// Register model: 8 globals g[0..7] (g0 == 0); a window file win[16*NWIN]
10// with the standard overlap (%o of window W == %i of window W+1) selected
11// by CWP. reg field 0..7=%g, 8..15=%o, 16..23=%l, 24..31=%i. save = CWP+1
12// (compute in old window, write rd in new), restore = CWP-1. Control
13// transfers (CALL/JMPL) take effect after the delay-slot instruction via
14// the PC/nPC model. Linux/SPARC syscalls: g1=number, o0..=args, `ta` traps.
15//
16// genealogy_id: sparc_v9_isa + linux_sparc64_abi
17// lineage_id: nishi_nx_emu_sparc64_m1
18// license_tier: ORIGINAL
19
20import "nx_syscalls_x86_64.nx"
21const SP_MAGIC_200000000: i64 = 200000000
22
23const SP_GUEST_SIZE: i64 = 16777216
24const SP_NWIN: i64 = 8
25const SP_SYS_EXIT: i64 = 1
26const SP_SYS_READ: i64 = 3
27const SP_SYS_WRITE: i64 = 4
28const SPE_UNSUPPORTED: i64 = -1
29const SPE_FAULT: i64 = -3
30
31// ---- CONDITION CODES + CONDITIONAL BRANCHES (added 2026-09-03) ----
32// WHAT WAS MISSING AND WHY IT MATTERED: this decoder carried NO condition
33// code state and NO branch of any kind -- format 2 handled only SETHI --
34// so it could not run a LOOP. "Nishi carries sparc64 execution" was a
35// claim about straight-line code. Every encoding below is taken from the
36// SPARC V9 manual (formats 2 and 3, and the Bicc/BPcc cond table); none of
37// it is read back out of this file, which would calibrate the ruler to the
38// subject. The ruler is nx_isa_sparc64_gate.
39const SP_OP2_BPCC: i64 = 1 // BPcc: disp19 plus a cc-field selector
40const SP_OP2_BICC: i64 = 2 // Bicc: disp22, always %icc
41const SP_OP2_SETHI: i64 = 4
42
43// SPARC V9 keeps TWO integer condition-code fields: icc is computed from
44// the LOW 32 BITS of a result and xcc from all 64. Folding them into one
45// set of flags makes every 64-bit compare answer a 32-bit question, and
46// the failure is silent for every value that fits in 32 bits -- which is
47// most of them. Slot layout per field: N Z V C.
48const SP_ICC_N: i64 = 0
49const SP_XCC_N: i64 = 4
50const SP_CC_SLOTS: i64 = 8
51
52const SP_IMM22_MASK: i64 = 4194303 // 0x3FFFFF: SETHI imm22 and Bicc disp22
53const SP_DISP22_SIGN: i64 = 2097152 // 0x200000
54const SP_DISP22_MOD: i64 = 4194304 // 0x400000
55const SP_DISP19_MASK: i64 = 524287 // 0x7FFFF: BPcc disp19
56const SP_DISP19_SIGN: i64 = 262144 // 0x40000
57const SP_DISP19_MOD: i64 = 524288 // 0x80000
58const SP_M32: i64 = 4294967295 // 0xFFFFFFFF
59const SP_M16: i64 = 65535
60const SP_B31: i64 = 2147483648 // 0x80000000
61const SP_2P32: i64 = 4294967296
62const SP_B15: i64 = 32768
63const SP_2P16: i64 = 65536
64const SP_B7: i64 = 128
65const SP_2P8: i64 = 256
66const SP_COND_BA: i64 = 8 // branch-always: the ONE cond whose
67 // annul bit fires on a TAKEN branch
68const SP_CCSEL_ICC: i64 = 0 // BPcc cc1cc0: 00 = %icc, 10 = %xcc;
69const SP_CCSEL_XCC: i64 = 2 // 01 and 11 are RESERVED -> refuse
70
71// This dialect's >> is ARITHMETIC (nx_emu_mips64 carries mi_srl for exactly
72// this reason), so SRLX and SRAX were the SAME expression in the incumbent
73// and one of the two was necessarily wrong for every negative operand. A
74// mask is the only way to get a true logical shift; n == 0 is guarded
75// because 1 << 64 is not a shift this machine performs.
76func sp_srl(v: i64, n: i64) -> i64 {
77 if n == 0 { return v }
78 let mask: i64 = (1 << (64 - n)) - 1
79 return (v >> n) & mask
80}
81func sp_not(v: i64) -> i64 { return (0 - v) - 1 }
82func sp_sx8(v: i64) -> i64 { let t: i64 = v & 0xff; if (t & SP_B7) != 0 { return t - SP_2P8 } return t }
83func sp_sx16(v: i64) -> i64 { let t: i64 = v & SP_M16; if (t & SP_B15) != 0 { return t - SP_2P16 } return t }
84func sp_sx32(v: i64) -> i64 { let t: i64 = v & SP_M32; if (t & SP_B31) != 0 { return t - SP_2P32 } return t }
85func sp_b31(v: i64) -> i64 { if (v & SP_B31) != 0 { return 1 } return 0 }
86func sp_b63(v: i64) -> i64 { if v < 0 { return 1 } return 0 }
87
88// UNSIGNED less-than over two i64s. The dialect's < is signed, so a bare
89// comparison answers the wrong question for exactly the values a carry
90// flag exists to describe.
91func sp_ltu(a: i64, b: i64) -> i64 {
92 if a < 0 {
93 if b < 0 {
94 if a < b { return 1 }
95 return 0
96 }
97 return 0
98 }
99 if b < 0 { return 1 }
100 if a < b { return 1 }
101 return 0
102}
103
104// SPARC V9 arithmetic-with-cc writes BOTH fields: icc from the low 32 bits,
105// xcc from all 64. C is a BORROW for subtraction -- so BLU really means
106// unsigned-less-than -- which is the OPPOSITE polarity from the ARM carry a
107// reader may be carrying in their head.
108func sp_setcc(cc: *i64, a: i64, b: i64, r: i64, is_sub: i64) -> i64 {
109 let a32: i64 = a & SP_M32
110 let b32: i64 = b & SP_M32
111 let r32: i64 = r & SP_M32
112 cc[SP_ICC_N] = sp_b31(r32)
113 var iz: i64 = 0
114 if r32 == 0 { iz = 1 }
115 cc[SP_ICC_N + 1] = iz
116 cc[SP_XCC_N] = sp_b63(r)
117 var xz: i64 = 0
118 if r == 0 { xz = 1 }
119 cc[SP_XCC_N + 1] = xz
120 let ia: i64 = sp_b31(a32)
121 let ib: i64 = sp_b31(b32)
122 let ir: i64 = sp_b31(r32)
123 let xa: i64 = sp_b63(a)
124 let xb: i64 = sp_b63(b)
125 let xr: i64 = sp_b63(r)
126 if is_sub == 1 {
127 cc[SP_ICC_N + 2] = (ia ^ ib) & (ia ^ ir)
128 cc[SP_XCC_N + 2] = (xa ^ xb) & (xa ^ xr)
129 var ic: i64 = 0
130 if a32 < b32 { ic = 1 }
131 cc[SP_ICC_N + 3] = ic
132 cc[SP_XCC_N + 3] = sp_ltu(a, b)
133 }
134 if is_sub == 0 {
135 cc[SP_ICC_N + 2] = (1 - (ia ^ ib)) & (ia ^ ir)
136 cc[SP_XCC_N + 2] = (1 - (xa ^ xb)) & (xa ^ xr)
137 var ac: i64 = 0
138 if (a32 + b32) > SP_M32 { ac = 1 }
139 cc[SP_ICC_N + 3] = ac
140 cc[SP_XCC_N + 3] = sp_ltu(r, a)
141 }
142 return 0
143}
144
145// The logical *cc forms set N and Z from the result and CLEAR V and C.
146func sp_setlog(cc: *i64, r: i64) -> i64 {
147 let r32: i64 = r & SP_M32
148 cc[SP_ICC_N] = sp_b31(r32)
149 var iz: i64 = 0
150 if r32 == 0 { iz = 1 }
151 cc[SP_ICC_N + 1] = iz
152 cc[SP_ICC_N + 2] = 0
153 cc[SP_ICC_N + 3] = 0
154 cc[SP_XCC_N] = sp_b63(r)
155 var xz: i64 = 0
156 if r == 0 { xz = 1 }
157 cc[SP_XCC_N + 1] = xz
158 cc[SP_XCC_N + 2] = 0
159 cc[SP_XCC_N + 3] = 0
160 return 0
161}
162
163// The Bicc/BPcc cond field, SPARC V9 manual. Written row by row rather
164// than packed into a table so a reader can check each line against the
165// manual without decoding a bitmask first.
166func sp_cond(cc: *i64, cond: i64, base: i64) -> i64 {
167 let n: i64 = cc[base]
168 let z: i64 = cc[base + 1]
169 let v: i64 = cc[base + 2]
170 let c: i64 = cc[base + 3]
171 let nv: i64 = n ^ v
172 var cz: i64 = 0
173 if c == 1 { cz = 1 }
174 if z == 1 { cz = 1 }
175 var le: i64 = 0
176 if z == 1 { le = 1 }
177 if nv == 1 { le = 1 }
178 if cond == 0 { return 0 } // BN never
179 if cond == 1 { return z } // BE Z
180 if cond == 2 { return le } // BLE Z or (N xor V)
181 if cond == 3 { return nv } // BL N xor V
182 if cond == 4 { return cz } // BLEU C or Z
183 if cond == 5 { return c } // BCS/BLU C
184 if cond == 6 { return n } // BNEG N
185 if cond == 7 { return v } // BVS V
186 if cond == 8 { return 1 } // BA always
187 if cond == 9 { return 1 - z } // BNE
188 if cond == 10 { return 1 - le } // BG
189 if cond == 11 { return 1 - nv } // BGE
190 if cond == 12 { return 1 - cz } // BGU
191 if cond == 13 { return 1 - c } // BCC/BGEU
192 if cond == 14 { return 1 - n } // BPOS
193 return 1 - v // BVC (cond 15)
194}
195
196// big-endian guest load/store (SPARC is MSB-first)
197func sp_g_ld(mem: *u8, va: i64, width: i64) -> i64 {
198 var v: i64 = 0
199 var i: i64 = 0
200 while i < width { v = (v << 8) | (mem[va + i] & 0xff); i = i + 1 }
201 return v
202}
203func sp_g_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 {
204 var i: i64 = 0
205 while i < width { mem[va + (width - 1 - i)] = (val >> (i * 8)) & 0xff; i = i + 1 }
206 return 0
207}
208
209// windowed register read/write. cwp passed by value (save/restore mutate it
210// in the loop; reads/writes use the value at call time).
211func sp_rd(g: *i64, win: *i64, cwp: i64, r: i64) -> i64 {
212 if r == 0 { return 0 }
213 if r < 8 { return g[r] }
214 if r < 16 { return win[((cwp + 1) % SP_NWIN) * 16 + (r - 8)] } // %o
215 if r < 24 { return win[cwp * 16 + 8 + (r - 16)] } // %l
216 return win[cwp * 16 + (r - 24)] // %i
217}
218func sp_wr(g: *i64, win: *i64, cwp: i64, r: i64, v: i64) -> i64 {
219 if r == 0 { return 0 }
220 if r < 8 { g[r] = v; return 0 }
221 if r < 16 { win[((cwp + 1) % SP_NWIN) * 16 + (r - 8)] = v; return 0 }
222 if r < 24 { win[cwp * 16 + 8 + (r - 16)] = v; return 0 }
223 win[cwp * 16 + (r - 24)] = v
224 return 0
225}
226
227func emu_sparc64_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 {
228 let g: *i64 = sys_mmap(8 * 8) as *i64
229 let win: *i64 = sys_mmap(16 * SP_NWIN * 8) as *i64
230 var i: i64 = 0
231 while i < 8 { g[i] = 0; i = i + 1 }
232 i = 0
233 while i < 16 * SP_NWIN { win[i] = 0; i = i + 1 }
234 var cwp: i64 = 0
235 // The integer condition codes. Two fields of N Z V C: icc (slots 0..3)
236 // from the low 32 bits of a result, xcc (slots 4..7) from all 64.
237 let cc: *i64 = sys_mmap(SP_CC_SLOTS * 8) as *i64
238 var ci: i64 = 0
239 while ci < SP_CC_SLOTS { cc[ci] = 0; ci = ci + 1 }
240 sp_wr(g, win, cwp, 14, sp0) // %o6 = %sp
241 var pc: i64 = entry
242 var npc: i64 = entry + 4
243 var steps: i64 = 0
244 var halted: i64 = 0
245 var result: i64 = SPE_FAULT
246 while halted == 0 && steps < SP_MAGIC_200000000 {
247 if pc < 0 { halted = 1; result = SPE_FAULT }
248 if pc + 4 > mem_size { halted = 1; result = SPE_FAULT }
249 if halted == 0 {
250 let w: i64 = sp_g_ld(mem, pc, 4)
251 let op: i64 = (w >> 30) & 3
252 let rd: i64 = (w >> 25) & 0x1F
253 var next_pc: i64 = npc
254 var next_npc: i64 = npc + 4
255 var handled: i64 = 0
256
257 if op == 1 { // CALL (format 1)
258 handled = 1
259 var disp: i64 = w & 0x3FFFFFFF
260 if (disp & 0x20000000) != 0 { disp = disp - 0x40000000 }
261 sp_wr(g, win, cwp, 15, pc) // %o7 = pc
262 next_npc = pc + (disp << 2)
263 }
264 if op == 0 { // format 2: SETHI / branches
265 let op2: i64 = (w >> 22) & 7
266 if op2 == SP_OP2_SETHI { // SETHI (NOP = sethi 0,%g0)
267 handled = 1
268 sp_wr(g, win, cwp, rd, (w & SP_IMM22_MASK) << 10)
269 }
270 // In format 2 the rd FIELD is not a register: bit 29 is the
271 // annul bit and bits 28..25 are cond. Reusing rd here is
272 // exact rather than a shortcut, because rd IS (w >> 25) & 0x1F.
273 let cond: i64 = rd & 0xF
274 let anl: i64 = (rd >> 4) & 1
275 if op2 == SP_OP2_BICC { // Bicc: disp22, %icc only
276 handled = 1
277 var d22: i64 = w & SP_IMM22_MASK
278 if (d22 & SP_DISP22_SIGN) != 0 { d22 = d22 - SP_DISP22_MOD }
279 let tk: i64 = sp_cond(cc, cond, SP_ICC_N)
280 // DELAY SLOT: in this pc/npc model the instruction at npc
281 // runs BEFORE the target, which is the semantic a naive
282 // branch silently gets wrong. ANNUL skips it when the
283 // branch is UNTAKEN, and ALSO on BA (cond 8) where it is
284 // taken -- that asymmetry is the whole of the annul rule
285 // and the half an implementation typically drops.
286 var anz: i64 = 0
287 if anl == 1 {
288 if tk == 0 { anz = 1 }
289 if cond == SP_COND_BA { anz = 1 }
290 }
291 let tgt: i64 = pc + (d22 << 2)
292 if tk == 1 {
293 next_npc = tgt
294 if anz == 1 { next_pc = tgt; next_npc = tgt + 4 }
295 }
296 if tk == 0 {
297 if anz == 1 { next_pc = npc + 4; next_npc = npc + 8 }
298 }
299 }
300 if op2 == SP_OP2_BPCC { // BPcc: disp19 + cc selector
301 let ccsel: i64 = (w >> 20) & 3
302 var base: i64 = -1
303 if ccsel == SP_CCSEL_ICC { base = SP_ICC_N }
304 if ccsel == SP_CCSEL_XCC { base = SP_XCC_N }
305 // cc1cc0 of 01 and 11 are RESERVED in V9. Leaving them
306 // unhandled reports UNSUPPORTED instead of confidently
307 // answering a question the manual does not define.
308 if base >= 0 {
309 handled = 1
310 var d19: i64 = w & SP_DISP19_MASK
311 if (d19 & SP_DISP19_SIGN) != 0 { d19 = d19 - SP_DISP19_MOD }
312 let tk2: i64 = sp_cond(cc, cond, base)
313 var anz2: i64 = 0
314 if anl == 1 {
315 if tk2 == 0 { anz2 = 1 }
316 if cond == SP_COND_BA { anz2 = 1 }
317 }
318 let tgt2: i64 = pc + (d19 << 2)
319 if tk2 == 1 {
320 next_npc = tgt2
321 if anz2 == 1 { next_pc = tgt2; next_npc = tgt2 + 4 }
322 }
323 if tk2 == 0 {
324 if anz2 == 1 { next_pc = npc + 4; next_npc = npc + 8 }
325 }
326 }
327 }
328 }
329 if op == 2 { // format 3: arithmetic / control
330 let op3: i64 = (w >> 19) & 0x3F
331 let rs1: i64 = (w >> 14) & 0x1F
332 let ibit: i64 = (w >> 13) & 1
333 var o2: i64 = 0
334 if ibit == 1 {
335 o2 = w & 0x1FFF
336 if (o2 & 0x1000) != 0 { o2 = o2 - 0x2000 }
337 } else {
338 o2 = sp_rd(g, win, cwp, w & 0x1F)
339 }
340 let a: i64 = sp_rd(g, win, cwp, rs1)
341 if op3 == 0x00 { handled = 1; sp_wr(g, win, cwp, rd, a + o2) } // ADD
342 if op3 == 0x04 { handled = 1; sp_wr(g, win, cwp, rd, a - o2) } // SUB
343 if op3 == 0x01 { handled = 1; sp_wr(g, win, cwp, rd, a & o2) } // AND
344 if op3 == 0x02 { handled = 1; sp_wr(g, win, cwp, rd, a | o2) } // OR
345 if op3 == 0x03 { handled = 1; sp_wr(g, win, cwp, rd, a ^ o2) } // XOR
346 if op3 == 0x09 { handled = 1; sp_wr(g, win, cwp, rd, a * o2) } // MULX
347 if op3 == 0x2d { handled = 1; if o2 != 0 { sp_wr(g, win, cwp, rd, a / o2) } } // SDIVX
348 if op3 == 0x0d { handled = 1; if o2 != 0 { sp_wr(g, win, cwp, rd, a / o2) } } // UDIVX
349 if op3 == 0x05 { handled = 1; sp_wr(g, win, cwp, rd, a & sp_not(o2)) } // ANDN
350 if op3 == 0x06 { handled = 1; sp_wr(g, win, cwp, rd, a | sp_not(o2)) } // ORN
351 if op3 == 0x07 { handled = 1; sp_wr(g, win, cwp, rd, sp_not(a ^ o2)) } // XNOR
352 // The *cc forms are the plain op3 with bit 4 set. Without a
353 // single one of them there was nothing for a branch to test,
354 // which is why the branch gap and the cc gap are ONE gap.
355 if op3 == 0x10 { // ADDcc
356 handled = 1
357 let res_add: i64 = a + o2
358 sp_wr(g, win, cwp, rd, res_add)
359 sp_setcc(cc, a, o2, res_add, 0)
360 }
361 if op3 == 0x14 { // SUBcc (cmp)
362 handled = 1
363 let res_sub: i64 = a - o2
364 sp_wr(g, win, cwp, rd, res_sub)
365 sp_setcc(cc, a, o2, res_sub, 1)
366 }
367 if op3 == 0x11 { // ANDcc
368 handled = 1
369 let res_and: i64 = a & o2
370 sp_wr(g, win, cwp, rd, res_and)
371 sp_setlog(cc, res_and)
372 }
373 if op3 == 0x12 { // ORcc
374 handled = 1
375 let res_or: i64 = a | o2
376 sp_wr(g, win, cwp, rd, res_or)
377 sp_setlog(cc, res_or)
378 }
379 if op3 == 0x13 { // XORcc
380 handled = 1
381 let res_xor: i64 = a ^ o2
382 sp_wr(g, win, cwp, rd, res_xor)
383 sp_setlog(cc, res_xor)
384 }
385 // SHIFTS. Bit 12 is the X bit: x=1 selects the 64-bit form
386 // (shcnt 5:0), x=0 the 32-bit form (shcnt 4:0) defined on the
387 // LOW 32 BITS. op3 0x27 (SRA/SRAX) was ABSENT entirely, and
388 // 0x26 (SRL/SRLX) was spelled with this dialect's ARITHMETIC
389 // >> , so the logical and the arithmetic right shift were one
390 // expression and one of them had to be wrong for every
391 // negative operand. Masking o2 with 63 recovers the raw
392 // shcnt whether i is 0 or 1, because the 13-bit sign
393 // extension only touches bits above 12.
394 let xbit: i64 = (w >> 12) & 1
395 var shc: i64 = o2 & 63
396 if xbit == 0 { shc = o2 & 31 }
397 if op3 == 0x25 { // SLL / SLLX
398 handled = 1
399 if xbit == 1 { sp_wr(g, win, cwp, rd, a << shc) }
400 if xbit == 0 { sp_wr(g, win, cwp, rd, ((a & SP_M32) << shc) & SP_M32) }
401 }
402 if op3 == 0x26 { // SRL / SRLX
403 handled = 1
404 if xbit == 1 { sp_wr(g, win, cwp, rd, sp_srl(a, shc)) }
405 if xbit == 0 { sp_wr(g, win, cwp, rd, (a & SP_M32) >> shc) }
406 }
407 if op3 == 0x27 { // SRA / SRAX
408 handled = 1
409 if xbit == 1 { sp_wr(g, win, cwp, rd, a >> shc) }
410 if xbit == 0 { sp_wr(g, win, cwp, rd, sp_sx32(a) >> shc) }
411 }
412 if op3 == 0x3c { // SAVE: compute old window, shift, write new
413 handled = 1
414 cwp = (cwp + 1) % SP_NWIN
415 sp_wr(g, win, cwp, rd, a + o2)
416 }
417 if op3 == 0x3d { // RESTORE
418 handled = 1
419 cwp = (cwp - 1 + SP_NWIN) % SP_NWIN
420 sp_wr(g, win, cwp, rd, a + o2)
421 }
422 if op3 == 0x38 { // JMPL (ret = jmpl %i7+8,%g0)
423 handled = 1
424 sp_wr(g, win, cwp, rd, pc)
425 next_npc = a + o2
426 }
427 if op3 == 0x3a { // Tcc (trap) -> Linux syscall (g1=num)
428 handled = 1
429 let nr: i64 = g[1]
430 if nr == SP_SYS_EXIT { result = sp_rd(g, win, cwp, 8) & 0xff; halted = 1 }
431 if nr == SP_SYS_WRITE { sp_wr(g, win, cwp, 8, sys_write(sp_rd(g, win, cwp, 8), ((mem as i64) + sp_rd(g, win, cwp, 9)) as *u8, sp_rd(g, win, cwp, 10))) }
432 if nr == SP_SYS_READ { sp_wr(g, win, cwp, 8, sys_read(sp_rd(g, win, cwp, 8), ((mem as i64) + sp_rd(g, win, cwp, 9)) as *u8, sp_rd(g, win, cwp, 10))) }
433 }
434 }
435 if op == 3 { // format 3: load / store
436 let op3: i64 = (w >> 19) & 0x3F
437 let rs1: i64 = (w >> 14) & 0x1F
438 let ibit: i64 = (w >> 13) & 1
439 var o2: i64 = 0
440 if ibit == 1 {
441 o2 = w & 0x1FFF
442 if (o2 & 0x1000) != 0 { o2 = o2 - 0x2000 }
443 } else {
444 o2 = sp_rd(g, win, cwp, w & 0x1F)
445 }
446 let ea: i64 = sp_rd(g, win, cwp, rs1) + o2
447 if op3 == 0x0b { handled = 1; sp_wr(g, win, cwp, rd, sp_g_ld(mem, ea, 8)) } // LDX
448 if op3 == 0x0e { handled = 1; sp_g_st(mem, ea, 8, sp_rd(g, win, cwp, rd)) } // STX
449 // op3 0x00 is LDUW and op3 0x08 is LDSW in SPARC V9. The
450 // incumbent had NO 0x00 at all and decoded 0x08 as an
451 // UNSIGNED load: so the only 32-bit load it could run was the
452 // signed one, answering with the wrong sign extension, while
453 // a real LDUW reported UNSUPPORTED. Both directions are
454 // pinned by KATs in nx_isa_sparc64_gate.
455 if op3 == 0x00 { handled = 1; sp_wr(g, win, cwp, rd, sp_g_ld(mem, ea, 4)) } // LDUW
456 if op3 == 0x08 { handled = 1; sp_wr(g, win, cwp, rd, sp_sx32(sp_g_ld(mem, ea, 4))) } // LDSW
457 if op3 == 0x01 { handled = 1; sp_wr(g, win, cwp, rd, sp_g_ld(mem, ea, 1)) } // LDUB
458 if op3 == 0x09 { handled = 1; sp_wr(g, win, cwp, rd, sp_sx8(sp_g_ld(mem, ea, 1))) } // LDSB
459 if op3 == 0x02 { handled = 1; sp_wr(g, win, cwp, rd, sp_g_ld(mem, ea, 2)) } // LDUH
460 if op3 == 0x0a { handled = 1; sp_wr(g, win, cwp, rd, sp_sx16(sp_g_ld(mem, ea, 2))) } // LDSH
461 if op3 == 0x04 { handled = 1; sp_g_st(mem, ea, 4, sp_rd(g, win, cwp, rd)) } // STW
462 if op3 == 0x05 { handled = 1; sp_g_st(mem, ea, 1, sp_rd(g, win, cwp, rd)) } // STB
463 if op3 == 0x06 { handled = 1; sp_g_st(mem, ea, 2, sp_rd(g, win, cwp, rd)) } // STH
464 }
465
466 if handled == 0 { result = SPE_UNSUPPORTED; halted = 1 }
467 pc = next_pc
468 npc = next_npc
469 steps = steps + 1
470 }
471 }
472 return result
473}
474
475func emu_sparc64_load_elf(buf: *u8, len: i64) -> i64 {
476 if len < 64 { return SPE_FAULT }
477 let e_entry: i64 = sp_g_ld(buf, 24, 8)
478 let e_phoff: i64 = sp_g_ld(buf, 32, 8)
479 let e_phnum: i64 = sp_g_ld(buf, 56, 2)
480 let e_phent: i64 = sp_g_ld(buf, 54, 2)
481 let mem: *u8 = sys_mmap(SP_GUEST_SIZE)
482 var idx: i64 = 0
483 while idx < e_phnum {
484 let ph: i64 = e_phoff + idx * e_phent
485 if sp_g_ld(buf, ph, 4) == 1 { // PT_LOAD
486 let p_off: i64 = sp_g_ld(buf, ph + 8, 8)
487 let p_va: i64 = sp_g_ld(buf, ph + 16, 8)
488 let p_fs: i64 = sp_g_ld(buf, ph + 32, 8)
489 var k: i64 = 0
490 while k < p_fs { if (p_va + k) < SP_GUEST_SIZE { mem[p_va + k] = buf[p_off + k] }; k = k + 1 }
491 }
492 idx = idx + 1
493 }
494 // initial %sp: biased; sp+2047+frame must stay in RAM
495 let sp: i64 = 0x00E00000
496 return emu_sparc64_run_mem(mem, SP_GUEST_SIZE, e_entry, sp)
497}