nx_emu_cortexm.nx source
↩ module page · 852 lines · 41672 B
1// nx_emu_cortexm.nx -- sovereign ARMv7-M / Cortex-M (Thumb-2) interpreter (NX-EMU).
2// Little-endian, MIXED 16/32-bit instructions (32-bit iff hw1[15:11] in {11101,11110,
3// 11111} i.e. hw1>=0xE800), 16 GPRs + NZCV. Bare-metal: BKPT halts with result=r0
4// (no OS). NO qemu. license_tier: ORIGINAL
5//
6// 2026-09-03, ISA LANE. WHAT THIS REVISION ADDS AND WHY.
7// The first cut decoded exactly the subset nxc2 cortex_m backend emits: push/pop,
8// mov(hi), movs, adds/subs/adcs/sbcs (register form only), sub-sp, ldr/str, blx, movw,
9// umull, mla, subw. Measured against the ARMv7-M Architecture Reference Manual that
10// left the machine unable to run a PROGRAM rather than a straight line:
11// * NO conditional branch at all (B-cond, encoding 1101 cond imm8) -- so no loop,
12// no if, no early exit could ever execute.
13// * NO unconditional branch (B T2, 11100 imm11).
14// * NO CMP in either form, and only ONE flag (C). N, Z and V did not exist, so even
15// a hand-written branch would have had nothing to test.
16// * NO immediate add/sub (imm3 and imm8 forms), no logic (AND EOR ORR BIC MVN TST),
17// no shifts (LSL LSR ASR ROR), no MUL, no byte/halfword access, no SP-relative or
18// PC-relative load, no CBZ/CBNZ, no extends.
19// An emulator that cannot take a branch cannot run a loop, and a loop is the first
20// program anyone writes. So the gap was CLOSED rather than reported: this file now
21// carries full NZCV, the ARM add/subtract-with-carry adder that derives all four
22// flags from one place, the condition-code table, and the decode above.
23//
24// THE OTHER DEFECT FIXED HERE, AND IT IS THE DANGEROUS ONE: the step-budget path used
25// to leave result at its initial 0 and halt. 0 is ALSO a legitimate exit status, so a
26// runaway program and a program that exited cleanly with 0 returned the SAME VALUE.
27// A non-completion that is indistinguishable from a real answer is worse than a crash.
28// Non-completion now has NAMED sentinels, matching the rv64/mips64 siblings so one
29// ruler can classify all of them: -1 UNSUPPORTED, -2 RAN-OFF-END, -3 FAULT.
30// RAN-OFF-END is structurally unreachable in this interpreter (the loop can only exit
31// through a halt) and that is stated rather than hidden -- the constant exists so the
32// classifier third state has a name here too, not because this file can produce it.
33//
34// SCOPE, STATED SO NOBODY READS THIS AS COMPLETE: IT blocks (0xBF00), SVC (0xDF00),
35// UDF (0xDE00), LDM/STM (0xC000), REV/REVSH, and every 32-bit Thumb-2 encoding outside
36// {MOVW SUBW UMULL MLA LDR.W STR.W} are still UNDECODED and correctly report
37// UNSUPPORTED. UDF is PERMANENTLY UNDEFINED by the manual, which makes it a stable
38// negative control: nx_isa_cortexm_gate uses it to prove the refusal path fires.
39import "nx_syscalls_x86_64.nx"
40
41const CM_GUEST: i64 = 16777216
42const CM_MASK: i64 = 0xFFFFFFFF
43
44// ---- machine shape ----
45const CM_WORD_BITS: i64 = 32
46const CM_SIGNBIT: i64 = 31
47const CM_NREGS: i64 = 16
48const CM_REG_BYTES: i64 = 128 // CM_NREGS * 8, the register file allocation
49const CM_SP: i64 = 13
50const CM_LR: i64 = 14
51const CM_PC: i64 = 15
52const CM_PC_BIAS: i64 = 4 // Thumb: PC reads as the instruction address + 4
53const CM_HW: i64 = 2 // halfword: the Thumb instruction quantum
54const CM_W32: i64 = 4
55const CM_B8: i64 = 1
56const CM_DEFAULT_SP: i64 = 8388608 // 0x00800000, used only by the run() convenience wrapper
57const CM_STEP_BUDGET: i64 = 5000000
58const CM_EXIT_MASK: i64 = 0xff
59
60// ---- non-completion sentinels (mirror EMU_RV_* / MIE_* so one classifier reads all) ----
61const CM_UNSUPPORTED: i64 = -1
62const CM_RANOFF: i64 = -2
63const CM_FAULT: i64 = -3
64
65// ---- NZCV, packed so one helper can return result AND flags ----
66const CM_FLAG_N: i64 = 1
67const CM_FLAG_Z: i64 = 2
68const CM_FLAG_C: i64 = 4
69const CM_FLAG_V: i64 = 8
70const CM_FLAG_CV: i64 = 12 // CM_FLAG_C + CM_FLAG_V, the pair a logic op preserves
71const CM_FLAGMASK: i64 = 15
72const CM_FLAGSHIFT: i64 = 32 // a 32-bit result never reaches bit 32, so the pack is lossless
73
74// ---- shifter kinds ----
75const CM_SH_LSL: i64 = 0
76const CM_SH_LSR: i64 = 1
77const CM_SH_ASR: i64 = 2
78const CM_SH_ROR: i64 = 3
79const CM_ROT_MASK: i64 = 31
80
81// ---- condition codes, Table A7-1 of the ARMv7-M ARM ----
82const CM_C_EQ: i64 = 0
83const CM_C_NE: i64 = 1
84const CM_C_CS: i64 = 2
85const CM_C_CC: i64 = 3
86const CM_C_MI: i64 = 4
87const CM_C_PL: i64 = 5
88const CM_C_VS: i64 = 6
89const CM_C_VC: i64 = 7
90const CM_C_HI: i64 = 8
91const CM_C_LS: i64 = 9
92const CM_C_GE: i64 = 10
93const CM_C_LT: i64 = 11
94const CM_C_GT: i64 = 12
95const CM_C_LE: i64 = 13
96const CM_C_MAX: i64 = 13 // 14 is UDF and 15 is SVC in the B-cond encoding
97
98// ---- decode masks ----
99const CM_M32_LO: i64 = 0xE800
100const CM_MSK_F000: i64 = 0xF000
101const CM_MSK_F800: i64 = 0xF800
102const CM_MSK_FD00: i64 = 0xFD00
103const CM_MSK_FE00: i64 = 0xFE00
104const CM_MSK_FF00: i64 = 0xFF00
105const CM_MSK_FF80: i64 = 0xFF80
106const CM_MSK_FF87: i64 = 0xFF87
107const CM_MSK_FFC0: i64 = 0xFFC0
108const CM_MSK_FBF0: i64 = 0xFBF0
109const CM_MSK_FFF0: i64 = 0xFFF0
110
111// ---- 16-bit opcode bases ----
112const CM_OP_LSLI: i64 = 0x0000
113const CM_OP_LSRI: i64 = 0x0800
114const CM_OP_ASRI: i64 = 0x1000
115const CM_OP_ADDR: i64 = 0x1800
116const CM_OP_SUBR: i64 = 0x1A00
117const CM_OP_ADDI3: i64 = 0x1C00
118const CM_OP_SUBI3: i64 = 0x1E00
119const CM_OP_MOVI8: i64 = 0x2000
120const CM_OP_CMPI8: i64 = 0x2800
121const CM_OP_ADDI8: i64 = 0x3000
122const CM_OP_SUBI8: i64 = 0x3800
123const CM_OP_AND: i64 = 0x4000
124const CM_OP_EOR: i64 = 0x4040
125const CM_OP_LSLR: i64 = 0x4080
126const CM_OP_LSRR: i64 = 0x40C0
127const CM_OP_ASRR: i64 = 0x4100
128const CM_OP_ADC: i64 = 0x4140
129const CM_OP_SBC: i64 = 0x4180
130const CM_OP_ROR: i64 = 0x41C0
131const CM_OP_TST: i64 = 0x4200
132const CM_OP_RSB: i64 = 0x4240
133const CM_OP_CMPR: i64 = 0x4280
134const CM_OP_CMN: i64 = 0x42C0
135const CM_OP_ORR: i64 = 0x4300
136const CM_OP_MUL: i64 = 0x4340
137const CM_OP_BIC: i64 = 0x4380
138const CM_OP_MVN: i64 = 0x43C0
139const CM_OP_ADDHI: i64 = 0x4400
140const CM_OP_CMPHI: i64 = 0x4500
141const CM_OP_MOVHI: i64 = 0x4600
142const CM_OP_BX: i64 = 0x4700
143const CM_OP_BLX: i64 = 0x4780
144const CM_OP_LDRLIT: i64 = 0x4800
145const CM_OP_STRR: i64 = 0x5000
146const CM_OP_STRHR: i64 = 0x5200
147const CM_OP_STRBR: i64 = 0x5400
148const CM_OP_LDRSBR: i64 = 0x5600
149const CM_OP_LDRR: i64 = 0x5800
150const CM_OP_LDRHR: i64 = 0x5A00
151const CM_OP_LDRBR: i64 = 0x5C00
152const CM_OP_LDRSHR: i64 = 0x5E00
153const CM_OP_STRI5: i64 = 0x6000
154const CM_OP_LDRI5: i64 = 0x6800
155const CM_OP_STRBI5: i64 = 0x7000
156const CM_OP_LDRBI5: i64 = 0x7800
157const CM_OP_STRHI5: i64 = 0x8000
158const CM_OP_LDRHI5: i64 = 0x8800
159const CM_OP_STRSP: i64 = 0x9000
160const CM_OP_LDRSP: i64 = 0x9800
161const CM_OP_ADR: i64 = 0xA000
162const CM_OP_ADDSPR: i64 = 0xA800
163const CM_OP_ADDSPI: i64 = 0xB000
164const CM_OP_SUBSPI: i64 = 0xB080
165const CM_OP_CBZ: i64 = 0xB100
166const CM_OP_SXTH: i64 = 0xB200
167const CM_OP_SXTB: i64 = 0xB240
168const CM_OP_UXTH: i64 = 0xB280
169const CM_OP_UXTB: i64 = 0xB2C0
170const CM_OP_PUSH: i64 = 0xB400
171const CM_OP_CBNZ: i64 = 0xB900
172const CM_OP_POP: i64 = 0xBC00
173const CM_OP_BKPT: i64 = 0xBE00
174const CM_OP_BCOND: i64 = 0xD000
175const CM_OP_B: i64 = 0xE000
176
177// ---- 32-bit opcode bases ----
178const CM_OP_MOVW: i64 = 0xF240
179const CM_OP_SUBW: i64 = 0xF2A0
180const CM_OP_UMULL: i64 = 0xFBA0
181const CM_OP_MLA: i64 = 0xFB00
182const CM_OP_LDRT4: i64 = 0xF850
183const CM_OP_STRT4: i64 = 0xF840
184
185// ---- immediate field widths and masks ----
186const CM_IMM5: i64 = 5
187const CM_IMM8: i64 = 8
188const CM_IMM16: i64 = 16
189const CM_IMM11: i64 = 11
190const CM_M_IMM3: i64 = 7
191const CM_M_IMM5: i64 = 31
192const CM_M_IMM7: i64 = 127
193const CM_M_IMM8: i64 = 255
194const CM_M_IMM11: i64 = 0x7FF
195const CM_M_REG3: i64 = 7
196const CM_M_REG4: i64 = 15
197const CM_M_BYTE: i64 = 255
198const CM_M_HALF: i64 = 0xFFFF
199const CM_ALIGN4: i64 = 3
200const CM_ODDCLR: i64 = 4294967294 // CM_MASK - 1: clears the Thumb bit on a branch target
201
202func cm_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 }
203func cm_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 }
204
205// Sign-extend an n-bit field. Written ONCE: an inline sign-extend copied per call
206// site is the same literal shape written twice, and the copies drift.
207func cm_sext(v: i64, bits: i64) -> i64 {
208 let m: i64 = 1 << (bits - 1)
209 if (v & m) != 0 { return v - (m + m) }
210 return v
211}
212
213// THE ARM ADDER. Every flag-setting add, subtract, compare, negate and
214// carry-propagating variant on this machine is this one function, because the
215// manual defines A op B as an add of A, B-or-NOT(B), and a carry-in. Returning
216// result-and-flags packed keeps the caller from re-deriving V three different
217// ways in three different places -- the duplicate-ruler defect in arithmetic.
218func cm_addf(a0: i64, b0: i64, cin: i64) -> i64 {
219 let a: i64 = a0 & CM_MASK
220 let b: i64 = b0 & CM_MASK
221 let s: i64 = a + b + cin
222 let res: i64 = s & CM_MASK
223 var f: i64 = 0
224 if (res >> CM_SIGNBIT) == 1 { f = f + CM_FLAG_N }
225 if res == 0 { f = f + CM_FLAG_Z }
226 if ((s >> CM_WORD_BITS) & 1) == 1 { f = f + CM_FLAG_C }
227 let sa: i64 = (a >> CM_SIGNBIT) & 1
228 let sb: i64 = (b >> CM_SIGNBIT) & 1
229 let sr: i64 = (res >> CM_SIGNBIT) & 1
230 if sa == sb {
231 if sr != sa { f = f + CM_FLAG_V }
232 }
233 return res | (f << CM_FLAGSHIFT)
234}
235
236// NOT(b) for a 32-bit word, without depending on a bitwise-complement operator.
237func cm_not(b: i64) -> i64 { return CM_MASK - (b & CM_MASK) }
238
239// N and Z from the result; C and V preserved. The logic-op flag rule.
240func cm_nzf(res0: i64, oldf: i64) -> i64 {
241 let res: i64 = res0 & CM_MASK
242 var f: i64 = oldf & CM_FLAG_CV
243 if (res >> CM_SIGNBIT) == 1 { f = f + CM_FLAG_N }
244 if res == 0 { f = f + CM_FLAG_Z }
245 return res | (f << CM_FLAGSHIFT)
246}
247
248// The shifter. Shift-by-zero leaves C alone but still writes N and Z, which is
249// the rule the manual states and the one an emulator most often gets wrong.
250func cm_shift(kind: i64, val0: i64, sh: i64, oldf: i64) -> i64 {
251 let val: i64 = val0 & CM_MASK
252 var res: i64 = val
253 var c: i64 = 0
254 if (oldf & CM_FLAG_C) != 0 { c = 1 }
255 if sh > 0 {
256 if kind == CM_SH_LSL {
257 if sh > CM_WORD_BITS { c = 0; res = 0 }
258 if sh == CM_WORD_BITS { c = val & 1; res = 0 }
259 if sh < CM_WORD_BITS {
260 c = (val >> (CM_WORD_BITS - sh)) & 1
261 res = (val << sh) & CM_MASK
262 }
263 }
264 if kind == CM_SH_LSR {
265 if sh > CM_WORD_BITS { c = 0; res = 0 }
266 if sh == CM_WORD_BITS { c = (val >> CM_SIGNBIT) & 1; res = 0 }
267 if sh < CM_WORD_BITS {
268 c = (val >> (sh - 1)) & 1
269 res = (val >> sh) & CM_MASK
270 }
271 }
272 if kind == CM_SH_ASR {
273 let sg: i64 = (val >> CM_SIGNBIT) & 1
274 if sh >= CM_WORD_BITS {
275 c = sg
276 res = 0
277 if sg == 1 { res = CM_MASK }
278 }
279 if sh < CM_WORD_BITS {
280 c = (val >> (sh - 1)) & 1
281 var t: i64 = (val >> sh) & CM_MASK
282 if sg == 1 { t = t | ((CM_MASK << (CM_WORD_BITS - sh)) & CM_MASK) }
283 res = t
284 }
285 }
286 if kind == CM_SH_ROR {
287 let m: i64 = sh & CM_ROT_MASK
288 if m == 0 {
289 res = val
290 c = (val >> CM_SIGNBIT) & 1
291 }
292 if m != 0 {
293 res = ((val >> m) | (val << (CM_WORD_BITS - m))) & CM_MASK
294 c = (res >> CM_SIGNBIT) & 1
295 }
296 }
297 }
298 var f: i64 = oldf & CM_FLAG_V
299 if (res >> CM_SIGNBIT) == 1 { f = f + CM_FLAG_N }
300 if res == 0 { f = f + CM_FLAG_Z }
301 if c == 1 { f = f + CM_FLAG_C }
302 return res | (f << CM_FLAGSHIFT)
303}
304
305// Condition-code evaluation, ARMv7-M ARM Table A7-1. This dialect has no
306// disjunction operator, so the two disjunctive conditions (LS and LE) are written
307// as two writes of the same flag rather than as one expression.
308func cm_cond(cond: i64, f: i64) -> i64 {
309 var n: i64 = 0
310 var z: i64 = 0
311 var c: i64 = 0
312 var v: i64 = 0
313 if (f & CM_FLAG_N) != 0 { n = 1 }
314 if (f & CM_FLAG_Z) != 0 { z = 1 }
315 if (f & CM_FLAG_C) != 0 { c = 1 }
316 if (f & CM_FLAG_V) != 0 { v = 1 }
317 var t: i64 = 0
318 if cond == CM_C_EQ { t = z }
319 if cond == CM_C_NE { if z == 0 { t = 1 } }
320 if cond == CM_C_CS { t = c }
321 if cond == CM_C_CC { if c == 0 { t = 1 } }
322 if cond == CM_C_MI { t = n }
323 if cond == CM_C_PL { if n == 0 { t = 1 } }
324 if cond == CM_C_VS { t = v }
325 if cond == CM_C_VC { if v == 0 { t = 1 } }
326 if cond == CM_C_HI { if c == 1 { if z == 0 { t = 1 } } }
327 if cond == CM_C_LS {
328 if c == 0 { t = 1 }
329 if z == 1 { t = 1 }
330 }
331 if cond == CM_C_GE { if n == v { t = 1 } }
332 if cond == CM_C_LT { if n != v { t = 1 } }
333 if cond == CM_C_GT { if z == 0 { if n == v { t = 1 } } }
334 if cond == CM_C_LE {
335 if z == 1 { t = 1 }
336 if n != v { t = 1 }
337 }
338 return t
339}
340
341// Reading r15 yields PC+4 in Thumb, never the stored register. Getting this
342// wrong makes every PC-relative form silently read zero.
343func cm_rd(r: *i64, i: i64, pc: i64) -> i64 {
344 if i == CM_PC { return (pc + CM_PC_BIAS) & CM_MASK }
345 return r[i] & CM_MASK
346}
347
348func cm_align4(v: i64) -> i64 { return v - (v & CM_ALIGN4) }
349
350func emu_cortexm_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 {
351 let r: *i64 = sys_mmap(CM_REG_BYTES) as *i64
352 var i: i64 = 0
353 while i < CM_NREGS { r[i] = 0; i = i + 1 }
354 r[CM_SP] = sp0
355 var pc: i64 = entry
356 var fl: i64 = 0 // NZCV, packed as CM_FLAG_*
357 var result: i64 = CM_RANOFF
358 var halted: i64 = 0
359 var steps: i64 = 0
360 while halted == 0 {
361 var live: i64 = 1
362 // A step budget that halts WITHOUT naming itself returns the initial
363 // result, which used to be 0 -- a legitimate exit status. Both
364 // non-completions now carry their own sentinel.
365 if steps > CM_STEP_BUDGET { halted = 1; result = CM_FAULT; live = 0 }
366 if live == 1 {
367 if pc < 0 { halted = 1; result = CM_FAULT; live = 0 }
368 }
369 if live == 1 {
370 if (pc + CM_HW) > mem_size { halted = 1; result = CM_FAULT; live = 0 }
371 }
372 if live == 1 {
373 let hw1: i64 = cm_ld(mem, pc, CM_HW)
374 var next: i64 = pc + CM_HW
375 var handled: i64 = 0
376 if (hw1 & CM_MSK_F800) >= CM_M32_LO {
377 // ---- 32-bit Thumb-2 ----
378 if (pc + CM_W32) > mem_size { halted = 1; result = CM_FAULT; live = 0 }
379 if live == 1 {
380 let hw2: i64 = cm_ld(mem, pc + CM_HW, CM_HW)
381 next = pc + CM_W32
382 if (hw1 & CM_MSK_FBF0) == CM_OP_MOVW { // MOVW T3
383 handled = 1
384 let rd: i64 = (hw2 >> CM_IMM8) & CM_M_REG4
385 let imm: i64 = (((hw1 & CM_M_REG4) << 12) | (((hw1 >> 10) & 1) << 11) | (((hw2 >> 12) & CM_M_REG3) << CM_IMM8) | (hw2 & CM_M_IMM8))
386 r[rd] = imm
387 }
388 if (hw1 & CM_MSK_FBF0) == CM_OP_SUBW { // SUBW (T4, plain imm12)
389 handled = 1
390 let rn: i64 = hw1 & CM_M_REG4
391 let rd: i64 = (hw2 >> CM_IMM8) & CM_M_REG4
392 let imm: i64 = (((hw1 >> 10) & 1) << 11) | (((hw2 >> 12) & CM_M_REG3) << CM_IMM8) | (hw2 & CM_M_IMM8)
393 r[rd] = (r[rn] - imm) & CM_MASK
394 }
395 if (hw1 & CM_MSK_FFF0) == CM_OP_UMULL { // UMULL
396 handled = 1
397 let rn: i64 = hw1 & CM_M_REG4
398 let rdlo: i64 = (hw2 >> 12) & CM_M_REG4
399 let rdhi: i64 = (hw2 >> CM_IMM8) & CM_M_REG4
400 let rm: i64 = hw2 & CM_M_REG4
401 let p: i64 = (r[rn] & CM_MASK) * (r[rm] & CM_MASK)
402 r[rdlo] = p & CM_MASK
403 r[rdhi] = (p >> CM_WORD_BITS) & CM_MASK
404 }
405 if (hw1 & CM_MSK_FFF0) == CM_OP_MLA { if (hw2 & 0xF0) == 0x00 { // MLA
406 handled = 1
407 let rn: i64 = hw1 & CM_M_REG4
408 let ra: i64 = (hw2 >> 12) & CM_M_REG4
409 let rd: i64 = (hw2 >> CM_IMM8) & CM_M_REG4
410 let rm: i64 = hw2 & CM_M_REG4
411 r[rd] = (r[rn] * r[rm] + r[ra]) & CM_MASK
412 } }
413 if (hw1 & CM_MSK_FFF0) == CM_OP_LDRT4 { // LDR (T4)
414 handled = 1
415 let rn: i64 = hw1 & CM_M_REG4
416 let rt: i64 = (hw2 >> 12) & CM_M_REG4
417 let u: i64 = (hw2 >> 9) & 1
418 var off: i64 = hw2 & CM_M_IMM8
419 if u == 0 { off = 0 - off }
420 r[rt] = cm_ld(mem, (r[rn] + off) & CM_MASK, CM_W32) & CM_MASK
421 }
422 if (hw1 & CM_MSK_FFF0) == CM_OP_STRT4 { // STR (T4)
423 handled = 1
424 let rn: i64 = hw1 & CM_M_REG4
425 let rt: i64 = (hw2 >> 12) & CM_M_REG4
426 let u: i64 = (hw2 >> 9) & 1
427 var off: i64 = hw2 & CM_M_IMM8
428 if u == 0 { off = 0 - off }
429 cm_st(mem, (r[rn] + off) & CM_MASK, CM_W32, r[rt] & CM_MASK)
430 }
431 }
432 } else {
433 // ---- 16-bit Thumb ----
434 if (hw1 & CM_MSK_FF00) == CM_OP_BKPT { handled = 1; result = r[0] & CM_EXIT_MASK; halted = 1 }
435 if (hw1 & CM_MSK_FF87) == CM_OP_BLX { // BLX reg
436 handled = 1
437 let rm: i64 = (hw1 >> 3) & CM_M_REG4
438 r[CM_LR] = (pc + CM_HW) | 1
439 next = cm_rd(r, rm, pc) & CM_ODDCLR
440 }
441 if (hw1 & CM_MSK_FF87) == CM_OP_BX { // BX reg
442 handled = 1
443 let rm: i64 = (hw1 >> 3) & CM_M_REG4
444 next = cm_rd(r, rm, pc) & CM_ODDCLR
445 }
446 if (hw1 & CM_MSK_FE00) == CM_OP_PUSH { // PUSH
447 handled = 1
448 var list: i64 = hw1 & CM_M_IMM8
449 if ((hw1 >> CM_IMM8) & 1) == 1 { list = list | (1 << CM_LR) }
450 var cnt: i64 = 0; var k: i64 = 0; while k < CM_NREGS { if (list & (1<<k)) != 0 { cnt = cnt + 1 } k = k + 1 }
451 var addr: i64 = (r[CM_SP] - CM_W32 * cnt) & CM_MASK
452 r[CM_SP] = addr
453 k = 0; while k < CM_NREGS { if (list & (1<<k)) != 0 { cm_st(mem, addr, CM_W32, r[k] & CM_MASK); addr = addr + CM_W32 } k = k + 1 }
454 }
455 if (hw1 & CM_MSK_FE00) == CM_OP_POP { // POP
456 handled = 1
457 var list: i64 = hw1 & CM_M_IMM8
458 var ppc: i64 = (hw1 >> CM_IMM8) & 1
459 var addr: i64 = r[CM_SP]
460 var k: i64 = 0; while k < CM_NREGS { if (list & (1<<k)) != 0 { r[k] = cm_ld(mem, addr, CM_W32) & CM_MASK; addr = addr + CM_W32 } k = k + 1 }
461 if ppc == 1 { next = cm_ld(mem, addr, CM_W32) & CM_ODDCLR; addr = addr + CM_W32 }
462 r[CM_SP] = addr
463 }
464 if (hw1 & CM_MSK_FF00) == CM_OP_MOVHI { // MOV (hi)
465 handled = 1
466 let rd: i64 = (((hw1 >> 7) & 1) << 3) | (hw1 & CM_M_REG3)
467 let rm: i64 = (hw1 >> 3) & CM_M_REG4
468 let v: i64 = cm_rd(r, rm, pc)
469 if rd == CM_PC { next = v & CM_ODDCLR } else { r[rd] = v }
470 }
471 if (hw1 & CM_MSK_FF00) == CM_OP_ADDHI { // ADD (hi)
472 handled = 1
473 let rd: i64 = (((hw1 >> 7) & 1) << 3) | (hw1 & CM_M_REG3)
474 let rm: i64 = (hw1 >> 3) & CM_M_REG4
475 let v: i64 = (cm_rd(r, rd, pc) + cm_rd(r, rm, pc)) & CM_MASK
476 if rd == CM_PC { next = v & CM_ODDCLR } else { r[rd] = v }
477 }
478 if (hw1 & CM_MSK_FF00) == CM_OP_CMPHI { // CMP (hi)
479 handled = 1
480 let rn: i64 = (((hw1 >> 7) & 1) << 3) | (hw1 & CM_M_REG3)
481 let rm: i64 = (hw1 >> 3) & CM_M_REG4
482 let t: i64 = cm_addf(cm_rd(r, rn, pc), cm_not(cm_rd(r, rm, pc)), 1)
483 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
484 }
485 if (hw1 & CM_MSK_F800) == CM_OP_MOVI8 { // MOVS imm8
486 handled = 1
487 let rd: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
488 let t: i64 = cm_nzf(hw1 & CM_M_IMM8, fl)
489 r[rd] = t & CM_MASK
490 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
491 }
492 if (hw1 & CM_MSK_F800) == CM_OP_CMPI8 { // CMP imm8
493 handled = 1
494 let rn: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
495 let t: i64 = cm_addf(r[rn], cm_not(hw1 & CM_M_IMM8), 1)
496 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
497 }
498 if (hw1 & CM_MSK_F800) == CM_OP_ADDI8 { // ADDS imm8
499 handled = 1
500 let rd: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
501 let t: i64 = cm_addf(r[rd], hw1 & CM_M_IMM8, 0)
502 r[rd] = t & CM_MASK
503 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
504 }
505 if (hw1 & CM_MSK_F800) == CM_OP_SUBI8 { // SUBS imm8
506 handled = 1
507 let rd: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
508 let t: i64 = cm_addf(r[rd], cm_not(hw1 & CM_M_IMM8), 1)
509 r[rd] = t & CM_MASK
510 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
511 }
512 if (hw1 & CM_MSK_F800) == CM_OP_LSLI { // LSLS imm5 (imm5=0 is MOV)
513 handled = 1
514 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
515 let t: i64 = cm_shift(CM_SH_LSL, r[rm], (hw1 >> 6) & CM_M_IMM5, fl)
516 r[rd] = t & CM_MASK
517 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
518 }
519 if (hw1 & CM_MSK_F800) == CM_OP_LSRI { // LSRS imm5 (imm5=0 means 32)
520 handled = 1
521 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
522 var sh: i64 = (hw1 >> 6) & CM_M_IMM5
523 if sh == 0 { sh = CM_WORD_BITS }
524 let t: i64 = cm_shift(CM_SH_LSR, r[rm], sh, fl)
525 r[rd] = t & CM_MASK
526 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
527 }
528 if (hw1 & CM_MSK_F800) == CM_OP_ASRI { // ASRS imm5 (imm5=0 means 32)
529 handled = 1
530 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
531 var sh: i64 = (hw1 >> 6) & CM_M_IMM5
532 if sh == 0 { sh = CM_WORD_BITS }
533 let t: i64 = cm_shift(CM_SH_ASR, r[rm], sh, fl)
534 r[rd] = t & CM_MASK
535 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
536 }
537 if (hw1 & CM_MSK_FE00) == CM_OP_ADDR { // ADDS 3-reg
538 handled = 1
539 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
540 let t: i64 = cm_addf(r[rn], r[rm], 0)
541 r[rd] = t & CM_MASK
542 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
543 }
544 if (hw1 & CM_MSK_FE00) == CM_OP_SUBR { // SUBS 3-reg
545 handled = 1
546 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
547 let t: i64 = cm_addf(r[rn], cm_not(r[rm]), 1)
548 r[rd] = t & CM_MASK
549 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
550 }
551 if (hw1 & CM_MSK_FE00) == CM_OP_ADDI3 { // ADDS imm3
552 handled = 1
553 let im: i64 = (hw1 >> 6) & CM_M_IMM3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
554 let t: i64 = cm_addf(r[rn], im, 0)
555 r[rd] = t & CM_MASK
556 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
557 }
558 if (hw1 & CM_MSK_FE00) == CM_OP_SUBI3 { // SUBS imm3
559 handled = 1
560 let im: i64 = (hw1 >> 6) & CM_M_IMM3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
561 let t: i64 = cm_addf(r[rn], cm_not(im), 1)
562 r[rd] = t & CM_MASK
563 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
564 }
565 // ---- the 0x4000..0x43FF data-processing register block ----
566 if (hw1 & CM_MSK_FFC0) == CM_OP_AND {
567 handled = 1
568 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
569 let t: i64 = cm_nzf(r[rd] & r[rm], fl)
570 r[rd] = t & CM_MASK
571 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
572 }
573 if (hw1 & CM_MSK_FFC0) == CM_OP_EOR {
574 handled = 1
575 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
576 let t: i64 = cm_nzf(r[rd] ^ r[rm], fl)
577 r[rd] = t & CM_MASK
578 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
579 }
580 if (hw1 & CM_MSK_FFC0) == CM_OP_LSLR {
581 handled = 1
582 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
583 let t: i64 = cm_shift(CM_SH_LSL, r[rd], r[rm] & CM_M_BYTE, fl)
584 r[rd] = t & CM_MASK
585 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
586 }
587 if (hw1 & CM_MSK_FFC0) == CM_OP_LSRR {
588 handled = 1
589 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
590 let t: i64 = cm_shift(CM_SH_LSR, r[rd], r[rm] & CM_M_BYTE, fl)
591 r[rd] = t & CM_MASK
592 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
593 }
594 if (hw1 & CM_MSK_FFC0) == CM_OP_ASRR {
595 handled = 1
596 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
597 let t: i64 = cm_shift(CM_SH_ASR, r[rd], r[rm] & CM_M_BYTE, fl)
598 r[rd] = t & CM_MASK
599 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
600 }
601 if (hw1 & CM_MSK_FFC0) == CM_OP_ADC { // ADCS rdn,rm
602 handled = 1
603 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
604 var cin: i64 = 0
605 if (fl & CM_FLAG_C) != 0 { cin = 1 }
606 let t: i64 = cm_addf(r[rd], r[rm], cin)
607 r[rd] = t & CM_MASK
608 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
609 }
610 if (hw1 & CM_MSK_FFC0) == CM_OP_SBC { // SBCS rdn,rm
611 handled = 1
612 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
613 var cin: i64 = 0
614 if (fl & CM_FLAG_C) != 0 { cin = 1 }
615 let t: i64 = cm_addf(r[rd], cm_not(r[rm]), cin)
616 r[rd] = t & CM_MASK
617 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
618 }
619 if (hw1 & CM_MSK_FFC0) == CM_OP_ROR {
620 handled = 1
621 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
622 let t: i64 = cm_shift(CM_SH_ROR, r[rd], r[rm] & CM_M_BYTE, fl)
623 r[rd] = t & CM_MASK
624 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
625 }
626 if (hw1 & CM_MSK_FFC0) == CM_OP_TST {
627 handled = 1
628 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rn: i64 = hw1 & CM_M_REG3
629 let t: i64 = cm_nzf(r[rn] & r[rm], fl)
630 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
631 }
632 if (hw1 & CM_MSK_FFC0) == CM_OP_RSB { // RSBS rd,rn,#0
633 handled = 1
634 let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
635 let t: i64 = cm_addf(0, cm_not(r[rn]), 1)
636 r[rd] = t & CM_MASK
637 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
638 }
639 if (hw1 & CM_MSK_FFC0) == CM_OP_CMPR { // CMP rn,rm
640 handled = 1
641 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rn: i64 = hw1 & CM_M_REG3
642 let t: i64 = cm_addf(r[rn], cm_not(r[rm]), 1)
643 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
644 }
645 if (hw1 & CM_MSK_FFC0) == CM_OP_CMN {
646 handled = 1
647 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rn: i64 = hw1 & CM_M_REG3
648 let t: i64 = cm_addf(r[rn], r[rm], 0)
649 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
650 }
651 if (hw1 & CM_MSK_FFC0) == CM_OP_ORR {
652 handled = 1
653 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
654 let t: i64 = cm_nzf(r[rd] | r[rm], fl)
655 r[rd] = t & CM_MASK
656 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
657 }
658 if (hw1 & CM_MSK_FFC0) == CM_OP_MUL { // MULS rdm,rn,rdm
659 handled = 1
660 let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
661 let t: i64 = cm_nzf((r[rn] * r[rd]) & CM_MASK, fl)
662 r[rd] = t & CM_MASK
663 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
664 }
665 if (hw1 & CM_MSK_FFC0) == CM_OP_BIC {
666 handled = 1
667 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
668 let t: i64 = cm_nzf(r[rd] & cm_not(r[rm]), fl)
669 r[rd] = t & CM_MASK
670 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
671 }
672 if (hw1 & CM_MSK_FFC0) == CM_OP_MVN {
673 handled = 1
674 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
675 let t: i64 = cm_nzf(cm_not(r[rm]), fl)
676 r[rd] = t & CM_MASK
677 fl = (t >> CM_FLAGSHIFT) & CM_FLAGMASK
678 }
679 // ---- extends ----
680 if (hw1 & CM_MSK_FFC0) == CM_OP_SXTH {
681 handled = 1
682 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
683 r[rd] = cm_sext(r[rm] & CM_M_HALF, CM_IMM16) & CM_MASK
684 }
685 if (hw1 & CM_MSK_FFC0) == CM_OP_SXTB {
686 handled = 1
687 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
688 r[rd] = cm_sext(r[rm] & CM_M_BYTE, CM_IMM8) & CM_MASK
689 }
690 if (hw1 & CM_MSK_FFC0) == CM_OP_UXTH {
691 handled = 1
692 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
693 r[rd] = r[rm] & CM_M_HALF
694 }
695 if (hw1 & CM_MSK_FFC0) == CM_OP_UXTB {
696 handled = 1
697 let rm: i64 = (hw1 >> 3) & CM_M_REG3; let rd: i64 = hw1 & CM_M_REG3
698 r[rd] = r[rm] & CM_M_BYTE
699 }
700 // ---- PC-relative and SP-relative ----
701 if (hw1 & CM_MSK_F800) == CM_OP_LDRLIT { // LDR rt,[pc,#imm8*4]
702 handled = 1
703 let rt: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
704 let base: i64 = cm_align4((pc + CM_PC_BIAS) & CM_MASK)
705 r[rt] = cm_ld(mem, (base + (hw1 & CM_M_IMM8) * CM_W32) & CM_MASK, CM_W32) & CM_MASK
706 }
707 if (hw1 & CM_MSK_F800) == CM_OP_ADR { // ADR rd,label
708 handled = 1
709 let rd: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
710 r[rd] = (cm_align4((pc + CM_PC_BIAS) & CM_MASK) + (hw1 & CM_M_IMM8) * CM_W32) & CM_MASK
711 }
712 if (hw1 & CM_MSK_F800) == CM_OP_ADDSPR { // ADD rd,sp,#imm8*4
713 handled = 1
714 let rd: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
715 r[rd] = (r[CM_SP] + (hw1 & CM_M_IMM8) * CM_W32) & CM_MASK
716 }
717 if (hw1 & CM_MSK_F800) == CM_OP_STRSP { // STR rt,[sp,#imm8*4]
718 handled = 1
719 let rt: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
720 cm_st(mem, (r[CM_SP] + (hw1 & CM_M_IMM8) * CM_W32) & CM_MASK, CM_W32, r[rt] & CM_MASK)
721 }
722 if (hw1 & CM_MSK_F800) == CM_OP_LDRSP { // LDR rt,[sp,#imm8*4]
723 handled = 1
724 let rt: i64 = (hw1 >> CM_IMM8) & CM_M_REG3
725 r[rt] = cm_ld(mem, (r[CM_SP] + (hw1 & CM_M_IMM8) * CM_W32) & CM_MASK, CM_W32) & CM_MASK
726 }
727 // ---- immediate-offset load/store ----
728 if (hw1 & CM_MSK_F800) == CM_OP_LDRI5 { // LDR imm5, scaled by 4
729 handled = 1
730 let im: i64 = ((hw1 >> 6) & CM_M_IMM5) * CM_W32; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
731 r[rt] = cm_ld(mem, (r[rn] + im) & CM_MASK, CM_W32) & CM_MASK
732 }
733 if (hw1 & CM_MSK_F800) == CM_OP_STRI5 { // STR imm5, scaled by 4
734 handled = 1
735 let im: i64 = ((hw1 >> 6) & CM_M_IMM5) * CM_W32; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
736 cm_st(mem, (r[rn] + im) & CM_MASK, CM_W32, r[rt] & CM_MASK)
737 }
738 if (hw1 & CM_MSK_F800) == CM_OP_STRBI5 { // STRB imm5, unscaled
739 handled = 1
740 let im: i64 = (hw1 >> 6) & CM_M_IMM5; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
741 cm_st(mem, (r[rn] + im) & CM_MASK, CM_B8, r[rt] & CM_M_BYTE)
742 }
743 if (hw1 & CM_MSK_F800) == CM_OP_LDRBI5 { // LDRB imm5, unscaled
744 handled = 1
745 let im: i64 = (hw1 >> 6) & CM_M_IMM5; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
746 r[rt] = cm_ld(mem, (r[rn] + im) & CM_MASK, CM_B8) & CM_M_BYTE
747 }
748 if (hw1 & CM_MSK_F800) == CM_OP_STRHI5 { // STRH imm5, scaled by 2
749 handled = 1
750 let im: i64 = ((hw1 >> 6) & CM_M_IMM5) * CM_HW; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
751 cm_st(mem, (r[rn] + im) & CM_MASK, CM_HW, r[rt] & CM_M_HALF)
752 }
753 if (hw1 & CM_MSK_F800) == CM_OP_LDRHI5 { // LDRH imm5, scaled by 2
754 handled = 1
755 let im: i64 = ((hw1 >> 6) & CM_M_IMM5) * CM_HW; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
756 r[rt] = cm_ld(mem, (r[rn] + im) & CM_MASK, CM_HW) & CM_M_HALF
757 }
758 // ---- register-offset load/store ----
759 if (hw1 & CM_MSK_FE00) == CM_OP_STRR {
760 handled = 1
761 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
762 cm_st(mem, (r[rn] + r[rm]) & CM_MASK, CM_W32, r[rt] & CM_MASK)
763 }
764 if (hw1 & CM_MSK_FE00) == CM_OP_STRHR {
765 handled = 1
766 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
767 cm_st(mem, (r[rn] + r[rm]) & CM_MASK, CM_HW, r[rt] & CM_M_HALF)
768 }
769 if (hw1 & CM_MSK_FE00) == CM_OP_STRBR {
770 handled = 1
771 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
772 cm_st(mem, (r[rn] + r[rm]) & CM_MASK, CM_B8, r[rt] & CM_M_BYTE)
773 }
774 if (hw1 & CM_MSK_FE00) == CM_OP_LDRSBR {
775 handled = 1
776 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
777 r[rt] = cm_sext(cm_ld(mem, (r[rn] + r[rm]) & CM_MASK, CM_B8) & CM_M_BYTE, CM_IMM8) & CM_MASK
778 }
779 if (hw1 & CM_MSK_FE00) == CM_OP_LDRR {
780 handled = 1
781 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
782 r[rt] = cm_ld(mem, (r[rn] + r[rm]) & CM_MASK, CM_W32) & CM_MASK
783 }
784 if (hw1 & CM_MSK_FE00) == CM_OP_LDRHR {
785 handled = 1
786 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
787 r[rt] = cm_ld(mem, (r[rn] + r[rm]) & CM_MASK, CM_HW) & CM_M_HALF
788 }
789 if (hw1 & CM_MSK_FE00) == CM_OP_LDRBR {
790 handled = 1
791 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
792 r[rt] = cm_ld(mem, (r[rn] + r[rm]) & CM_MASK, CM_B8) & CM_M_BYTE
793 }
794 if (hw1 & CM_MSK_FE00) == CM_OP_LDRSHR {
795 handled = 1
796 let rm: i64 = (hw1 >> 6) & CM_M_REG3; let rn: i64 = (hw1 >> 3) & CM_M_REG3; let rt: i64 = hw1 & CM_M_REG3
797 r[rt] = cm_sext(cm_ld(mem, (r[rn] + r[rm]) & CM_MASK, CM_HW) & CM_M_HALF, CM_IMM16) & CM_MASK
798 }
799 // ---- stack pointer adjust ----
800 if (hw1 & CM_MSK_FF80) == CM_OP_ADDSPI { // ADD SP,#imm7*4
801 handled = 1
802 r[CM_SP] = (r[CM_SP] + (hw1 & CM_M_IMM7) * CM_W32) & CM_MASK
803 }
804 if (hw1 & CM_MSK_FF80) == CM_OP_SUBSPI { // SUB SP,#imm7*4
805 handled = 1
806 r[CM_SP] = (r[CM_SP] - (hw1 & CM_M_IMM7) * CM_W32) & CM_MASK
807 }
808 // ---- compare-and-branch (forward only, unsigned imm, no flags read) ----
809 if (hw1 & CM_MSK_FD00) == CM_OP_CBZ {
810 handled = 1
811 let rn: i64 = hw1 & CM_M_REG3
812 let im: i64 = ((((hw1 >> 9) & 1) << CM_IMM5) | ((hw1 >> 3) & CM_M_IMM5)) * CM_HW
813 if (r[rn] & CM_MASK) == 0 { next = pc + CM_PC_BIAS + im }
814 }
815 if (hw1 & CM_MSK_FD00) == CM_OP_CBNZ {
816 handled = 1
817 let rn: i64 = hw1 & CM_M_REG3
818 let im: i64 = ((((hw1 >> 9) & 1) << CM_IMM5) | ((hw1 >> 3) & CM_M_IMM5)) * CM_HW
819 if (r[rn] & CM_MASK) != 0 { next = pc + CM_PC_BIAS + im }
820 }
821 // ---- branches. cond 14 is UDF and 15 is SVC: both stay UNSUPPORTED
822 // ---- on purpose, so the gate has a stable refusal to prove against.
823 if (hw1 & CM_MSK_F000) == CM_OP_BCOND {
824 let cond: i64 = (hw1 >> CM_IMM8) & CM_M_REG4
825 if cond <= CM_C_MAX {
826 handled = 1
827 if cm_cond(cond, fl) == 1 {
828 next = pc + CM_PC_BIAS + cm_sext(hw1 & CM_M_IMM8, CM_IMM8) * CM_HW
829 }
830 }
831 }
832 if (hw1 & CM_MSK_F800) == CM_OP_B { // B T2
833 handled = 1
834 next = pc + CM_PC_BIAS + cm_sext(hw1 & CM_M_IMM11, CM_IMM11) * CM_HW
835 }
836 }
837 if live == 1 {
838 if handled == 0 { result = CM_UNSUPPORTED; halted = 1 }
839 pc = next
840 steps = steps + 1
841 }
842 }
843 }
844 return result
845}
846
847func emu_cortexm_run(code: *u8, code_len: i64) -> i64 {
848 let mem: *u8 = sys_mmap(CM_GUEST)
849 var i: i64 = 0
850 while i < code_len { mem[i] = code[i]; i = i + 1 }
851 return emu_cortexm_run_mem(mem, CM_GUEST, 0, CM_DEFAULT_SP) // entry at offset 0 (aligned)
852}