|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
SEGGER RTT up-buffer drain model for ra8_emulator. More...
#include <stdint.h>#include <stdio.h>#include <string.h>#include "board_console.h"#include "board_periph_block.h"#include "emu_host_io_internal.h"Go to the source code of this file.
Data Structures | |
| struct | rtt_state_t |
| RTT drain-model state (discovery, line assembly, observability). More... | |
Enumerations | |
| enum | rtt_scan_window_t : uint64_t { k_rtt_scan_base = 0x22000000UL , k_rtt_scan_span = 0x00400000UL , k_rtt_scan_step = 0x00010000UL } |
| SRAM window the control-block scan covers (mirrors main.c's map). More... | |
| enum | rtt_cb_layout_t : uint32_t { k_rtt_off_max_up = 16U , k_rtt_off_up0 = 24U , k_rtt_up_off_buf = 4U , k_rtt_up_off_size = 8U , k_rtt_up_off_wr = 12U , k_rtt_up_off_rd = 16U } |
| Control-block field offsets (SEGGER_RTT.h, 32-bit target layout). More... | |
| enum | rtt_tune_t : uint32_t { k_rtt_id_len = 10U , k_rtt_scan_first_tick = 64U , k_rtt_scan_max_gap = 1024U , k_rtt_max_up_sane = 16U , k_rtt_size_sane = 1048576U , k_rtt_drain_max = 4096U , k_rtt_line_max = 240U } |
| Model tuning: scan cadence, sanity caps, and line assembly. More... | |
| enum | rtt_order_t : uint32_t { k_rtt_block_order = 32U } |
| Per-tick order slot for the RTT drain (right after the SCI console). More... | |
Functions | |
| static RA8_INTERNAL uint32_t | internal_rtt_rd32 (uc_engine *uc, uint64_t addr) |
| Read a 32-bit little-endian word from emulated memory. | |
| static RA8_INTERNAL bool | internal_rtt_cb_valid (uc_engine *uc, uint64_t cb_addr) |
| Validate a candidate control block beyond its ID match. | |
| static RA8_INTERNAL uint64_t | internal_rtt_match_stage (uc_engine *uc, uint64_t stage_addr, uint64_t len) |
| Match the staged bytes for a validated control-block ID. | |
| static RA8_INTERNAL void | internal_rtt_scan (uc_engine *uc) |
| Scan the emulated SRAM window for the RTT control-block ID. | |
| static RA8_INTERNAL void | internal_rtt_line_feed (uint8_t byte) |
| Feed one drained byte into the line assembler. | |
| static RA8_INTERNAL void | internal_rtt_drain (uc_engine *uc) |
| Drain up-buffer 0 of the discovered control block, host-style. | |
| static RA8_INTERNAL void | internal_rtt_tick (uc_engine *uc) |
| Per-chunk advance: discover the control block, then keep it drained. | |
| static RA8_INTERNAL void | internal_rtt_reset (void) |
| Reset the RTT drain model to power-on state (warm reboot). | |
| static RA8_INTERNAL void | internal_rtt_report (void) |
| End-of-run RTT section: block address + drained totals. | |
| static RA8_INTERNAL uint64_t | internal_rtt_mmio_read (uc_engine *uc, uint64_t addr, unsigned size) |
| MMIO read stub – never dispatched (this block owns no window). | |
| static RA8_INTERNAL void | internal_rtt_mmio_write (uc_engine *uc, uint64_t addr, unsigned size, uint64_t value) |
| MMIO write stub – never dispatched (this block owns no window). | |
| static RA8_INTERNAL void | internal_rtt_block_register (void) |
| Self-register the RTT drain model before main (host constructor). | |
Variables | |
| static const char | s_k_rtt_id [k_rtt_id_len] = {'S', 'E', 'G', 'G', 'E', 'R', ' ', 'R', 'T', 'T'} |
| The 10-byte control-block ID a debug probe scans RAM for. | |
| static rtt_state_t | s_rtt |
| static uint8_t | s_rtt_stage [(uint32_t) k_rtt_scan_step+(uint32_t) k_rtt_id_len] |
| Staging buffer for scan sub-reads (step + ID overlap carry). | |
| static uint8_t | s_rtt_seg [k_rtt_drain_max] |
| Staging buffer for the per-tick ring drain (bounded segments). | |
| static const board_periph_block_t | s_k_rtt_block |
| This block's descriptor: tick/reset/report only, no MMIO window. | |
SEGGER RTT up-buffer drain model for ra8_emulator.
Models the HOST side of the SEGGER Real-Time Transfer channel: the debug probe that finds the in-RAM _SEGGER_RTT-compatible control block and drains its terminal up-buffer. On real hardware the J-Link OB scans target RAM for the 10-byte "SEGGER RTT" ID string the control block begins with, then reads bytes out of up-buffer 0's ring (advancing the read offset so the firmware sees the buffer emptying). This block does exactly that against the emulated SRAM, so an RTT-logging app (rtt_log_demo) surfaces its banner in ra8_emulator with no UART pin – the same text JLinkRTTViewer would show on the bench.
Control-block layout drained here (SEGGER_RTT.h, 32-bit target): char id[16] ("SEGGER RTT" + NUL padding), u32 max_up, u32 max_down, then max_up up-buffer descriptors of {const char* name; u8* buf; u32 size; u32 wr_off; u32 rd_off; u32 flags}. Only up-buffer 0 (the standard "Terminal" channel) is drained; down-buffers (host -> target input) are not modelled.
Discovery is by RAM scan, not ELF symbol: the firmware deliberately writes the ID string byte-by-byte at runtime so an image scan cannot match a stale literal-pool copy, and a scan needs no per-app symbol name (the demo's block is a file-static, not _SEGGER_RTT). The scan walks the 4 MiB SRAM window on a backoff cadence until the block appears, then re-verifies the ID once per drain so a clobbered block is forgotten and re-discovered.
Drained bytes are assembled into lines (CR dropped, latched on LF) and surfaced exactly like the SCI console: each completed line prints to injected output sink as [rtt] <line> and lands in the board_console RTT channel, whose newest line the run loop's RA8_EMU_STOP_ON banner guard also checks – so the EIL gate scrapes an RTT banner the same way it scrapes a UART one.
This block owns NO MMIO window (base = span = 0): RTT is a plain-RAM protocol, so only the tick / reset / report hooks do work and the required read / write handlers are never-dispatched stubs.
Definition in file board_periph_rtt.c.
| enum rtt_cb_layout_t : uint32_t |
Control-block field offsets (SEGGER_RTT.h, 32-bit target layout).
Definition at line 61 of file board_periph_rtt.c.
| enum rtt_order_t : uint32_t |
Per-tick order slot for the RTT drain (right after the SCI console).
| Enumerator | |
|---|---|
| k_rtt_block_order | After SCI (30), before the core IRQ section (35). |
Definition at line 503 of file board_periph_rtt.c.
| enum rtt_scan_window_t : uint64_t |
SRAM window the control-block scan covers (mirrors main.c's map).
| Enumerator | |
|---|---|
| k_rtt_scan_base | On-chip SRAM base (dual-core banks). |
| k_rtt_scan_span | The full 4 MiB window main.c maps. |
| k_rtt_scan_step | Bytes staged per scan sub-read. |
Definition at line 54 of file board_periph_rtt.c.
| enum rtt_tune_t : uint32_t |
Model tuning: scan cadence, sanity caps, and line assembly.
Definition at line 71 of file board_periph_rtt.c.
|
static |
Self-register the RTT drain model before main (host constructor).
Definition at line 521 of file board_periph_rtt.c.
References board_periph_register_block(), RA8_INTERNAL, and s_k_rtt_block.
|
static |
Validate a candidate control block beyond its ID match.
A 10-byte ID hit alone could be a coincidental byte pattern (or a half-initialised block), so the descriptor fields are sanity-checked the way a real probe does before trusting the ring: at least one up-buffer must be declared (and not absurdly many), the ring storage pointer must be non-NULL, the ring capacity must be non-zero and sane, and both offsets must lie inside the ring. A block that is mid-rtt_init simply fails here and is re-tried on the next scan.
| [in,out] | uc | Unicorn engine (descriptor fields are read from RAM). |
| [in] | cb_addr | Candidate control-block base (the ID match address). |
| true | The block is a live, fully-initialised RTT control block. |
| false | A field is out of range; the candidate is rejected. |
uc is a live engine with the SRAM window mapped. cb_addr begins with the 10-byte RTT ID (the caller matched it). Definition at line 170 of file board_periph_rtt.c.
References internal_rtt_rd32(), k_rtt_max_up_sane, k_rtt_off_max_up, k_rtt_off_up0, k_rtt_size_sane, k_rtt_up_off_buf, k_rtt_up_off_rd, k_rtt_up_off_size, k_rtt_up_off_wr, and RA8_INTERNAL.
Referenced by internal_rtt_match_stage().
|
static |
Drain up-buffer 0 of the discovered control block, host-style.
Re-verifies the block ID (a warm-clobbered block is forgotten and re-discovered by the scan), reads the live descriptor, then consumes up to k_rtt_drain_max pending bytes this tick – at most two contiguous segments around the ring wrap – and stores the advanced read offset back, exactly as JLinkRTTViewer does so the firmware's writer sees space free up. A descriptor that fails validation this tick is skipped (drained next tick once the firmware finishes touching it).
| [in,out] | uc | Unicorn engine (ring bytes + offsets live in guest RAM). |
s_rtt.cb_addr points at a previously validated control block. uc is a live engine with the SRAM window mapped. Definition at line 330 of file board_periph_rtt.c.
References emu_mem_read(), emu_mem_write(), internal_rtt_line_feed(), internal_rtt_rd32(), k_rtt_drain_max, k_rtt_id_len, k_rtt_off_up0, k_rtt_size_sane, k_rtt_up_off_buf, k_rtt_up_off_rd, k_rtt_up_off_size, k_rtt_up_off_wr, memcmp(), RA8_INTERNAL, s_k_rtt_id, s_rtt, and s_rtt_seg.
Referenced by internal_rtt_tick().
|
static |
Feed one drained byte into the line assembler.
Mirrors the ITM / UART console formatting: CR is dropped, and a LF (or a full buffer) latches the pending text – printed to injected output sink as [rtt] <line> and pushed into the board_console RTT channel, where the run loop's RA8_EMU_STOP_ON banner guard reads the newest line back.
| [in] | byte | The drained up-buffer byte. |
s_rtt.line_len < k_rtt_line_max (the flush below maintains it). Definition at line 289 of file board_periph_rtt.c.
References board_console_push(), k_board_console_ch_rtt, k_rtt_line_max, priv_emu_io_outf(), RA8_INTERNAL, and s_rtt.
Referenced by internal_rtt_drain().
|
static |
Match the staged bytes for a validated control-block ID.
Walks s_rtt_stage memchr-first (candidates share the ID's first byte) and memcmp-confirms each candidate, then internal_rtt_cb_valid-checks the matching guest address. Bounded: every iteration advances at least one byte through the fixed-size stage.
| [in,out] | uc | Unicorn engine (descriptor validation reads RAM). |
| [in] | stage_addr | Guest address of s_rtt_stage byte 0. |
| [in] | len | Staged byte count (<= sizeof s_rtt_stage). |
| 0 | No validated ID match in this stage. |
len is at least k_rtt_id_len (the caller guarantees it). len bytes read from stage_addr. Definition at line 208 of file board_periph_rtt.c.
References internal_rtt_cb_valid(), k_rtt_id_len, memchr(), memcmp(), s_k_rtt_id, and s_rtt_stage.
Referenced by internal_rtt_scan().
|
static |
MMIO read stub – never dispatched (this block owns no window).
| [in,out] | uc | Unicorn engine; unused. |
| [in] | addr | Access address; unused. |
| [in] | size | Access width; unused. |
| 0 | The only value (unreachable in practice: span is 0). |
MMIO read stub – never dispatched (this block owns no window); this step is contained within the board periph rtt model and uses bounded caller or module-owned storage.
Definition at line 469 of file board_periph_rtt.c.
References RA8_INTERNAL.
|
static |
MMIO write stub – never dispatched (this block owns no window).
| [in,out] | uc | Unicorn engine; unused. |
| [in] | addr | Access address; unused. |
| [in] | size | Access width; unused. |
| [in] | value | Written value; unused. |
MMIO write stub – never dispatched (this block owns no window); this step is contained within the board periph rtt model and uses bounded caller or module-owned storage.
Definition at line 494 of file board_periph_rtt.c.
|
static |
Read a 32-bit little-endian word from emulated memory.
| [in,out] | uc | Unicorn engine to read through. |
| [in] | addr | Guest address of the word. |
uc is a live engine with the SRAM window mapped. addr points into mapped guest memory for a meaningful result. Read a 32-bit little-endian word from emulated memory; this step is contained within the board periph rtt model and uses bounded caller or module-owned storage.
| value | The operation-specific rtt rd32 value. |
Definition at line 138 of file board_periph_rtt.c.
References emu_mem_read(), and RA8_INTERNAL.
Referenced by internal_rtt_cb_valid(), and internal_rtt_drain().
|
static |
End-of-run RTT section: block address + drained totals.
End-of-run rtt section: block address + drained totals; this step is contained within the board periph rtt model and uses bounded caller or module-owned storage.
Definition at line 441 of file board_periph_rtt.c.
References priv_emu_io_errf(), RA8_INTERNAL, and s_rtt.
|
static |
Reset the RTT drain model to power-on state (warm reboot).
Reset the rtt drain model to power-on state (warm reboot); this step is contained within the board periph rtt model and uses bounded caller or module-owned storage.
Definition at line 422 of file board_periph_rtt.c.
References k_rtt_scan_first_tick, RA8_INTERNAL, and s_rtt.
|
static |
Scan the emulated SRAM window for the RTT control-block ID.
Stages the window through s_rtt_stage in k_rtt_scan_step sub-reads, carrying an ID-length overlap so a control block straddling a stage boundary still matches, and hands each stage to internal_rtt_match_stage – exactly how the J-Link OB discovers the block on silicon. The first validated match is latched into s_rtt.cb_addr. The walk is bounded by the fixed window span (64 sub-reads).
| [in,out] | uc | Unicorn engine (the SRAM bytes are read through it). |
uc is a live engine with the SRAM window mapped. s_rtt.cb_addr is 0 (the caller only scans while undiscovered). s_rtt.cb_addr holds the block address. Definition at line 249 of file board_periph_rtt.c.
References emu_mem_read(), internal_rtt_match_stage(), k_rtt_id_len, k_rtt_scan_base, k_rtt_scan_span, k_rtt_scan_step, RA8_INTERNAL, s_rtt, and s_rtt_stage.
Referenced by internal_rtt_tick().
|
static |
Per-chunk advance: discover the control block, then keep it drained.
While undiscovered, runs internal_rtt_scan on a backoff cadence (first at tick k_rtt_scan_first_tick, then doubling the gap up to k_rtt_scan_max_gap) so an app that never initialises RTT costs a bounded handful of scans per run instead of one per tick. Once found, drains up-buffer 0 every tick – far faster than any firmware writer, so the ring never back-pressures the target.
| [in,out] | uc | Unicorn engine (all block state lives in guest RAM). |
uc is a live engine with the SRAM window mapped. s_rtt.ticks advanced by one. Definition at line 390 of file board_periph_rtt.c.
References internal_rtt_drain(), internal_rtt_scan(), k_rtt_scan_max_gap, RA8_INTERNAL, and s_rtt.
|
static |
This block's descriptor: tick/reset/report only, no MMIO window.
Definition at line 508 of file board_periph_rtt.c.
Referenced by internal_rtt_block_register().
|
static |
The 10-byte control-block ID a debug probe scans RAM for.
Spelled as a char array (not a string literal) for the same reason the firmware writes it byte-by-byte: this host tool's own rodata must never be mistaken for a control block if it is ever staged through a scan buffer.
Definition at line 91 of file board_periph_rtt.c.
Referenced by internal_rtt_drain(), and internal_rtt_match_stage().
|
static |
Definition at line 115 of file board_periph_rtt.c.
Referenced by internal_rtt_drain(), internal_rtt_line_feed(), internal_rtt_report(), internal_rtt_reset(), internal_rtt_scan(), and internal_rtt_tick().
|
static |
Staging buffer for the per-tick ring drain (bounded segments).
Definition at line 121 of file board_periph_rtt.c.
Referenced by internal_rtt_drain().
|
static |
Staging buffer for scan sub-reads (step + ID overlap carry).
Definition at line 118 of file board_periph_rtt.c.
Referenced by internal_rtt_match_stage(), and internal_rtt_scan().