20#include <capstone/capstone.h>
141typedef enum : uint32_t {
216 const uint32_t size =
269 const uint32_t adjusted = op->
add ? (base + op->
off) : (base - op->
off);
270 const uint32_t addr = op->
post ? base : adjusted;
271 const int d_lo = (int)UC_ARM_REG_D0 + (
int)(2U * op->
qd);
277 (void)
memcpy(&lo, buf,
sizeof(lo));
278 (void)
memcpy(&hi, buf +
sizeof(lo),
sizeof(hi));
279 (void)uc_reg_write(uc, d_lo, &lo);
280 (void)uc_reg_write(uc, d_lo + 1, &hi);
282 (void)uc_reg_read(uc, d_lo, &lo);
283 (void)uc_reg_read(uc, d_lo + 1, &hi);
284 (void)
memcpy(buf, &lo,
sizeof(lo));
285 (void)
memcpy(buf +
sizeof(lo), &hi,
sizeof(hi));
319 const uint16_t hw1 = (uint16_t)(code[0] | ((uint16_t)code[1] << (uint16_t)
k_byte_bits));
320 const uint16_t hw2 = (uint16_t)(code[2] | ((uint16_t)code[3] << (uint16_t)
k_byte_bits));
343 const unsigned int idx = qreg - (
unsigned int)ARM_REG_Q0;
344 return (
int)UC_ARM_REG_D0 + (int)(2U * idx) + (high ? 1 : 0);
361 const cs_arm* d = &insn->detail->arm;
362 const bool op0_q = (d->op_count == 2) && (d->operands[0].type == ARM_OP_REG) &&
363 (d->operands[0].reg >= ARM_REG_Q0) && (d->operands[0].reg <= ARM_REG_Q7);
368 if ((insn->id == ARM_INS_VMOV) && (d->operands[1].type == ARM_OP_IMM) &&
369 (
strstr(insn->mnemonic,
".i32") !=
nullptr)) {
370 const uint32_t imm = (uint32_t)d->operands[1].imm;
371 const uint64_t pair = ((uint64_t)imm << (uint64_t)
k_mve_lane_shift) | (uint64_t)imm;
383 static bool s_cs_ok =
false;
385 if (cs_open(CS_ARCH_ARM, (cs_mode)(CS_MODE_THUMB | CS_MODE_MCLASS), &s_cs) != CS_ERR_OK) {
388 (void)cs_option(s_cs, CS_OPT_DETAIL, CS_OPT_ON);
407bool emulate_mve(uc_engine* uc, uint32_t pc0,
const uint8_t code0[4])
415 (void)
memcpy(code, code0,
sizeof(code));
416 uint32_t handled = 0U;
424 if (
emu_mem_read(uc, (uint64_t)pc, code,
sizeof(code)) != UC_ERR_OK) {
429 cs_insn* insn =
nullptr;
430 const size_t n = cs_disasm(*cs, code, (
size_t)
k_mve_insn_len, pc, 1, &insn);
441 if (
emu_mem_read(uc, (uint64_t)pc, code,
sizeof(code)) != UC_ERR_OK) {
446 (void)uc_reg_write(uc, UC_ARM_REG_PC, &pc);
455 if (
emu_mem_read(uc, (uint64_t)pc, code,
sizeof(code)) != UC_ERR_OK) {
462 (void)uc_reg_write(uc, UC_ARM_REG_PC, &next);
Shared Unicorn engine access utilities for the board emulator.
const int k_arm_reg_id[16]
ARM register index (0..15) -> Unicorn register id.
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_byte_bits
Bits per byte (SHPR field width).
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
uc_err emu_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t count)
Write guest memory through the central access seam.
static uint32_t s_mve_resume_pc
Address the seam advanced PC to after servicing the last NoCP fault.
static RA8_INTERNAL void internal_mve_mem_exec(uc_engine *uc, const mve_mem_op_t *op)
Perform one decoded MVE contiguous load/store against emulated state.
uint64_t emu_mve_emulated_count(void)
Implementation of emu_mve_emulated_count() – plain counter read.
bool emu_mve_nocp_spurious(uint32_t pc)
Report whether an invalid-instruction trap at pc is the bogus one Unicorn raises just after the MVE s...
static bool s_mve_resume_armed
True while one bogus post-NoCP invalid report is still expected.
static uint64_t s_mve_emulated
Count of MVE instructions emulated this run (run-end telemetry).
bool emu_mve_nocp_emulate(uc_engine *uc, uint32_t pc)
Emulate an MVE contiguous load/store from the NoCP UsageFault.
@ k_mve_insn_len
MVE instructions are 32-bit Thumb-2.
@ k_mve_lane_shift
32-bit lane width (two lanes per D register).
@ k_mve_max_run
Loop bound: max consecutive MVE ops per trap.
@ k_mve_q_bytes
Bytes in a Q (128-bit) register.
static RA8_INTERNAL int internal_mve_q_d(unsigned int qreg, bool high)
Map capstone Q-reg qreg to its Unicorn D-register half (low/high).
static RA8_INTERNAL bool internal_mve_mem_decode(uint16_t hw1, uint16_t hw2, mve_mem_op_t *op)
Decode an MVE contiguous load/store from its two halfwords.
@ k_mve_mem_sz_half
size 0b01: halfword lanes.
@ k_mve_mem_h2_mask
Isolates hw2[12:9], the coprocessor space.
@ k_mve_mem_h1_post
hw1 match for post-index write-back forms.
@ k_mve_mem_scl_half
imm7 scale for halfword lanes.
@ k_mve_mem_scl_word
imm7 scale for word lanes.
@ k_mve_mem_h1_val
hw1 match for immediate-offset forms.
@ k_mve_qd_shift
Qd field position in hw2.
@ k_mve_mem_h1_mask
hw1 fixed bits with P/U/W/L/Rn excluded.
@ k_mve_rn_mask
Rn field (four bits) in hw1[3:0].
@ k_mve_mem_scl_byte
imm7 scale for byte lanes.
@ k_mve_mem_size_msk
Width of the size field (two bits).
@ k_mve_mem_bit_u
hw1[7]: add (1) or subtract (0) the offset.
@ k_mve_mem_h2_val
hw2[12:9] == 0b1111 selects MVE, not FP.
@ k_mve_mem_bit_w
hw1[5]: write the computed address to Rn.
@ k_mve_mem_size_sh
Position of the size field in hw2.
@ k_mve_mem_sz_byte
size 0b00: byte lanes.
@ k_mve_qd_mask
Qd field width (three bits) after shift.
@ k_mve_imm7_mask
imm7 field (unscaled offset) in hw2[6:0].
@ k_mve_mem_bit_l
hw1[4]: load (1) or store (0).
@ k_mve_mem_sz_word
size 0b10: word lanes.
static RA8_INTERNAL csh * internal_mve_capstone(void)
Lazily open the shared Thumb/M-class Capstone handle; nullptr on failure.
static RA8_INTERNAL bool internal_mve_mem_try(uc_engine *uc, const uint8_t code[4])
Perform the MVE contiguous load/store at code, if that is what it is.
static bool s_mve_nocp_handled
Latch: the chunk just ended in a NoCP fault this seam serviced.
static RA8_INTERNAL bool internal_mve_exec_one(uc_engine *uc, const cs_insn *insn)
Execute one decoded MVE instruction (no PC change); true iff handled.
bool emu_mve_nocp_take(void)
Implementation of emu_mve_nocp_take() – test-and-clear the latch.
bool emulate_mve(uc_engine *uc, uint32_t pc0, const uint8_t code0[4])
Emulate a run of consecutive auto-vectoriser MVE instructions.
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
char * strstr(const char *haystack, const char *needle)
Locate substring in string.
One decoded MVE contiguous load/store.
uint32_t rn
Base core register 0..15, from hw1[3:0].
bool load
True for VLDR*, false for VSTR*.
bool post
True when access precedes write-back adjustment.
uint32_t qd
Vector register Q0..Q7, from hw2[15:13].
bool add
True to add the offset, false to subtract it.
bool wback
True when the computed address is written to Rn.
uint32_t off
Byte offset: imm7 scaled by the element size.