ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_exc_scs.c
Go to the documentation of this file.
1
17
18#include <stdio.h>
19
20#include "board_periph.h"
21#include "emu_console.h"
22#include "emu_engine.h"
23#include "emu_exc.h"
24#include "emu_seams.h"
25
27static bool s_reboot_request;
28
61RA8_INTERNAL static void internal_on_scb_ctrl_write(uc_engine* uc,
62 uc_mem_type type,
63 uint64_t addr,
64 int size,
65 int64_t value,
66 void* user)
67{
68 (void)type;
69 (void)size;
70 (void)user;
71 const uint32_t word = (uint32_t)addr & ~3U;
72 if (word == (uint32_t)k_scb_ccr) {
73 if (((uint32_t)value & (uint32_t)k_ccr_div_0_trp) != 0U) {
74 div0_patch_sites(uc); /* firmware opted in: overwrite the divides with UDF. */
75 }
76 return;
77 }
78 if (word != (uint32_t)k_scb_aircr) {
79 return; /* an intervening SCB word (VTOR / SCR): not ours. */
80 }
81 if (((uint32_t)value & (1U << (uint32_t)k_aircr_sysresetreq)) == 0U) {
82 return; /* a non-reset AIRCR write (e.g. priority grouping) */
83 }
84 s_reboot_request = true;
85 (void)uc_emu_stop(uc); /* end the chunk; the run loop performs the reboot */
86}
87
115RA8_INTERNAL static void internal_on_nvic_en_write(uc_engine* uc,
116 uc_mem_type type,
117 uint64_t addr,
118 int size,
119 int64_t value,
120 void* user)
121{
122 (void)uc;
123 (void)type;
124 (void)size;
125 (void)user;
126 const bool is_set = (addr >= (uint64_t)k_nvic_iser_base) &&
127 (addr < ((uint64_t)k_nvic_iser_base + (uint64_t)k_nvic_en_span));
128 const uint64_t base = is_set ? (uint64_t)k_nvic_iser_base : (uint64_t)k_nvic_icer_base;
129 const uint32_t word = (uint32_t)((addr - base) / 4U);
130 const uint32_t bits = (uint32_t)value;
131 for (uint32_t b = 0U; b < 32U; b++) {
132 if ((bits & (1U << b)) != 0U) {
133 board_periph_nvic_set_enable((word * 32U) + b, is_set);
134 }
135 }
136}
137
152typedef enum : uint64_t {
153 k_dwt_ctrl_addr = 0xE0001000UL,
154 k_dwt_cyccnt_addr = 0xE0001004UL,
155 k_dwt_ctrl_cyccntena = 0x00000001UL,
160
190void dwt_cyccnt_advance(uc_engine* uc)
191{
192 const uint32_t demcr = rd32(uc, (uint64_t)k_scb_demcr_addr);
193 if ((demcr & (uint32_t)k_scb_demcr_trcena) == 0U) {
194 return; /* Trace subsystem off: CYCCNT does not count. */
195 }
196 const uint32_t ctrl = rd32(uc, (uint64_t)k_dwt_ctrl_addr);
197 if ((ctrl & (uint32_t)k_dwt_ctrl_cyccntena) == 0U) {
198 return; /* Cycle counter disabled: leave CYCCNT untouched. */
199 }
200 const uint32_t next = rd32(uc, (uint64_t)k_dwt_cyccnt_addr) + (uint32_t)k_dwt_cyccnt_per_chunk;
201 wr32(uc, (uint64_t)k_dwt_cyccnt_addr, next);
202}
203
205void emu_exc_install_scb_nvic(uc_engine* uc)
206{
207 /* Watch the SCB control words AIRCR..CCR with ONE hook (internal_on_scb_ctrl_write): a
208 * SYSRESETREQ store triggers a warm reboot and a CCR.DIV_0_TRP store arms the
209 * div-0 trap (which then patches divides -- no per-access cost). Both are PPB
210 * RAM, so a write-hook is the only way to observe them. */
211 static uc_hook s_h_scb;
212 (void)uc_hook_add(uc,
213 &s_h_scb,
214 UC_HOOK_MEM_WRITE,
216 nullptr,
217 (uint64_t)k_scb_aircr,
218 (uint64_t)k_scb_ccr + 3U);
219 /* NVIC ISER / ICER are set-enable / clear-enable: fold each written bit into
220 * board_periph's enable shadow so enabling several lines does not clobber the
221 * earlier ones (see internal_on_nvic_en_write). The PPB is RAM, so this hook is the
222 * only place the W1S/W1C semantics can be applied. */
223 static uc_hook s_h_nvic_iser;
224 static uc_hook s_h_nvic_icer;
225 (void)uc_hook_add(uc,
226 &s_h_nvic_iser,
227 UC_HOOK_MEM_WRITE,
229 nullptr,
230 (uint64_t)k_nvic_iser_base,
231 (uint64_t)k_nvic_iser_base + (uint64_t)k_nvic_en_span - 1U);
232 (void)uc_hook_add(uc,
233 &s_h_nvic_icer,
234 UC_HOOK_MEM_WRITE,
236 nullptr,
237 (uint64_t)k_nvic_icer_base,
238 (uint64_t)k_nvic_icer_base + (uint64_t)k_nvic_en_span - 1U);
239}
240
243{
244 return s_reboot_request;
245}
246
249{
250 s_reboot_request = false;
251}
Register-accurate peripheral-model framework for the board emulator.
void board_periph_nvic_set_enable(uint32_t irq, bool enable)
Set or clear a NVIC line's enable in the model's set-enable shadow.
Emulator text-console surfaces: UART echo, ITM/SWO echo, escapes.
@ k_scb_demcr_trcena
DEMCR bit 24: trace subsystem enable.
Definition emu_console.h:75
@ k_scb_demcr_addr
Debug Exception + Monitor Control.
Definition emu_console.h:52
Shared Unicorn engine access utilities for the board emulator.
static uint32_t rd32(uc_engine *uc, uint64_t addr)
Read a 32-bit little-endian word from emulated memory.
Definition emu_engine.h:67
static void wr32(uc_engine *uc, uint64_t addr, uint32_t v)
Write a 32-bit little-endian word to emulated memory.
Definition emu_engine.h:91
Cortex-M exception model constants and interfaces for ra8_emulator.
@ k_scb_ccr
Configuration and Control (CCR).
Definition emu_exc.h:50
@ k_nvic_en_span
Byte span of one set/clear array.
Definition emu_exc.h:66
@ k_scb_aircr
App interrupt/reset control (AIRCR).
Definition emu_exc.h:40
@ k_aircr_sysresetreq
AIRCR.SYSRESETREQ bit (request reset).
Definition emu_exc.h:41
@ k_ccr_div_0_trp
CCR.DIV_0_TRP bit4: divide-by-0 traps.
Definition emu_exc.h:51
static RA8_INTERNAL void internal_on_scb_ctrl_write(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
UC_HOOK_MEM_WRITE handler for the SCB control words AIRCR and CCR.
Definition emu_exc_scs.c:61
dwt_model_t
Data Watchpoint and Trace (DWT) cycle-counter register model.
@ k_dwt_ctrl_addr
DWT_CTRL (bit 0 CYCCNTENA).
@ k_dwt_cyccnt_addr
DWT_CYCCNT free-running cycle counter.
@ k_dwt_ctrl_cyccntena
DWT_CTRL.CYCCNTENA: counter enable.
@ k_dwt_cyccnt_per_chunk
Cycles charged per outer chunk (==.
void dwt_cyccnt_advance(uc_engine *uc)
Advance the DWT cycle counter by one outer chunk's worth of cycles.
static RA8_INTERNAL void internal_on_nvic_en_write(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user)
UC_HOOK_MEM_WRITE handler for the NVIC ISER / ICER arrays.
void emu_exc_clear_reboot_request(void)
Implementation of emu_exc_clear_reboot_request() – plain clear.
bool emu_exc_reboot_requested(void)
Implementation of emu_exc_reboot_requested() – plain flag read.
void emu_exc_install_scb_nvic(uc_engine *uc)
Implementation of emu_exc_install_scb_nvic() – SCB ctrl + NVIC hooks.
static bool s_reboot_request
AIRCR.SYSRESETREQ observed: the run loop performs a warm reboot.
Definition emu_exc_scs.c:27
Armv8.1-M instruction-emulation seams (M85 ops on Unicorn's M33).
void div0_patch_sites(uc_engine *uc)
Overwrite every tracked divide with UDF so divide-by-zero can trap.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_nvic_icer_base
NVIC Interrupt Clear-Enable Register array.
@ k_nvic_iser_base
NVIC Interrupt Set-Enable Register array.