ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_exc.c File Reference

Hand-modelled Cortex-M exception engine (see emu_exc.h). More...

#include "emu_exc.h"
#include <stdio.h>
#include "board_periph.h"
#include "emu_console.h"
#include "emu_engine.h"
#include "emu_host_io_internal.h"
#include "emu_memmap.h"
#include "emu_seams.h"
Include dependency graph for emu_exc.c:

Go to the source code of this file.

Enumerations

enum  emu_exc_decode_t : uint32_t {
  k_op_branch_self = 0xE7FEU ,
  k_op_wfi = 0xBF30U ,
  k_op_cpsie_i = 0xB662U ,
  k_op_bn_mask = 0xF800U ,
  k_op_bn_base = 0xE000U ,
  k_op_bn_imm = 0x07FFU ,
  k_bn_imm_sext_shl = 21U ,
  k_bn_imm_sext_shr = 20U ,
  k_idle_scan_fwd = 8U ,
  k_idle_loop_max = 32U ,
  k_thumb_op5_shift = 11U ,
  k_thumb_op5_mask = 0x1FU ,
  k_thumb32_op5_min = 0x1DU
}
 Thumb decode + idle-spin scan constants for this exception engine. More...

Functions

static RA8_INTERNAL uint32_t internal_exc_active_prio (void)
 Priority value (lower = higher) of the active handler, or sentinel.
static RA8_INTERNAL uint32_t internal_exc_priority (uc_engine *uc, uint32_t exc_num)
 Read a system-handler priority byte from an SHPR register.
static RA8_INTERNAL void internal_exc_stack_frame (uc_engine *uc, uint32_t sp, bool fp_active, uint32_t frame_xpsr)
 Stack the basic {R0-R3,R12,LR,PC,xPSR} frame + optional FP frame at sp.
static RA8_INTERNAL uint32_t internal_exc_return_value (bool in_thread, bool use_psp, bool fp_active)
 Select the EXC_RETURN magic for the outgoing mode/stack/FP state.
void exc_enter (uc_engine *uc, uint32_t exc_num, uint32_t handler)
 Enter a Cortex-M exception: stack the basic frame and vector in.
static RA8_INTERNAL void internal_exc_restore_fp_frame (uc_engine *uc, uint32_t sp)
 Restore the Armv8-M FP extended frame (S0-S15 + FPSCR) from sp.
static RA8_INTERNAL void internal_exc_restore_mode (uc_engine *uc, uint32_t xpsr, bool to_thread, bool to_psp)
 Restore CONTROL.SPSEL + xPSR/IPSR for the returned-to context.
void exc_return (uc_engine *uc, uint32_t exc_ret)
 Perform a Cortex-M exception return for an observed EXC_RETURN branch.
static RA8_INTERNAL bool internal_is_exc_return (uint64_t pc)
 True if pc is an EXC_RETURN magic value.
uint32_t exc_vector (uc_engine *uc, uint32_t vtor_base, uint32_t exc_num)
 Read the handler address for an exception from the vector table.
static RA8_INTERNAL bool internal_exc_take_periph_irq (uc_engine *uc, uint32_t vtor_base, uint32_t active)
 Take one pending peripheral NVIC IRQ the ICU has queued, if allowed.
bool exc_take_pending (uc_engine *uc, uint32_t vtor_base, bool allow_systick)
 Take the highest-priority pending exception, if one may activate now.
static RA8_INTERNAL const char * internal_unmapped_access_kind (uc_mem_type type)
 Name the access kind that hit an unmapped address.
static RA8_INTERNAL bool internal_on_unmapped (uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
 Hook fired on access to unmapped memory (peripheral surface gap).
static RA8_INTERNAL bool internal_on_intr_sec_insn (uc_engine *uc, uint32_t pc, uint32_t insn)
 Model the Armv8-M Security-Extension opcodes Unicorn's M33 lacks.
static RA8_INTERNAL bool internal_on_intr_bkpt (uc_engine *uc, uint32_t pc, uint32_t insn)
 Model a firmware BKPT as a halt (record the site and stop).
static RA8_INTERNAL void internal_on_intr (uc_engine *uc, uint32_t int_no, void *user_data)
 UC_HOOK_INTR handler: take the SVCall exception on an svc opcode.
static RA8_INTERNAL void internal_on_icsr_write (uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
 UC_HOOK_MEM_WRITE handler for SCB ICSR – take PendSV promptly.
void emu_exc_install_core (uc_engine *uc)
 Implementation of emu_exc_install_core() – unmapped/INTR/ICSR hooks.
void emu_exc_arm_systick (void)
 Implementation of emu_exc_arm_systick() – pend the periodic tick.
bool emu_exc_take_exc_return (uint64_t *out_pc)
 Implementation of emu_exc_take_exc_return() – read + clear latch.
void emu_exc_clear_pendsv_stop (void)
 Implementation of emu_exc_clear_pendsv_stop() – per-launch clear.
bool emu_exc_pendsv_stop (void)
 Implementation of emu_exc_pendsv_stop() – plain flag read.
bool emu_exc_bkpt_hit (void)
 Implementation of emu_exc_bkpt_hit() – plain flag read.
uint32_t emu_exc_bkpt_pc (void)
 Implementation of emu_exc_bkpt_pc() – plain state read.
uint32_t emu_exc_systick_fires (void)
 Implementation of emu_exc_systick_fires() – plain counter read.
uint32_t emu_exc_pendsv_takes (void)
 Implementation of emu_exc_pendsv_takes() – plain counter read.
uint32_t emu_exc_svc_takes (void)
 Implementation of emu_exc_svc_takes() – plain counter read.
void emu_exc_reset (void)
 Implementation of emu_exc_reset() – warm-reboot exception state.

Variables

static uint32_t s_systick_fires
static uint32_t s_exc_stack [k_exc_nest_max]
 Active-handler priorities.
static uint32_t s_exc_depth
 Number of active handlers.
static uint32_t s_pendsv_takes
 PendSV exceptions taken.
static uint32_t s_svc_takes
 SVCall exceptions taken.
static uint64_t s_exc_return_pc
 Pending EXC_RETURN to unstack.
static bool s_exc_return_hit
 An EXC_RETURN branch was seen.
static bool s_systick_pending
 SysTick exception is pended.
static bool s_pendsv_stop
 Chunk ended on a PENDSVSET.
static bool s_bkpt_hit
 Firmware executed a BKPT.
static uint32_t s_bkpt_pc
 PC of the BKPT that halted.

Detailed Description

Hand-modelled Cortex-M exception engine (see emu_exc.h).

Unicorn's Cortex-M33 core carries no NVIC / exception unit, so ra8_emulator takes exceptions by hand: the active-priority stack, the basic + FP frame stacking/unstacking of exception entry/return, SysTick/PendSV/SVCall and peripheral-IRQ activation with hardware priority rules, the EXC_RETURN recognition, the SVC/BKPT/security-instruction INTR dispatch, the ICSR PendSV promptness hook, the SCB control-word watcher (SYSRESETREQ warm reboot + CCR.DIV_0_TRP arming), the NVIC ISER/ICER W1S/W1C folding, the idle-spin detector and the DWT cycle-counter model. Moved verbatim out of the ra8_emulator main translation unit.

Since
0.1.0

Definition in file emu_exc.c.

Enumeration Type Documentation

◆ emu_exc_decode_t

enum emu_exc_decode_t : uint32_t

Thumb decode + idle-spin scan constants for this exception engine.

Enumerator
k_op_branch_self 

Thumb "b ." (branch-to-self idle loop).

k_op_wfi 

Thumb wfi (wait-for-interrupt).

k_op_cpsie_i 

Thumb cpsie i (re-enable IRQ in a poll).

k_op_bn_mask 

Mask selecting a Thumb T2 b.n opcode.

k_op_bn_base 

Thumb T2 unconditional b.n base value.

k_op_bn_imm 

Thumb T2 b.n imm11 field mask.

k_bn_imm_sext_shl 

Shift imm11 bit10 up to bit31 (sign bit).

k_bn_imm_sext_shr 

Arith >> sign-extends and scales imm by 2.

k_idle_scan_fwd 

Halfwords scanned ahead for a loop edge.

k_idle_loop_max 

Largest idle loop (bytes) that may hold PC.

k_thumb_op5_shift 

op5 = hw0[15:11].

k_thumb_op5_mask 

5-bit op5 field.

k_thumb32_op5_min 

op5 >= this -> 32-bit instruction.

Definition at line 33 of file emu_exc.c.

Function Documentation

◆ emu_exc_arm_systick()

void emu_exc_arm_systick ( void )

Implementation of emu_exc_arm_systick() – pend the periodic tick.

Pend the periodic SysTick for this outer chunk.

Definition at line 926 of file emu_exc.c.

References s_systick_pending.

Referenced by internal_run_loop_tick_inputs().

◆ emu_exc_bkpt_hit()

bool emu_exc_bkpt_hit ( void )

Implementation of emu_exc_bkpt_hit() – plain flag read.

Whether the firmware executed a BKPT (deliberate trap / give-up).

Definition at line 955 of file emu_exc.c.

References s_bkpt_hit.

Referenced by internal_run_inner_check_stops(), internal_run_print_stop_summary(), internal_run_print_verdict(), and priv_run_cleanup().

◆ emu_exc_bkpt_pc()

uint32_t emu_exc_bkpt_pc ( void )

Implementation of emu_exc_bkpt_pc() – plain state read.

PC of the BKPT that halted the run.

Definition at line 961 of file emu_exc.c.

References s_bkpt_pc.

Referenced by internal_run_print_stop_summary().

◆ emu_exc_clear_pendsv_stop()

void emu_exc_clear_pendsv_stop ( void )

Implementation of emu_exc_clear_pendsv_stop() – per-launch clear.

Clear the PendSV context-switch stop marker (per relaunch).

Definition at line 943 of file emu_exc.c.

References s_pendsv_stop.

Referenced by priv_run_inner().

◆ emu_exc_install_core()

void emu_exc_install_core ( uc_engine * uc)

Implementation of emu_exc_install_core() – unmapped/INTR/ICSR hooks.

Arm the core exception hooks (unmapped / INTR / ICSR watch).

Definition at line 898 of file emu_exc.c.

References internal_on_icsr_write(), internal_on_intr(), internal_on_unmapped(), and k_scb_icsr.

Referenced by internal_main_install_core_seams().

◆ emu_exc_pendsv_stop()

bool emu_exc_pendsv_stop ( void )

Implementation of emu_exc_pendsv_stop() – plain flag read.

Whether the last engine stop was a PENDSVSET context-switch stop.

Definition at line 949 of file emu_exc.c.

References s_pendsv_stop.

Referenced by internal_run_inner_take_exception().

◆ emu_exc_pendsv_takes()

uint32_t emu_exc_pendsv_takes ( void )

Implementation of emu_exc_pendsv_takes() – plain counter read.

PendSV exceptions taken this run (report + idle signature).

Definition at line 973 of file emu_exc.c.

References s_pendsv_takes.

Referenced by internal_run_print_stop_summary(), and internal_run_stop_idle().

◆ emu_exc_reset()

void emu_exc_reset ( void )

Implementation of emu_exc_reset() – warm-reboot exception state.

Reset the exception bookkeeping for a warm reboot.

Definition at line 985 of file emu_exc.c.

References s_bkpt_hit, s_exc_depth, s_exc_return_hit, s_pendsv_stop, s_pendsv_takes, s_svc_takes, s_systick_fires, and s_systick_pending.

Referenced by warm_reboot().

◆ emu_exc_svc_takes()

uint32_t emu_exc_svc_takes ( void )

Implementation of emu_exc_svc_takes() – plain counter read.

SVCall exceptions taken this run (report + idle signature).

Definition at line 979 of file emu_exc.c.

References s_svc_takes.

Referenced by internal_run_print_stop_summary(), and internal_run_stop_idle().

◆ emu_exc_systick_fires()

uint32_t emu_exc_systick_fires ( void )

Implementation of emu_exc_systick_fires() – plain counter read.

SysTick exceptions taken this run (report telemetry).

Definition at line 967 of file emu_exc.c.

References s_systick_fires.

Referenced by internal_run_print_stop_summary().

◆ emu_exc_take_exc_return()

bool emu_exc_take_exc_return ( uint64_t * out_pc)

Implementation of emu_exc_take_exc_return() – read + clear latch.

Consume a latched EXC_RETURN branch (read + clear).

Definition at line 932 of file emu_exc.c.

References s_exc_return_hit, and s_exc_return_pc.

Referenced by internal_run_inner_take_exception().

◆ exc_enter()

void exc_enter ( uc_engine * uc,
uint32_t exc_num,
uint32_t handler )

Enter a Cortex-M exception: stack the basic frame and vector in.

Reproduces Armv7E-M / Armv8-M exception entry that Unicorn's core does not model. The active stack is chosen exactly as hardware would: PSP when in Thread mode with CONTROL.SPSEL set, else MSP. The 8-word basic frame {R0,R1,R2,R3,R12,LR,PC,xPSR} is pushed with 8-byte alignment (the realign pad is recorded in the stacked xPSR bit 9 so exit can undo it), the banked SP is updated, the core is switched to Handler mode on MSP, LR is loaded with the matching EXC_RETURN, IPSR is set to exc_num, and PC is vectored to the handler fetched from the VTOR-relative table. The handler's priority is pushed on the active-exception stack so nesting respects priority.

Parameters
[in,out]ucUnicorn engine.
[in]exc_numException number to take (11, 14, or 15).
[in]handlerHandler entry address (Thumb bit ignored).
Returns
Nothing.
Precondition
uc has MSP/PSP/CONTROL/xPSR readable and the target stack mapped.
Taking exc_num is permitted now (priority/PRIMASK already checked).
Postcondition
The core is in Handler mode (IPSR == exc_num) running on MSP.
LR holds a valid EXC_RETURN and the outgoing frame is on the old stack.
Note
When CONTROL.FPCA is set, the FP extended frame (S0-S15 + FPSCR) is stacked above the basic frame and EXC_RETURN bit4 (FType) is cleared.
Since
0.1.0

Definition at line 210 of file emu_exc.c.

References internal_exc_priority(), internal_exc_return_value(), internal_exc_stack_frame(), k_control_fpca, k_control_spsel, k_exc_frame_bytes, k_exc_nest_max, k_fp_frame_extra, k_xpsr_align9, k_xpsr_ipsr_mask, k_xpsr_t_bit, reg_get(), reg_set(), s_exc_depth, and s_exc_stack.

Referenced by div0_synth_usagefault(), exc_take_pending(), internal_exc_take_periph_irq(), internal_on_intr(), and mpu_synth_memmanage().

◆ exc_return()

void exc_return ( uc_engine * uc,
uint32_t exc_ret )

Perform a Cortex-M exception return for an observed EXC_RETURN branch.

The inverse of exc_enter. exc_ret (the magic value the core branched to) selects the stack to unstack from (bit2: PSP vs MSP) and the mode to return to (bit3: Thread vs Handler). The 8-word basic frame is popped (plus the S0-S15 + FPSCR words when FType, bit4, is clear), the recorded 8-byte realignment (stacked xPSR bit 9) is undone, the banked SP and CONTROL.SPSEL are restored, xPSR (hence IPSR) is reloaded, the active-exception stack is popped, and PC resumes the interrupted instruction stream.

Parameters
[in,out]ucUnicorn engine.
[in]exc_retThe EXC_RETURN value (prefix bits[31:7] set) returned to.
Returns
Nothing.
Precondition
uc is in Handler mode with a valid basic frame on the indicated stack.
exc_ret has the EXC_RETURN prefix (bits[31:7] all set).
Postcondition
The core has resumed the unstacked context (PC/SP/xPSR restored).
The active-exception nesting depth has decreased by one (if non-zero).
Note
When FType (bit4) is clear, the FP extended frame (S0-S15 + FPSCR) is unstacked too, matching exc_enter.
Since
0.1.0

Definition at line 335 of file emu_exc.c.

References internal_exc_restore_fp_frame(), internal_exc_restore_mode(), k_exc_frame_bytes, k_exc_ret_ftype, k_exc_ret_mode, k_exc_ret_spsel, k_fp_frame_extra, k_frame_off_lr, k_frame_off_pc, k_frame_off_r3, k_frame_off_xpsr, k_xpsr_align9, rd32(), reg_get(), reg_set(), and s_exc_depth.

Referenced by internal_run_inner_take_exception().

◆ exc_take_pending()

bool exc_take_pending ( uc_engine * uc,
uint32_t vtor_base,
bool allow_systick )

Take the highest-priority pending exception, if one may activate now.

The software replacement for the NVIC's "take the highest-priority pending, enabled exception whose priority is greater than the current execution priority" rule – called at every instruction boundary AND immediately after each exception return (so a lower-priority pend tail-chains exactly as hardware would instead of returning to the interrupted code first). Two sources are modelled:

  • SysTick (#15): periodic. s_systick_pending is armed once per tick period by the run loop; this routine consumes it and vectors in #15 so _tx_timer_interrupt runs in real handler context (correct for ThreadX and for bare-metal SysTick handlers alike). Arming it elsewhere – rather than re-deriving "armed" from SYST_CSR on every call – is what lets a pending PendSV run between ticks instead of being starved by a perpetual SysTick.
  • PendSV (#14): level-pending via ICSR.PENDSVSET (ThreadX's context-switch request); the bit is cleared on activation, as hardware does.

SysTick (priority 0x40) outranks PendSV (0xFF), so when both are pending SysTick activates first and may even pre-empt a PendSV that is spinning in its idle wait – exactly the nesting ThreadX relies on to make a sleeping thread runnable. PRIMASK and the active-priority stack are both honoured.

Parameters
[in,out]ucUnicorn engine.
[in]vtor_baseFallback vector base if VTOR reads as 0.
[in]allow_systickWhen false, the armed SysTick is left pending (not taken) so modelled time does NOT advance. The run loop passes false on a context-switch stop (a PENDSVSET write consumes no time), so a thread that just suspended on a tick-based wait is not woken before lower-priority ready threads run. Passes true on a full-budget boundary, where genuine execution (or an idle spin) has elapsed a tick's worth of time.
Returns
true if an exception was taken (PC now points at a handler).
Precondition
uc has stopped at an instruction boundary or just returned.
The PPB (SYST_CSR / ICSR / SHPRn / VTOR) is mapped as RAM.
Postcondition
At most one exception is taken per call (the highest-priority due one).
ICSR.PENDSVSET / s_systick_pending is cleared iff that one was taken.
Note
SysTick is dropped (not queued) if SYST_CSR is disarmed when its period elapses, matching a masked/disabled SysTick on hardware.
Since
0.1.0

Definition at line 530 of file emu_exc.c.

References exc_enter(), exc_vector(), internal_exc_active_prio(), internal_exc_priority(), internal_exc_take_periph_irq(), k_exc_pendsv, k_exc_systick, k_icsr_pendsvset, k_scb_icsr, k_syst_csr, k_syst_csr_run, rd32(), reg_get(), s_pendsv_takes, s_systick_fires, s_systick_pending, and wr32().

Referenced by internal_run_inner_take_exception().

◆ exc_vector()

uint32_t exc_vector ( uc_engine * uc,
uint32_t vtor_base,
uint32_t exc_num )

Read the handler address for an exception from the vector table.

Parameters
[in,out]ucUnicorn engine.
[in]vtor_baseFallback vector base used when VTOR reads as 0.
[in]exc_numException/vector index to look up.
Returns
Handler entry address with the Thumb bit cleared.
Return values
0when no usable handler is installed at that vector slot.
Precondition
uc has the vector table mapped at VTOR (or vtor_base).
exc_num is a valid vector index (< table length).
Postcondition
No engine state is modified (read-only).
The returned address (when non-zero) is halfword-aligned code.
Note
VTOR lives in PPB RAM here, written by SystemInit at boot.
Since
0.1.0

Definition at line 417 of file emu_exc.c.

References k_scb_vtor, k_vector_erased, and rd32().

Referenced by div0_synth_usagefault(), exc_take_pending(), internal_exc_take_periph_irq(), internal_on_intr(), and mpu_synth_memmanage().

◆ internal_exc_active_prio()

RA8_INTERNAL uint32_t internal_exc_active_prio ( void )
static

Priority value (lower = higher) of the active handler, or sentinel.

Priority value (lower = higher) of the active handler, or sentinel; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Returns
The exc active prio result produced by the emu exc model.
Return values
valueThe operation-specific exc active prio value.
Precondition
Arguments satisfy the ranges documented for exc active prio.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
Synchronous; transfers no heap ownership.
Since
0.1.0

Definition at line 76 of file emu_exc.c.

References k_exc_prio_none, RA8_INTERNAL, s_exc_depth, and s_exc_stack.

Referenced by exc_take_pending(), and internal_on_icsr_write().

◆ internal_exc_priority()

RA8_INTERNAL uint32_t internal_exc_priority ( uc_engine * uc,
uint32_t exc_num )
static

Read a system-handler priority byte from an SHPR register.

Cortex-M packs four 8-bit handler priorities per SHPRn word. SVCall (#11) is byte 3 of SHPR2; PendSV (#14) is byte 2 and SysTick (#15) byte 3 of SHPR3. ThreadX's tx_initialize_low_level programs these (SysTick 0x40, PendSV/SVC 0xFF), and the value drives whether one exception may pre-empt another. The PPB is plain RAM here, so the firmware's stores are simply read back.

Parameters
[in,out]ucUnicorn engine.
[in]exc_numException/vector number (11, 14, or 15).
Returns
The 8-bit configured priority (0 = highest, 0xFF = lowest).
Return values
0xFFwhen exc_num is not one of the modelled system handlers.
Precondition
uc is an initialised engine with the PPB mapped as RAM.
SystemInit / tx_initialize_low_level have programmed SHPR2/SHPR3.
Postcondition
No register or memory state is modified (read-only).
The returned value is in [0, 0xFF].
Note
Sub-priority / priority grouping is ignored – only the raw byte is compared, which is sufficient for the SysTick > PendSV nesting ThreadX relies on.
Since
0.1.0

Definition at line 104 of file emu_exc.c.

References k_byte_bits, k_byte_mask, k_exc_pendsv, k_exc_prio_max, k_exc_svcall, k_exc_systick, k_scb_shpr2, k_scb_shpr3, RA8_INTERNAL, and rd32().

Referenced by exc_enter(), exc_take_pending(), and internal_on_icsr_write().

◆ internal_exc_restore_fp_frame()

RA8_INTERNAL void internal_exc_restore_fp_frame ( uc_engine * uc,
uint32_t sp )
static

Restore the Armv8-M FP extended frame (S0-S15 + FPSCR) from sp.

Restore the armv8-m fp extended frame (s0-s15 + fpscr) from sp; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]spSp input used by the operation.
Precondition
Arguments satisfy the ranges documented for exc restore fp frame.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 267 of file emu_exc.c.

References k_fp_s_words, k_frame_off_fpscr, k_frame_off_s0, k_word_bytes, RA8_INTERNAL, rd32(), and reg_set().

Referenced by exc_return().

◆ internal_exc_restore_mode()

RA8_INTERNAL void internal_exc_restore_mode ( uc_engine * uc,
uint32_t xpsr,
bool to_thread,
bool to_psp )
static

Restore CONTROL.SPSEL + xPSR/IPSR for the returned-to context.

Restore control.spsel + xpsr/ipsr for the returned-to context; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]xpsrXpsr input used by the operation.
[in]to_threadTo thread input used by the operation.
[in]to_pspTo psp input used by the operation.
Precondition
Arguments satisfy the ranges documented for exc restore mode.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 292 of file emu_exc.c.

References k_control_spsel, k_xpsr_ipsr_mask, k_xpsr_t_bit, reg_get(), and reg_set().

Referenced by exc_return().

◆ internal_exc_return_value()

RA8_INTERNAL uint32_t internal_exc_return_value ( bool in_thread,
bool use_psp,
bool fp_active )
static

Select the EXC_RETURN magic for the outgoing mode/stack/FP state.

Select the exc_return magic for the outgoing mode/stack/fp state; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Parameters
[in]in_threadIn thread input used by the operation.
[in]use_pspUse psp input used by the operation.
[in]fp_activeFp active input used by the operation.
Returns
The exc return value result produced by the emu exc model.
Return values
valueThe operation-specific exc return value value.
Precondition
Arguments satisfy the ranges documented for exc return value.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
Synchronous; transfers no heap ownership.
Since
0.1.0

Definition at line 165 of file emu_exc.c.

References k_exc_ret_ftype, k_exc_ret_handler, k_exc_ret_msp, k_exc_ret_psp, and RA8_INTERNAL.

Referenced by exc_enter().

◆ internal_exc_stack_frame()

RA8_INTERNAL void internal_exc_stack_frame ( uc_engine * uc,
uint32_t sp,
bool fp_active,
uint32_t frame_xpsr )
static

Stack the basic {R0-R3,R12,LR,PC,xPSR} frame + optional FP frame at sp.

Stack the basic {r0-r3,r12,lr,pc,xpsr} frame + optional fp frame at sp; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]spSp input used by the operation.
[in]fp_activeFp active input used by the operation.
[in]frame_xpsrFrame xpsr input used by the operation.
Precondition
Arguments satisfy the ranges documented for exc stack frame.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
Synchronous; transfers no heap ownership.
Since
0.1.0

Definition at line 132 of file emu_exc.c.

References k_fp_s_words, k_frame_off_fpscr, k_frame_off_lr, k_frame_off_pc, k_frame_off_r3, k_frame_off_s0, k_frame_off_xpsr, k_word_bytes, reg_get(), and wr32().

Referenced by exc_enter().

◆ internal_exc_take_periph_irq()

RA8_INTERNAL bool internal_exc_take_periph_irq ( uc_engine * uc,
uint32_t vtor_base,
uint32_t active )
static

Take one pending peripheral NVIC IRQ the ICU has queued, if allowed.

The peripheral counterpart to the SysTick / PendSV logic in exc_take_pending. board_periph's ICU model queues an IRQ whenever a peripheral event is event-linked through IELSR and its NVIC line is enabled; this pops one and – if its NVIC priority (IPR byte, top nibble used) outranks the active execution priority – vectors it in as a real Cortex-M exception (vector 16 + IRQn read from VTOR), exactly the path a hardware IRQ takes. The ISR therefore runs in genuine handler context and returns via the same EXC_RETURN unstack as every other exception. The matching ISPR pending bit is cleared on activation, as hardware does.

Parameters
[in,out]ucUnicorn engine.
[in]vtor_baseFallback vector base when VTOR reads as 0.
[in]activeCurrent active-handler priority (sentinel if none).
Returns
true if a peripheral IRQ was taken (PC now points at its ISR).
Precondition
uc has stopped at an instruction boundary; PRIMASK already checked.
Postcondition
At most one IRQ is taken; its ISPR pending bit is cleared if so.
Note
If no handler is installed at the vector, the IRQ is dropped, not spun.
Since
0.1.0
Return values
trueThe exc take periph interrupt condition holds or completed successfully; false otherwise.
Precondition
The call executes on the emulator's single owning thread.
Postcondition
Ownership of caller-supplied storage is unchanged.

Definition at line 457 of file emu_exc.c.

References board_periph_next_irq(), board_periph_note_irq_taken(), exc_enter(), exc_vector(), k_exc_irq_vec0, k_lo4_mask, k_nvic_ipr_base, k_nvic_ispr_base, k_nvic_prio_shift, rd32(), and wr32().

Referenced by exc_take_pending().

◆ internal_is_exc_return()

RA8_INTERNAL bool internal_is_exc_return ( uint64_t pc)
static

True if pc is an EXC_RETURN magic value.

Matches the Armv8-M EXC_RETURN prefix – bits[31:7] all set (0xFFFFFF80..0xFFFFFFFF). This covers both the Armv7-M values ra8_emulator itself generates (0xFFFFFFF1/F9/FD) and the Armv8-M Non-Secure thread returns ThreadX uses (0xFFFFFFBC basic, 0xFFFFFFAC with an FP frame), where bit6 (S) is clear. Nothing in this firmware's map executes at 0xFFFFFFxx, so a fetch into that range is always an exception return, never a real branch.

Parameters
[in]pcGuest program-counter value associated with the operation.
Returns
The is exc return result produced by the emu exc model.
Return values
trueThe is exc return condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for is exc return.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 398 of file emu_exc.c.

References k_exc_ret_v8_mask, and RA8_INTERNAL.

Referenced by internal_on_intr(), and internal_on_unmapped().

◆ internal_on_icsr_write()

RA8_INTERNAL void internal_on_icsr_write ( uc_engine * uc,
uc_mem_type type,
uint64_t addr,
int size,
int64_t value,
void * user )
static

UC_HOOK_MEM_WRITE handler for SCB ICSR – take PendSV promptly.

On hardware, writing ICSR.PENDSVSET pends PendSV, and – because ThreadX follows the store with DSB+ISB and PendSV is enabled at a priority above thread level with interrupts unmasked – the exception activates at the very next instruction. ra8_emulator runs the CPU in long chunks, so without help it would only notice PENDSVSET at the end of a 500k-instruction chunk; by then the requesting thread (e.g. a thread suspending inside tx_queue_receive) has run far past the point where it expected to be switched out and observes inconsistent scheduler state. Stopping the chunk the instant PENDSVSET is written hands control straight back to the run loop, which takes PendSV at that boundary – restoring next-instruction activation semantics. The store itself has already landed in PPB RAM, so exc_take_pending sees the bit set.

Parameters
[in,out]ucUnicorn engine.
[in]typeMemory access type (write); unused.
[in]addrFaulting/observed address (the ICSR word).
[in]sizeAccess width in bytes; unused.
[in]valueThe value being written to ICSR.
[in]userHook user pointer; unused.
Returns
Nothing.
Precondition
uc is mid-chunk executing the store to ICSR.
The hook is registered for the 4-byte ICSR word only.
Postcondition
Emulation is stopped iff the write sets PENDSVSET.
The PENDSVSET bit is left in PPB RAM for exc_take_pending to read.
Note
PENDSVCLR / status-only writes do not stop the chunk.
Since
0.1.0

Definition at line 843 of file emu_exc.c.

References emu_mem_read(), internal_exc_active_prio(), internal_exc_priority(), k_exc_pendsv, k_icsr_pendsvset, k_thumb32_op5_min, k_thumb_op5_mask, k_thumb_op5_shift, RA8_INTERNAL, and s_pendsv_stop.

Referenced by emu_exc_install_core().

◆ internal_on_intr()

RA8_INTERNAL void internal_on_intr ( uc_engine * uc,
uint32_t int_no,
void * user_data )
static

UC_HOOK_INTR handler: take the SVCall exception on an svc opcode.

Unicorn raises UC_HOOK_INTR when the firmware executes the Thumb svc instruction but, lacking an exception unit, does not vector it. This models SVCall (#11): the basic frame is stacked and the core vectors to SVC_Handler via exc_enter, then emulation is stopped so the chunked run loop relaunches cleanly from the handler entry (editing PC mid-block and continuing corrupts Unicorn's block/Thumb state – the same stop-then-relaunch contract the touch and conditional-select stubs use). ThreadX in single-mode never issues an SVC, but bare-metal / future RTOS paths that start the first thread via svc are handled correctly here. PRIMASK does not mask SVCall (it is synchronous), matching hardware.

Parameters
[in,out]ucUnicorn engine.
[in]int_noInterrupt/exception number reported by Unicorn.
[in]user_dataHook user pointer (unused; signature fixed by Unicorn).
Returns
Nothing.
Precondition
uc has just executed an svc instruction or branched to EXC_RETURN.
The vector table (at VTOR or the MRAM fallback) holds SVC_Handler.
Postcondition
Either an exception was taken/returned (PC updated) or, on a missing SVC handler, the core is left untouched.
Emulation is stopped so the run loop resumes from the new PC.
Note
Only the SVC interrupt class is acted on; other int_no values are ignored so unrelated traps fall through.
Since
0.1.0

Definition at line 752 of file emu_exc.c.

References emu_mem_read(), emu_memmap_mram_base(), emu_mve_nocp_emulate(), exc_enter(), exc_vector(), internal_is_exc_return(), internal_on_intr_bkpt(), internal_on_intr_sec_insn(), k_exc_svcall, RA8_INTERNAL, s_exc_return_hit, s_exc_return_pc, and s_svc_takes.

Referenced by emu_exc_install_core().

◆ internal_on_intr_bkpt()

RA8_INTERNAL bool internal_on_intr_bkpt ( uc_engine * uc,
uint32_t pc,
uint32_t insn )
static

Model a firmware BKPT as a halt (record the site and stop).

A BKPT (0xBExx) is a deliberate firmware trap – Default_Handler's bkpt #0, a failed assert, or a fault give-up. It is NOT an svc: taking SVCall here would stack a frame, vector to the (often Default_Handler) SVC slot, return to the same bkpt, and re-trap forever – the stack grows until it underflows (the historical tz_nsc_cgc_usb storm). Model it as a halt: record the site and stop so the run loop ends and the report shows where the firmware trapped.

Parameters
[in,out]ucUnicorn engine.
[in]pcPC of the trapping instruction.
[in]insnThe 32-bit opcode word read at pc.
Returns
true if insn was a BKPT and the core was halted.
Return values
trueThe on intr bkpt condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for on intr bkpt.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 711 of file emu_exc.c.

References k_bkpt_hw_base, k_bkpt_hw_mask, k_lo16_mask, RA8_INTERNAL, s_bkpt_hit, and s_bkpt_pc.

Referenced by internal_on_intr().

◆ internal_on_intr_sec_insn()

RA8_INTERNAL bool internal_on_intr_sec_insn ( uc_engine * uc,
uint32_t pc,
uint32_t insn )
static

Model the Armv8-M Security-Extension opcodes Unicorn's M33 lacks.

ra8_emulator is a single flat (no Secure/Non-Secure split) address space, so these reduce to their plain effects here:

  • SG (secure gateway, 32-bit): a NOP – the following B.W reaches the __acle_se_ entry directly.
  • VSTR FPCXTNS,[sp,#-4]! / VLDR FPCXTNS,[sp],#4: the FP context across the security boundary is meaningless with one FP bank, so model only the stack push/pop they perform (keeping SP balanced for the C frame). Without this the unrecognised opcode is mis-taken as an svc, vectors to Default_Handler's bkpt, and re-traps forever until the stack underflows (the tz_nsc_cgc_usb fault). On a match PC (and SP) are advanced and emulation is stopped so the run loop relaunches from the next instruction.
Parameters
[in,out]ucUnicorn engine.
[in]pcPC of the trapping instruction.
[in]insnThe 32-bit opcode word read at pc.
Returns
true if insn was an SG / FPCXTNS opcode and was handled.
Return values
trueThe on intr sec insn condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for on intr sec insn.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 664 of file emu_exc.c.

References emu_mem_write(), k_armv8m_sg_opcode, k_fpcxtns_pop, k_fpcxtns_push, k_thumb2_insn_bytes, k_word_bytes, and RA8_INTERNAL.

Referenced by internal_on_intr().

◆ internal_on_unmapped()

RA8_INTERNAL bool internal_on_unmapped ( uc_engine * uc,
uc_mem_type type,
uint64_t addr,
int size,
int64_t value,
void * user )
static

Hook fired on access to unmapped memory (peripheral surface gap).

Hook fired on access to unmapped memory (peripheral surface gap); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]typeType input used by the operation.
[in]addrGuest address involved in the operation.
[in]sizeSize of the requested region or access in bytes.
[in]valueRegister or payload value involved in the operation.
[in,out]userHook context supplied when the callback was registered.
Returns
The on unmapped result produced by the emu exc model.
Return values
trueThe on unmapped condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for on unmapped.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the emu exc model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 613 of file emu_exc.c.

References internal_is_exc_return(), internal_unmapped_access_kind(), priv_emu_io_errf(), RA8_INTERNAL, s_exc_return_hit, and s_exc_return_pc.

Referenced by emu_exc_install_core().

◆ internal_unmapped_access_kind()

RA8_INTERNAL const char * internal_unmapped_access_kind ( uc_mem_type type)
static

Name the access kind that hit an unmapped address.

Parameters
[in]typeUnicorn memory-access type reported by the hook.
Returns
"read", "write" or "fetch".
Precondition
type is one of the UC_MEM_*_UNMAPPED values.
Postcondition
No state is modified.

Definition at line 589 of file emu_exc.c.

References RA8_INTERNAL.

Referenced by internal_on_unmapped().

Variable Documentation

◆ s_bkpt_hit

bool s_bkpt_hit
static

Firmware executed a BKPT.

Definition at line 66 of file emu_exc.c.

Referenced by emu_exc_bkpt_hit(), emu_exc_reset(), and internal_on_intr_bkpt().

◆ s_bkpt_pc

uint32_t s_bkpt_pc
static

PC of the BKPT that halted.

Definition at line 67 of file emu_exc.c.

Referenced by emu_exc_bkpt_pc(), and internal_on_intr_bkpt().

◆ s_exc_depth

uint32_t s_exc_depth
static

Number of active handlers.

Definition at line 59 of file emu_exc.c.

Referenced by emu_exc_reset(), exc_enter(), exc_return(), and internal_exc_active_prio().

◆ s_exc_return_hit

bool s_exc_return_hit
static

An EXC_RETURN branch was seen.

Definition at line 63 of file emu_exc.c.

Referenced by emu_exc_reset(), emu_exc_take_exc_return(), internal_on_intr(), and internal_on_unmapped().

◆ s_exc_return_pc

uint64_t s_exc_return_pc
static

Pending EXC_RETURN to unstack.

Definition at line 62 of file emu_exc.c.

Referenced by emu_exc_take_exc_return(), internal_on_intr(), and internal_on_unmapped().

◆ s_exc_stack

uint32_t s_exc_stack[k_exc_nest_max]
static

Active-handler priorities.

Definition at line 58 of file emu_exc.c.

Referenced by exc_enter(), and internal_exc_active_prio().

◆ s_pendsv_stop

bool s_pendsv_stop
static

Chunk ended on a PENDSVSET.

Definition at line 65 of file emu_exc.c.

Referenced by emu_exc_clear_pendsv_stop(), emu_exc_pendsv_stop(), emu_exc_reset(), and internal_on_icsr_write().

◆ s_pendsv_takes

uint32_t s_pendsv_takes
static

PendSV exceptions taken.

Definition at line 60 of file emu_exc.c.

Referenced by emu_exc_pendsv_takes(), emu_exc_reset(), and exc_take_pending().

◆ s_svc_takes

uint32_t s_svc_takes
static

SVCall exceptions taken.

Definition at line 61 of file emu_exc.c.

Referenced by emu_exc_reset(), emu_exc_svc_takes(), and internal_on_intr().

◆ s_systick_fires

uint32_t s_systick_fires
static

Definition at line 49 of file emu_exc.c.

Referenced by emu_exc_reset(), emu_exc_systick_fires(), and exc_take_pending().

◆ s_systick_pending

bool s_systick_pending
static

SysTick exception is pended.

Definition at line 64 of file emu_exc.c.

Referenced by emu_exc_arm_systick(), emu_exc_reset(), and exc_take_pending().