code wiki / (root) / nx_emu_armv7a.nx

nx_emu_armv7a.nx

buildroot/runtime/nx_emu_armv7a.nx

23282 B496 linesdepth 3pulls 3 transitivereach 1 importersview sourcekind librarytopic emu
docsdependenciesstructsconstsfunctions

about

nx_emu_armv7a.nx -- sovereign ARMv7-A (32-bit ARM) interpreter (NX-EMU). Little-endian, fixed 32-bit ARM (not Thumb) encoding, 16 GPRs + NZCV. Linux EABI: svc, r7=num, args r0.., exit=1 (code in r0). NO qemu. license_tier: ORIGINAL ---- 2026-09-03, ISA LANE: WHAT WAS MEASURED AND WHAT WAS BUILT ---- The incumbent decoded a useful subset and had FIVE structural gaps. Each was found by reading the decoder, not by guessing, and each one failed in the SILENT direction -- the interpreter kept running and produced a wrong number rather than saying it could not do the job: 1. THE CONDITION FIELD (bits 31:28) WAS NEVER READ. Every ARM instruction is predicated; BEQ, MOVNE and B were all executed unconditionally. So the emulator could not run a LOOP at all: a backward BNE was always taken, the program spun to the step budget, and the budget path returned the initial result 0 -- which the caller reads as exited-with-status-0, i.e. SUCCESS. A hang was indistinguishable from a pass. 2. THERE WERE NO N, Z OR V FLAGS, only C. Nothing could set them. 3. CMP / CMN / TST / TEQ (opcodes 8..11) claimed handled=1 and then matched no branch, so a comparison was a silent no-op -- the worst possible shape, because it looks exactly like execution. 4. EOR, RSB, RSC, BIC and MVN were the same silent no-op. 5. THE SHIFTER WAS ABSENT: operand2 in register form was taken as the bare register, so add r0, r0, r1, lsl 3 quietly added r1. LDR/STR ignored the B (byte), P (pre/post) and W (writeback) bits and misread a register-offset form as an immediate one. All five are implemented here. Two further classes are now NAMED rather than misdecoded: the extra load/store space (halfword, signed byte, SWP -- told apart from data processing by bit7=1 AND bit4=1) and the cond 0b1111 unconditional-instruction space return A7_UNSUPPORTED instead of being run as a data-processing op. NON-COMPLETION IS THREE NAMED STATES, NOT ONE NEGATIVE WORD. An unimplemented instruction class and a miscomputed value need OPPOSITE fixes, and a program that walked off its image is neither. A7_UNSUPPORTED (-1) a class this interpreter does not decode A7_RANOFF (-2) pc left the image with no exit syscall A7_FAULT (-3) negative pc, out-of-range access, step budget

dependencies 1 imports · 1 importers

nx_syscalls_x86_64.nx nx_emu_armv7a.nx nx_isa_armv7a_gate.nx

imports: nx_syscalls_x86_64.nx

imported by: nx_isa_armv7a_gate.nx

structs

none

consts

53const A7_GUEST: i64 = 16777216
54const A7_MASK: i64 = 0xFFFFFFFF
55const A7_SYS_EXIT: i64 = 1
57const A7_UNSUPPORTED: i64 = -1
58const A7_RANOFF: i64 = -2
59const A7_FAULT: i64 = -3
61const A7_W: i64 = 32
62const A7_WBYTES: i64 = 4
63const A7_BBYTES: i64 = 1
64const A7_SIGNBIT: i64 = 31
65const A7_NREGS: i64 = 16
66const A7_REGBYTES: i64 = 128
67const A7_R_SP: i64 = 13
68const A7_R_LR: i64 = 14
69const A7_R_SVCNUM: i64 = 7
70const A7_R_A0: i64 = 0
71const A7_PIPE: i64 = 8
72const A7_STEP_MAX: i64 = 5000000
73const A7_EXIT_MASK: i64 = 0xff
75const A7_LOW2: i64 = 0x3
76const A7_LOW3: i64 = 0x7
77const A7_LOW4: i64 = 0xF
78const A7_LOW5: i64 = 0x1F
79const A7_LOW8: i64 = 0xFF
80const A7_LOW12: i64 = 0xFFF
81const A7_LOW16: i64 = 0xFFFF
82const A7_LOW24: i64 = 0xFFFFFF
83const A7_ROT_STEP: i64 = 2
84const A7_COND_SH: i64 = 28
85const A7_IMM24_BITS: i64 = 24
86const A7_SH_RD: i64 = 12
87const A7_SH_RN: i64 = 16
88const A7_SH_RM8: i64 = 8
89const A7_SH_OPC: i64 = 21
90const A7_SH_SBIT: i64 = 20
91const A7_SH_IBIT: i64 = 25
92const A7_SH_PBIT: i64 = 24
93const A7_SH_UBIT: i64 = 23
94const A7_SH_BBIT: i64 = 22
95const A7_SH_TYPE: i64 = 5
96const A7_SH_AMT: i64 = 7
97const A7_SH_B4: i64 = 4
98const A7_SH_B7: i64 = 7 // the extra-load/store discriminator, NOT the shift-amount field
99const A7_SH_WBIT: i64 = 21 // writeback bit in load/store and block transfer
100const A7_SH_LBIT: i64 = 20 // load bit in load/store and block transfer
101const A7_SH_BLBIT: i64 = 24 // link bit in the branch encoding
102const A7_SH_HI16: i64 = 16
105const A7_CC_EQ: i64 = 0
106const A7_CC_NE: i64 = 1
107const A7_CC_CS: i64 = 2
108const A7_CC_CC: i64 = 3
109const A7_CC_MI: i64 = 4
110const A7_CC_PL: i64 = 5
111const A7_CC_VS: i64 = 6
112const A7_CC_VC: i64 = 7
113const A7_CC_HI: i64 = 8
114const A7_CC_LS: i64 = 9
115const A7_CC_GE: i64 = 10
116const A7_CC_LT: i64 = 11
117const A7_CC_GT: i64 = 12
118const A7_CC_LE: i64 = 13
119const A7_CC_AL: i64 = 14
120const A7_CC_NV: i64 = 15
123const A7_SH_LSL: i64 = 0
124const A7_SH_LSR: i64 = 1
125const A7_SH_ASR: i64 = 2
126const A7_SH_ROR: i64 = 3
129const A7_DP_AND: i64 = 0
130const A7_DP_EOR: i64 = 1
131const A7_DP_SUB: i64 = 2
132const A7_DP_RSB: i64 = 3
133const A7_DP_ADD: i64 = 4
134const A7_DP_ADC: i64 = 5
135const A7_DP_SBC: i64 = 6
136const A7_DP_RSC: i64 = 7
137const A7_DP_TST: i64 = 8
138const A7_DP_TEQ: i64 = 9
139const A7_DP_CMP: i64 = 10
140const A7_DP_CMN: i64 = 11
141const A7_DP_ORR: i64 = 12
142const A7_DP_MOV: i64 = 13
143const A7_DP_BIC: i64 = 14
144const A7_DP_MVN: i64 = 15
147const A7_MUL_MUL: i64 = 0
148const A7_MUL_MLA: i64 = 1
149const A7_MUL_UMULL: i64 = 4
152const A7_M_MULFAM: i64 = 0x0F0000F0
153const A7_V_MULFAM: i64 = 0x00000090
154const A7_M_MOVW: i64 = 0x0FF00000
155const A7_V_MOVW: i64 = 0x03000000
156const A7_V_MOVT: i64 = 0x03400000
157const A7_M_BXFAM: i64 = 0x0FFFFFF0
158const A7_V_BX: i64 = 0x012FFF10
159const A7_V_BLXR: i64 = 0x012FFF30
160const A7_M_CLASS: i64 = 0x0C000000
161const A7_V_DP: i64 = 0x00000000
162const A7_V_LDST: i64 = 0x04000000
163const A7_M_BRBLK: i64 = 0x0E000000
164const A7_V_BR: i64 = 0x0A000000
165const A7_V_BLK: i64 = 0x08000000
166const A7_M_SVC: i64 = 0x0F000000
167const A7_V_SVC: i64 = 0x0F000000

functions

169func 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] & A7_LOW8) << (i * A7_PIPE)); i = i + 1 } return v }
called by 1: emu_armv7a_run_mem
170func a7_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 { var i: i64 = 0; while i < width { mem[va + i] = (val >> (i * A7_PIPE)) & A7_LOW8; i = i + 1 } return 0 }
called by 1: emu_armv7a_run_mem
171func a7_sx(v: i64, bits: i64) -> i64 { let m: i64 = 1 << (bits - 1); if (v & m) != 0 { return v - (1 << bits) } return v }
172func a7_ror(v: i64, n: i64) -> i64 { if n == 0 { return v & A7_MASK } return ((v >> n) | (v << (A7_W - n))) & A7_MASK }
173func a7_pop(list: i64) -> i64 { var c: i64 = 0; var i: i64 = 0; while i < A7_NREGS { if (list & (1 << i)) != 0 { c = c + 1 } i = i + 1 } return c }
called by 1: emu_armv7a_run_mem
179func a7_lsl(v: i64, n: i64) -> i64 { if n >= A7_W { return 0 } return (v << n) & A7_MASK }
180func a7_lsr(v: i64, n: i64) -> i64 { if n >= A7_W { return 0 } return (v & A7_MASK) >> n }
181func a7_asr(v: i64, n: i64) -> i64
called by 2: a7_shift_imma7_shift_reg calls 1: a7_sx
190func a7_shift_imm(v: i64, ty: i64, amt: i64, cin: i64) -> i64
201func a7_shift_reg(v: i64, ty: i64, amt: i64) -> i64
213func a7_addc(a: i64, b: i64, cin: i64) -> i64 { return ((a + b + cin) >> A7_W) & 1 }
called by 1: emu_armv7a_run_mem
214func a7_subc(a: i64, b: i64, cin: i64) -> i64 { if (a - b - (1 - cin)) >= 0 { return 1 } return 0 }
called by 1: emu_armv7a_run_mem
215func a7_addv(a: i64, b: i64, res: i64) -> i64
called by 1: emu_armv7a_run_mem
222func a7_subv(a: i64, b: i64, res: i64) -> i64
called by 1: emu_armv7a_run_mem
233func a7_cond(c: i64, n: i64, z: i64, cv: i64, v: i64) -> i64
called by 1: emu_armv7a_run_mem
253func emu_armv7a_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64
491func emu_armv7a_run(code: *u8, code_len: i64) -> i64