ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph.c
Go to the documentation of this file.
1
30
31#include "board_periph.h"
32
33#include <stdint.h>
34#include <stdio.h>
35
36#include "board_periph_block.h"
38#include "board_usb.h"
39#include "board_usb_host.h"
41
42/* =============================================================================
43 * ICU / NVIC register map (addresses verified against libs/ra8_hal regs).
44 * =============================================================================
45 */
46
48typedef enum : uint64_t {
49 k_icu_base = 0x40006000UL,
50 k_icu_off_ielsr = 0x6300UL,
52 k_icu_span = 0x6300UL + (96UL * 4UL),
53} icu_map_t;
54
56typedef enum : uint32_t {
57 k_ielsr_iels_mask = 0x000003FFU,
59 k_ielsr_ir_mask = 0x00010000U,
60 k_ielsr_dtce_mask = 0x01000000U,
62
64typedef enum : uint64_t {
65 k_nvic_iser_base = 0xE000E100UL,
66 k_nvic_ispr_base = 0xE000E200UL,
69
71typedef enum : uint32_t {
75
77typedef enum : uint32_t {
78 /* Sized with headroom over the current block population (41 as of the RTT
79 * drain model): overflowing this cap silently un-modelled whichever block
80 * happened to register last (the constructor link order), which surfaced as
81 * a baffling family of app regressions (the XSPI NOR flash apps) rather
82 * than an error. board_periph_register_block now also reports the drop. */
84 /* The core prints its NVIC-IRQ section after SCI (order 30) and before the
85 * touch line (order 40), so it slots its report at this synthetic order. */
88
89static bool s_trace;
90
91/* Active emulation device -- RA8D2 by default so a run with no --device flag is
92 * byte-for-behaviour unchanged. Gates the RA8P1-only NPU block in internal_block_for_addr;
93 * set once by main.c before the run loop and persisted across warm reboots
94 * (board_periph_init does not touch it -- the part is fixed). */
96
97/* --usbhs-loop: when set, loop-only blocks (the USBHS host controller model)
98 * own their register windows; when clear (default) they are skipped and fall
99 * through to the sparse fallback, so a run without the flag is unchanged. Set
100 * once by main.c after argument parsing; board_periph_init does not touch it. */
101static bool s_usbhs_loop;
102
103/* =============================================================================
104 * Block registry -- decentralized: each block self-registers its descriptor.
105 * =============================================================================
106 */
107
109static uint32_t s_block_count;
110static uint8_t s_block_order[k_block_max];
111static bool s_order_built;
112
114{
115 if (block == nullptr) {
116 return;
117 }
118 if (s_block_count >= (uint32_t)k_block_max) {
119 /* NEVER drop a block silently: an un-registered block reads as an
120 * unmodelled peripheral and fails its apps with no hint of the cause. */
121 (void)priv_emu_io_errf("board_periph: block registry FULL (k_block_max=%u) -- "
122 "DROPPING '%s'; raise k_block_max\n",
123 (unsigned)k_block_max,
124 (block->name != nullptr) ? block->name : "?");
125 return;
126 }
127 s_blocks[s_block_count] = block;
129 s_order_built = false; /* a new block invalidates the cached tick/report order */
130}
131
148{
149 for (uint32_t i = 0U; i < s_block_count; i++) {
150 uint32_t j = i;
151 while ((j > 0U) && (s_blocks[s_block_order[j - 1U]]->order > s_blocks[i]->order)) {
152 s_block_order[j] = s_block_order[j - 1U];
153 j--;
154 }
155 s_block_order[j] = (uint8_t)i;
156 }
157 s_order_built = true;
158}
159
173RA8_INTERNAL static bool internal_in_range(uint64_t addr, uint64_t base, uint64_t span)
174{
175 return (addr >= base) && (addr < (base + span));
176}
177
197
199{
201 s_last_block = nullptr; /* a device change can alter which block owns an address */
202}
203
205{
206 return s_device;
207}
208
210{
211 s_usbhs_loop = on;
212 s_last_block = nullptr; /* the gate change alters which block owns 0x40351000 */
213}
214
216{
217 return s_usbhs_loop;
218}
219
232{
233 if (b->loop_only && !s_usbhs_loop) {
234 return false; /* loop-only block, --usbhs-loop off: fall through to sparse. */
235 }
236 if (b->device == k_board_block_dev_ra8p1) {
238 }
239 return true; /* k_board_block_dev_any: present on every device. */
240}
241
244{
245 if ((s_last_block != nullptr) &&
246 internal_in_range(addr, s_last_block->base, s_last_block->span)) {
247 return s_last_block;
248 }
249 for (uint32_t i = 0U; i < s_block_count; i++) {
250 if (internal_in_range(addr, s_blocks[i]->base, s_blocks[i]->span)) {
252 continue; /* RA8P1-only block on a non-RA8P1 run: fall through to sparse. */
253 }
255 return s_blocks[i];
256 }
257 }
258 return nullptr;
259}
260
261/* =============================================================================
262 * Core-owned ICU / NVIC state.
263 * =============================================================================
264 */
265
266/* ICU IELSR event-link table. The ICU registers live inside the callback-MMIO
267 * peripheral window (0x40006xxx), so the model owns this state itself rather
268 * than reading it back through the MMIO callback. The firmware's IELSR writes
269 * (ra8_isr_register / ra8_icu_route) land here; icu_raise_event scans it. */
270static uint32_t s_ielsr[k_icu_ielsr_cnt];
271
272/* Pending-IRQ ring: the ICU pushes a line here when a linked, NVIC-enabled
273 * event fires; the run loop pops it and the engine vectors it in. */
275static uint32_t s_irq_head;
276static uint32_t s_irq_tail;
277static uint32_t s_irq_taken[k_irq_track_max];
278static uint32_t s_irq_total;
279
280/* NVIC set-enable shadow. The Cortex-M NVIC ISER/ICER registers are
281 * set-enable / clear-enable (a written 1 sets / clears that line, a written 0
282 * is ignored), but ra8_emulator maps the PPB as plain RAM, so a raw store of
283 * "1 << bit" to ISER would clobber every other already-enabled line. main.c
284 * decodes ISER/ICER writes and routes the set/clear bits here, where this
285 * accumulating mask is the authoritative enable state the ICU model checks --
286 * so a firmware that enables several NVIC lines (e.g. SCI RXI + TXI + TEI, or
287 * the USB controller lines later) has them all stay enabled. */
288typedef enum : uint32_t {
292
293/* =============================================================================
294 * Small memory helpers (the model reads PPB / NVIC straight from emulated RAM).
295 * =============================================================================
296 */
297
310RA8_INTERNAL static uint32_t internal_periph_rd32(uc_engine* uc, uint64_t addr)
311{
312 uint32_t v = 0U;
313 (void)emu_mem_read(uc, addr, &v, sizeof(v));
314 return v;
315}
316
329RA8_INTERNAL static bool internal_nvic_enabled(uc_engine* uc, uint32_t irq)
330{
331 (void)uc; /* enable state is the accumulating shadow, not raw PPB RAM */
332 const uint32_t word = irq / 32U;
333 if (word >= (uint32_t)k_nvic_enable_words) {
334 return false;
335 }
336 return ((s_nvic_iser_shadow[word] >> (irq % 32U)) & 1U) != 0U;
337}
338
349RA8_INTERNAL static void internal_nvic_set_pending(uc_engine* uc, uint32_t irq)
350{
351 const uint64_t word = (uint64_t)k_nvic_ispr_base + ((uint64_t)(irq / 32U) * 4U);
352 uint32_t ispr = internal_periph_rd32(uc, word);
353 ispr |= (1U << (irq % 32U));
354 (void)emu_mem_write(uc, word, &ispr, sizeof(ispr));
355}
356
357void board_periph_nvic_set_enable(uint32_t irq, bool enable)
358{
359 const uint32_t word = irq / 32U;
360 if (word >= (uint32_t)k_nvic_enable_words) {
361 return;
362 }
363 const uint32_t bit = 1U << (irq % 32U);
364 if (enable) {
365 s_nvic_iser_shadow[word] |= bit;
366 } else {
367 s_nvic_iser_shadow[word] &= ~bit;
368 }
369}
370
371/* =============================================================================
372 * ICU event routing -- link a peripheral event to an NVIC line and pend it.
373 * =============================================================================
374 */
375
385RA8_INTERNAL static void internal_irq_ring_push(uint32_t irq)
386{
387 const uint32_t next = (s_irq_tail + 1U) % (uint32_t)k_irq_queue_len;
388 if (next == s_irq_head) {
389 return; /* ring full: the run loop drains it every boundary, so rare */
390 }
391 s_irq_ring[s_irq_tail] = irq;
392 s_irq_tail = next;
393}
394
395void board_periph_icu_raise_event(uc_engine* uc, uint16_t event)
396{
397 for (uint32_t slot = 0U; slot < (uint32_t)k_icu_ielsr_cnt; slot++) {
398 if ((s_ielsr[slot] & (uint32_t)k_ielsr_iels_mask) != (uint32_t)event) {
399 continue;
400 }
401 s_ielsr[slot] |= (uint32_t)k_ielsr_ir_mask; /* latch IR (W0C by handler) */
402 if (internal_nvic_enabled(uc, slot)) {
405 if (s_trace) {
406 (void)priv_emu_io_errf(" [trace] ICU event 0x%03X -> NVIC IRQ %u pended\n", event, slot);
407 }
408 }
409 return; /* one IELSR slot owns a given event */
410 }
411}
412
413uint32_t board_periph_icu_dtc_slot(uint16_t event)
414{
415 for (uint32_t slot = 0U; slot < (uint32_t)k_icu_ielsr_cnt; slot++) {
416 const bool links = (s_ielsr[slot] & (uint32_t)k_ielsr_iels_mask) == (uint32_t)event;
417 const bool dtce = (s_ielsr[slot] & (uint32_t)k_ielsr_dtce_mask) != 0U;
418 if (links && dtce) {
419 return slot;
420 }
421 }
422 return (uint32_t)k_icu_ielsr_cnt;
423}
424
436RA8_INTERNAL static uint32_t internal_icu_ielsr_slot(uint64_t addr)
437{
438 const uint64_t lo = (uint64_t)k_icu_base + (uint64_t)k_icu_off_ielsr;
439 const uint64_t hi = lo + ((uint64_t)k_icu_ielsr_cnt * 4U);
440 if ((addr < lo) || (addr >= hi)) {
441 return (uint32_t)k_icu_ielsr_cnt;
442 }
443 return (uint32_t)((addr - lo) / 4U);
444}
445
457RA8_INTERNAL static uint64_t internal_icu_read(uint64_t addr)
458{
459 const uint32_t slot = internal_icu_ielsr_slot(addr);
460 return (slot < (uint32_t)k_icu_ielsr_cnt) ? s_ielsr[slot] : 0U;
461}
462
473RA8_INTERNAL static void internal_icu_write(uint64_t addr, uint32_t value)
474{
475 const uint32_t slot = internal_icu_ielsr_slot(addr);
476 if (slot >= (uint32_t)k_icu_ielsr_cnt) {
477 return;
478 }
479 /* IR (bit 16) is WRITE-ZERO-to-clear, not write-one-to-clear: HUM Ch 14.2.17
480 * p 547, "IR flag (Interrupt Status Flag)" -> [Clearing condition] -- "the IR
481 * flag is cleared to 0 by writing 0". A written 0 clears the latched flag; a
482 * written 1 leaves it set. Every other bit takes the written value.
483 *
484 * This model had the polarity inverted (RW1C), which silently satisfied a
485 * driver that ORed a 1 into IR to "clear" it -- a write real silicon ignores.
486 * The emulator therefore ran every ISR-driven app cleanly while the bench
487 * live-locked in an interrupt storm (#170: lpm_periodic_idle emitted no UART
488 * at all, stuck in IRQ0_Handler with IELSR0 = 0x00010080). Modelling the real
489 * polarity makes the emulator reproduce that storm, so the bug cannot hide here
490 * again. */
491 const uint32_t ir_now = s_ielsr[slot] & (uint32_t)k_ielsr_ir_mask;
492 const uint32_t ir_keep = ((value & (uint32_t)k_ielsr_ir_mask) != 0U) ? ir_now : 0U;
493 s_ielsr[slot] = (value & ~(uint32_t)k_ielsr_ir_mask) | ir_keep;
494}
495
496/* The USBFS model (board_usb.c) pends its controller interrupt by asserting the
497 * USBFS_INT ELC event; it goes through the same IELSR -> NVIC path as every
498 * other peripheral, so board_periph hands it the event-raise via a thin wrapper
499 * (the engine is the only extra argument the event-raise needs). */
500
511RA8_INTERNAL static void internal_usb_irq_raiser(uc_engine* uc, uint16_t event)
512{
514}
515
516/* =============================================================================
517 * Shared framework services published to the block files.
518 * =============================================================================
519 */
520
522{
523 return s_trace;
524}
525
526/* =============================================================================
527 * Lifecycle.
528 * =============================================================================
529 */
530
531void board_periph_init(bool trace)
532{
533 s_trace = trace;
534 s_last_block = nullptr; /* drop the dispatch cache across a warm reboot */
535 if (!s_order_built) {
537 }
538 /* Reset every registered block to its power-on state. */
539 for (uint32_t i = 0U; i < s_block_count; i++) {
541 if (b->reset != nullptr) {
542 b->reset();
543 }
544 }
545 /* Core ICU / NVIC bookkeeping. */
546 for (uint32_t i = 0U; i < (uint32_t)k_icu_ielsr_cnt; i++) {
547 s_ielsr[i] = 0U;
548 }
549 for (uint32_t i = 0U; i < (uint32_t)k_irq_track_max; i++) {
550 s_irq_taken[i] = 0U;
551 }
552 for (uint32_t i = 0U; i < (uint32_t)k_nvic_enable_words; i++) {
553 s_nvic_iser_shadow[i] = 0U;
554 }
555 s_irq_head = 0U;
556 s_irq_tail = 0U;
557 s_irq_total = 0U;
558 /* Bring the USBFS controller model + virtual host up and wire its interrupt
559 * pend through this module's ICU/NVIC path (Phase 3, issue #67). */
560 board_usb_init(trace);
562 /* USBHS HOST-mode model (self-loop peer of the USBFS device above). Dormant
563 * until main.c grants the loop AND the firmware selects host mode. */
564 board_usb_host_init(trace);
565}
566
567/* =============================================================================
568 * MMIO dispatch -- route an address to its block, else report "not handled".
569 * =============================================================================
570 */
571
572uint64_t board_periph_read(uc_engine* uc, uint64_t addr, unsigned size, bool* handled)
573{
574 *handled = true;
576 if ((block != nullptr) && !block->observe) {
578 /* Module-stopped peripheral: unclocked on silicon, so it reads 0 and the
579 * modelled block must NOT answer (#405). This is the same fidelity shape
580 * as the #247 graphics power domain -- a block whose enable was never
581 * cancelled does nothing on hardware, and now nothing in the emulator. */
583 return 0U;
584 }
585 return block->read(uc, addr, size);
586 }
587 /* An observe-only block (e.g. GLCDC) does not own its window: fall through so
588 * the caller's sparse model answers the read, exactly as if it were
589 * unmodelled. */
590 {
591 bool usb_hit = false;
592 const uint64_t usb_val = board_usb_read(uc, addr, size, &usb_hit);
593 if (usb_hit) {
594 return usb_val;
595 }
596 }
597 {
598 bool usbh_hit = false;
599 const uint64_t usbh_val = board_usb_host_read(uc, addr, size, &usbh_hit);
600 if (usbh_hit) {
601 return usbh_val;
602 }
603 }
604 if (internal_icu_ielsr_slot(addr) < (uint32_t)k_icu_ielsr_cnt) {
605 return internal_icu_read(addr);
606 }
607 *handled = false;
608 return 0U;
609}
610
611void board_periph_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value, bool* handled)
612{
613 *handled = true;
615 if (block != nullptr) {
616 if (!block->observe && priv_board_mstp_addr_stopped(addr)) {
617 /* Module-stopped peripheral: unclocked on silicon, so the write is
618 * dropped (#405). Reported handled -- the access is consumed and
619 * discarded exactly as the hardware discards it (no fault, no flag). */
621 return;
622 }
623 block->write(uc, addr, size, value);
624 /* An observe-only block snoops the write but does not consume it: report
625 * NOT handled so the caller's sparse model also records it (the panel
626 * compositor reads the GLCDC registers back from that shadow). */
627 *handled = !block->observe;
628 return;
629 }
630 {
631 bool usb_hit = false;
632 board_usb_write(uc, addr, size, value, &usb_hit);
633 if (usb_hit) {
634 return;
635 }
636 }
637 {
638 bool usbh_hit = false;
639 board_usb_host_write(uc, addr, size, value, &usbh_hit);
640 if (usbh_hit) {
641 return;
642 }
643 }
644 if (internal_icu_ielsr_slot(addr) < (uint32_t)k_icu_ielsr_cnt) {
645 internal_icu_write(addr, (uint32_t)value);
646 return;
647 }
648 *handled = false;
649}
650
651void board_periph_tick(uc_engine* uc)
652{
653 for (uint32_t i = 0U; i < s_block_count; i++) {
655 if (b->tick != nullptr) {
656 b->tick(uc);
657 }
658 }
659 /* Step the virtual USB host: it advances the chapter-9 enumeration and pends
660 * the USBFS interrupt through ::internal_usb_irq_raiser when it delivers a SETUP. */
661 board_usb_tick(uc);
662}
663
664bool board_periph_next_irq(uint32_t* out_irq)
665{
666 if (s_irq_head == s_irq_tail) {
667 return false; /* ring empty */
668 }
669 *out_irq = s_irq_ring[s_irq_head];
670 s_irq_head = (s_irq_head + 1U) % (uint32_t)k_irq_queue_len;
671 return true;
672}
673
675{
676 s_irq_total++;
677 if (irq < (uint32_t)k_irq_track_max) {
678 s_irq_taken[irq]++;
679 }
680 if (s_trace) {
681 (void)priv_emu_io_errf(" [trace] NVIC IRQ %u taken (real exception via VTOR)\n", irq);
682 }
683}
684
685uint32_t board_periph_irq_count(uint32_t irq)
686{
687 if (irq >= (uint32_t)k_irq_track_max) {
688 return 0U;
689 }
690 return s_irq_taken[irq];
691}
692
694{
695 return s_irq_total;
696}
697
698/* =============================================================================
699 * End-of-run summary -- each block prints its section in ascending order, with
700 * the core's NVIC-IRQ section slotted between SCI and the touch line, then USB.
701 * =============================================================================
702 */
703
713{
714 if (s_irq_total == 0U) {
715 (void)priv_emu_io_errf(" NVIC IRQs : 0 taken (no event-linked, enabled line fired)\n");
716 return;
717 }
718 (void)priv_emu_io_errf(" NVIC IRQs : %u taken [", s_irq_total);
719 bool first = true;
720 for (uint32_t i = 0U; i < (uint32_t)k_irq_track_max; i++) {
721 if (s_irq_taken[i] > 0U) {
722 (void)priv_emu_io_errf("%sIRQ%u x%u", first ? "" : " ", i, s_irq_taken[i]);
723 first = false;
724 }
725 }
726 (void)priv_emu_io_errf("]\n");
727}
728
729void board_periph_report(uc_engine* uc)
730{
731 (void)uc;
732 bool irq_done = false;
733 for (uint32_t i = 0U; i < s_block_count; i++) {
735 /* The core's NVIC-IRQ section sits between SCI and the touch line. */
736 if (!irq_done && (b->order >= (uint32_t)k_core_irq_report_order)) {
738 irq_done = true;
739 }
740 if (b->report != nullptr) {
741 b->report();
742 }
743 }
744 if (!irq_done) {
746 }
749}
nvic_addr_t
Cortex-M NVIC register bases (PPB, read straight from memory).
@ k_nvic_word_bits
Lines per ISER/ISPR word.
void board_periph_tick(uc_engine *uc)
Advance every modelled timer by one emulation chunk and raise events.
void board_periph_icu_raise_event(uc_engine *uc, uint16_t event)
Raise a peripheral ELC event through the core's ICU -> NVIC path.
static const board_periph_block_t * s_blocks[k_block_max]
Registered blocks.
void board_periph_init(bool trace)
One-time reset of all peripheral-model state.
static uint32_t s_nvic_iser_shadow[k_nvic_enable_words]
static bool internal_nvic_enabled(uc_engine *uc, uint32_t irq)
True iff NVIC line irq is enabled in the set-enable shadow.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
static void internal_board_periph_build_order(void)
Build s_block_order: registry indices sorted by descriptor order.
static void internal_usb_irq_raiser(uc_engine *uc, uint16_t event)
ICU event-raise hook handed to the USB model (see board_usb.h).
board_device_t board_periph_device(void)
Report which RA8 device the peripheral model is emulating.
static uint64_t internal_icu_read(uint64_t addr)
Dispatch an ICU IELSR read from the model's own event-link state.
core_tune_t
Registry capacity + the core's own report slot ordering.
@ k_block_max
Max registered peripheral blocks.
@ k_core_irq_report_order
Where the IRQ report sits among blocks.
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.
static board_device_t s_device
static uint32_t s_irq_ring[k_irq_queue_len]
static uint32_t s_ielsr[k_icu_ielsr_cnt]
static uint32_t s_irq_taken[k_irq_track_max]
Times each IRQ was taken.
static void internal_report_irqs(void)
Print the per-IRQ taken totals (or a "none fired" note).
static uint32_t s_irq_tail
void board_periph_note_irq_taken(uint32_t irq)
Record that NVIC IRQ irq was actually taken (for the summary).
static uint32_t internal_periph_rd32(uc_engine *uc, uint64_t addr)
Read a 32-bit little-endian word from emulated memory.
uint32_t board_periph_icu_dtc_slot(uint16_t event)
Find the IELSR slot that activates the DTC for an ELC event.
static void internal_irq_ring_push(uint32_t irq)
Push an IRQ onto the pending ring (drop silently if full).
static bool internal_in_range(uint64_t addr, uint64_t base, uint64_t span)
True iff addr is inside [base, base + span).
static const board_periph_block_t * internal_block_for_addr(uint64_t addr)
Find the registered block owning addr on the active device, or NULL.
irq_tune_t
Pending-IRQ ring + per-IRQ tracking sizing.
@ k_irq_track_max
Distinct IRQ numbers tracked.
@ k_irq_queue_len
Pending-IRQ ring capacity.
void board_periph_set_usbhs_loop(bool on)
Enable the chip-internal USBHS-host self-loop model (–usbhs-loop).
static bool s_usbhs_loop
ielsr_field_t
ICU IELSR layout – ra8_ielsr_bit_t / ra8_ielsr_mask_t.
@ k_ielsr_dtce_mask
DTCE: DTC activation enable [24].
@ k_ielsr_iels_mask
IELS event-select field [9:0].
@ k_ielsr_ir_bit
IR interrupt status flag (W0C).
@ k_ielsr_ir_mask
IR bit mask.
void board_periph_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value, bool *handled)
Dispatch an MMIO write to the owning block, if any.
static const board_periph_block_t * s_last_block
Last block returned by internal_block_for_addr (one-entry dispatch cache).
bool board_periph_usbhs_loop(void)
Report whether the USBHS-host self-loop model is enabled.
static void internal_nvic_set_pending(uc_engine *uc, uint32_t irq)
Mirror the pended line into NVIC ISPR so firmware can observe it.
static uint8_t s_block_order[k_block_max]
Tick/report order.
static uint32_t s_irq_total
Total IRQs delivered.
uint32_t board_periph_irq_total(void)
Total NVIC interrupts the ICU has delivered in this run.
uint64_t board_periph_read(uc_engine *uc, uint64_t addr, unsigned size, bool *handled)
Dispatch an MMIO read to the owning block, if any.
static uint32_t s_block_count
Live entries.
bool board_periph_trace(void)
Whether –trace is active (blocks log transitions when true).
icu_map_t
ICU block geometry (ra8_icu_regs.h).
@ k_icu_span
Icu span.
@ k_icu_base
R_ICU base.
@ k_icu_off_ielsr
IELSR[0..95], 32-bit each.
@ k_icu_ielsr_cnt
IELSR slot count on RA8D2.
void board_periph_report(uc_engine *uc)
Print the peripheral-model section of the end-of-run summary.
static uint32_t internal_icu_ielsr_slot(uint64_t addr)
Index of the IELSR slot owning addr, or k_icu_ielsr_cnt if none.
static bool internal_block_on_active_device(const board_periph_block_t *b)
Whether block b is exposed on the active emulation device + run.
static uint32_t s_irq_head
void board_periph_set_device(board_device_t device)
Select which RA8 device the peripheral model emulates.
static void internal_icu_write(uint64_t addr, uint32_t value)
Dispatch an ICU IELSR write; IR is W0C, the IELS/DTCE bits are RW.
bool board_periph_next_irq(uint32_t *out_irq)
Pop the next pending, enabled NVIC IRQ number the ICU has queued.
nvic_shadow_t
@ k_nvic_enable_words
256 NVIC lines tracked (8 * 32).
uint32_t board_periph_irq_count(uint32_t irq)
Number of times a given NVIC line was taken in this run.
static bool s_order_built
s_block_order valid.
Register-accurate peripheral-model framework for the board emulator.
board_device_t
The RA8 device the emulator models for this run.
@ k_board_device_ra8p1
Renesas RA8P1: adds the Ethos-U55 NPU.
@ k_board_device_ra8d2
Renesas RA8D2 (default): no NPU.
Decentralized peripheral-block registry for the board emulator core.
@ k_board_block_dev_ra8p1
RA8P1-only (Ethos-U55 NPU).
Module-private module-stop (MSTP) gate state shared with the core.
void priv_board_mstp_note_gated_access(uint64_t addr, bool is_write)
Record that an MMIO access to a module-stopped peripheral was dropped.
bool priv_board_mstp_addr_stopped(uint64_t addr)
Report whether the peripheral instance owning addr is module-stopped.
USBFS controller model + a virtual USB host for the board emulator.
void board_usb_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value, bool *handled)
Dispatch an MMIO write inside the USBFS register window.
void board_usb_report(void)
Print the USB section of the end-of-run summary.
Definition board_usb.c:250
void board_usb_tick(uc_engine *uc)
Advance the virtual USB host one emulation chunk.
Definition board_usb.c:116
void board_usb_init(bool trace)
Reset the USBFS controller model and the virtual host state machine.
Definition board_usb.c:165
void board_usb_set_irq_raiser(board_usb_irq_raiser_t raise)
Install the ICU event-raise hook used to pend the USBFS interrupt.
Definition board_usb.c:186
uint64_t board_usb_read(uc_engine *uc, uint64_t addr, unsigned size, bool *handled)
Dispatch an MMIO read inside the USBFS register window.
USBHS HOST-mode controller model (self-loop peer of the USBFS device).
void board_usb_host_report(void)
Print the USBHS host-model section of the end-of-run summary.
void board_usb_host_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value, bool *handled)
Dispatch an MMIO write inside the USBHS register window.
uint64_t board_usb_host_read(uc_engine *uc, uint64_t addr, unsigned size, bool *handled)
Dispatch an MMIO read inside the USBHS register window.
void board_usb_host_init(bool trace)
Reset the USBHS host-mode model to its power-on state.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
uc_err emu_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t count)
Read guest memory through the central access seam.
uc_err emu_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t count)
Write guest memory through the central access seam.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
A modelled peripheral block's self-description for the core registry.
bool observe
Observe-only: snoop, do not own the MMIO.
const char * name
Short label (diagnostics only).
board_periph_write_fn write
MMIO write handler (required).
board_periph_read_fn read
MMIO read handler (required).
@ k_nvic_ispr_base
NVIC Interrupt Set-Pending Register array.
@ k_nvic_iser_base
NVIC Interrupt Set-Enable Register array.
static volatile uint32_t s_trace[k_dcd_trace_entries]
JLink-readable ring of packed transfer/SETUP events.