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

CPU0 (Cortex-M85) cache-coherency validator against CPU1 (Cortex-M33). More...

#include <stddef.h>
#include <stdint.h>
#include "cache_coherency_shared.h"
#include "ra8_board_ek_ra8d2_peripherals.h"
#include "ra8_boot_entry.h"
#include "ra8_cgc.h"
#include "ra8_dual_core.h"
#include "ra8_err.h"
#include "ra8_log.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  cache_coherency_hil_const_t : uint32_t { k_cache_coherency_hil_baud = 115200U }
 VCOM-console line rate for the deterministic HIL banner. More...

Functions

static RA8_INTERNAL bool internal_console_init (void)
 Bring up the SCI8 / J-Link OB VCOM console for the HIL banner.
static RA8_INTERNAL void internal_emit_pass (void)
 Emit the deterministic HIL success banner over the VCOM console + ITM.
static RA8_INTERNAL void internal_park_forever (void)
 Park the M85 forever after an unrecoverable startup failure.
static RA8_INTERNAL bool internal_wait_for_pong (const volatile cache_coherency_shared_t *shared, uint32_t target)
 Poll until pong_seq reaches target or the budget runs out.
static RA8_INTERNAL void internal_round (volatile cache_coherency_shared_t *shared, uint32_t round, uint32_t *next_seq)
 Run one cross-core round and update the HIL counters.
void main (void)
 CPU0 (Cortex-M85) application entry.

Variables

uint32_t g_ra8_ls_cpu1_mram_start
 Base of the embedded M33 image / its vector table (MRAM_CPU1).
uint32_t g_ra8_ls_cpu1_stack_top
 Initial stack pointer handed to the M33 at release.
volatile uint32_t g_cache_coherency_match = 0U
 HIL liveness counter – incremented on every verified M85 -> M33 -> M85 round-trip (echo == pong_base + round).
volatile uint32_t g_cache_coherency_mismatch = 0U
 HIL failure counter – incremented whenever a round cannot complete: the bounded pong wait timed out, or the echoed payload was not pong_base + round.
static const uint8_t s_cache_coherency_pass_banner [] = "cache_coherency_hil: 8 rounds PASS\r\n"
 Deterministic HIL success banner (uart_scrape / emulator-scrape).

Detailed Description

CPU0 (Cortex-M85) cache-coherency validator against CPU1 (Cortex-M33).

Tag
[Ring 1 / app] {World: NS}

This M85 image is built with RA8_BOOT_ENABLE_CACHE_MPU defined (see the per-app CMakeLists.txt), so the shared boot (system_init.c) brings up the MPU + I-cache + D-cache before main runs. With the D-cache ON, the only way a cross-core hand-off through SRAM stays coherent with the cacheless Cortex-M33 is for the shared bytes to live in a non-cacheable region – which the boot's MPU region 4 maps over 0x22100000..0x2219FFFF. This test exercises exactly that path and proves it works without any software cache maintenance.

Flow:

  1. Zero the shared block (see cache_coherency_shared.h) and release the Cortex-M33 with ra8_cpu1_release (HUM Ch 2.9.1 "CPU control registers").
  2. Round-trip a data-carrying payload: write ping_base + r, DSB, bump ping_seq; wait (bounded) for pong_seq to advance; verify pong_payload == pong_base + r. No clean/invalidate is issued – the non-cacheable region is what keeps it coherent.
  3. g_cache_coherency_match advances per verified round; g_cache_coherency_mismatch advances on a timeout or wrong echo. After the first k_cache_coherency_rounds verified rounds the success banner is emitted once over the VCOM console + ITM.

Two-phase loop (the design reconciles the two HIL surfaces):

  • Self-test phase (rounds 0..N-1): each round toggles LED1, a peripheral (IOPORT) write. The cross-core hand-off itself is pure SRAM, which ra8_emulator's MMIO-keyed idle detector cannot see; the LED heartbeat keeps it awake so the success banner surfaces even under RA8_EMU_IDLE_STOP=1. On the bench the LED visibly blinks while the test runs.
  • Steady phase (rounds N..): keep round-tripping forever with no heartbeat so the J-Link memprobe HIL gate sees g_cache_coherency_match advance across its sample window (a one-shot counter frozen in a terminal WFI would read unchanged at both probe halts and fail the delta check). In ra8_emulator this steady phase is pure SRAM, so RA8_EMU_IDLE_STOP terminates the run cleanly right after the banner – the same clean stop a terminal WFI would give, without breaking the memprobe gate.
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ cache_coherency_hil_const_t

enum cache_coherency_hil_const_t : uint32_t

VCOM-console line rate for the deterministic HIL banner.

The EK-RA8D2 J-Link OB VCOM bridge (SCI8, PD02/PD03) runs 8N1 at this rate. The banner is additive to the existing ra8_log ITM trace.

Since
0.1.0
Enumerator
k_cache_coherency_hil_baud 

VCOM console line rate (8N1).

Definition at line 75 of file main.c.

Function Documentation

◆ internal_console_init()

RA8_INTERNAL bool internal_console_init ( void )
static

Bring up the SCI8 / J-Link OB VCOM console for the HIL banner.

Configures the clock tree (ra8_cgc_init) then the EK-RA8D2 debug console (ra8_board_uart_console_init at k_cache_coherency_hil_baud). Best-effort: a failure only means the additive banner cannot reach the host; the memprobe counters and the M33 hand-off are unaffected.

Returns
Whether the VCOM console is ready to carry the banner.
Return values
trueClock + SCI8 console are up.
falseA bring-up step failed (the banner is then silently skipped).
Precondition
Called once during M85 bring-up, before ra8_cpu1_release.
SystemInit has enabled the caches + MPU (this build).
Postcondition
On true, SCI8 is enabled and PD02/PD03 route to it.
On false, no console state persists; the app continues normally.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 148 of file main.c.

References k_cache_coherency_hil_baud, k_ra8_ok, ra8_board_uart_console_init(), ra8_cgc_init(), and RA8_INTERNAL.

◆ internal_emit_pass()

RA8_INTERNAL void internal_emit_pass ( void )
static

Emit the deterministic HIL success banner over the VCOM console + ITM.

Writes s_cache_coherency_pass_banner to the SCI8 / J-Link OB VCOM console and flushes it, then mirrors the same verdict over ra8_log so ra8_emulator surfaces it as an [itm] line. A no-op on the wire if the console never came up (the write returns k_ra8_err_not_initialized, ignored).

Returns
Nothing.
Precondition
Reached only after k_cache_coherency_rounds rounds verified.
internal_console_init was attempted during bring-up.
Postcondition
The banner has been handed to SCI8 and the TX FIFO drained (if up).
No shared / M33 state is modified.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 177 of file main.c.

References ra8_board_uart_console_flush(), ra8_board_uart_console_write(), RA8_INTERNAL, ra8_log_info, and s_cache_coherency_pass_banner.

◆ internal_park_forever()

RA8_INTERNAL void internal_park_forever ( void )
static

Park the M85 forever after an unrecoverable startup failure.

Reached only if ra8_cpu1_release fails, so the M33 never started.

Returns
This function never returns.
Note
The core spins in place.
Precondition
A fatal error (CPU1 release failure) has occurred.
The failure has already been logged.
Postcondition
The M85 makes no further forward progress.
The M33 stays held in reset.
Note
Mirrors the M33's fault handler for symmetry.
Since
0.1.0

Definition at line 201 of file main.c.

References RA8_INTERNAL.

◆ internal_round()

RA8_INTERNAL void internal_round ( volatile cache_coherency_shared_t * shared,
uint32_t round,
uint32_t * next_seq )
static

Run one cross-core round and update the HIL counters.

Writes ping_base + round (no cache clean – region 4 is non-cacheable), bumps ping_seq, waits (bounded) for the M33 echo, and verifies it equals pong_base + round. Bumps g_cache_coherency_match on success or g_cache_coherency_mismatch on a timeout / wrong echo. The two checks are split (no compound decision) so each is independently visible.

Parameters
[in]sharedPointer to the shared message struct (never NULL).
[in]roundZero-based round index; selects the payload values.
[in,out]next_seqNext ping_seq value to publish; advanced by one.
Returns
Nothing (results land in the global counters).
Precondition
shared != nullptr.
next_seq != nullptr.
Postcondition
Exactly one of the two HIL counters advanced by one.
*next_seq advanced by one.
Note
Not thread-safe; single-threaded M85 context.
Since
0.1.0

Definition at line 269 of file main.c.

References g_cache_coherency_match, g_cache_coherency_mismatch, internal_wait_for_pong(), k_cache_coherency_ping_base, k_cache_coherency_pong_base, cache_coherency_shared_t::ping_payload, cache_coherency_shared_t::ping_seq, and cache_coherency_shared_t::pong_payload.

Referenced by main().

◆ internal_wait_for_pong()

RA8_INTERNAL bool internal_wait_for_pong ( const volatile cache_coherency_shared_t * shared,
uint32_t target )
static

Poll until pong_seq reaches target or the budget runs out.

Re-reads the volatile sequence field up to the fixed budget and returns immediately on the target value; a null pointer is treated as a bounded failure without dereferencing shared SRAM.

Parameters
[in]sharedPointer to the shared message struct (never NULL).
[in]targetSequence value to wait for (the value just written to ping_seq).
Returns
Whether the wait observed the target.
Return values
truepong_seq == target was observed inside the budget.
falsek_cache_coherency_poll_budget iters elapsed first.
Precondition
shared != nullptr.
target equals the most recent value the caller wrote to ping_seq.
Postcondition
No shared state is mutated.
Iteration count bounded by k_cache_coherency_poll_budget.
Note
Not thread-safe. CPU1 must already have been released or this always times out.
Since
0.1.0

Definition at line 231 of file main.c.

References k_cache_coherency_poll_budget, cache_coherency_shared_t::pong_seq, and RA8_INTERNAL.

Referenced by internal_round(), and main().

◆ main()

void main ( void )

CPU0 (Cortex-M85) application entry.

The application entry point Reset_Handler hands control to.

See the file header for the full behaviour summary.

Precondition
SystemInit has enabled the caches + MPU (this build defines RA8_BOOT_ENABLE_CACHE_MPU).
The M33 is held in reset by hardware until released here.
Postcondition
The M33 has been released and the round-trip loop is running.
This function never returns to its caller.
Note
Single-threaded; no RTOS on the M85 in this template.
Since
0.1.0

Definition at line 303 of file main.c.

References g_cache_coherency_match, g_ra8_ls_cpu1_mram_start, g_ra8_ls_cpu1_stack_top, internal_console_init(), internal_emit_pass(), internal_park_forever(), internal_round(), internal_shared(), k_cache_coherency_rounds, k_ra8_board_led1, k_ra8_ok, cache_coherency_shared_t::ping_payload, cache_coherency_shared_t::ping_seq, cache_coherency_shared_t::pong_payload, cache_coherency_shared_t::pong_seq, ra8_board_led_init(), ra8_board_led_toggle(), ra8_cpu1_release(), ra8_log_info, ra8_log_info_val, and ra8_log_init().

Variable Documentation

◆ g_cache_coherency_match

volatile uint32_t g_cache_coherency_match = 0U

HIL liveness counter – incremented on every verified M85 -> M33 -> M85 round-trip (echo == pong_base + round).

Read externally by scripts/hil/jlink_memprobe.sh via SWD. The probe asserts this counter advances by >= k_cache_coherency_rounds across its sample window, proving the Cortex-M33 was released and is servicing the non-cacheable shared block coherently with the M85 D-cache on. If the shared region were cacheable, a stale M85 read would land in g_cache_coherency_mismatch instead.

Note
Read externally by J-Link only; firmware never reads it back.
Warning
Do not rename; hil.conf HIL_PROBE_SYMBOL matches it exactly.
Since
0.1.0

Definition at line 96 of file main.c.

Referenced by internal_round(), and main().

◆ g_cache_coherency_mismatch

volatile uint32_t g_cache_coherency_mismatch = 0U

HIL failure counter – incremented whenever a round cannot complete: the bounded pong wait timed out, or the echoed payload was not pong_base + round.

The memprobe asserts this stays at 0. On silicon with the D-cache on and a (wrongly) cacheable shared region this would climb as the M85 reads stale pong values; the non-cacheable region 4 keeps it at 0.

Note
Read externally by J-Link only; firmware never reads it back.
Warning
Do not rename; hil.conf HIL_PROBE_FAILURE_SYMBOL matches it.
Since
0.1.0

Definition at line 113 of file main.c.

Referenced by internal_round().

◆ g_ra8_ls_cpu1_mram_start

uint32_t g_ra8_ls_cpu1_mram_start
extern

Base of the embedded M33 image / its vector table (MRAM_CPU1).

◆ g_ra8_ls_cpu1_stack_top

uint32_t g_ra8_ls_cpu1_stack_top
extern

Initial stack pointer handed to the M33 at release.

◆ s_cache_coherency_pass_banner

const uint8_t s_cache_coherency_pass_banner[] = "cache_coherency_hil: 8 rounds PASS\r\n"
static

Deterministic HIL success banner (uart_scrape / emulator-scrape).

Emitted once, after k_cache_coherency_rounds rounds verify, on the success path only. Additive to the ra8_log ITM trace so a rig with no SWO capture can still gate the boot + cache + dual-core path.

Note
Trailing CRLF terminates the line on the wire; the gate matches the text.
Warning
Do not modify; it must stay >= 12 chars and never be a substring of a failure string in the binary.
Since
0.1.0

Definition at line 126 of file main.c.

Referenced by internal_emit_pass().