|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Cortex-M exception model constants and interfaces for ra8_emulator. More...
Go to the source code of this file.
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. | |
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.
Definition in file emu_exc.h.
| enum cortexm_exc_t : uint32_t |
| enum cortexm_scs_t : uint64_t |
| 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.
| [in,out] | uc | Active Unicorn engine (CYCCNT lives in PPB RAM). |
uc has stopped at an instruction boundary (outer-chunk cadence). 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.
| [in,out] | uc | Active Unicorn engine (CYCCNT and its enables live in PPB RAM, read/written through uc). |
uc has stopped at an instruction boundary (outer-chunk cadence). 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().
| void emu_exc_arm_systick | ( | void | ) |
Pend the periodic SysTick for this outer chunk.
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.
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().
| bool emu_exc_bkpt_hit | ( | void | ) |
Whether the firmware executed a BKPT (deliberate trap / give-up).
| false | No BKPT was executed. |
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.
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().
| uint32_t emu_exc_bkpt_pc | ( | void | ) |
PC of the BKPT that halted the run.
| 0 | No BKPT was executed this run. |
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.
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().
| void emu_exc_clear_pendsv_stop | ( | void | ) |
Clear the PendSV context-switch stop marker (per relaunch).
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.
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().
| void emu_exc_clear_reboot_request | ( | void | ) |
Clear the latched warm-reboot request (after performing it).
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.
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().
| void emu_exc_install_core | ( | uc_engine * | uc | ) |
Arm the core exception hooks (unmapped / INTR / ICSR watch).
uc is initialised (setup phase). 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.
| [in,out] | uc | Unicorn engine whose emulated state is read or updated. |
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().
| void emu_exc_install_scb_nvic | ( | uc_engine * | uc | ) |
Arm the SCB control-word and NVIC ISER/ICER write watchers.
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.
| [in,out] | uc | Unicorn engine whose emulated state is read or updated. |
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().
| bool emu_exc_pendsv_stop | ( | void | ) |
Whether the last engine stop was a PENDSVSET context-switch stop.
| false | The stop had another cause. |
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.
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().
| uint32_t emu_exc_pendsv_takes | ( | void | ) |
PendSV exceptions taken this run (report + idle signature).
| 0 | No context switch has happened yet. |
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.
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().
| bool emu_exc_reboot_requested | ( | void | ) |
Whether AIRCR.SYSRESETREQ requested a warm reboot.
| false | No reset was requested. |
Whether aircr.sysresetreq requested a warm reboot; this step is contained within the emu exc model and uses bounded caller or module-owned storage.
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().
| 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.
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().
| uint32_t emu_exc_svc_takes | ( | void | ) |
SVCall exceptions taken this run (report + idle signature).
| 0 | No SVC has been taken yet. |
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.
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().
| uint32_t emu_exc_systick_fires | ( | void | ) |
SysTick exceptions taken this run (report telemetry).
| 0 | No tick has fired yet. |
Systick exceptions taken this run (report telemetry); this step is contained within the emu exc model and uses bounded caller or module-owned storage.
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().
| bool emu_exc_take_exc_return | ( | uint64_t * | out_pc | ) |
Consume a latched EXC_RETURN branch (read + clear).
| [out] | out_pc | Receives the EXC_RETURN magic value on true. |
| false | No exception return is pending (out_pc untouched). |
out_pc is non-null. 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.
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().
| 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.
| [in,out] | uc | Unicorn engine. |
| [in] | exc_num | Exception number to take. |
| [in] | handler | Handler entry address (Thumb bit ignored). |
exc_num is permitted now (priority/PRIMASK already checked). exc_num) running on MSP. 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.
| [in,out] | uc | Unicorn engine. |
| [in] | exc_num | Exception number to take (11, 14, or 15). |
| [in] | handler | Handler entry address (Thumb bit ignored). |
uc has MSP/PSP/CONTROL/xPSR readable and the target stack mapped. exc_num is permitted now (priority/PRIMASK already checked). exc_num) running on MSP. 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().
| 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.
| [in,out] | uc | Unicorn engine. |
| [in] | exc_ret | The EXC_RETURN value (prefix bits[31:7] set). |
uc is in Handler mode with a valid frame on the indicated stack. exc_ret carries the EXC_RETURN prefix. 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.
| [in,out] | uc | Unicorn engine. |
| [in] | exc_ret | The EXC_RETURN value (prefix bits[31:7] set) returned to. |
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). 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().
| 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.
| [in,out] | uc | Unicorn engine. |
| [in] | vtor_base | Fallback vector base if VTOR reads as 0. |
| [in] | allow_systick | When false, the armed SysTick is left pending so modelled time does NOT advance (used on zero-time context-switch boundaries). |
| false | Nothing pended, masked, or outprioritised. |
uc has stopped at an instruction boundary or just returned. 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 (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.
| [in,out] | uc | Unicorn engine. |
| [in] | vtor_base | Fallback vector base if VTOR reads as 0. |
| [in] | allow_systick | When 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. |
uc has stopped at an instruction boundary or just returned. 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().
| 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.
| [in,out] | uc | Unicorn engine. |
| [in] | vtor_base | Fallback vector base used when VTOR reads as 0. |
| [in] | exc_num | Exception/vector index to look up. |
| 0 | when no usable handler is installed at that vector slot. |
uc has the vector table mapped at VTOR (or vtor_base). exc_num is a valid vector index (< table length). 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.
| [in,out] | uc | Unicorn engine. |
| [in] | vtor_base | Fallback vector base used when VTOR reads as 0. |
| [in] | exc_num | Exception/vector index to look up. |
| 0 | when no usable handler is installed at that vector slot. |
uc has the vector table mapped at VTOR (or vtor_base). exc_num is a valid vector index (< table length). 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().
| 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.
| [in,out] | uc | Unicorn engine (instructions are read from its memory). |
| [in] | pc | Program counter to inspect (Thumb bit ignored). |
pc is on, or enclosed by, a wait-for-interrupt idle loop. | false | Busy/straight-line code (never truncated). |
uc has the code region containing pc mapped. pc is halfword-aligned once the Thumb bit is cleared. uc is unchanged (a read-only probe). 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:
pc is itself a halt: b . (0xE7FE, branch-to-self) or wfi (0xBF30).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.
| [in,out] | uc | Unicorn engine (instructions are read from its memory). |
| [in] | pc | Program counter to inspect (Thumb bit ignored). |
pc is on, or enclosed by, a wait-for-interrupt idle loop.uc has the code region containing pc mapped. pc is halfword-aligned once the Thumb bit is cleared. uc is unchanged (a read-only probe). 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().