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

On-silicon HIL: reflow pagination-cache round-trip on SD (#117). More...

#include <stddef.h>
#include <stdint.h>
#include "literata_latin1.h"
#include "ra8_attributes.h"
#include "ra8_board_ek_ra8d2.h"
#include "ra8_boot_entry.h"
#include "ra8_cgc.h"
#include "ra8_err.h"
#include "ra8_fs.h"
#include "ra8_isr.h"
#include "ra8_log.h"
#include "ra8_port_utils.h"
#include "ra8_sci_spi.h"
#include "ra8_sdmmc_spi.h"
#include "ra8_spi.h"
#include "ra8_time.h"
#include "reflow.h"
#include "reflow_cache.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  pc_consts_t : uint32_t {
  k_pc_uart_baud = 115200U ,
  k_pc_spi_chan = 0U ,
  k_pc_font_cap ,
  k_pc_blob_cap = 16384U ,
  k_pc_view_w = 600U ,
  k_pc_view_h = 800U ,
  k_pc_font_px = 18U ,
  k_pc_font_px_alt = 24U ,
  k_pc_ink_argb = 0xFF101010U ,
  k_pc_link_argb = 0xFF2A52BEU ,
  k_pc_crc_init = 0xFFFFFFFFU ,
  k_pc_crc_poly = 0xEDB88320U ,
  k_pc_crc_bits = 8U
}
 Console / SPI / reflow knobs (no magic numbers). More...
enum  pc_err_t : uint32_t {
  k_pc_err_none = 0U ,
  k_pc_err_init = 1U ,
  k_pc_err_card = 2U ,
  k_pc_err_mount = 3U ,
  k_pc_err_font = 4U ,
  k_pc_err_layout = 5U ,
  k_pc_err_ser = 6U ,
  k_pc_err_persist = 7U ,
  k_pc_err_readback = 8U ,
  k_pc_err_load = 9U ,
  k_pc_err_crc = 10U ,
  k_pc_err_invalid = 11U
}
 Failure-stage codes stamped to g_pc_err for SWD / --dump-sym. More...
enum  pc_pace_t : uint32_t { k_pc_frame_ms = 100U }
 Idle-loop pacing for the success heartbeat. More...

Functions

static void internal_pc_print (const uint8_t *msg, uint32_t len)
 Emit a byte run on the board console.
static void internal_pc_fail (uint32_t err)
 Stamp the failure stage and park the CPU without a heartbeat.
static uint32_t internal_pc_crc32 (const uint8_t *data, size_t len)
 Calculate reflected CRC-32 over a byte span.
static bool internal_pc_blob_equal (const uint8_t *a, const uint8_t *b, size_t len)
 Compare two equal-length cache-blob spans.
static ra8_err_t internal_pc_spi_set_clock (void *ctx, uint32_t hz)
 Apply an SD-card SPI clock through the SCI transport.
static ra8_err_t internal_pc_spi_cs (void *ctx, bool asserted)
 Drive the SD-card active-low chip-select GPIO.
static ra8_err_t internal_pc_spi_xfer (void *ctx, const uint8_t *tx, uint8_t *rx, uint32_t len)
 Exchange an SD-card byte span through SCI SPI.
static ra8_err_t internal_pc_spi_pins_init (void)
 Route Pmod2 SPI signals and initialize chip select high.
static void internal_pc_setup_or_halt (uint32_t *out_pclka_hz)
 Bring up clocks, timekeeping, console, and the SD SPI controller.
static void internal_pc_init_card_or_halt (uint32_t *pclka_hz)
 Initialize the SD card over the configured SPI transport.
static ra8_fs_mount_tinternal_pc_mount_or_halt (void)
 Bind and mount the SD filesystem, formatting blank media if needed.
static void internal_pc_font_or_halt (ra8_fs_mount_t *mount, uint32_t *out_len)
 Provision FONT.OTF if absent, then read it into s_font_buf.
static uint32_t internal_pc_read_cache (ra8_fs_mount_t *mount, uint8_t *buf, uint32_t cap)
 Read the persisted cache file into a bounded caller buffer.
static bool internal_pc_engine_init (uint16_t font_px, uint32_t font_len)
 Initialise the engine at font_px over the SD font.
static void internal_pc_live_layout_or_halt (uint32_t font_len, size_t *out_n)
 Lay out the chapter live and serialise it into s_live_blob.
static void internal_pc_persist_and_verify_or_halt (ra8_fs_mount_t *mount, size_t n)
 Persist the live cache blob and verify an exact read-back.
static void internal_pc_reload_check_or_halt (uint32_t font_len, size_t n)
 Load the read-back blob into a fresh same-size engine and CRC it.
static void internal_pc_invalidate_check_or_halt (uint32_t font_len, size_t n)
 Verify that a font-size change invalidates the persisted cache.
void main (void)
 App entry: SD bring-up -> font -> cache round-trip -> heartbeat idle.

Variables

static const ra8_port_pin_t s_pc_pin_sck = (ra8_port_pin_t)k_ra8_board_pmod2_spi_sck
 Pmod2 SCI clock pin used by the SD-card transport.
static const ra8_port_pin_t s_pc_pin_cipo = (ra8_port_pin_t)k_ra8_board_pmod2_spi_cipo
 Pmod2 controller-input/peripheral-output pin.
static const ra8_port_pin_t s_pc_pin_copi = (ra8_port_pin_t)k_ra8_board_pmod2_spi_copi
 Pmod2 controller-output/peripheral-input pin.
static const ra8_port_pin_t s_pc_pin_cs = (ra8_port_pin_t)k_ra8_board_pmod2_spi_cs
 GPIO-driven active-low SD-card chip-select pin.
static const char s_pc_font_path [] = "FONT.OTF"
 Root-directory 8.3 name for the persisted font.
static const char s_pc_cache_path [] = "PCACHE.BIN"
 Root-directory 8.3 name for the serialized pagination cache.
static const char s_pc_body []
 Fixed HTML chapter used by the live and cached layout passes.
volatile uint32_t g_pc_err = (uint32_t)k_pc_err_none
 First failing stage (pc_err_t), 0 on success.
volatile uint32_t g_pc_hit = 0U
 1 if the cache file existed at boot (reset-survival hit).
volatile uint32_t g_pc_crc_match = 0U
 1 if the reloaded-cache blob CRC equals the live-layout blob CRC.
volatile uint32_t g_pc_invalidate = 0U
 1 if loading the blob at the alt font size returned invalid_state.
volatile uint32_t g_pc_pages = 0U
 Page count produced by the live layout.
volatile uint32_t g_pc_live_crc = 0U
 CRC-32 of the live-layout serialised blob.
volatile uint32_t g_pc_cache_crc = 0U
 CRC-32 of the reloaded-then-reserialised blob.
volatile uint32_t g_pc_heartbeat = 0U
 Idle heartbeat; advances ONLY after every assertion passes.
static uint8_t s_font_buf [k_pc_font_cap]
 Font blob read off the card.
static reflow_t s_engine
 Reflow engine (glyph / page / token / text pools live inside).
static uint8_t s_live_blob [k_pc_blob_cap]
 Serialised cache blob from the live layout.
static uint8_t s_read_blob [k_pc_blob_cap]
 Blob read back off SD (compared to s_live_blob).
static uint8_t s_reser_blob [k_pc_blob_cap]
 Blob re-serialised from the reloaded engine (CRC vs live).
static ra8_fs_backend_t s_backend
 SD backend; file-scope so the mount handle may reference it.
static const uint8_t s_msg_boot [] = "pagecache-hil: boot\r\n"
 Console marker emitted after core and peripheral setup.
static const uint8_t s_msg_pass [] = "pagecache-hil: hit="
 Prefix for the final reset-survival hit diagnostic.
static const uint8_t s_msg_ok [] = " crc_match=1 invalidate=1 PASS\r\n"
 Final cache-CRC and invalidation success suffix.

Detailed Description

On-silicon HIL: reflow pagination-cache round-trip on SD (#117).

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

#79 added the import-time pagination cache (reflow_cache): lay a chapter out once, serialise the flattened glyph/page result to a keyed blob, persist it, and on the next open skip the expensive layout by loading the blob. That path was host-tested only; this app runs it on the M85 against a real microSD volume through ra8_fs – the exact storage the e-reader uses.

Flow: bring up the Pmod2 microSD over ra8_sdmmc_spi, mount an ra8_fs volume (formatting FAT32 if blank), self-provision FONT.OTF (a baked Latin-1 OTF), then exercise the cache three ways:

  1. ROUND-TRIP: lay out a fixed chapter live, reflow_cache_serialize it, write the blob to SD, read it back, reflow_cache_load it into a fresh engine, re-serialise, and assert the reloaded blob is byte-for-byte equal to the live one (the serialised form is the per-page glyph/page data, so equal blobs prove the layout was restored exactly).
  2. INVALIDATE: load the same blob into an engine initialised at a DIFFERENT font size and assert k_ra8_err_invalid_state (the key mismatch is caught; no stale page is served).
  3. RESET-SURVIVAL: g_pc_hit reflects whether the cache file already existed at boot, so a second boot against a persisted card reports a hit (served from the on-disk cache without a fresh layout).

The HIL gate is memprobe (J-Link / ra8_emulator --dump-sym), not the console: an SD app drives the SCI0 Simple-SPI bus, and ra8_emulator folds every SCI channel into one console line, so a SCI8 banner is interleaved with SPI traffic there (the same reason the sibling SD HIL apps gate on SWD globals). The success path advances g_pc_heartbeat once per frame and only after every assertion passes; any failure stamps g_pc_err and parks without bumping it.

Required external hardware (on-bench): Digilent PMOD MicroSD (410-380) in Pmod2 (J25) with a microSD inserted. THIS APP MAY FORMAT THE CARD. Under ra8_emulator attach a blank card with --sd-new 64:fat32 (round-trip + invalidate), and a second run against a --save-sd image to prove the cache-hit reset-survival.

Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ pc_consts_t

enum pc_consts_t : uint32_t

Console / SPI / reflow knobs (no magic numbers).

Enumerator
k_pc_uart_baud 

Console baud.

k_pc_spi_chan 

Pmod2 / J25 SCI0 Simple-SPI.

k_pc_font_cap 

Font read buffer (OTF is ~57 KiB; trimmed from 128 KiB when the fs sector arena grew .bss, #683).

k_pc_blob_cap 

Cache-blob buffer capacity, bytes.

k_pc_view_w 

Reflow viewport width, px.

k_pc_view_h 

Reflow viewport height, px.

k_pc_font_px 

Body font size, px (round-trip key).

k_pc_font_px_alt 

Alt font size to force invalidation.

k_pc_ink_argb 

Body text colour.

k_pc_link_argb 

Anchor text colour.

k_pc_crc_init 

CRC-32 initial value.

k_pc_crc_poly 

CRC-32 reflected polynomial.

k_pc_crc_bits 

Bits folded per byte.

Definition at line 68 of file main.c.

◆ pc_err_t

enum pc_err_t : uint32_t

Failure-stage codes stamped to g_pc_err for SWD / --dump-sym.

Enumerator
k_pc_err_none 

No failure (success path).

k_pc_err_init 

CGC / time / console / SPI bring-up.

k_pc_err_card 

SD card SPI init.

k_pc_err_mount 

Mount (and format-if-blank).

k_pc_err_font 

Provision / read FONT.OTF.

k_pc_err_layout 

reflow_init / layout_chapter.

k_pc_err_ser 

reflow_cache_serialize.

k_pc_err_persist 

Write / read-back the blob on SD.

k_pc_err_readback 

Read-back blob != written blob.

k_pc_err_load 

reflow_cache_load (expected hit).

k_pc_err_crc 

Reloaded layout CRC != live CRC.

k_pc_err_invalid 

Alt-size load did not invalidate.

Definition at line 155 of file main.c.

◆ pc_pace_t

enum pc_pace_t : uint32_t

Idle-loop pacing for the success heartbeat.

Enumerator
k_pc_frame_ms 

Heartbeat period in milliseconds.

Definition at line 171 of file main.c.

Function Documentation

◆ internal_pc_blob_equal()

bool internal_pc_blob_equal ( const uint8_t * a,
const uint8_t * b,
size_t len )
static

Compare two equal-length cache-blob spans.

Scans from the first byte and returns immediately on the first mismatch, avoiding any allocation or temporary buffer.

Parameters
[in]aFirst input span.
[in]bSecond input span.
[in]lenNumber of bytes to compare.
Returns
Whether every compared byte is equal.
Return values
trueAll len bytes match.
falseAt least one byte differs.
Precondition
a and b each reference at least len readable bytes.
Both spans describe cache blobs of the same expected length.
Postcondition
Both input spans remain unchanged.
No state outside the function is modified.
Note
This comparison is not intended to be constant-time.
Since
0.1.0

Definition at line 319 of file main.c.

References RA8_INTERNAL.

Referenced by internal_pc_persist_and_verify_or_halt().

◆ internal_pc_crc32()

uint32_t internal_pc_crc32 ( const uint8_t * data,
size_t len )
static

Calculate reflected CRC-32 over a byte span.

Starts with k_pc_crc_init, folds eight reflected polynomial steps per byte, and returns the one's-complement accumulator.

Parameters
[in]dataFirst byte of the input span.
[in]lenNumber of bytes to fold.
Returns
CRC-32 of the supplied bytes.
Return values
0x00000000..0xFFFFFFFFComputed reflected CRC value.
Precondition
data references at least len readable bytes.
len is bounded by the caller-owned cache buffer.
Postcondition
Input bytes remain unchanged.
The result depends only on the supplied byte sequence.
Note
The implementation uses polynomial 0xEDB88320.
Since
0.1.0

Definition at line 289 of file main.c.

References k_pc_crc_bits, k_pc_crc_init, k_pc_crc_poly, and RA8_INTERNAL.

Referenced by internal_pc_live_layout_or_halt(), and internal_pc_reload_check_or_halt().

◆ internal_pc_engine_init()

bool internal_pc_engine_init ( uint16_t font_px,
uint32_t font_len )
static

Initialise the engine at font_px over the SD font.

Reinitializes the single static reflow engine with the requested font size, fixed viewport, and fixed ink/link colors.

Parameters
[in]font_pxRequested font pixel height.
[in]font_lenNumber of valid font bytes in s_font_buf.
Returns
true on success, false on init failure.
Return values
trueThe reflow engine accepted the font and configuration.
falseThe font or layout configuration was invalid.
Precondition
font_len is nonzero and does not exceed k_pc_font_cap.
No caller is concurrently using s_engine.
Postcondition
On success s_engine is ready for layout or cache loading.
On failure callers must not use the engine for reflow work.
Note
Each validation phase deliberately replaces the prior engine state.
Since
0.1.0

Definition at line 608 of file main.c.

References k_pc_ink_argb, k_pc_link_argb, k_pc_view_h, k_pc_view_w, k_ra8_ok, RA8_INTERNAL, reflow_init(), s_engine, and s_font_buf.

Referenced by internal_pc_invalidate_check_or_halt(), internal_pc_live_layout_or_halt(), and internal_pc_reload_check_or_halt().

◆ internal_pc_fail()

void internal_pc_fail ( uint32_t err)
static

Stamp the failure stage and park the CPU without a heartbeat.

Records the first detected stage code for SWD inspection, then repeatedly waits for interrupts without resuming the test flow.

Parameters
[in]errFailure-stage code (pc_err_t).
Precondition
err identifies the failed stage and is nonzero.
Diagnostic SRAM remains writable.
Postcondition
g_pc_err contains err.
Control never returns and g_pc_heartbeat does not advance.
Note
A debugger may inspect the latched globals while the core is parked.
Since
0.1.0

Definition at line 266 of file main.c.

References g_pc_err, and RA8_INTERNAL.

Referenced by internal_pc_font_or_halt(), internal_pc_init_card_or_halt(), internal_pc_invalidate_check_or_halt(), internal_pc_live_layout_or_halt(), internal_pc_mount_or_halt(), internal_pc_persist_and_verify_or_halt(), internal_pc_reload_check_or_halt(), and internal_pc_setup_or_halt().

◆ internal_pc_font_or_halt()

void internal_pc_font_or_halt ( ra8_fs_mount_t * mount,
uint32_t * out_len )
static

Provision FONT.OTF if absent, then read it into s_font_buf.

Opens the persisted font, writes the linked Literata asset when the file is absent, then reads a bounded span into static storage.

Parameters
[in]mountMounted SD volume.
[out]out_lenReceives the font length in bytes.
Precondition
mount is a valid mounted filesystem handle.
out_len points to writable storage and the linked font fits the cap.
Postcondition
On success s_font_buf contains a nonempty font and *out_len its size.
On failure the font stage is latched and execution parks.
Note
The file handle is closed before either success or a read-failure halt.
Since
0.1.0

Definition at line 537 of file main.c.

References g_ra8_font_literata_latin1, g_ra8_font_literata_latin1_len, internal_pc_fail(), k_pc_err_font, k_pc_font_cap, k_ra8_fs_mode_read, k_ra8_ok, ra8_fs_close(), ra8_fs_open(), ra8_fs_read(), ra8_fs_write_file(), RA8_INTERNAL, s_font_buf, and s_pc_font_path.

Referenced by main().

◆ internal_pc_init_card_or_halt()

void internal_pc_init_card_or_halt ( uint32_t * pclka_hz)
static

Initialize the SD card over the configured SPI transport.

Binds the three local transport callbacks with a caller-owned PCLKA context and runs the card's bounded initialization sequence.

Parameters
[in]pclka_hzStable PCLKA frequency used by clock changes.
Precondition
pclka_hz points to a valid frequency for the function's duration.
SCI0 and its GPIO chip select have been initialized.
Postcondition
On success the card accepts block operations through the SPI backend.
On failure g_pc_err identifies the card stage and execution parks.
Note
The transport structure may be temporary because initialization copies it.
Since
0.1.0

Definition at line 482 of file main.c.

References internal_pc_fail(), internal_pc_spi_cs(), internal_pc_spi_set_clock(), internal_pc_spi_xfer(), k_pc_err_card, k_ra8_ok, RA8_INTERNAL, and ra8_sdmmc_spi_init().

Referenced by main().

◆ internal_pc_invalidate_check_or_halt()

void internal_pc_invalidate_check_or_halt ( uint32_t font_len,
size_t n )
static

Verify that a font-size change invalidates the persisted cache.

Initializes a fresh engine at the alternate size and requires cache loading to reject the normal-size blob with invalid_state.

Parameters
[in]font_lenFont length in s_font_buf.
[in]nNumber of valid cache bytes in s_read_blob.
Precondition
The same font bytes and chapter body used to create the cache remain available.
n does not exceed k_pc_blob_cap.
Postcondition
On success g_pc_invalidate is set to one.
Any unexpected cache-load result latches the invalidation stage and parks.
Note
Font size is intentionally part of the cache identity contract.
Since
0.1.0

Definition at line 740 of file main.c.

References g_pc_invalidate, internal_pc_engine_init(), internal_pc_fail(), k_pc_err_invalid, k_pc_err_layout, k_pc_font_px_alt, k_ra8_err_invalid_state, RA8_INTERNAL, reflow_cache_load(), s_engine, s_pc_body, and s_read_blob.

Referenced by main().

◆ internal_pc_live_layout_or_halt()

void internal_pc_live_layout_or_halt ( uint32_t font_len,
size_t * out_n )
static

Lay out the chapter live and serialise it into s_live_blob.

Initializes the normal-font engine, lays out the fixed HTML body, serializes the resulting cache, and records page and CRC diagnostics.

Parameters
[in]font_lenFont length, bytes.
[out]out_nReceives the live blob length, bytes.
Precondition
font_len describes the valid prefix of s_font_buf.
out_n points to writable storage and the static blob capacity is sufficient.
Postcondition
On success s_live_blob and the live page/CRC diagnostics are populated.
On failure the appropriate layout or serialization stage is latched.
Note
The helper does not persist the generated blob to the card.
Since
0.1.0

Definition at line 633 of file main.c.

References g_pc_live_crc, g_pc_pages, internal_pc_crc32(), internal_pc_engine_init(), internal_pc_fail(), k_pc_blob_cap, k_pc_err_layout, k_pc_err_ser, k_pc_font_px, k_ra8_ok, RA8_INTERNAL, reflow_cache_serialize(), reflow_layout_chapter(), s_engine, s_live_blob, and s_pc_body.

Referenced by main().

◆ internal_pc_mount_or_halt()

ra8_fs_mount_t * internal_pc_mount_or_halt ( void )
static

Bind and mount the SD filesystem, formatting blank media if needed.

Attempts a normal mount first; when that fails, creates a FAT32 volume labeled RAPCACHE and retries exactly once.

Returns
Mounted filesystem handle.
Return values
non-NULLValid mount retained by the filesystem layer.
Precondition
The SD SPI card backend has completed initialization.
s_backend is available for binding and remains alive after return.
Postcondition
On success a mounted root volume is available to later helpers.
On unrecoverable failure the mount stage is latched and execution parks.
Note
Existing formatted volumes are never reformatted after a successful mount.
Since
0.1.0

Definition at line 506 of file main.c.

References internal_pc_fail(), k_pc_err_mount, k_ra8_fs_type_fat32, k_ra8_ok, ra8_fs_format_opts_t::label, ra8_fs_format(), ra8_fs_mount(), RA8_INTERNAL, ra8_sdmmc_spi_bind_fs_backend(), s_backend, and ra8_fs_format_opts_t::type.

Referenced by main().

◆ internal_pc_persist_and_verify_or_halt()

void internal_pc_persist_and_verify_or_halt ( ra8_fs_mount_t * mount,
size_t n )
static

Persist the live cache blob and verify an exact read-back.

Replaces the cache file, reads it into independent static storage, validates the byte count, and compares every serialized byte.

Parameters
[in]mountMounted filesystem handle.
[in]nNumber of valid bytes in s_live_blob.
Precondition
mount is valid and n does not exceed k_pc_blob_cap.
s_live_blob contains the current live serialization.
Postcondition
On success s_read_blob[0..n) exactly matches the live blob.
On failure the persist or read-back stage is latched and execution parks.
Note
The comparison distinguishes storage corruption from serialization failure.
Since
0.1.0

Definition at line 672 of file main.c.

References internal_pc_blob_equal(), internal_pc_fail(), internal_pc_read_cache(), k_pc_blob_cap, k_pc_err_persist, k_pc_err_readback, k_ra8_ok, ra8_fs_write_file(), RA8_INTERNAL, s_live_blob, s_pc_cache_path, and s_read_blob.

Referenced by main().

◆ internal_pc_print()

void internal_pc_print ( const uint8_t * msg,
uint32_t len )
static

Emit a byte run on the board console.

Forwards the caller-owned span directly to the initialized UART console and deliberately ignores diagnostic write failure.

Parameters
[in]msgFirst byte of the diagnostic span.
[in]lenNumber of bytes to attempt.
Precondition
msg references at least len readable bytes.
The board UART console has been initialized.
Postcondition
At most len bytes have been offered to the console backend.
The caller's buffer remains unchanged.
Note
This HIL diagnostic path does not influence acceptance state.
Since
0.1.0

Definition at line 249 of file main.c.

References ra8_board_uart_console_write(), and RA8_INTERNAL.

Referenced by main().

◆ internal_pc_read_cache()

uint32_t internal_pc_read_cache ( ra8_fs_mount_t * mount,
uint8_t * buf,
uint32_t cap )
static

Read the persisted cache file into a bounded caller buffer.

Treats absence and read failure as a cache miss while ensuring any successfully opened file is closed before returning.

Parameters
[in]mountMounted filesystem handle.
[out]bufDestination for cache bytes.
[in]capWritable capacity of buf in bytes.
Returns
Number of cache bytes read.
Return values
0The file was absent, empty, or unreadable.
1..capNumber of bytes placed in buf.
Precondition
mount is valid and buf references cap writable bytes.
cap is representable by the filesystem read API.
Postcondition
The cache file is closed if it was opened.
Bytes beyond the returned length remain unspecified.
Note
A miss is intentionally nonfatal because the live layout can rebuild it.
Since
0.1.0

Definition at line 578 of file main.c.

References k_ra8_fs_mode_read, k_ra8_ok, ra8_fs_close(), ra8_fs_open(), ra8_fs_read(), and s_pc_cache_path.

Referenced by internal_pc_persist_and_verify_or_halt(), and main().

◆ internal_pc_reload_check_or_halt()

void internal_pc_reload_check_or_halt ( uint32_t font_len,
size_t n )
static

Load the read-back blob into a fresh same-size engine and CRC it.

Reinitializes the engine with the original font size, loads the persisted cache, serializes it again, and compares length and CRC.

Parameters
[in]font_lenFont length, bytes.
[in]nBlob length, bytes.
Precondition
font_len describes the valid prefix of s_font_buf.
n valid bytes are present in s_read_blob.
Postcondition
On success g_pc_cache_crc matches g_pc_live_crc and the match flag is set.
On failure the layout, load, serialization, or CRC stage is latched.
Note
Re-serialization proves that the loaded engine state is structurally usable.
Since
0.1.0

Definition at line 699 of file main.c.

References g_pc_cache_crc, g_pc_crc_match, g_pc_live_crc, internal_pc_crc32(), internal_pc_engine_init(), internal_pc_fail(), k_pc_blob_cap, k_pc_err_crc, k_pc_err_layout, k_pc_err_load, k_pc_err_ser, k_pc_font_px, k_ra8_ok, RA8_INTERNAL, reflow_cache_load(), reflow_cache_serialize(), s_engine, s_pc_body, s_read_blob, and s_reser_blob.

Referenced by main().

◆ internal_pc_setup_or_halt()

void internal_pc_setup_or_halt ( uint32_t * out_pclka_hz)
static

Bring up clocks, timekeeping, console, and the SD SPI controller.

Resolves CPUCLK0 and PCLKA, initializes SysTick and the console, routes Pmod2 pins, and configures SCI0 at the card-init rate.

Parameters
[out]out_pclka_hzReceives the configured PCLKA frequency.
Precondition
out_pclka_hz points to writable storage.
Board clock and pin-control registers are at their reset-safe state.
Postcondition
On success all host-side SD transport dependencies are initialized.
On failure the error stage is latched and the core does not return.
Note
Interrupts remain globally masked until the caller enables them.
Since
0.1.0

Definition at line 444 of file main.c.

References internal_pc_fail(), internal_pc_spi_pins_init(), k_pc_err_init, k_pc_spi_chan, k_pc_uart_baud, k_ra8_clock_id_cpuclk0, k_ra8_clock_id_pclka, k_ra8_ok, k_ra8_sdmmc_spi_clock_init_hz, k_ra8_spi_mode_0, ra8_board_uart_console_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), RA8_INTERNAL, ra8_sci_spi_init(), and ra8_time_init().

Referenced by main().

◆ internal_pc_spi_cs()

ra8_err_t internal_pc_spi_cs ( void * ctx,
bool asserted )
static

Drive the SD-card active-low chip-select GPIO.

Converts the transport's logical assertion state to the board pin's physical low/high level; the unused context is accepted.

Parameters
[in]ctxTransport context, unused by the GPIO operation.
[in]assertedWhether the SD card must be selected.
Returns
GPIO write status.
Return values
k_ra8_okThe requested level was driven.
k_ra8_err_invalid_argThe board pin is not a valid GPIO output.
Precondition
s_pc_pin_cs has been initialized as an output.
The SD transport serializes chip-select transitions with transfers.
Postcondition
The pin is low when asserted and high when deasserted.
The unused transport context remains unchanged.
Note
Signature matches ra8_sdmmc_spi_transport_t::cs.
Since
0.1.0

Definition at line 370 of file main.c.

References k_ra8_level_high, k_ra8_level_low, ra8_gpio_write(), RA8_INTERNAL, and s_pc_pin_cs.

Referenced by internal_pc_init_card_or_halt().

◆ internal_pc_spi_pins_init()

ra8_err_t internal_pc_spi_pins_init ( void )
staticnodiscard

Route Pmod2 SPI signals and initialize chip select high.

Claims SCK, CIPO, and COPI for SCI operation in dependency order, then configures the separate chip-select pin as a GPIO output.

Returns
Pin-routing and GPIO initialization status.
Return values
k_ra8_okAll four pins were configured.
k_ra8_err_invalid_argA requested route or GPIO pin is unsupported.
Precondition
The board pin manifest identifies the Pmod2 SPI pins.
No conflicting peripheral owns those pins.
Postcondition
On success SCI owns SCK/CIPO/COPI and chip select is high.
On failure no later routing step is attempted.
Note
The caller treats any nonzero status as a fatal initialization error.
Since
0.1.0

Definition at line 415 of file main.c.

References k_ra8_level_high, k_ra8_ok, k_ra8_psel_sci_async, ra8_gpio_output_init(), RA8_INTERNAL, ra8_pfs_route_peripheral(), s_pc_pin_cipo, s_pc_pin_copi, s_pc_pin_cs, and s_pc_pin_sck.

Referenced by internal_pc_setup_or_halt().

◆ internal_pc_spi_set_clock()

ra8_err_t internal_pc_spi_set_clock ( void * ctx,
uint32_t hz )
static

Apply an SD-card SPI clock through the SCI transport.

Reads the caller-owned PCLKA frequency from ctx and delegates divisor selection to the SCI SPI driver.

Parameters
[in]ctxPointer to the initialized PCLKA frequency value.
[in]hzRequested SPI clock frequency in hertz.
Returns
SCI clock-configuration status.
Return values
k_ra8_okThe requested clock was configured.
k_ra8_err_invalid_argThe context or requested rate is invalid.
Precondition
ctx points to a readable uint32_t PCLKA value.
SCI0 has already been initialized for SPI operation.
Postcondition
SCI0 retains either its prior clock or a valid clock near hz.
The caller-owned PCLKA value remains unchanged.
Note
Signature matches ra8_sdmmc_spi_transport_t::set_clock.
Since
0.1.0

Definition at line 348 of file main.c.

References k_pc_spi_chan, RA8_INTERNAL, and ra8_sci_spi_set_clock().

Referenced by internal_pc_init_card_or_halt().

◆ internal_pc_spi_xfer()

ra8_err_t internal_pc_spi_xfer ( void * ctx,
const uint8_t * tx,
uint8_t * rx,
uint32_t len )
static

Exchange an SD-card byte span through SCI SPI.

Delegates the full-duplex transaction to the configured SCI channel; the transport context is unused because channel selection is fixed.

Parameters
[in]ctxTransport context, unused by the SCI operation.
[in]txTransmit bytes, or the driver's supported null form.
[out]rxReceive buffer, or the driver's supported null form.
[in]lenNumber of bytes to exchange.
Returns
SCI transfer status.
Return values
k_ra8_okAll requested bytes were transferred.
k_ra8_err_timeoutThe synchronous transfer did not complete in time.
Precondition
SCI0 has been initialized for SPI mode.
Non-null tx and rx spans each cover at least len bytes.
Postcondition
On success rx contains len received bytes when non-null.
The transmit span remains unchanged.
Note
Signature matches ra8_sdmmc_spi_transport_t::xfer.
Since
0.1.0

Definition at line 395 of file main.c.

References k_pc_spi_chan, and ra8_sci_spi_xfer().

Referenced by internal_pc_init_card_or_halt().

◆ main()

void main ( void )

App entry: SD bring-up -> font -> cache round-trip -> heartbeat idle.

The application entry point Reset_Handler hands control to.

Precondition
Reset_Handler copied .data and zeroed .bss.
SystemInit set VTOR / FPU / priority grouping.
Postcondition
On success the cache globals are latched and g_pc_heartbeat advances.
On any failure g_pc_err is non-zero and the CPU parks (no heartbeat).
Since
0.1.0

Definition at line 764 of file main.c.

References g_pc_heartbeat, g_pc_hit, internal_pc_font_or_halt(), internal_pc_init_card_or_halt(), internal_pc_invalidate_check_or_halt(), internal_pc_live_layout_or_halt(), internal_pc_mount_or_halt(), internal_pc_persist_and_verify_or_halt(), internal_pc_print(), internal_pc_read_cache(), internal_pc_reload_check_or_halt(), internal_pc_setup_or_halt(), k_pc_blob_cap, k_pc_frame_ms, ra8_delay_ms(), ra8_isr_globals_enable(), ra8_log_init(), s_msg_boot, s_msg_ok, s_msg_pass, and s_read_blob.

Variable Documentation

◆ g_pc_cache_crc

volatile uint32_t g_pc_cache_crc = 0U

CRC-32 of the reloaded-then-reserialised blob.

Definition at line 190 of file main.c.

Referenced by internal_pc_reload_check_or_halt().

◆ g_pc_crc_match

volatile uint32_t g_pc_crc_match = 0U

1 if the reloaded-cache blob CRC equals the live-layout blob CRC.

Definition at line 182 of file main.c.

Referenced by internal_pc_reload_check_or_halt().

◆ g_pc_err

volatile uint32_t g_pc_err = (uint32_t)k_pc_err_none

First failing stage (pc_err_t), 0 on success.

SWD / --dump-sym.

Definition at line 178 of file main.c.

Referenced by internal_pc_fail().

◆ g_pc_heartbeat

volatile uint32_t g_pc_heartbeat = 0U

Idle heartbeat; advances ONLY after every assertion passes.

Definition at line 192 of file main.c.

Referenced by main().

◆ g_pc_hit

volatile uint32_t g_pc_hit = 0U

1 if the cache file existed at boot (reset-survival hit).

Definition at line 180 of file main.c.

Referenced by main().

◆ g_pc_invalidate

volatile uint32_t g_pc_invalidate = 0U

1 if loading the blob at the alt font size returned invalid_state.

Definition at line 184 of file main.c.

Referenced by internal_pc_invalidate_check_or_halt().

◆ g_pc_live_crc

volatile uint32_t g_pc_live_crc = 0U

CRC-32 of the live-layout serialised blob.

Definition at line 188 of file main.c.

Referenced by internal_pc_live_layout_or_halt(), and internal_pc_reload_check_or_halt().

◆ g_pc_pages

volatile uint32_t g_pc_pages = 0U

Page count produced by the live layout.

Definition at line 186 of file main.c.

Referenced by internal_pc_live_layout_or_halt().

◆ s_backend

ra8_fs_backend_t s_backend
static

SD backend; file-scope so the mount handle may reference it.

Definition at line 207 of file main.c.

◆ s_engine

◆ s_font_buf

uint8_t s_font_buf[k_pc_font_cap]
static

◆ s_live_blob

uint8_t s_live_blob[k_pc_blob_cap]
static

Serialised cache blob from the live layout.

Definition at line 201 of file main.c.

Referenced by internal_pc_live_layout_or_halt(), and internal_pc_persist_and_verify_or_halt().

◆ s_msg_boot

const uint8_t s_msg_boot[] = "pagecache-hil: boot\r\n"
static

Console marker emitted after core and peripheral setup.

Lets a bench operator distinguish startup from later cache output.

Note
The byte count excludes the terminating null character.
Since
0.1.0

Definition at line 216 of file main.c.

Referenced by main().

◆ s_msg_ok

const uint8_t s_msg_ok[] = " crc_match=1 invalidate=1 PASS\r\n"
static

Final cache-CRC and invalidation success suffix.

Records the two acceptance conditions in a stable bench-readable line.

Note
Emitted only after all cache assertions pass.
Since
0.1.0

Definition at line 234 of file main.c.

Referenced by main().

◆ s_msg_pass

const uint8_t s_msg_pass[] = "pagecache-hil: hit="
static

Prefix for the final reset-survival hit diagnostic.

Followed by one ASCII hit digit and the fixed success suffix.

Note
Emitted only after all cache assertions pass.
Since
0.1.0

Definition at line 225 of file main.c.

Referenced by main().

◆ s_pc_body

const char s_pc_body[]
static
Initial value:
= "<html><body><h1>Cache</h1>"
"<p>Pagination cache round-trip on silicon.</p>"
"<p>Second paragraph for the break engine.</p></body></html>"

Fixed HTML chapter used by the live and cached layout passes.

The intentionally short content keeps the silicon and emulator pagination checks bounded while still exercising paragraph breaks.

Note
Every cache load uses these exact bytes as part of its identity key.
Since
0.1.0

Definition at line 147 of file main.c.

Referenced by internal_pc_invalidate_check_or_halt(), internal_pc_live_layout_or_halt(), and internal_pc_reload_check_or_halt().

◆ s_pc_cache_path

const char s_pc_cache_path[] = "PCACHE.BIN"
static

Root-directory 8.3 name for the serialized pagination cache.

The same file is used for reset-survival detection and verification.

Note
Its contents are replaced after each successful live layout.
Since
0.1.0

Definition at line 137 of file main.c.

Referenced by internal_pc_persist_and_verify_or_halt(), and internal_pc_read_cache().

◆ s_pc_font_path

const char s_pc_font_path[] = "FONT.OTF"
static

Root-directory 8.3 name for the persisted font.

The filesystem layer is root-only, so no directory prefix is used.

Note
The file is provisioned from the linked Literata asset when absent.
Since
0.1.0

Definition at line 128 of file main.c.

Referenced by internal_pc_font_or_halt().

◆ s_pc_pin_cipo

Pmod2 controller-input/peripheral-output pin.

Carries SD-card data toward SCI0 during SPI transfers.

Note
Immutable for the lifetime of the application.
Since
0.1.0

Definition at line 101 of file main.c.

Referenced by internal_pc_spi_pins_init().

◆ s_pc_pin_copi

Pmod2 controller-output/peripheral-input pin.

Carries SCI0 command and payload data toward the SD card.

Note
Immutable for the lifetime of the application.
Since
0.1.0

Definition at line 110 of file main.c.

Referenced by internal_pc_spi_pins_init().

◆ s_pc_pin_cs

GPIO-driven active-low SD-card chip-select pin.

Uses the board manifest's Pmod2 chip-select route outside SCI0.

Note
Initialized high before the SD transport is invoked.
Since
0.1.0

Definition at line 119 of file main.c.

Referenced by internal_pc_spi_cs(), and internal_pc_spi_pins_init().

◆ s_pc_pin_sck

Pmod2 SCI clock pin used by the SD-card transport.

Resolves the board manifest's J25 clock route once at compile time.

Note
Immutable for the lifetime of the application.
Since
0.1.0

Definition at line 92 of file main.c.

Referenced by internal_pc_spi_pins_init().

◆ s_read_blob

uint8_t s_read_blob[k_pc_blob_cap]
static

Blob read back off SD (compared to s_live_blob).

Definition at line 203 of file main.c.

Referenced by internal_pc_invalidate_check_or_halt(), internal_pc_persist_and_verify_or_halt(), internal_pc_reload_check_or_halt(), and main().

◆ s_reser_blob

uint8_t s_reser_blob[k_pc_blob_cap]
static

Blob re-serialised from the reloaded engine (CRC vs live).

Definition at line 205 of file main.c.

Referenced by internal_pc_reload_check_or_halt().