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

Cortex-M85 L1 cache + MPU "runs correctly with them on" HIL self-test. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_board_ek_ra8d2.h"
#include "ra8_boot_entry.h"
#include "ra8_cache.h"
#include "ra8_cgc.h"
#include "ra8_err.h"
#include "ra8_log.h"
#include "ra8_system_regs.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  cache_mpu_config_t : uint32_t {
  k_cache_mpu_baud = 115200U ,
  k_cache_mpu_buf_bytes = 4096U ,
  k_cache_mpu_buf_min = 4096U ,
  k_cache_mpu_sckdivcr_exp = 0x32233432U ,
  k_cache_mpu_mram_sum_exp = 0xAAAAAAAAU
}
 Compile-time scalar parameters for the cache + MPU self-test. More...
enum  cache_mpu_pattern_t : uint8_t {
  k_cache_mpu_pat_mul = 31U ,
  k_cache_mpu_pat_add = 7U
}
 Affine byte-pattern coefficients: buf[i] = i * MUL + ADD. More...
enum  cache_mpu_mram_t : uint8_t { k_cache_mpu_mram_words = 4U }
 Geometry of the read-only MRAM const table summed in MPU region 0. More...
enum  cache_mpu_result_t : uint8_t {
  k_cache_mpu_result_pass = 0U ,
  k_cache_mpu_result_fail_sram = 1U ,
  k_cache_mpu_result_fail_mram = 2U ,
  k_cache_mpu_result_fail_mmio = 3U
}
 Verdict of the self-test, naming which step failed (if any). More...

Functions

static void cache_mpu_wfi_forever (void)
 Park the Cortex-M85 forever in a WFI idle loop.
static uint32_t cache_mpu_mram_const_sum (void)
 Sum the read-only MRAM const table (executes from MRAM, region 0).
static bool cache_mpu_test_cacheable_rw (void)
 Step 1 – prove cacheable RW works in M85-private SRAM (region 1).
static bool cache_mpu_test_mram_const (void)
 Step 2 – prove RO MRAM const + MRAM code execution (region 0).
static bool cache_mpu_test_device_mmio (void)
 Step 3 – prove Device-nGnRE peripheral MMIO is accessible (region 3).
static cache_mpu_result_t cache_mpu_run_selftest (void)
 Run all three self-test steps in order, naming the first failure.
static bool cache_mpu_setup (void)
 Bring up the clock tree and the VCOM console for the banner.
static void cache_mpu_emit (const uint8_t *line, size_t len)
 Emit one banner line over the VCOM console and flush it.
void main (void)
 Application entry: run the cache + MPU self-test and report the verdict.

Variables

static uint8_t s_cache_mpu_buf [k_cache_mpu_buf_bytes]
 4 KiB cacheable scratch buffer in M85-private SRAM (MPU region 1).
static const uint32_t k_cache_mpu_mram_table [k_cache_mpu_mram_words]
 Read-only word table placed in MRAM .rodata (MPU region 0).
static const uint8_t k_cache_mpu_pass_banner [] = "cache_mpu_hil: cache+mpu PASS\r\n"
 Deterministic one-shot HIL success banner (uart_scrape gate).
static const uint8_t k_cache_mpu_fail_setup [] = "cache_mpu_hil: setup FAIL\r\n"
 Failure banner: clock / console bring-up failed before the self-test.
static const uint8_t k_cache_mpu_fail_sram [] = "cache_mpu_hil: cacheable-SRAM FAIL\r\n"
 Failure banner: the cacheable-SRAM (region 1) readback mismatched.
static const uint8_t k_cache_mpu_fail_mram [] = "cache_mpu_hil: MRAM-const FAIL\r\n"
 Failure banner: the RO-MRAM-const (region 0) sum mismatched.
static const uint8_t k_cache_mpu_fail_mmio [] = "cache_mpu_hil: device-MMIO FAIL\r\n"
 Failure banner: the Device-nGnRE MMIO (region 3) readback mismatched.

Detailed Description

Cortex-M85 L1 cache + MPU "runs correctly with them on" HIL self-test.

Tag
[Ring 6 / APP] {World: S}

Single-core (Cortex-M85) HIL validator for the T4 cache-coherency chain. The app's build defines RA8_BOOT_ENABLE_CACHE_MPU (see CMakeLists.txt), so the shared boot SystemInit() programmes the 5-region MPU and enables the I-cache, D-cache, and branch predictor before main() runs. Everything in main() therefore executes with the caches and MPU live; this app proves the core still produces correct results in that posture.

Self-test (each step independent; runs once, then the core parks in WFI):

  1. Cacheable RW (MPU region 1, M85-private SRAM @ 0x22000000). Fill a 4 KiB static buffer (in .bss, region 1) with a deterministic pattern buf[i] = (uint8_t)(i * 31 + 7), clean+invalidate those (now dirty) D-cache lines back to SRAM, then read every byte back – the read misses the cache and refills from memory, exercising the full write-back + refill path with the D-cache enabled.
  2. RO MRAM const + code execution (MPU region 0, MRAM @ 0x02000000, RO + execute, cacheable). Call a small non-inlined helper that lives in MRAM .text and sums a const table in MRAM .rodata via volatile loads – proving code executes through the I-cache and the read-only MRAM region is readable.
  3. Device-nGnRE MMIO (MPU region 3, peripherals @ 0x40000000). Read the live SYSTEM SCKDIVCR register through the ra8_sys_sckdivcr() HAL accessor and confirm it reads back the value ra8_cgc_init() programmed (0x32233432) – proving peripheral MMIO is mapped Device (not cached) and accessible with the D-cache on.

On success the app emits "cache_mpu_hil: cache+mpu PASS\r\n" over the J-Link OB VCOM console (SCI8, PD02/PD03 @ 115200 8N1) and mirrors the verdict over ra8_log (the emulator echoes it as an [itm] line). On any mismatch it emits a distinct ... FAIL line (never containing "PASS") and parks. The core ends every path in WFI so ra8_emulator's RA8_EMU_IDLE_STOP terminates the run after the one-shot banner is scraped.

Note
ra8_emulator models memory byte-exact and does not model the L1 D-cache, so the cacheable-RW step passes there trivially; the cache hazard this app guards against is only real on silicon. The point of the emulator run is to prove the app boots and reports PASS with the cache+MPU boot path compiled in.
Author
Brighton Sikarskie
Date
2026-06-29
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ cache_mpu_config_t

enum cache_mpu_config_t : uint32_t

Compile-time scalar parameters for the cache + MPU self-test.

Groups the console baud, the cacheable buffer size, and the two golden readback constants the self-test checks against.

Since
0.1.0
Enumerator
k_cache_mpu_baud 

VCOM console line rate (8N1).

k_cache_mpu_buf_bytes 

Cacheable self-test buffer size (>= 4 KiB).

k_cache_mpu_buf_min 

Self-test buffer floor (4 KiB minimum).

k_cache_mpu_sckdivcr_exp 

SCKDIVCR readback after ra8_cgc_init().

k_cache_mpu_mram_sum_exp 

Expected sum of the MRAM const table.

Definition at line 75 of file main.c.

◆ cache_mpu_mram_t

enum cache_mpu_mram_t : uint8_t

Geometry of the read-only MRAM const table summed in MPU region 0.

The table is summed via a non-inlined MRAM helper to prove code executes from MRAM and the RO MRAM region is readable.

Since
0.1.0
Enumerator
k_cache_mpu_mram_words 

Number of 32-bit words in the const table.

Definition at line 102 of file main.c.

◆ cache_mpu_pattern_t

enum cache_mpu_pattern_t : uint8_t

Affine byte-pattern coefficients: buf[i] = i * MUL + ADD.

A per-index affine pattern makes every byte distinct modulo 256, so a stuck or swapped line is caught by the readback compare.

Since
0.1.0
Enumerator
k_cache_mpu_pat_mul 

Pattern multiplier.

k_cache_mpu_pat_add 

Pattern addend.

Definition at line 90 of file main.c.

◆ cache_mpu_result_t

enum cache_mpu_result_t : uint8_t

Verdict of the self-test, naming which step failed (if any).

Drives the banner main() emits; k_cache_mpu_result_pass is the only value that produces the PASS line.

Since
0.1.0
Enumerator
k_cache_mpu_result_pass 

All three steps passed.

k_cache_mpu_result_fail_sram 

Cacheable-RW (region 1) step failed.

k_cache_mpu_result_fail_mram 

RO-MRAM-const (region 0) step failed.

k_cache_mpu_result_fail_mmio 

Device-MMIO (region 3) step failed.

Definition at line 113 of file main.c.

Function Documentation

◆ cache_mpu_emit()

void cache_mpu_emit ( const uint8_t * line,
size_t len )
static

Emit one banner line over the VCOM console and flush it.

Writes line then drains the SCI8 TX so the bytes clock out before the core parks. A no-op if line is NULL or empty, or if the console never came up (the write returns an error that is ignored here).

Parameters
[in]linePointer to the ASCII banner bytes (no NUL sent). Must be non-NULL for output.
[in]lenNumber of bytes to send; 0 sends nothing.
Returns
Nothing.
Precondition
line points to at least len readable bytes when len > 0.
cache_mpu_setup was attempted during bring-up.
Postcondition
The bytes have been handed to SCI8 and the TX FIFO drained (if up).
No application state is modified.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 446 of file main.c.

References ra8_board_uart_console_flush(), and ra8_board_uart_console_write().

Referenced by main().

◆ cache_mpu_mram_const_sum()

uint32_t cache_mpu_mram_const_sum ( void )
static

Sum the read-only MRAM const table (executes from MRAM, region 0).

Kept non-inlined so a real call/branch retires from MRAM .text (proving I-cache + executable MRAM), and reads the table through a volatile pointer so the loads are not constant-folded away – they genuinely touch the RO MRAM .rodata region.

Returns
The 32-bit sum of all table words (wrapping). Expected 0xAAAAAAAA.
Return values
0xAAAAAAAAThe table is intact and the MRAM read path works.
Precondition
k_cache_mpu_mram_table is resident in the RO MRAM region.
The MPU has region 0 mapped RO + execute, cacheable (cache+MPU boot).
Postcondition
No memory is modified (pure read of a const table).
The returned value reflects the live MRAM contents, not a folded const.
Note
Thread-safe; reads immutable data only.
Since
0.1.0

Definition at line 238 of file main.c.

References k_cache_mpu_mram_table, and k_cache_mpu_mram_words.

Referenced by cache_mpu_test_mram_const().

◆ cache_mpu_run_selftest()

cache_mpu_result_t cache_mpu_run_selftest ( void )
static

Run all three self-test steps in order, naming the first failure.

Steps are independent and short-circuit: the first failing step determines the verdict so main() can emit a step-specific FAIL banner.

Returns
The self-test verdict.
Return values
k_cache_mpu_result_passAll three steps passed.
k_cache_mpu_result_fail_sramThe cacheable-RW step failed.
k_cache_mpu_result_fail_mramThe RO-MRAM-const step failed.
k_cache_mpu_result_fail_mmioThe Device-MMIO step failed.
Precondition
The cache + MPU boot path is active (set by RA8_BOOT_ENABLE_CACHE_MPU).
ra8_cgc_init() has run (Device-MMIO step needs the programmed divider).
Postcondition
No persistent state beyond s_cache_mpu_buf is modified.
Exactly one verdict is returned.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 380 of file main.c.

References cache_mpu_test_cacheable_rw(), cache_mpu_test_device_mmio(), cache_mpu_test_mram_const(), k_cache_mpu_result_fail_mmio, k_cache_mpu_result_fail_mram, k_cache_mpu_result_fail_sram, and k_cache_mpu_result_pass.

Referenced by main().

◆ cache_mpu_setup()

bool cache_mpu_setup ( void )
static

Bring up the clock tree and the VCOM console for the banner.

ra8_cgc_init() programmes the FSP-quickstart tree (and thereby the SCKDIVCR the Device-MMIO step checks) and publishes PCLKA; the EK-RA8D2 debug console (SCI8 on PD02/PD03 @ k_cache_mpu_baud) then comes up over the J-Link OB VCOM bridge.

Returns
Whether the clock + console are ready to carry the banner.
Return values
trueCGC and SCI8 console are up.
falseA bring-up step failed.
Precondition
Called once during M85 bring-up, before the self-test.
ra8_log_init() has run (failures are narrated over ITM).
Postcondition
On true SCI8 is enabled and PD02/PD03 route to it.
On false no console state persists.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 414 of file main.c.

References k_cache_mpu_baud, k_ra8_ok, ra8_board_uart_console_init(), and ra8_cgc_init().

Referenced by main().

◆ cache_mpu_test_cacheable_rw()

bool cache_mpu_test_cacheable_rw ( void )
static

Step 1 – prove cacheable RW works in M85-private SRAM (region 1).

Fills s_cache_mpu_buf with the affine pattern, cleans + invalidates the dirty D-cache lines back to SRAM, then verifies every byte on read-back so the refill path from memory is exercised with the D-cache enabled.

Returns
Whether the buffer read back exactly as written.
Return values
trueEvery byte matched the pattern after the cache round-trip.
falseA byte mismatched, or the cache maintenance call failed.
Precondition
The D-cache + MPU are enabled (cache+MPU boot path active).
s_cache_mpu_buf lies in cacheable SRAM (MPU region 1).
Postcondition
On true the buffer holds the affine pattern in SRAM.
No memory outside s_cache_mpu_buf is modified.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 267 of file main.c.

References k_cache_mpu_buf_bytes, k_cache_mpu_pat_add, k_cache_mpu_pat_mul, k_ra8_ok, ra8_cache_dcache_clean_invalidate_by_addr(), and s_cache_mpu_buf.

Referenced by cache_mpu_run_selftest().

◆ cache_mpu_test_device_mmio()

bool cache_mpu_test_device_mmio ( void )
static

Step 3 – prove Device-nGnRE peripheral MMIO is accessible (region 3).

Reads the live SYSTEM SCKDIVCR register through the ra8_sys_sckdivcr() HAL accessor (peripheral window @ 0x40000000, mapped Device-nGnRE by MPU region 3) and checks it equals the divider word ra8_cgc_init() programmed. A correct readback proves the peripheral bus is reachable and uncached with the D-cache on; a zero/garbage read would indicate a dead or mis-mapped Device region.

Returns
Whether the SYSTEM register read back the post-init value.
Return values
trueSCKDIVCR read back 0x32233432.
falseThe read returned 0 (dead bus) or a value other than expected.
Precondition
ra8_cgc_init() has programmed SCKDIVCR earlier this boot.
The MPU maps the peripheral window Device-nGnRE (region 3).
Postcondition
No register is modified (pure read).
On true the peripheral MMIO path is proven accessible and uncached.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 347 of file main.c.

References k_cache_mpu_sckdivcr_exp, and ra8_sys_sckdivcr().

Referenced by cache_mpu_run_selftest().

◆ cache_mpu_test_mram_const()

bool cache_mpu_test_mram_const ( void )
static

Step 2 – prove RO MRAM const + MRAM code execution (region 0).

Calls cache_mpu_mram_const_sum twice: once to check the value against the golden sum, and again to confirm the RO MRAM region reads back identically (immutable), executing the MRAM helper through the I-cache both times.

Returns
Whether the MRAM const path is correct and stable.
Return values
trueThe sum equals 0xAAAAAAAA and is stable across two reads.
falseThe sum mismatched the golden value, or two reads disagreed.
Precondition
The I-cache + MPU are enabled with region 0 RO + execute.
k_cache_mpu_mram_table is resident in MRAM .rodata.
Postcondition
No memory is modified.
On true the MRAM read-only region is proven readable and stable.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 312 of file main.c.

References cache_mpu_mram_const_sum(), and k_cache_mpu_mram_sum_exp.

Referenced by cache_mpu_run_selftest().

◆ cache_mpu_wfi_forever()

void cache_mpu_wfi_forever ( void )
static

Park the Cortex-M85 forever in a WFI idle loop.

Reached after the one-shot banner has been emitted (pass or fail). The WFI lets ra8_emulator's idle detector stop the run cleanly and models the low-power posture on silicon.

Returns
This function never returns.
Note
The core stays asleep between (unconfigured) wake events.
Precondition
The self-test verdict has been emitted over the console.
No further forward progress is required of the M85.
Postcondition
The core makes no further architectural progress.
Any pending console bytes have already been flushed by the caller.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 212 of file main.c.

Referenced by main().

◆ main()

void main ( void )

Application entry: run the cache + MPU self-test and report the verdict.

The application entry point Reset_Handler hands control to.

Brings up logging, the clock tree, and the VCOM console, runs the three-step self-test (cacheable SRAM, RO MRAM const, Device MMIO), emits the matching PASS / FAIL banner over the console and ra8_log, then parks in WFI. Every byte the self-test touches runs with the L1 caches and MPU enabled by the shared boot (RA8_BOOT_ENABLE_CACHE_MPU).

Precondition
Reset_Handler has copied .data and zeroed .bss.
SystemInit enabled the MPU + I-cache + D-cache (cache+MPU build).
Postcondition
Exactly one banner (PASS or a step-specific FAIL) has been emitted.
The core is parked in WFI.
Note
Single-threaded; no RTOS and no IRQ sources in this template.
Since
0.1.0

Definition at line 475 of file main.c.

References cache_mpu_emit(), cache_mpu_run_selftest(), cache_mpu_setup(), cache_mpu_wfi_forever(), k_cache_mpu_fail_mmio, k_cache_mpu_fail_mram, k_cache_mpu_fail_setup, k_cache_mpu_fail_sram, k_cache_mpu_pass_banner, k_cache_mpu_result_fail_mmio, k_cache_mpu_result_fail_mram, k_cache_mpu_result_fail_sram, k_cache_mpu_result_pass, ra8_log_info, and ra8_log_init().

Variable Documentation

◆ k_cache_mpu_fail_mmio

const uint8_t k_cache_mpu_fail_mmio[] = "cache_mpu_hil: device-MMIO FAIL\r\n"
static

Failure banner: the Device-nGnRE MMIO (region 3) readback mismatched.

Distinct from the PASS banner and free of "PASS".

Since
0.1.0

Definition at line 192 of file main.c.

Referenced by main().

◆ k_cache_mpu_fail_mram

const uint8_t k_cache_mpu_fail_mram[] = "cache_mpu_hil: MRAM-const FAIL\r\n"
static

Failure banner: the RO-MRAM-const (region 0) sum mismatched.

Distinct from the PASS banner and free of "PASS".

Since
0.1.0

Definition at line 184 of file main.c.

Referenced by main().

◆ k_cache_mpu_fail_setup

const uint8_t k_cache_mpu_fail_setup[] = "cache_mpu_hil: setup FAIL\r\n"
static

Failure banner: clock / console bring-up failed before the self-test.

Distinct from the PASS banner and free of "PASS"; matched by the hil.conf HIL_EXPECT_NEGATIVE "FAIL" alternative.

Since
0.1.0

Definition at line 168 of file main.c.

Referenced by main().

◆ k_cache_mpu_fail_sram

const uint8_t k_cache_mpu_fail_sram[] = "cache_mpu_hil: cacheable-SRAM FAIL\r\n"
static

Failure banner: the cacheable-SRAM (region 1) readback mismatched.

Distinct from the PASS banner and free of "PASS".

Since
0.1.0

Definition at line 176 of file main.c.

Referenced by main().

◆ k_cache_mpu_mram_table

const uint32_t k_cache_mpu_mram_table[k_cache_mpu_mram_words]
static
Initial value:
= {
0x11111111U,
0x22222222U,
0x33333333U,
0x44444444U,
}

Read-only word table placed in MRAM .rodata (MPU region 0).

Summed by cache_mpu_mram_const_sum through volatile loads so the read genuinely targets the RO MRAM region. Sum is 0xAAAAAAAA.

Note
Const; never written at run time.
Since
0.1.0

Definition at line 143 of file main.c.

Referenced by cache_mpu_mram_const_sum().

◆ k_cache_mpu_pass_banner

const uint8_t k_cache_mpu_pass_banner[] = "cache_mpu_hil: cache+mpu PASS\r\n"
static

Deterministic one-shot HIL success banner (uart_scrape gate).

Emitted only on the all-pass path over the VCOM console. The trailing CRLF terminates the line on the wire; the HIL gate matches the text exactly. Contains "PASS" and is not a substring of any FAIL banner.

Warning
Do not modify; hil.conf HIL_EXPECT matches it verbatim.
Since
0.1.0

Definition at line 159 of file main.c.

Referenced by main().

◆ s_cache_mpu_buf

uint8_t s_cache_mpu_buf[k_cache_mpu_buf_bytes]
static

4 KiB cacheable scratch buffer in M85-private SRAM (MPU region 1).

Lives in .bss (SRAM @ 0x22000000, cacheable per MPU region 1). Cache-line aligned (32 bytes) so the clean+invalidate covers whole lines with no partial-line surprises.

Note
Mutated only by the cacheable-RW self-test on the single boot thread.
Warning
Not for cross-core use – region 1 is M85-private cacheable.
Since
0.1.0

Definition at line 133 of file main.c.

Referenced by cache_mpu_test_cacheable_rw().