code wiki / (root) / nx_emu_armv7a.nx

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}