code wiki / (root) / nx_emu_cortexm.nx

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}