nx_emu_armv7a.nx source
↩ module page · 134 lines · 7089 B
1// nx_emu_armv7a.nx -- sovereign ARMv7-A (32-bit ARM) interpreter (NX-EMU).
2// Little-endian, fixed 32-bit instrs, 16 GPRs + C flag (for i64-pair add/sub carry).
3// Decodes the subset nxc2's armv7a backend emits: DP add/adc/sub/sbc/adds/subs/mov
4// (reg+rotated-imm), movw, mla, umull, ldr/str (imm offset, U-bit sign), push/pop
5// (STMDB/LDMIA sp!), bx, bl (ARM pc+8 pipeline), svc. Linux EABI: svc, r7=num,
6// args r0.., exit=1 (code in r0). NO qemu. license_tier: ORIGINAL
7import "nx_syscalls_x86_64.nx"
8
9const A7_GUEST: i64 = 16777216
10const A7_MASK: i64 = 0xFFFFFFFF
11const A7_SYS_EXIT: i64 = 1
12
13func a7_ld(mem: *u8, va: i64, width: i64) -> i64 { var v: i64 = 0; var i: i64 = 0; while i < width { v = v | ((mem[va + i] & 0xff) << (i * 8)); i = i + 1 } return v }
14func a7_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 { var i: i64 = 0; while i < width { mem[va + i] = (val >> (i * 8)) & 0xff; i = i + 1 } return 0 }
15func a7_sx(v: i64, bits: i64) -> i64 { let m: i64 = 1 << (bits - 1); if (v & m) != 0 { return v - (1 << bits) } return v }
16func a7_ror(v: i64, n: i64) -> i64 { if n == 0 { return v & A7_MASK } return ((v >> n) | (v << (32 - n))) & A7_MASK }
17func a7_pop(list: i64) -> i64 { var c: i64 = 0; var i: i64 = 0; while i < 16 { if (list & (1 << i)) != 0 { c = c + 1 } i = i + 1 } return c }
18
19func emu_armv7a_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 {
20 let r: *i64 = sys_mmap(16 * 8) as *i64
21 var i: i64 = 0
22 while i < 16 { r[i] = 0; i = i + 1 }
23 r[13] = sp0
24 var pc: i64 = entry
25 var cf: i64 = 0
26 var result: i64 = 0
27 var halted: i64 = 0
28 var steps: i64 = 0
29 while halted == 0 {
30 if steps > 5000000 { halted = 1 } else {
31 let w: i64 = a7_ld(mem, pc, 4)
32 var next: i64 = pc + 4
33 var handled: i64 = 0
34 // --- multiply family: bits27:24=0000, bits7:4=1001 ---
35 if (w & 0x0F0000F0) == 0x00000090 {
36 handled = 1
37 let sub: i64 = (w >> 21) & 0x7
38 let Rd: i64 = (w >> 16) & 0xF
39 let Ra: i64 = (w >> 12) & 0xF
40 let Rm: i64 = (w >> 8) & 0xF
41 let Rn: i64 = w & 0xF
42 if sub == 0 { r[Rd] = (r[Rn] * r[Rm]) & A7_MASK } // mul
43 if sub == 1 { r[Rd] = (r[Rn] * r[Rm] + r[Ra]) & A7_MASK } // mla
44 if sub == 4 { let p: i64 = (r[Rn] & A7_MASK) * (r[Rm] & A7_MASK); r[Ra] = p & A7_MASK; r[Rd] = (p >> 32) & A7_MASK } // umull: Rd=hi,Ra=lo
45 }
46 // --- movw ---
47 if handled == 0 { if (w & 0x0FF00000) == 0x03000000 {
48 handled = 1
49 let Rd: i64 = (w >> 12) & 0xF
50 r[Rd] = (((w >> 16) & 0xF) << 12) | (w & 0xFFF)
51 } }
52 // --- bx (special bits27:26=00 encoding; MUST precede the DP catch-all) ---
53 if handled == 0 { if (w & 0x0FFFFFF0) == 0x012FFF10 {
54 handled = 1
55 next = r[w & 0xF] & (A7_MASK - 1)
56 } }
57 // --- data processing (bits27:26=00) ---
58 if handled == 0 { if (w & 0x0C000000) == 0x00000000 {
59 handled = 1
60 let I: i64 = (w >> 25) & 1
61 let opc: i64 = (w >> 21) & 0xF
62 let S: i64 = (w >> 20) & 1
63 let Rn: i64 = (w >> 16) & 0xF
64 let Rd: i64 = (w >> 12) & 0xF
65 var op2: i64 = 0
66 if I == 1 { op2 = a7_ror(w & 0xFF, ((w >> 8) & 0xF) * 2) } else { op2 = r[w & 0xF] & A7_MASK }
67 let a: i64 = r[Rn] & A7_MASK
68 if opc == 4 { let s2: i64 = a + op2; if S == 1 { cf = (s2 >> 32) & 1 } r[Rd] = s2 & A7_MASK } // add/adds
69 if opc == 5 { r[Rd] = (a + op2 + cf) & A7_MASK } // adc
70 if opc == 2 { if S == 1 { if a < op2 { cf = 0 } else { cf = 1 } } r[Rd] = (a - op2) & A7_MASK } // sub/subs
71 if opc == 6 { r[Rd] = (a - op2 - (1 - cf)) & A7_MASK } // sbc
72 if opc == 13 { r[Rd] = op2 } // mov
73 if opc == 0 { r[Rd] = a & op2 } // and
74 if opc == 12 { r[Rd] = a | op2 } // orr
75 } }
76 // --- load/store (bits27:26=01) ---
77 if handled == 0 { if (w & 0x0C000000) == 0x04000000 {
78 handled = 1
79 let U: i64 = (w >> 23) & 1
80 let L: i64 = (w >> 20) & 1
81 let Rn: i64 = (w >> 16) & 0xF
82 let Rd: i64 = (w >> 12) & 0xF
83 var off: i64 = w & 0xFFF
84 if U == 0 { off = 0 - off }
85 let ea: i64 = (r[Rn] + off) & A7_MASK
86 if L == 1 { r[Rd] = a7_ld(mem, ea, 4) & A7_MASK } else { a7_st(mem, ea, 4, r[Rd] & A7_MASK) }
87 } }
88 // --- branch / bl (bits27:25=101) ---
89 if handled == 0 { if (w & 0x0E000000) == 0x0A000000 {
90 handled = 1
91 let L: i64 = (w >> 24) & 1
92 let off: i64 = a7_sx(w & 0xFFFFFF, 24) << 2
93 if L == 1 { r[14] = (pc + 4) & A7_MASK }
94 next = pc + 8 + off
95 } }
96 // --- block transfer push/pop (bits27:25=100) ---
97 if handled == 0 { if (w & 0x0E000000) == 0x08000000 {
98 handled = 1
99 let U: i64 = (w >> 23) & 1
100 let L: i64 = (w >> 20) & 1
101 let Rn: i64 = (w >> 16) & 0xF
102 let list: i64 = w & 0xFFFF
103 let cnt: i64 = a7_pop(list)
104 var addr: i64 = r[Rn]
105 if U == 0 { addr = (addr - 4 * cnt) & A7_MASK } // decrement-before base
106 var k: i64 = 0
107 while k < 16 {
108 if (list & (1 << k)) != 0 {
109 if L == 1 { r[k] = a7_ld(mem, addr, 4) & A7_MASK } else { a7_st(mem, addr, 4, r[k] & A7_MASK) }
110 addr = (addr + 4) & A7_MASK
111 }
112 k = k + 1
113 }
114 if U == 0 { r[Rn] = (r[Rn] - 4 * cnt) & A7_MASK } else { r[Rn] = (r[Rn] + 4 * cnt) & A7_MASK } // writeback (sp!)
115 } }
116 // --- svc ---
117 if handled == 0 { if (w & 0x0F000000) == 0x0F000000 {
118 handled = 1
119 if r[7] == A7_SYS_EXIT { result = r[0] & 0xff; halted = 1 }
120 } }
121 if handled == 0 { result = 0 - 1; halted = 1 }
122 pc = next
123 steps = steps + 1
124 }
125 }
126 return result
127}
128
129func emu_armv7a_run(code: *u8, code_len: i64) -> i64 {
130 let mem: *u8 = sys_mmap(A7_GUEST)
131 var i: i64 = 0
132 while i < code_len { mem[i] = code[i]; i = i + 1 }
133 return emu_armv7a_run_mem(mem, A7_GUEST, 0, 0x00800000)
134}