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

Cortex-M exception model constants and interfaces for ra8_emulator. More...

#include <stdint.h>
#include <unicorn/unicorn.h>
#include "ra8_attributes.h"
Include dependency graph for emu_exc.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  cortexm_scs_t : uint64_t {
  k_syst_csr = 0xE000E010UL ,
  k_syst_csr_run = 0x3UL ,
  k_scb_icsr = 0xE000ED04UL ,
  k_scb_vtor = 0xE000ED08UL ,
  k_scb_aircr = 0xE000ED0CUL ,
  k_aircr_sysresetreq = 2UL ,
  k_scb_shpr2 = 0xE000ED1CUL ,
  k_scb_shpr3 = 0xE000ED20UL ,
  k_mpu_type = 0xE000ED90UL ,
  k_mpu_type_seed = 0x00000800UL ,
  k_mpu_ctrl = 0xE000ED94UL ,
  k_mpu_rnr = 0xE000ED98UL ,
  k_mpu_rbar = 0xE000ED9CUL ,
  k_mpu_rlar = 0xE000EDA0UL ,
  k_scb_ccr = 0xE000ED14UL ,
  k_ccr_div_0_trp = 0x10UL ,
  k_scb_cfsr = 0xE000ED28UL ,
  k_scb_mmfar = 0xE000ED34UL ,
  k_icsr_pendsvset = 28UL ,
  k_icsr_pendstset = 26UL ,
  k_exc_usagefault = 6UL ,
  k_exc_memmanage = 4UL ,
  k_exc_svcall = 11UL ,
  k_exc_pendsv = 14UL ,
  k_exc_systick = 15UL ,
  k_nvic_ipr_base = 0xE000E400UL ,
  k_nvic_ispr_base = 0xE000E200UL ,
  k_nvic_iser_base = 0xE000E100UL ,
  k_nvic_icer_base = 0xE000E180UL ,
  k_nvic_en_words = 8UL ,
  k_nvic_en_span = 8UL * 4UL ,
  k_exc_irq_vec0 = 16UL
}
enum  cortexm_exc_t : uint32_t {
  k_exc_frame_words = 8U ,
  k_exc_frame_bytes = 32U ,
  k_exc_ret_v8_mask = 0xFFFFFF80U ,
  k_exc_ret_ftype = 0x10U ,
  k_exc_ret_handler = 0xFFFFFFF1U ,
  k_exc_ret_msp = 0xFFFFFFF9U ,
  k_exc_ret_psp = 0xFFFFFFFDU ,
  k_exc_ret_spsel = 0x4U ,
  k_exc_ret_mode = 0x8U ,
  k_control_spsel = 0x2U ,
  k_control_fpca = 0x4U ,
  k_xpsr_t_bit = 0x01000000U ,
  k_xpsr_align9 = 0x00000200U ,
  k_xpsr_ipsr_mask = 0x000001FFU ,
  k_exc_prio_none = 0x100U ,
  k_exc_prio_max = 0xFFU ,
  k_exc_nest_max = 4U ,
  k_byte_bits = 8U ,
  k_frame_off_r3 = 12U ,
  k_frame_off_lr = 20U ,
  k_frame_off_pc = 24U ,
  k_frame_off_xpsr = 28U ,
  k_fp_frame_extra = 72U ,
  k_fp_s_words = 16U ,
  k_frame_off_s0 = 32U ,
  k_frame_off_fpscr = 96U ,
  k_vector_erased = 0xFFFFFFFEU ,
  k_nvic_prio_shift = 4U ,
  k_lo4_mask = 0xFU ,
  k_armv8m_sg_opcode = 0xE97FE97FU ,
  k_thumb2_insn_bytes = 4U ,
  k_fpcxtns_push = 0xCF81ED6DU ,
  k_fpcxtns_pop = 0xCF81ECFDU ,
  k_word_bytes = 4U ,
  k_clrm_hw0 = 0xE89FU ,
  k_vscclrm_hw0_s = 0xEC9FU ,
  k_vscclrm_hw0_d = 0xECDFU ,
  k_lo16_mask = 0xFFFFU ,
  k_bkpt_hw_base = 0xBE00U ,
  k_bkpt_hw_mask = 0xFF00U ,
  k_thumb_bx_lr = 0x4770U ,
  k_thumb_hw_bytes = 2U ,
  k_byte_mask = 0xFFU
}

Functions

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.
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.
void exc_return (uc_engine *uc, uint32_t exc_ret)
 Perform a Cortex-M exception return for an observed EXC_RETURN branch.
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.
bool idle_spin_at (uc_engine *uc, uint32_t pc)
 True if pc sits in a wait-for-interrupt spin (the core is idle).
void dwt_cyccnt_advance (uc_engine *uc)
 Advance the DWT cycle counter by one outer chunk's worth of cycles.
void emu_exc_install_core (uc_engine *uc)
 Arm the core exception hooks (unmapped / INTR / ICSR watch).
void emu_exc_install_scb_nvic (uc_engine *uc)
 Arm the SCB control-word and NVIC ISER/ICER write watchers.
void emu_exc_arm_systick (void)
 Pend the periodic SysTick for this outer chunk.
bool emu_exc_take_exc_return (uint64_t *out_pc)
 Consume a latched EXC_RETURN branch (read + clear).
void emu_exc_clear_pendsv_stop (void)
 Clear the PendSV context-switch stop marker (per relaunch).
bool emu_exc_pendsv_stop (void)
 Whether the last engine stop was a PENDSVSET context-switch stop.
bool emu_exc_bkpt_hit (void)
 Whether the firmware executed a BKPT (deliberate trap / give-up).
uint32_t emu_exc_bkpt_pc (void)
 PC of the BKPT that halted the run.
bool emu_exc_reboot_requested (void)
 Whether AIRCR.SYSRESETREQ requested a warm reboot.
void emu_exc_clear_reboot_request (void)
 Clear the latched warm-reboot request (after performing it).
uint32_t emu_exc_systick_fires (void)
 SysTick exceptions taken this run (report telemetry).
uint32_t emu_exc_pendsv_takes (void)
 PendSV exceptions taken this run (report + idle signature).
uint32_t emu_exc_svc_takes (void)
 SVCall exceptions taken this run (report + idle signature).
void emu_exc_reset (void)
 Reset the exception bookkeeping for a warm reboot.

Detailed Description

Cortex-M exception model constants and interfaces for ra8_emulator.

The architectural constants of the Armv7E-M / Armv8-M exception model the emulator reproduces by hand (Unicorn's Cortex-M33 core carries no NVIC / exception unit): the system-control-space register addresses the models poll/edit in flat PPB RAM, and the EXC_RETURN / stack-frame / instruction encoding constants the entry/return and instruction-seam logic decodes.

Split out of the ra8_emulator main translation unit; behaviour unchanged.

Since
0.1.0

Definition in file emu_exc.h.

Enumeration Type Documentation

◆ cortexm_exc_t

enum cortexm_exc_t : uint32_t
Enumerator
k_exc_frame_words 

{R0-R3,R12,LR,PC,xPSR} basic frame.

k_exc_frame_bytes 

8 words * 4 bytes.

k_exc_ret_v8_mask 

Armv8-M EXC_RETURN prefix: bits[31:7].

k_exc_ret_ftype 

EXC_RETURN bit4: 1 = basic, 0 = FP.

k_exc_ret_handler 

Return to Handler mode, MSP.

k_exc_ret_msp 

Return to Thread mode, MSP.

k_exc_ret_psp 

Return to Thread mode, PSP.

k_exc_ret_spsel 

EXC_RETURN bit2: return stack = PSP.

k_exc_ret_mode 

EXC_RETURN bit3: return to Thread.

k_control_spsel 

CONTROL.SPSEL: thread SP = PSP.

k_control_fpca 

CONTROL.FPCA: FP context is active.

k_xpsr_t_bit 

xPSR.T (Thumb) – must stay set.

k_xpsr_align9 

xPSR bit9: stack-frame realignment.

k_xpsr_ipsr_mask 

xPSR[8:0] = IPSR (active exception).

k_exc_prio_none 

Sentinel "no handler active" prio.

k_exc_prio_max 

Lowest configurable priority value.

k_exc_nest_max 

Tracked active-exception nesting cap.

k_byte_bits 

Bits per byte (SHPR field width).

k_frame_off_r3 

Basic exception-frame offset of R3.

k_frame_off_lr 

Basic exception-frame offset of LR.

k_frame_off_pc 

Basic exception-frame offset of PC.

k_frame_off_xpsr 

Basic exception-frame offset of xPSR.

k_fp_frame_extra 

FP ext frame above basic: S0-15+FPSCR.

k_fp_s_words 

S0-S15 saved in the FP extended frame.

k_frame_off_s0 

FP-frame offset of S0 (above basic).

k_frame_off_fpscr 

FP-frame offset of FPSCR (32 + 16*4).

k_vector_erased 

Erased-flash / invalid vector word.

k_nvic_prio_shift 

Implemented priority is the 4 MSBs.

k_lo4_mask 

Low nibble (register / cond field).

k_armv8m_sg_opcode 

Armv8-M SG secure-gateway opcode.

k_thumb2_insn_bytes 

32-bit Thumb-2 instruction width.

k_fpcxtns_push 

VSTR FPCXTNS,[sp,#-4]! (LE word).

k_fpcxtns_pop 

VLDR FPCXTNS,[sp],#4 (LE word).

k_word_bytes 

One stacked word.

k_clrm_hw0 

CLRM {regs} first halfword.

k_vscclrm_hw0_s 

VSCCLRM {s..,VPR} first halfword.

k_vscclrm_hw0_d 

VSCCLRM {d..,VPR} first halfword.

k_lo16_mask 

Low halfword of a 32-bit fetch.

k_bkpt_hw_base 

BKPT #imm8 halfword (imm free).

k_bkpt_hw_mask 

Mask isolating the BKPT opcode.

k_thumb_bx_lr 

BX LR (stub a function to return).

k_thumb_hw_bytes 

Bytes per Thumb halfword.

k_byte_mask 

Low 8 bits of a value (one byte).

Definition at line 81 of file emu_exc.h.

◆ cortexm_scs_t

enum cortexm_scs_t : uint64_t
Enumerator
k_syst_csr 

SysTick control/status (SYST_CSR).

k_syst_csr_run 

ENABLE | TICKINT both set.

k_scb_icsr 

Interrupt control/state (ICSR).

k_scb_vtor 

Vector table offset register.

k_scb_aircr 

App interrupt/reset control (AIRCR).

k_aircr_sysresetreq 

AIRCR.SYSRESETREQ bit (request reset).

k_scb_shpr2 

System handler priority 2 (SVC=b3).

k_scb_shpr3 

System handler priority 3 (PSV/SYT).

k_mpu_type 

MPU_TYPE (DREGION in bits 15:8).

k_mpu_type_seed 

8 data regions (matches the M85 MPU).

k_mpu_ctrl 

MPU_CTRL (ENABLE in bit 0).

k_mpu_rnr 

MPU_RNR (region number select).

k_mpu_rbar 

MPU_RBAR (BASE[31:5]|SH|AP[2:1]|XN).

k_mpu_rlar 

MPU_RLAR (LIMIT[31:5]|AttrIdx|EN).

k_scb_ccr 

Configuration and Control (CCR).

k_ccr_div_0_trp 

CCR.DIV_0_TRP bit4: divide-by-0 traps.

k_scb_cfsr 

Config Fault Status (MMFSR low byte).

k_scb_mmfar 

MemManage Fault Address Register.

k_icsr_pendsvset 

ICSR.PENDSVSET bit (request PendSV).

k_icsr_pendstset 

ICSR.PENDSTSET bit (request SysTick).

k_exc_usagefault 

UsageFault exception / vector index.

k_exc_memmanage 

MemManage exception / vector index.

k_exc_svcall 

SVCall exception / vector index.

k_exc_pendsv 

PendSV exception / vector index.

k_exc_systick 

SysTick exception / vector index.

k_nvic_ipr_base 

NVIC IPR priority bytes (one per IRQ).

k_nvic_ispr_base 

NVIC ISPR set-pending (per-IRQ bit).

k_nvic_iser_base 

NVIC ISER set-enable array base.

k_nvic_icer_base 

NVIC ICER clear-enable array base.

k_nvic_en_words 

ISER/ICER words modelled (256 lines).

k_nvic_en_span 

Byte span of one set/clear array.

k_exc_irq_vec0 

Vector index of IRQ0 (16 + IRQn).

Definition at line 35 of file emu_exc.h.

Function Documentation

◆ dwt_cyccnt_advance()

void dwt_cyccnt_advance ( uc_engine * uc)

Advance the DWT cycle counter by one outer chunk's worth of cycles.

Models DWT_CYCCNT as the free-running counter Armv8-M specifies: it counts only while DEMCR.TRCENA and DWT_CTRL.CYCCNTENA are both set, so an app that never enables it is untouched. Keeps a masked-context ra8_delay_ms (which spins on CYCCNT while PRIMASK is set) making progress.

Parameters
[in,out]ucActive Unicorn engine (CYCCNT lives in PPB RAM).
Returns
Nothing.
Precondition
uc has stopped at an instruction boundary (outer-chunk cadence).
The PPB (DEMCR / DWT_CTRL / DWT_CYCCNT) is mapped as RAM.
Postcondition
CYCCNT advanced iff the trace subsystem and counter are enabled.
Note
Not thread-safe; the run loop is single-threaded host-side.
Since
0.1.0
Postcondition
Ownership of caller-supplied storage is unchanged.

Models DWT_CYCCNT as the free-running cycle counter the Armv8-M architecture (DDI0553 D1.2.1) specifies: it counts only while DEMCR.TRCENA and DWT_CTRL.CYCCNTENA are both set. ra8_time_init arms both bits, so once the firmware has initialised its time base the counter advances; an app that never enables the cycle counter sees CYCCNT stay at its firmware-written value (zero by default), so this model is inert for every such app and cannot regress it.

The per-chunk increment (k_dwt_cyccnt_per_chunk) equals the busy chunk's instruction budget, i.e. one chunk of execution is charged one chunk of cycles (~1 instruction per cycle on the M85). A read-modify-write is used so a firmware CYCCNT reset (a DWT->CYCCNT = 0 at init) is honoured and the count simply resumes from there. Called once per outer chunk, in lockstep with the SysTick period the run loop already advances, so time bases stay consistent.

Parameters
[in,out]ucActive Unicorn engine (CYCCNT and its enables live in PPB RAM, read/written through uc).
Returns
Nothing.
Precondition
uc has stopped at an instruction boundary (outer-chunk cadence).
The PPB (DEMCR / DWT_CTRL / DWT_CYCCNT) is mapped as RAM.
Postcondition
CYCCNT is advanced iff the trace subsystem and cycle counter are enabled.
No PPB word other than DWT_CYCCNT is modified.
Note
Not thread-safe; the run loop is single-threaded host-side.
Since
0.1.0

Definition at line 190 of file emu_exc_scs.c.

References k_dwt_ctrl_addr, k_dwt_ctrl_cyccntena, k_dwt_cyccnt_addr, k_dwt_cyccnt_per_chunk, k_scb_demcr_addr, k_scb_demcr_trcena, rd32(), and wr32().

Referenced by internal_run_loop_tick_inputs().

◆ emu_exc_arm_systick()

void emu_exc_arm_systick ( void )

Pend the periodic SysTick for this outer chunk.

Returns
Nothing.
Precondition
The run loop is at an outer-chunk boundary (one tick per chunk).
None otherwise.
Postcondition
The tick is armed; exc_take_pending() may take it when permitted.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Pend the periodic systick for this outer chunk; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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 )

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

Returns
true once a BKPT halted the run.
Return values
falseNo BKPT was executed.
Precondition
None.
None.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Whether the firmware executed a bkpt (deliberate trap / give-up); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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 )

PC of the BKPT that halted the run.

Returns
The trapping BKPT's address.
Return values
0No BKPT was executed this run.
Precondition
emu_exc_bkpt_hit() returned true (else the value is stale/zero).
None otherwise.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Pc of the bkpt that halted the run; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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 )

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

Returns
Nothing.
Precondition
The inner run loop is about to (re)launch the engine.
None otherwise.
Postcondition
The marker is clear until the next PENDSVSET-triggered stop.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Clear the pendsv context-switch stop marker (per relaunch); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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_clear_reboot_request()

void emu_exc_clear_reboot_request ( void )

Clear the latched warm-reboot request (after performing it).

Returns
Nothing.
Precondition
The run loop just performed the warm reboot.
None otherwise.
Postcondition
No reset request is pending.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Clear the latched warm-reboot request (after performing it); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

Clear the latched warm-reboot request (after performing it).

Definition at line 248 of file emu_exc_scs.c.

References s_reboot_request.

Referenced by internal_run_loop_run_chunk().

◆ emu_exc_install_core()

void emu_exc_install_core ( uc_engine * uc)

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

Returns
Nothing.
Precondition
uc is initialised (setup phase).
Called once, at the same setup position the hooks were always added.
Postcondition
The unmapped-access, interrupt and ICSR write hooks are live.
Note
Not thread-safe; call once during single-threaded setup.
See also
emu_exc_install_scb_nvic() The second hook batch.
Since
0.1.0

Arm the core exception hooks (unmapped / intr / icsr watch); 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.
Postcondition
Ownership of caller-supplied storage is unchanged.

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_install_scb_nvic()

void emu_exc_install_scb_nvic ( uc_engine * uc)

Arm the SCB control-word and NVIC ISER/ICER write watchers.

Returns
Nothing.
Precondition
emu_exc_install_core() ran (hook order is install order).
Called once, at the same setup position the hooks were always added.
Postcondition
The AIRCR..CCR and ISER/ICER write hooks are live.
Note
Not thread-safe; call once during single-threaded setup.
Since
0.1.0

Arm the scb control-word and nvic iser/icer write watchers; 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.
Postcondition
Ownership of caller-supplied storage is unchanged.

Arm the SCB control-word and NVIC ISER/ICER write watchers.

Definition at line 205 of file emu_exc_scs.c.

References internal_on_nvic_en_write(), internal_on_scb_ctrl_write(), k_nvic_en_span, k_nvic_icer_base, k_nvic_iser_base, k_scb_aircr, and k_scb_ccr.

Referenced by internal_main_install_core_seams().

◆ emu_exc_pendsv_stop()

bool emu_exc_pendsv_stop ( void )

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

Returns
true when the chunk ended on a PENDSVSET write.
Return values
falseThe stop had another cause.
Precondition
The engine just stopped.
None otherwise.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Whether the last engine stop was a pendsvset context-switch stop; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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 )

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

Returns
The PendSV activation count.
Return values
0No context switch has happened yet.
Precondition
None.
None.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Pendsv exceptions taken this run (report + idle signature); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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_reboot_requested()

bool emu_exc_reboot_requested ( void )

Whether AIRCR.SYSRESETREQ requested a warm reboot.

Returns
true while a reset request is latched.
Return values
falseNo reset was requested.
Precondition
None.
None.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Whether aircr.sysresetreq requested a warm reboot; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

Whether AIRCR.SYSRESETREQ requested a warm reboot.

Definition at line 242 of file emu_exc_scs.c.

References s_reboot_request.

Referenced by internal_run_inner_check_stops(), and internal_run_loop_run_chunk().

◆ emu_exc_reset()

void emu_exc_reset ( void )

Reset the exception bookkeeping for a warm reboot.

Clears the active-handler stack, re-arms the periodic SysTick, drops the BKPT / EXC_RETURN / PendSV-stop latches and zeroes the activation counters – exactly the state a fresh boot starts with. The reboot request latch is owned by the SCB watcher and cleared separately.

Returns
Nothing.
Precondition
A warm reboot just re-loaded the image.
None otherwise.
Postcondition
The exception engine is in its boot state.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0
Postcondition
Ownership of caller-supplied storage is unchanged.

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 )

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

Returns
The SVCall activation count.
Return values
0No SVC has been taken yet.
Precondition
None.
None.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Svcall exceptions taken this run (report + idle signature); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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 )

SysTick exceptions taken this run (report telemetry).

Returns
The SysTick activation count.
Return values
0No tick has fired yet.
Precondition
None.
None.
Postcondition
No state is modified.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Systick exceptions taken this run (report telemetry); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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)

Consume a latched EXC_RETURN branch (read + clear).

Parameters
[out]out_pcReceives the EXC_RETURN magic value on true.
Returns
true when an EXC_RETURN branch was captured since the last take.
Return values
falseNo exception return is pending (out_pc untouched).
Precondition
out_pc is non-null.
The engine just stopped.
Postcondition
The latch is clear.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0

Consume a latched exc_return branch (read + clear); this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.

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: stack selection (PSP in Thread mode with CONTROL.SPSEL, else MSP), the 8-word basic frame push with 8-byte realignment recorded in the stacked xPSR, the FP extended frame when CONTROL.FPCA is set, the EXC_RETURN load, the IPSR update and the vector fetch. 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.
[in]handlerHandler entry address (Thumb bit ignored).
Returns
Nothing.
Precondition
Taking exc_num is permitted now (priority/PRIMASK already checked).
The target stack is mapped.
Postcondition
The core is in Handler mode (IPSR == exc_num) running on MSP.
LR holds a valid EXC_RETURN and the outgoing frame is stacked.
Note
Not thread-safe; the emulator is single-threaded host-side.
See also
exc_return() The inverse operation.
Since
0.1.0

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(): pops the basic (and, when FType is clear, FP extended) frame from the stack EXC_RETURN selects, undoes the recorded realignment, restores CONTROL.SPSEL / xPSR / the banked SP, and pops the active-exception stack.

Parameters
[in,out]ucUnicorn engine.
[in]exc_retThe EXC_RETURN value (prefix bits[31:7] set).
Returns
Nothing.
Precondition
uc is in Handler mode with a valid frame on the indicated stack.
exc_ret carries the EXC_RETURN prefix.
Postcondition
The core has resumed the unstacked context (PC/SP/xPSR restored).
The active-exception nesting depth decreased by one (if non-zero).
Note
Not thread-safe; the emulator is single-threaded host-side.
See also
exc_enter() The inverse operation.
Since
0.1.0

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 activation rule, called at every instruction boundary AND after each exception return so a pend tail-chains as hardware would. Models SysTick (periodic, armed once per outer chunk), PendSV (level-pending via ICSR.PENDSVSET, cleared on activation) and the ICU-queued peripheral IRQs, honouring PRIMASK and the active-priority stack.

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 so modelled time does NOT advance (used on zero-time context-switch boundaries).
Returns
true if an exception was taken (PC now points at a handler).
Return values
falseNothing pended, masked, or outprioritised.
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.
Note
Not thread-safe; the emulator is single-threaded host-side.
Since
0.1.0
Postcondition
Ownership of caller-supplied storage is unchanged.

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).
Note
VTOR lives in PPB RAM here, written by SystemInit at boot.
Since
0.1.0

Read the handler address for an exception from the vector table; this step is contained within the emu exc model and uses bounded caller or module-owned storage.

Postcondition
Ownership of caller-supplied storage is unchanged.
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().

◆ idle_spin_at()

bool idle_spin_at ( uc_engine * uc,
uint32_t pc )

True if pc sits in a wait-for-interrupt spin (the core is idle).

Recognises a halt instruction at pc (b . / wfi) or an enclosing tight poll loop whose back-edge brackets pc and whose body holds a wfi or cpsie i – genuine idle, where the next thing that can happen is the periodic SysTick. The run loop caps the idle chunk budget so the spin returns at once instead of burning wall time; tick COUNT is unchanged.

Parameters
[in,out]ucUnicorn engine (instructions are read from its memory).
[in]pcProgram counter to inspect (Thumb bit ignored).
Returns
true if pc is on, or enclosed by, a wait-for-interrupt idle loop.
Return values
falseBusy/straight-line code (never truncated).
Precondition
uc has the code region containing pc mapped.
pc is halfword-aligned once the Thumb bit is cleared.
Postcondition
uc is unchanged (a read-only probe).
Note
Detection only; advancing time stays the run loop's job.
Since
0.1.0
Postcondition
Ownership of caller-supplied storage is unchanged.

Reports whether the core at pc is parked in a loop that can only make progress once an interrupt arrives – genuine idle, where the next thing that can happen is the periodic SysTick. Two cases are recognised:

  1. The instruction AT pc is itself a halt: b . (0xE7FE, branch-to-self) or wfi (0xBF30).
  2. pc is ENCLOSED by a wait-for-interrupt poll loop: scanning forward a few halfwords finds an unconditional backward b.n (the loop back-edge) whose target is at or before pc (so the loop wraps around pc), and the loop body holds a wfi or a cpsie i – the "re-enable interrupts and poll" idiom ThreadX's __tx_ts_wait uses (cpsid/ldr/str/cbnz/cpsie/ b .-N, spinning on execute_ptr until a tick makes a thread runnable).

The enclosing-loop test is deliberately tight: it requires the back-edge to bracket pc, so STRAIGHT-LINE code is never matched even when it sits in memory next to an idle loop (an ISR returns via bx lr, not a backward branch over itself – matching a nearby opcode would wrongly truncate it). A compute/busy loop is also excluded: it exits on a conditional branch and never re-enables interrupts mid-loop, so it carries no wfi/cpsie wait. The run loop uses this to cap the idle chunk's budget to k_idle_spin_insns instead of spinning a full k_run_chunk_insns to reach the same already-armed tick. Tick COUNT is unchanged; only idle wall-time is skipped.

Parameters
[in,out]ucUnicorn engine (instructions are read from its memory).
[in]pcProgram counter to inspect (Thumb bit ignored).
Returns
true if pc is on, or enclosed by, a wait-for-interrupt idle loop.
Precondition
uc has the code region containing pc mapped.
pc is halfword-aligned once the Thumb bit is cleared.
Postcondition
uc is unchanged (a read-only probe).
Note
Detection only; advancing time stays the run loop's job, so the tick count – and every tick-based sleep/heartbeat deadline – is preserved.
Since
0.1.0

Definition at line 120 of file emu_idle.c.

References emu_mem_read(), internal_idle_back_edge(), k_idle_scan_fwd, k_op_branch_self, k_op_wfi, and k_thumb_hw_bytes.

Referenced by internal_run_inner_budget().