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

Peripheral-block registry core + ICU/NVIC routing for ra8_emulator. More...

#include "board_periph.h"
#include <stdint.h>
#include <stdio.h>
#include "board_periph_block.h"
#include "board_periph_mstp_internal.h"
#include "board_usb.h"
#include "board_usb_host.h"
#include "emu_host_io_internal.h"
Include dependency graph for board_periph.c:

Go to the source code of this file.

Enumerations

enum  icu_map_t : uint64_t {
  k_icu_base = 0x40006000UL ,
  k_icu_off_ielsr = 0x6300UL ,
  k_icu_ielsr_cnt = 96UL ,
  k_icu_span = 0x6300UL + (96UL * 4UL)
}
 ICU block geometry (ra8_icu_regs.h). More...
enum  ielsr_field_t : uint32_t {
  k_ielsr_iels_mask = 0x000003FFU ,
  k_ielsr_ir_bit = 16U ,
  k_ielsr_ir_mask = 0x00010000U ,
  k_ielsr_dtce_mask = 0x01000000U
}
 ICU IELSR layout – ra8_ielsr_bit_t / ra8_ielsr_mask_t. More...
enum  nvic_addr_t : uint64_t {
  k_nvic_iser_base = 0xE000E100UL ,
  k_nvic_ispr_base = 0xE000E200UL ,
  k_nvic_word_bits = 32UL
}
 Cortex-M NVIC register bases (PPB, read straight from memory). More...
enum  irq_tune_t : uint32_t {
  k_irq_queue_len = 32U ,
  k_irq_track_max = 64U
}
 Pending-IRQ ring + per-IRQ tracking sizing. More...
enum  core_tune_t : uint32_t {
  k_block_max = 56U ,
  k_core_irq_report_order = 35U
}
 Registry capacity + the core's own report slot ordering. More...
enum  nvic_shadow_t : uint32_t { k_nvic_enable_words = 8U }

Functions

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 bool internal_in_range (uint64_t addr, uint64_t base, uint64_t span)
 True iff addr is inside [base, base + span).
void board_periph_set_device (board_device_t device)
 Select which RA8 device the peripheral model emulates.
board_device_t board_periph_device (void)
 Report which RA8 device the peripheral model is emulating.
void board_periph_set_usbhs_loop (bool on)
 Enable the chip-internal USBHS-host self-loop model (–usbhs-loop).
bool board_periph_usbhs_loop (void)
 Report whether the USBHS-host self-loop model is enabled.
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 const board_periph_block_tinternal_block_for_addr (uint64_t addr)
 Find the registered block owning addr on the active device, or NULL.
static uint32_t internal_periph_rd32 (uc_engine *uc, uint64_t addr)
 Read a 32-bit little-endian word from emulated memory.
static bool internal_nvic_enabled (uc_engine *uc, uint32_t irq)
 True iff NVIC line irq is enabled in the set-enable shadow.
static void internal_nvic_set_pending (uc_engine *uc, uint32_t irq)
 Mirror the pended line into NVIC ISPR so firmware can observe it.
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 void internal_irq_ring_push (uint32_t irq)
 Push an IRQ onto the pending ring (drop silently if full).
void board_periph_icu_raise_event (uc_engine *uc, uint16_t event)
 Raise a peripheral ELC event through the core's ICU -> NVIC path.
uint32_t board_periph_icu_dtc_slot (uint16_t event)
 Find the IELSR slot that activates the DTC for an ELC event.
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 uint64_t internal_icu_read (uint64_t addr)
 Dispatch an ICU IELSR read from the model's own event-link state.
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.
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).
bool board_periph_trace (void)
 Whether –trace is active (blocks log transitions when true).
void board_periph_init (bool trace)
 One-time reset of all peripheral-model state.
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.
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.
void board_periph_tick (uc_engine *uc)
 Advance every modelled timer by one emulation chunk and raise events.
bool board_periph_next_irq (uint32_t *out_irq)
 Pop the next pending, enabled NVIC IRQ number the ICU has queued.
void board_periph_note_irq_taken (uint32_t irq)
 Record that NVIC IRQ irq was actually taken (for the summary).
uint32_t board_periph_irq_count (uint32_t irq)
 Number of times a given NVIC line was taken in this run.
uint32_t board_periph_irq_total (void)
 Total NVIC interrupts the ICU has delivered in this run.
static void internal_report_irqs (void)
 Print the per-IRQ taken totals (or a "none fired" note).
void board_periph_report (uc_engine *uc)
 Print the peripheral-model section of the end-of-run summary.

Variables

static bool s_trace
 –trace: log transitions + IRQs as they happen.
static board_device_t s_device = k_board_device_ra8d2
static bool s_usbhs_loop
static const board_periph_block_ts_blocks [k_block_max]
 Registered blocks.
static uint32_t s_block_count
 Live entries.
static uint8_t s_block_order [k_block_max]
 Tick/report order.
static bool s_order_built
 s_block_order valid.
static const board_periph_block_ts_last_block
 Last block returned by internal_block_for_addr (one-entry dispatch cache).
static uint32_t s_ielsr [k_icu_ielsr_cnt]
static uint32_t s_irq_ring [k_irq_queue_len]
static uint32_t s_irq_head
static uint32_t s_irq_tail
static uint32_t s_irq_taken [k_irq_track_max]
 Times each IRQ was taken.
static uint32_t s_irq_total
 Total IRQs delivered.
static uint32_t s_nvic_iser_shadow [k_nvic_enable_words]

Detailed Description

Peripheral-block registry core + ICU/NVIC routing for ra8_emulator.

The framework half of the peripheral model: a dynamic registry of peripheral blocks (board_periph_block.h) that the MMIO callbacks dispatch into by address range, plus the cross-block machinery the blocks share – the ICU IELSR event-link table, the pending-IRQ ring, and the NVIC set-enable shadow. The block IMPLEMENTATIONS live in their own files (board_periph_gpio.c, board_periph_timer.c, board_periph_sci.c, board_periph_i2c.c); each self-registers its descriptor from a constructor, so this core keeps NO hand-maintained block list and a new block is just a new file + a CMake line.

Dispatch order: a registered block (by disjoint address range), then the USBFS model (board_usb.c, forwarded), then the ICU IELSR window the core owns. Per-chunk tick and the end-of-run report walk the registry in ascending descriptor order so the historical cadence / section order is preserved regardless of constructor registration order.

Design: this module owns no Unicorn engine of its own and takes no AppKit dependency. main.c passes the engine in where the model must read or write emulated memory / pend an NVIC line, so board_periph stays plain C and the exception delivery stays in the one place that already models it.

Since
0.1.0

Definition in file board_periph.c.

Enumeration Type Documentation

◆ core_tune_t

enum core_tune_t : uint32_t

Registry capacity + the core's own report slot ordering.

Enumerator
k_block_max 

Max registered peripheral blocks.

k_core_irq_report_order 

Where the IRQ report sits among blocks.

Definition at line 77 of file board_periph.c.

◆ icu_map_t

enum icu_map_t : uint64_t

ICU block geometry (ra8_icu_regs.h).

Enumerator
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.

k_icu_span 

Icu span.

Definition at line 48 of file board_periph.c.

◆ ielsr_field_t

enum ielsr_field_t : uint32_t

ICU IELSR layout – ra8_ielsr_bit_t / ra8_ielsr_mask_t.

Enumerator
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.

k_ielsr_dtce_mask 

DTCE: DTC activation enable [24].

Definition at line 56 of file board_periph.c.

◆ irq_tune_t

enum irq_tune_t : uint32_t

Pending-IRQ ring + per-IRQ tracking sizing.

Enumerator
k_irq_queue_len 

Pending-IRQ ring capacity.

k_irq_track_max 

Distinct IRQ numbers tracked.

Definition at line 71 of file board_periph.c.

◆ nvic_addr_t

enum nvic_addr_t : uint64_t

Cortex-M NVIC register bases (PPB, read straight from memory).

Enumerator
k_nvic_iser_base 

Interrupt Set-Enable array.

k_nvic_ispr_base 

Interrupt Set-Pending array.

k_nvic_word_bits 

Lines per ISER/ISPR word.

Definition at line 64 of file board_periph.c.

◆ nvic_shadow_t

enum nvic_shadow_t : uint32_t
Enumerator
k_nvic_enable_words 

256 NVIC lines tracked (8 * 32).

Definition at line 288 of file board_periph.c.

Function Documentation

◆ board_periph_device()

board_device_t board_periph_device ( void )

Report which RA8 device the peripheral model is emulating.

Read-only accessor over the active-device selection last set by board_periph_set_device (defaults to k_board_device_ra8d2).

Returns
The active device (k_board_device_ra8d2 / k_board_device_ra8p1).
Return values
k_board_device_ra8d2Default, or the last RA8D2 selection.
k_board_device_ra8p1Last selected via board_periph_set_device.
Precondition
None; safe at any time – the selection is statically initialized to RA8D2.
Postcondition
No model state is modified (read-only accessor).
The returned value is a valid board_device_t enumerator.
Note
Not thread-safe; single-threaded run-loop / setup use.
See also
board_periph_set_device
Since
0.1.0
Precondition
The call executes on the emulator's single owning thread.

Definition at line 204 of file board_periph.c.

References s_device.

Referenced by internal_main_load_primary().

◆ board_periph_icu_dtc_slot()

uint32_t board_periph_icu_dtc_slot ( uint16_t event)

Find the IELSR slot that activates the DTC for an ELC event.

The DTC block model needs to know which IELSR slot a software / peripheral event is routed to with DTC activation enabled, so it can index the DTC vector table (DTCVBR + slot*4) at the matching Transfer Information block. The core owns the IELSR event-link table (the same state board_periph_icu_raise_event scans), so it answers the query: the first slot whose IELS event-select field equals event and whose DTCE bit is set.

Parameters
[in]eventELC event number to resolve (e.g. ELC_SWEVT0 = 0x0CC).
Returns
The IELSR slot index [0, 95] when a DTCE-enabled slot links event, or a value >= 96 when none does.
Since
0.1.0
Return values
valueThe operation-specific board periph icu DTC slot value.
Precondition
Arguments satisfy the ranges documented for board periph icu DTC slot.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph block model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 413 of file board_periph.c.

References k_icu_ielsr_cnt, k_ielsr_dtce_mask, k_ielsr_iels_mask, and s_ielsr.

Referenced by internal_dtc_activate_swevt0().

◆ board_periph_icu_raise_event()

void board_periph_icu_raise_event ( uc_engine * uc,
uint16_t event )

Raise a peripheral ELC event through the core's ICU -> NVIC path.

The single entry point a block uses to assert an interrupt: the core owns the ICU IELSR event-link table, the NVIC enable shadow and the pending-IRQ ring, so a timer / UART block calls this rather than touching that state. The core latches IELSR.IR for the slot linked to event and, if that NVIC line is enabled, pends it for the engine to take.

Parameters
[in,out]ucUnicorn engine (the ICU reads IELSR / NVIC from PPB).
[in]eventELC event number the block is asserting.
Returns
Nothing.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph icu raise event.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph block model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 395 of file board_periph.c.

References internal_irq_ring_push(), internal_nvic_enabled(), internal_nvic_set_pending(), k_icu_ielsr_cnt, k_ielsr_iels_mask, k_ielsr_ir_mask, priv_emu_io_errf(), s_ielsr, and s_trace.

Referenced by internal_adc_write(), internal_agt_tick_channel(), internal_canfd_loopback_deliver(), internal_dmac_run_transfer(), internal_gpt_tick_channel(), internal_ipc_write(), internal_npu_execute(), internal_rtc_raise_events(), internal_sci_tick_channel(), internal_ulpt_tick_channel(), and internal_usb_irq_raiser().

◆ board_periph_init()

void board_periph_init ( bool trace)

One-time reset of all peripheral-model state.

Clears every modelled block (PORT latches/direction, AGT/GPT counters and status, ICU event-link table and NVIC pend records) and the observability counters. Call once after the memory map is created and before the run loop.

Parameters
[in]traceWhen true, each LED / GPIO transition and each taken IRQ is logged to injected error sink as it happens (the –trace flag).
Returns
Nothing.
Postcondition
All counters read zero and every block is in its reset state.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph init.
The call executes on the emulator's single owning thread.
Postcondition
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 531 of file board_periph.c.

References board_usb_host_init(), board_usb_init(), board_usb_set_irq_raiser(), internal_board_periph_build_order(), internal_usb_irq_raiser(), k_icu_ielsr_cnt, k_irq_track_max, k_nvic_enable_words, s_block_count, s_block_order, s_blocks, s_ielsr, s_irq_head, s_irq_tail, s_irq_taken, s_irq_total, s_last_block, s_nvic_iser_shadow, s_order_built, and s_trace.

Referenced by internal_main_bringup_peripherals(), and warm_reboot().

◆ board_periph_irq_count()

uint32_t board_periph_irq_count ( uint32_t irq)

Number of times a given NVIC line was taken in this run.

Parameters
[in]irqNVIC line number (0-based).
Returns
Times the engine vectored in irq (0 if never, or out of range).
Since
0.1.0

Number of times a given nvic line was taken in this run; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Return values
valueThe operation-specific board periph interrupt count value.
Precondition
Arguments satisfy the ranges documented for board periph interrupt count.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 685 of file board_periph.c.

References k_irq_track_max, and s_irq_taken.

Referenced by internal_fill_status_hw().

◆ board_periph_irq_total()

uint32_t board_periph_irq_total ( void )

Total NVIC interrupts the ICU has delivered in this run.

Returns
Sum of every taken IRQ (the board view's "IRQ" activity total).
Since
0.1.0

Total nvic interrupts the icu has delivered in this run; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Return values
valueThe operation-specific board periph interrupt total value.
Precondition
Arguments satisfy the ranges documented for board periph interrupt total.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 693 of file board_periph.c.

References s_irq_total.

Referenced by internal_fill_status_hw(), and internal_run_stop_idle().

◆ board_periph_next_irq()

bool board_periph_next_irq ( uint32_t * out_irq)

Pop the next pending, enabled NVIC IRQ number the ICU has queued.

The software half of "the ICU asserts a line and the NVIC latches it". The run loop calls this at an instruction boundary; the returned IRQ number is vectored in by the engine's exception layer as a real Cortex-M exception (vector 16 + IRQn from VTOR). Priority and PRIMASK are handled by that layer, so this only reports a line that is event-linked and NVIC-enabled.

Parameters
[out]out_irqReceives the IRQ number (0-based, NVIC line) on success.
Returns
true if a pending IRQ was popped into out_irq.
Since
0.1.0
Return values
trueThe board periph next interrupt condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for board periph next interrupt.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 664 of file board_periph.c.

References k_irq_queue_len, s_irq_head, s_irq_ring, and s_irq_tail.

Referenced by internal_exc_take_periph_irq().

◆ board_periph_note_irq_taken()

void board_periph_note_irq_taken ( uint32_t irq)

Record that NVIC IRQ irq was actually taken (for the summary).

Parameters
[in]irqIRQ number that the engine just vectored in.
Returns
Nothing.
Since
0.1.0

Record that nvic irq irq was actually taken (for the summary); this step is contained within the board periph model and uses bounded caller or module-owned storage.

Precondition
Arguments satisfy the ranges documented for board periph note interrupt taken.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 674 of file board_periph.c.

References k_irq_track_max, priv_emu_io_errf(), s_irq_taken, s_irq_total, and s_trace.

Referenced by internal_exc_take_periph_irq().

◆ board_periph_nvic_set_enable()

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.

The Cortex-M NVIC ISER / ICER registers are set-enable / clear-enable: a written 1 sets (ISER) or clears (ICER) that interrupt line and a written 0 is ignored, so several independent stores accumulate. ra8_emulator maps the PPB as plain RAM, where a raw "1 << bit" store to ISER would instead overwrite the whole word and drop every other enabled line. main.c decodes ISER / ICER writes and calls this so the ICU model sees the correct accumulated enable state – essential once firmware enables more than one line at once (SCI RXI + TXI + TEI, and the USB controller lines in Phase 3).

Parameters
[in]irqNVIC line number (0-based).
[in]enabletrue to set the line's enable, false to clear it.
Returns
Nothing.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph NVIC set enable.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 357 of file board_periph.c.

References k_nvic_enable_words, and s_nvic_iser_shadow.

Referenced by internal_on_nvic_en_write().

◆ board_periph_read()

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.

Looks up addr in the block table; on a hit the block's read handler returns the register value and *handled is set true. On a miss *handled is false and the caller falls back to the sparse model.

Parameters
[in,out]ucUnicorn engine (handlers may read emulated memory).
[in]addrAbsolute peripheral address being read.
[in]sizeAccess width in bytes (1/2/4).
[out]handledTrue iff a modelled block answered the read.
Returns
The register value when *handled is true, else 0.
Since
0.1.0
Return values
valueThe operation-specific board periph read value.
Precondition
Arguments satisfy the ranges documented for board periph read.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 572 of file board_periph.c.

References board_usb_host_read(), board_usb_read(), internal_block_for_addr(), internal_icu_ielsr_slot(), internal_icu_read(), k_icu_ielsr_cnt, board_periph_block_t::observe, priv_board_mstp_addr_stopped(), priv_board_mstp_note_gated_access(), and board_periph_block_t::read.

Referenced by mmio_read().

◆ board_periph_register_block()

void board_periph_register_block ( const board_periph_block_t * block)

Register a peripheral block's descriptor with the core registry.

Called by each block file from a file-scope __attribute__((constructor)), so every block is registered before main runs. The core keeps the supplied pointer (the descriptor must be static) and dispatches MMIO / tick / reset through it. Registering more blocks than the fixed registry capacity drops the extra (a build-time assert in the core guards the common case); registration order is irrelevant to behaviour.

Parameters
[in]blockStatic block descriptor to add (ignored if NULL).
Returns
Nothing.
Postcondition
Subsequent board_periph_read / _write / _tick / reset see block.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph register block.
The call executes on the emulator's single owning thread.
Postcondition
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 113 of file board_periph.c.

References k_block_max, board_periph_block_t::name, priv_emu_io_errf(), s_block_count, s_blocks, and s_order_built.

Referenced by internal_bkup_block_register(), internal_board_periph_adc_register(), internal_board_periph_canfd_register(), internal_board_periph_ceu_register(), internal_board_periph_dac_register(), internal_board_periph_dmac_register(), internal_board_periph_gpio_register(), internal_board_periph_i2c_register(), internal_board_periph_ipc_register(), internal_board_periph_pdm_register(), internal_board_periph_riic_register(), internal_board_periph_rtc_register(), internal_board_periph_sci_register(), internal_board_periph_spi_register(), internal_board_periph_timer_register(), internal_board_periph_ulpt_register(), internal_cac_block_register(), internal_crc_block_register(), internal_doc_block_register(), internal_drw_block_register(), internal_dtc_block_register(), internal_eth_block_register(), internal_glcdc_block_register(), internal_gptp_block_register(), internal_lvd_block_register(), internal_mram_block_register(), internal_mstp_block_register(), internal_npu_block_register(), internal_pdctr_block_register(), internal_poeg_block_register(), internal_prcr_block_register(), internal_reset_block_register(), internal_rtt_block_register(), internal_sdhi_block_register(), internal_sram_block_register(), internal_ssie_block_register(), internal_usbhs_block_register(), internal_wdt_block_register(), and internal_xspi_block_register().

◆ board_periph_report()

void board_periph_report ( uc_engine * uc)

Print the peripheral-model section of the end-of-run summary.

Reports the final driven level of each board LED and its transition count, each modelled timer's final counter / event totals, the per-IRQ taken count, and each active SCI channel's transmitted / received byte totals – the observability the epic asks for (GPIO/LED transitions + per-IRQ interrupt counts + captured serial), beyond the generic MMIO table main.c already prints.

Parameters
[in,out]ucUnicorn engine (read for any final register state).
Returns
Nothing.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph report.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 729 of file board_periph.c.

References board_usb_host_report(), board_usb_report(), internal_report_irqs(), k_core_irq_report_order, s_block_count, s_block_order, and s_blocks.

Referenced by internal_run_print_stop_summary().

◆ board_periph_set_device()

void board_periph_set_device ( board_device_t device)

Select which RA8 device the peripheral model emulates.

Sets the active device used to gate the RA8P1-only NPU block. Called once by main.c after parsing --device and before the run loop; the selection persists across warm reboots (the emulated silicon does not change part between resets). An out-of-range value is clamped to k_board_device_ra8d2 so a malformed flag can never leave the model in an undefined device state.

Parameters
[in]deviceDevice to emulate (k_board_device_ra8d2 / k_board_device_ra8p1); out-of-range clamps to RA8D2.
Returns
Nothing.
Precondition
The peripheral registry constructors have run (they always do, pre-main).
Called once during single-threaded setup, before the run loop (not re-entrant).
Postcondition
board_periph_device reports the clamped selection.
RA8P1-only blocks are dispatched iff device is k_board_device_ra8p1.
Note
Not thread-safe; call once from the single-threaded setup path.
See also
board_periph_device
Since
0.1.0

Definition at line 198 of file board_periph.c.

References k_board_device_ra8d2, k_board_device_ra8p1, s_device, and s_last_block.

Referenced by internal_main_bringup_peripherals().

◆ board_periph_set_usbhs_loop()

void board_periph_set_usbhs_loop ( bool on)

Enable the chip-internal USBHS-host self-loop model (–usbhs-loop).

Gates every board_periph_block_t whose loop_only flag is set: a loop-only block (the USBHS host controller model, board_periph_usbhs_host.c) owns its register window ONLY when this is enabled. Off (the default), such a block is skipped and its window falls through to the sparse fallback, exactly as an unmodelled reserved region does – so a run WITHOUT the flag is byte-for-behaviour unchanged (the USBHS host apps that rely on the function seam are untouched). main.c sets this once, after argument parsing, for an app declared as a chip-internal self-loop.

Parameters
[in]ontrue to activate loop-only blocks for this run.
Returns
Nothing.
Postcondition
Loop-only blocks own their windows iff on; the dispatch cache is invalidated so the change takes effect immediately.
Note
Not thread-safe; single-threaded setup use.
See also
board_periph_usbhs_loop
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph set usbhs loop.
The call executes on the emulator's single owning thread.
Postcondition
Ownership of caller-supplied storage is unchanged.

Definition at line 209 of file board_periph.c.

References s_last_block, and s_usbhs_loop.

Referenced by internal_main_bringup_peripherals().

◆ board_periph_tick()

void board_periph_tick ( uc_engine * uc)

Advance every modelled timer by one emulation chunk and raise events.

Called once per run-loop chunk (the same cadence as one SysTick period). Each running AGT / GPT counter steps by its per-chunk increment; a wrap past the period sets the block's status flag (overflow / underflow / compare-match) and, if that event is linked through the ICU with its NVIC line enabled, records a pending IRQ for the engine to take. Stopped timers do not advance. The SCI_B model is also serviced here: with TX always drained in the model, an enabled TXI / TEI re-pends each tick so an interrupt-driven transmitter keeps streaming, and an enabled RXI pends while queued RX bytes remain.

Parameters
[in,out]ucUnicorn engine (the ICU reads IELSR / NVIC ISER from PPB).
Returns
Nothing.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph tick.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 651 of file board_periph.c.

References board_usb_tick(), s_block_count, s_block_order, and s_blocks.

Referenced by internal_run_loop_tick_inputs().

◆ board_periph_trace()

bool board_periph_trace ( void )

Whether –trace is active (blocks log transitions when true).

Returns
true when the run was started with –trace, else false.
Since
0.1.0

Whether –trace is active (blocks log transitions when true); this step is contained within the board periph block model and uses bounded caller or module-owned storage.

Return values
trueThe board periph trace condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for board periph trace.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph block model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 521 of file board_periph.c.

References s_trace.

Referenced by board_periph_sci_feed_rx(), internal_adc_write(), internal_canfd_loopback_deliver(), internal_ceu_do_capture(), internal_dac_write(), internal_dmac_run_transfer(), internal_ipc_write(), internal_port_trace_leds(), internal_rtc_raise_events(), and internal_ulpt_tick_channel().

◆ board_periph_usbhs_loop()

bool board_periph_usbhs_loop ( void )

Report whether the USBHS-host self-loop model is enabled.

Returns
true when board_periph_set_usbhs_loop last enabled it, else false.
Precondition
None; safe at any time (defaults to false).
Postcondition
No model state is modified (read-only accessor).
Note
Not thread-safe; single-threaded run-loop / setup use.
See also
board_periph_set_usbhs_loop
Since
0.1.0

Report whether the usbhs-host self-loop model is enabled; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Return values
trueThe board periph usbhs loop condition holds or completed successfully; false otherwise.
Precondition
The call executes on the emulator's single owning thread.
Postcondition
Ownership of caller-supplied storage is unchanged.

Definition at line 215 of file board_periph.c.

References s_usbhs_loop.

◆ board_periph_write()

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.

Parameters
[in,out]ucUnicorn engine (handlers may read emulated memory).
[in]addrAbsolute peripheral address being written.
[in]sizeAccess width in bytes (1/2/4).
[in]valueValue being written.
[out]handledTrue iff a modelled block consumed the write.
Returns
Nothing.
Since
0.1.0

Dispatch an mmio write to the owning block, if any; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Precondition
Arguments satisfy the ranges documented for board periph write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 611 of file board_periph.c.

References board_usb_host_write(), board_usb_write(), internal_block_for_addr(), internal_icu_ielsr_slot(), internal_icu_write(), k_icu_ielsr_cnt, board_periph_block_t::observe, priv_board_mstp_addr_stopped(), priv_board_mstp_note_gated_access(), and board_periph_block_t::write.

Referenced by mmio_write().

◆ internal_block_for_addr()

const board_periph_block_t * internal_block_for_addr ( uint64_t addr)
static

Find the registered block owning addr on the active device, or NULL.

Definition at line 243 of file board_periph.c.

References internal_block_on_active_device(), internal_in_range(), RA8_INTERNAL, s_block_count, s_blocks, and s_last_block.

Referenced by board_periph_read(), and board_periph_write().

◆ internal_block_on_active_device()

bool internal_block_on_active_device ( const board_periph_block_t * b)
static

Whether block b is exposed on the active emulation device + run.

Whether block b is exposed on the active emulation device + run; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in]bB input used by the operation.
Returns
The block on active device result produced by the board periph model.
Return values
trueThe block on active device condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for block on active device.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 231 of file board_periph.c.

References k_board_block_dev_ra8p1, k_board_device_ra8p1, RA8_INTERNAL, s_device, and s_usbhs_loop.

Referenced by internal_block_for_addr().

◆ internal_board_periph_build_order()

void internal_board_periph_build_order ( void )
static

Build s_block_order: registry indices sorted by descriptor order.

A stable insertion sort by board_periph_block_t::order so the per-chunk tick and the end-of-run report visit blocks in a deterministic cadence regardless of the constructor registration order (ties keep registration order). MMIO dispatch does not use this – blocks own disjoint address ranges.

Returns
Nothing.
Since
0.1.0
Precondition
Arguments satisfy the ranges documented for board periph build order.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.

Definition at line 147 of file board_periph.c.

References RA8_INTERNAL, s_block_count, s_block_order, s_blocks, and s_order_built.

Referenced by board_periph_init().

◆ internal_icu_ielsr_slot()

uint32_t internal_icu_ielsr_slot ( uint64_t addr)
static

Index of the IELSR slot owning addr, or k_icu_ielsr_cnt if none.

Index of the ielsr slot owning addr, or k_icu_ielsr_cnt if none; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in]addrGuest address involved in the operation.
Returns
The icu ielsr slot result produced by the board periph model.
Return values
valueThe operation-specific icu ielsr slot value.
Precondition
Arguments satisfy the ranges documented for icu ielsr slot.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 436 of file board_periph.c.

References k_icu_base, k_icu_ielsr_cnt, k_icu_off_ielsr, and RA8_INTERNAL.

Referenced by board_periph_read(), board_periph_write(), internal_icu_read(), and internal_icu_write().

◆ internal_icu_read()

uint64_t internal_icu_read ( uint64_t addr)
static

Dispatch an ICU IELSR read from the model's own event-link state.

Dispatch an icu ielsr read from the model's own event-link state; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in]addrGuest address involved in the operation.
Returns
The icu read result produced by the board periph model.
Return values
valueThe operation-specific icu read value.
Precondition
Arguments satisfy the ranges documented for icu read.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 457 of file board_periph.c.

References internal_icu_ielsr_slot(), k_icu_ielsr_cnt, RA8_INTERNAL, and s_ielsr.

Referenced by board_periph_read().

◆ internal_icu_write()

void internal_icu_write ( uint64_t addr,
uint32_t value )
static

Dispatch an ICU IELSR write; IR is W0C, the IELS/DTCE bits are RW.

Dispatch an icu ielsr write; ir is w0c, the iels/dtce bits are rw; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in]addrGuest address involved in the operation.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for icu write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 473 of file board_periph.c.

References internal_icu_ielsr_slot(), k_icu_ielsr_cnt, k_ielsr_ir_mask, RA8_INTERNAL, and s_ielsr.

Referenced by board_periph_write().

◆ internal_in_range()

bool internal_in_range ( uint64_t addr,
uint64_t base,
uint64_t span )
static

True iff addr is inside [base, base + span).

True iff addr is inside [base, base + span); this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in]addrGuest address involved in the operation.
[in]baseBase input used by the operation.
[in]spanBounded address span covered by the operation.
Returns
The in range result produced by the board periph model.
Return values
trueThe in range condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for in range.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 173 of file board_periph.c.

References RA8_INTERNAL.

Referenced by internal_block_for_addr().

◆ internal_irq_ring_push()

void internal_irq_ring_push ( uint32_t irq)
static

Push an IRQ onto the pending ring (drop silently if full).

Push an irq onto the pending ring (drop silently if full); this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in]irqInterrupt number or state handled by the operation.
Precondition
Arguments satisfy the ranges documented for interrupt ring push.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 385 of file board_periph.c.

References k_irq_queue_len, RA8_INTERNAL, s_irq_head, s_irq_ring, and s_irq_tail.

Referenced by board_periph_icu_raise_event().

◆ internal_nvic_enabled()

bool internal_nvic_enabled ( uc_engine * uc,
uint32_t irq )
static

True iff NVIC line irq is enabled in the set-enable shadow.

True iff nvic line irq is enabled in the set-enable shadow; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]irqInterrupt number or state handled by the operation.
Returns
The NVIC enabled result produced by the board periph model.
Return values
trueThe NVIC enabled condition holds or completed successfully; false otherwise.
Precondition
Arguments satisfy the ranges documented for NVIC enabled.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 329 of file board_periph.c.

References k_nvic_enable_words, RA8_INTERNAL, and s_nvic_iser_shadow.

Referenced by board_periph_icu_raise_event().

◆ internal_nvic_set_pending()

void internal_nvic_set_pending ( uc_engine * uc,
uint32_t irq )
static

Mirror the pended line into NVIC ISPR so firmware can observe it.

Mirror the pended line into nvic ispr so firmware can observe it; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]irqInterrupt number or state handled by the operation.
Precondition
Arguments satisfy the ranges documented for NVIC set pending.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 349 of file board_periph.c.

References emu_mem_write(), internal_periph_rd32(), k_nvic_ispr_base, and RA8_INTERNAL.

Referenced by board_periph_icu_raise_event().

◆ internal_periph_rd32()

uint32_t internal_periph_rd32 ( uc_engine * uc,
uint64_t addr )
static

Read a 32-bit little-endian word from emulated memory.

Read a 32-bit little-endian word from emulated memory; this step is contained within the board periph model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]addrGuest address involved in the operation.
Returns
The periph rd32 result produced by the board periph model.
Return values
valueThe operation-specific periph rd32 value.
Precondition
Arguments satisfy the ranges documented for periph rd32.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 310 of file board_periph.c.

References emu_mem_read(), and RA8_INTERNAL.

Referenced by internal_nvic_set_pending().

◆ internal_report_irqs()

void internal_report_irqs ( void )
static

Print the per-IRQ taken totals (or a "none fired" note).

Print the per-irq taken totals (or a "none fired" note); this step is contained within the board periph model and uses bounded caller or module-owned storage.

Precondition
Arguments satisfy the ranges documented for report irqs.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 712 of file board_periph.c.

References k_irq_track_max, priv_emu_io_errf(), RA8_INTERNAL, s_irq_taken, and s_irq_total.

Referenced by board_periph_report().

◆ internal_usb_irq_raiser()

void internal_usb_irq_raiser ( uc_engine * uc,
uint16_t event )
static

ICU event-raise hook handed to the USB model (see board_usb.h).

Icu event-raise hook handed to the usb model (see board_usb.h); this step is contained within the board periph model and uses bounded caller or module-owned storage.

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

Definition at line 511 of file board_periph.c.

References board_periph_icu_raise_event(), and RA8_INTERNAL.

Referenced by board_periph_init().

Variable Documentation

◆ s_block_count

◆ s_block_order

uint8_t s_block_order[k_block_max]
static

Tick/report order.

Definition at line 110 of file board_periph.c.

Referenced by board_periph_init(), board_periph_report(), board_periph_tick(), and internal_board_periph_build_order().

◆ s_blocks

◆ s_device

◆ s_ielsr

◆ s_irq_head

uint32_t s_irq_head
static

◆ s_irq_ring

uint32_t s_irq_ring[k_irq_queue_len]
static

Definition at line 274 of file board_periph.c.

Referenced by board_periph_next_irq(), and internal_irq_ring_push().

◆ s_irq_tail

uint32_t s_irq_tail
static

◆ s_irq_taken

uint32_t s_irq_taken[k_irq_track_max]
static

Times each IRQ was taken.

Definition at line 277 of file board_periph.c.

Referenced by board_periph_init(), board_periph_irq_count(), board_periph_note_irq_taken(), and internal_report_irqs().

◆ s_irq_total

uint32_t s_irq_total
static

Total IRQs delivered.

Definition at line 278 of file board_periph.c.

Referenced by board_periph_init(), board_periph_irq_total(), board_periph_note_irq_taken(), and internal_report_irqs().

◆ s_last_block

const board_periph_block_t* s_last_block
static

Last block returned by internal_block_for_addr (one-entry dispatch cache).

The firmware's polled SD-over-Simple-SPI byte protocol hammers a single peripheral block (the SCI window) thousands of times in a row, and every MMIO callback would otherwise re-scan all ~28 registered blocks. Caching the last owner and testing it first collapses that scan to a single internal_in_range compare on the overwhelmingly common same-block run. It only changes HOW the owning block is located, never WHICH block answers, so the byte/flag stream the firmware observes is unchanged.

Note
Cleared in board_periph_init so a warm reboot cannot reuse a stale pointer (the descriptor list is static, but this keeps the invariant explicit).
Warning
Not thread-safe; the run loop is single-threaded.
Since
0.1.0

Definition at line 196 of file board_periph.c.

Referenced by board_periph_init(), board_periph_set_device(), board_periph_set_usbhs_loop(), and internal_block_for_addr().

◆ s_nvic_iser_shadow

uint32_t s_nvic_iser_shadow[k_nvic_enable_words]
static

◆ s_order_built

bool s_order_built
static

s_block_order valid.

Definition at line 111 of file board_periph.c.

Referenced by board_periph_init(), board_periph_register_block(), and internal_board_periph_build_order().

◆ s_trace

bool s_trace
static

–trace: log transitions + IRQs as they happen.

Definition at line 89 of file board_periph.c.

◆ s_usbhs_loop

bool s_usbhs_loop
static