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 primary core) driver for the e-reader-on-M33 demo. More...

#include <stdint.h>
#include "ereader_m33.h"
#include "ra8_attributes.h"
#include "ra8_boot_entry.h"
#include "ra8_dual_core.h"
#include "ra8_err.h"
#include "ra8_ipc.h"
#include "ra8_isr.h"
#include "ra8_log.h"
#include "ra8_lpm.h"
Include dependency graph for main.c:

Go to the source code of this file.

Enumerations

enum  m85_poll_t : uint32_t {
  k_m85_sig_poll_budget = 10000000UL ,
  k_m85_done_poll_budget = 200000000UL
}
 Bounded iteration limits for the M85 polling loops. More...
enum  m85_banner_t : uint32_t { k_banner_cap = 96U }
 Capacity of the verdict banner the M85 assembles in a stack buffer. More...
enum  m85_hex_t : uint8_t {
  k_hex_nibbles = 8U ,
  k_nibble_bits = 4U ,
  k_nibble_mask = 0x0FU
}
 Constants for formatting a 32-bit value as 8 uppercase hex digits. More...
enum  m85_dec_t : uint8_t {
  k_dec_digits_max = 10U ,
  k_dec_radix = 10U
}
 Constants for formatting a 32-bit value as decimal digits. More...
enum  m85_work_t : uint32_t { k_heavy_work_iters = 256U }
 Bound for the M85's deterministic "heavy next-page work" stand-in. More...
enum  m85_ipc_t : uint8_t { k_ipc_wake_channel = 0U }
 IPC channel the M85 watches for the M33's page-turn wake. More...

Functions

static void banner_append (char *dst, uint32_t *off, uint32_t cap, const char *src)
 Append a NUL-terminated string into a bounded banner buffer.
static void banner_append_hex (char *dst, uint32_t *off, uint32_t cap, uint32_t value)
 Append value as 8 uppercase hex digits into the banner buffer.
static void banner_append_u32 (char *dst, uint32_t *off, uint32_t cap, uint32_t value)
 Append value as decimal digits (no leading zeros) into the banner.
static void prep_mailbox (volatile erm33_mailbox_t *mb)
 Publish the shared mailbox and stamp its magic before release.
static bool wait_for_m33_sig (const volatile erm33_mailbox_t *mb)
 Poll the mailbox until the M33 stamps its boot signature.
static bool wait_for_done (const volatile erm33_mailbox_t *mb)
 Poll the mailbox until the M33 publishes its held page (done).
static bool verify_page (const volatile erm33_mailbox_t *mb)
 Validate the M33's published held-page descriptor.
static void emit_verdict (uint32_t crc, bool pass)
 Assemble and log the single deterministic verdict banner.
static void ipc_wake_handler (void *ctx, uint8_t channel, ra8_ipc_irq_event_id_t event_id)
 IPC0 receive event callback: record that a page-turn poke arrived.
static void ipc0_receive_isr (void *ctx)
 IPC0 receive ISR trampoline: decode the channel's pending events.
static bool arm_ipc_wake (void)
 Arm the IPC0 receive interrupt so the M85 can WFI-wake on a page turn.
static void m85_lpm_configure (void)
 Configure the LPM block once so a plain WFI is a CPU Sleep.
static void m85_gate_hoco (bool stop)
 Gate or restore the HOCO via the LPM clock-stop matrix (CGC OCR write).
static bool m85_wait_turn (const volatile erm33_mailbox_t *mb, uint32_t turn)
 Park in Sleep-mode WFI until the M33 requests page turn turn.
static uint32_t m85_heavy_work (uint32_t turn)
 Deterministic stand-in for the M85's heavy next-page work.
static bool m85_wait_turn_done (const volatile erm33_mailbox_t *mb, uint32_t turn)
 Bounded-poll the mailbox until the M33 republishes through turn.
static bool run_handoff_cycle (volatile erm33_mailbox_t *mb)
 Run the #150 mode-switch cycle: park, wake on a page turn, repeat.
static void emit_cycle_verdict (const volatile erm33_mailbox_t *mb, bool pass)
 Assemble and log the single deterministic handoff-cycle verdict banner.
static void run_mode_switch (volatile erm33_mailbox_t *mb)
 Run the #150 mode-switch and log its verdict.
static void park_low_power (void)
 Park the M85 in low-power WFI after the M33 owns the page.
static void park_forever (void)
 Park the M85 forever after an unrecoverable startup failure.
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.
static volatile bool s_m33_woke
 Set by the IPC0 receive callback when the M33 signals a page turn.

Detailed Description

CPU0 (Cortex-M85 primary core) driver for the e-reader-on-M33 demo.

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

This is the firmware that runs on the RA8D2's primary core, the Cortex-M85, out of reset. It demonstrates the #150 power-saving model: an e-reader spends almost all its time idle on a rendered page, so handing that held page to the M33 @ 250 MHz – while the M85 @ 1 GHz sleeps – is the high-leverage battery win. "Power saving = drop to the slow core."

What the M85 does here:

  1. Publishes the progress mailbox (see ereader_m33.h) and stamps its magic so the M33 trusts it, and arms the IPC0 receive IRQ so a later page-turn poke from the M33 can wake it out of WFI.
  2. Releases the Cortex-M33 with ra8_cpu1_release (HUM Ch 2.9.1) into the reader, confirms it booted (signature), then waits for the M33 to render and publish one held page.
  3. Reads back the M33's published framebuffer descriptor – SDRAM base, RGB565 geometry, glyph count and the CRC-32 the M33 folded over the rendered pixels – validates it, and logs a single deterministic banner "ereader_m33: rgb565 256x64 sdram crc=<8 hex> PASS". ra8_emulator echoes only the primary core's ITM, so the M85 speaks for the M33.
  4. Runs the #150 MODE-SWITCH cycle k_erm33_max_turns times: it PARKS – writes the CGC clock-gate (an LPM clock-stop) and drops into Sleep-mode WFI – handing the live core to the slow M33, which holds the page and polls a (fake) touch. On a page turn the M33 pokes IPC0 and the M85 wakes, does the "heavy" next-page work the 1 GHz core owns, acknowledges, and re-parks. It logs the handoff verdict, then parks for good.

Why the M85 reports the M33's CRC rather than re-CRCing the framebuffer: on the ra8_emulator the two cores share only the on-chip SRAM mailbox; each core's external-SDRAM window is a separate mapping, so the parked M85 cannot read the bytes the M33 wrote at 0x68000000. The M33 reads its own SDRAM framebuffer back to fold the CRC (the proof the pixels landed) and publishes it through the shared mailbox; the M85 narrates that value. On silicon the single physical SDRAM is shared, so an M85 re-read would match.

Note
ra8_log_info is compiled to a no-op unless the build defines INFO-level logging (a Debug build). just apps::emulator::run ereader_m33 builds Debug so [itm] lines appear; a release build runs the same logic but stays silent.
Since
0.1.0

Definition in file main.c.

Enumeration Type Documentation

◆ m85_banner_t

enum m85_banner_t : uint32_t

Capacity of the verdict banner the M85 assembles in a stack buffer.

Since
0.1.0
Enumerator
k_banner_cap 

Bytes reserved for the assembled verdict line.

Definition at line 89 of file main.c.

◆ m85_dec_t

enum m85_dec_t : uint8_t

Constants for formatting a 32-bit value as decimal digits.

Since
0.1.0
Enumerator
k_dec_digits_max 

Decimal digits in a 32-bit value (4294967295).

k_dec_radix 

Base-10 radix for the digit extraction.

Definition at line 109 of file main.c.

◆ m85_hex_t

enum m85_hex_t : uint8_t

Constants for formatting a 32-bit value as 8 uppercase hex digits.

Since
0.1.0
Enumerator
k_hex_nibbles 

Hex digits in a 32-bit value.

k_nibble_bits 

Bits per hex nibble.

k_nibble_mask 

Low-nibble mask.

Definition at line 98 of file main.c.

◆ m85_ipc_t

enum m85_ipc_t : uint8_t

IPC channel the M85 watches for the M33's page-turn wake.

The M33 (CPU1) pokes IPC0 channel 0 (the CPU1 -> CPU0 receive direction); the M85 arms this channel's IRQ-line-0 receive event so a page-turn poke wakes it out of Sleep-mode WFI – the same #149 wake path the sibling compile_on_m33 driver uses for compile-done.

Since
0.1.0
Enumerator
k_ipc_wake_channel 

IPC0 channel 0 (CPU1 -> CPU0 receive side).

Definition at line 435 of file main.c.

◆ m85_poll_t

enum m85_poll_t : uint32_t

Bounded iteration limits for the M85 polling loops.

Large enough that a normally-running M33 always completes within budget, yet finite so the M85 never hangs if the M33 does not boot. ra8_emulator runs cpu0 in 500k-instruction chunks and cpu1 in 100k chunks between them, so the M33's render lands in a few dozen interleaves – far inside these budgets.

Since
0.1.0
Enumerator
k_m85_sig_poll_budget 

Max iters waiting for M33 signature.

k_m85_done_poll_budget 

Max iters waiting for M33 done flag.

Definition at line 79 of file main.c.

◆ m85_work_t

enum m85_work_t : uint32_t

Bound for the M85's deterministic "heavy next-page work" stand-in.

The on-wake compute the 1 GHz core owns on a page turn (pagination, decompression) is modelled here as a fixed-count integer fold so the ra8_emulator cycle stays deterministic; the bound keeps it short.

Since
0.1.0
Enumerator
k_heavy_work_iters 

Iterations of the placeholder next-page fold.

Definition at line 122 of file main.c.

Function Documentation

◆ arm_ipc_wake()

bool arm_ipc_wake ( void )
static

Arm the IPC0 receive interrupt so the M85 can WFI-wake on a page turn.

Initialises the ISR substrate, configures IPC0 channel 0 for the IRQ-line-0 event, attaches ipc_wake_handler, routes the k_ra8_ipc_elc_event_irq0 ELC event to ipc0_receive_isr through the NVIC, then unmasks interrupts globally. Each step is its own guarded return so the failing stage is unambiguous (no compound decisions).

Returns
Whether the wake path was fully armed.
Return values
trueIPC0 RX IRQ is routed, attached, and interrupts are enabled.
falseA setup stage failed; the caller falls back to a bounded poll.
Precondition
Called once during M85 bring-up, before ra8_cpu1_release.
Interrupts are not yet globally enabled.
Postcondition
On true, an IPC0 channel-0 poke vectors into ipc0_receive_isr.
On true, PRIMASK is clear (interrupts globally enabled).
Note
Single-threaded boot context; not reentrant.
Since
0.1.0

Definition at line 519 of file main.c.

References ipc0_receive_isr(), ipc_wake_handler(), k_ipc_wake_channel, k_ra8_ipc_elc_event_irq0, k_ra8_ipc_event_irq0, k_ra8_ipc_irq_event_0, k_ra8_isr_prio_default, k_ra8_ok, ra8_ipc_attach_event_handler(), ra8_ipc_init(), ra8_isr_globals_enable(), ra8_isr_init(), and ra8_isr_register().

◆ banner_append()

void banner_append ( char * dst,
uint32_t * off,
uint32_t cap,
const char * src )
static

Append a NUL-terminated string into a bounded banner buffer.

Parameters
[in,out]dstDestination buffer (never NULL).
[in,out]offIn/out write offset; advanced by the bytes copied.
[in]capCapacity of dst (one byte reserved for the final NUL).
[in]srcSource string (never NULL).
Returns
Nothing.
Precondition
dst, off and src are non-NULL; *off < cap.
cap is the true size of dst.
Postcondition
*off <= cap - 1 and dst[*off] is the terminating NUL.
Iteration bounded by cap (NASA Rule 2).
Note
Single-threaded; boot context only.
Since
0.1.0

Definition at line 144 of file main.c.

References k_banner_cap, and RA8_LOOP_BOUND.

Referenced by emit_cycle_verdict(), and emit_verdict().

◆ banner_append_hex()

void banner_append_hex ( char * dst,
uint32_t * off,
uint32_t cap,
uint32_t value )
static

Append value as 8 uppercase hex digits into the banner buffer.

Parameters
[in,out]dstDestination buffer (never NULL).
[in,out]offIn/out write offset; advanced by up to 8.
[in]capCapacity of dst.
[in]value32-bit value to format big-endian (MSB nibble first).
Returns
Nothing.
Precondition
dst and off are non-NULL; *off < cap.
cap is the true size of dst.
Postcondition
*off <= cap - 1.
Iteration bounded by k_hex_nibbles (NASA Rule 2).
Note
Single-threaded; boot context only.
Since
0.1.0

Definition at line 188 of file main.c.

References k_hex_nibbles, k_nibble_bits, k_nibble_mask, and RA8_LOOP_BOUND.

Referenced by emit_cycle_verdict(), and emit_verdict().

◆ banner_append_u32()

void banner_append_u32 ( char * dst,
uint32_t * off,
uint32_t cap,
uint32_t value )
static

Append value as decimal digits (no leading zeros) into the banner.

Extracts the decimal digits least-significant first into a small scratch array, then copies them back most-significant first. A lone 0 prints as "0". Both passes are bounded by k_dec_digits_max (NASA Rule 2).

Parameters
[in,out]dstDestination buffer (never NULL).
[in,out]offIn/out write offset; advanced by the digits copied.
[in]capCapacity of dst.
[in]value32-bit value to format in base 10.
Returns
Nothing.
Precondition
dst and off are non-NULL; *off < cap.
cap is the true size of dst.
Postcondition
*off <= cap - 1.
Both loops are bounded by k_dec_digits_max (NASA Rule 2).
Note
Single-threaded; boot context only.
Since
0.1.0

Definition at line 231 of file main.c.

References k_dec_digits_max, k_dec_radix, and RA8_LOOP_BOUND.

Referenced by emit_cycle_verdict().

◆ emit_cycle_verdict()

void emit_cycle_verdict ( const volatile erm33_mailbox_t * mb,
bool pass )
static

Assemble and log the single deterministic handoff-cycle verdict banner.

Emits "ereader_m33: handoff turns=<n> crc=<8 hex> PARKED" on success, narrating the M33's re-render count (turn_done) and the stable framebuffer CRC the M33 re-folded on every page turn. The ra8_emulator gate greps this line.

Parameters
[in]mbPointer to the shared mailbox (never NULL).
[in]passWhether the full cycle completed and the re-render published.
Returns
Nothing.
Precondition
ra8_log_init has run (the banner reaches ITM in a Debug build).
mb is the fixed-address mailbox pointer.
Postcondition
Exactly one banner line is emitted.
No shared state is modified.
Note
The gate asserts both this banner and the page-0 verdict from emit_verdict to prove the whole park / wake / re-render cycle ran.
Since
0.1.0

Definition at line 784 of file main.c.

References banner_append(), banner_append_hex(), banner_append_u32(), erm33_mailbox_t::fb_crc, k_banner_cap, ra8_log_info, and erm33_mailbox_t::turn_done.

Referenced by run_mode_switch().

◆ emit_verdict()

void emit_verdict ( uint32_t crc,
bool pass )
static

Assemble and log the single deterministic verdict banner.

Parameters
[in]crcThe CRC-32 the M33 published over its rendered pixels.
[in]passWhether verify_page accepted the held page.
Returns
Nothing.
Precondition
ra8_log_init has run (the banner reaches ITM in a Debug build).
crc is the value read from the mailbox.
Postcondition
Exactly one banner line is emitted.
No shared state is modified.
Note
The ra8_emulator gate greps this line for crc=<hex> and the verdict word.
Since
0.1.0

Definition at line 416 of file main.c.

References banner_append(), banner_append_hex(), k_banner_cap, and ra8_log_info.

Referenced by main().

◆ ipc0_receive_isr()

void ipc0_receive_isr ( void * ctx)
static

IPC0 receive ISR trampoline: decode the channel's pending events.

Parameters
[in]ctxUnused registration context.
Returns
Nothing.
Precondition
Registered for k_ra8_ipc_elc_event_irq0 via ra8_isr_register.
The NVIC line for the IPC0 receive event is enabled.
Postcondition
Any pending IPC0 channel-0 IRQ line has been dispatched and cleared.
ipc_wake_handler has run for each pending line.
Note
Runs in NVIC handler-mode; forwards to the HAL dispatcher.
Since
0.1.0

Definition at line 492 of file main.c.

References k_ipc_wake_channel, and ra8_ipc_dispatch().

◆ ipc_wake_handler()

void ipc_wake_handler ( void * ctx,
uint8_t channel,
ra8_ipc_irq_event_id_t event_id )
static

IPC0 receive event callback: record that a page-turn poke arrived.

Parameters
[in]ctxUnused registration context.
[in]channelChannel that fired (always k_ipc_wake_channel here).
[in]event_idIRQ line that fired (always line 0 here).
Returns
Nothing.
Precondition
Attached to IPC channel 0 IRQ line 0 via ra8_ipc_attach_event_handler.
Runs in IPC IRQ handler context (invoked from ra8_ipc_dispatch).
Postcondition
s_m33_woke reads true.
No other state is modified.
Note
ISR context; touches only the one volatile flag.
Since
0.1.0

Definition at line 469 of file main.c.

References s_m33_woke.

◆ m85_gate_hoco()

void m85_gate_hoco ( bool stop)
static

Gate or restore the HOCO via the LPM clock-stop matrix (CGC OCR write).

The M85 e-reader runs on its boot clock and never needs the high-speed on-chip oscillator while it is parked, so the park writes HOCOCR.HCSTP through ra8_lpm_set_clock_stop to model the power drop, and the wake clears it again. This is the "CGC clock-gate / down-clock" register write the #150 model calls for: real on silicon, routed to ra8_emulator's catch-all in the emulator so it neither faults nor changes the run.

Parameters
[in]stoptrue – gate the HOCO (park); false – restore it (wake).
Returns
Nothing.
Precondition
Called from single-threaded main context with the M33 already released.
The ra8_lpm HAL owns the HUM citation for the OCR write.
Postcondition
On a successful PRCR unlock, HOCOCR.HCSTP reflects stop.
PRCR.PRC1 is re-locked.
Note
Not thread-safe; the unlock / write / relock is one critical section.
Since
0.1.0

Definition at line 604 of file main.c.

References k_ra8_lpm_clock_hoco, k_ra8_ok, ra8_lpm_prcr_relock(), ra8_lpm_prcr_unlock(), and ra8_lpm_set_clock_stop().

Referenced by park_low_power(), and run_handoff_cycle().

◆ m85_heavy_work()

uint32_t m85_heavy_work ( uint32_t turn)
static

Deterministic stand-in for the M85's heavy next-page work.

Folds a fixed k_heavy_work_iters-count integer sum seeded by the turn number. On a real e-reader this is where the 1 GHz core does the genuinely heavy page work – paginating / decompressing the next chapter – that justifies waking it from the slow-core hold. Here it is a bounded, side-effect-free computation so the ra8_emulator cycle stays byte-deterministic; the rendered page content is unchanged, so the framebuffer CRC the M33 re-folds stays stable.

Parameters
[in]turnThe page-turn number being serviced (the work seed).
Returns
A deterministic fold of turn (logged as proof the work ran).
Return values
(value)turn + sum(0 .. k_heavy_work_iters-1).
Precondition
turn is a 1-based page-turn index.
Runs in thread mode on the woken M85, interrupts enabled.
Postcondition
No shared state is modified.
Iteration count bounded by k_heavy_work_iters (NASA Rule 2).
Note
Pure; placeholder for the real pagination work (a HIL follow-up).
Since
0.1.0

Definition at line 672 of file main.c.

References k_heavy_work_iters, and RA8_LOOP_BOUND.

Referenced by run_handoff_cycle().

◆ m85_lpm_configure()

void m85_lpm_configure ( void )
static

Configure the LPM block once so a plain WFI is a CPU Sleep.

Unlocks PRCR.PRC1, writes SBYCR / DPSBYCR / SSCR1 and clears LPSCR to System-Active via ra8_lpm_init, then re-locks PRCR. With LPMD = 0 the M85's WFI is an ordinary CPU Sleep – peripherals (and the M33) keep their clocks, so the armed IPC0 receive IRQ still wakes the core. Deeper modes (Software Standby) would stop the M33 too, which is wrong for this hand-off cycle.

Returns
Nothing.
Precondition
Called once during M85 bring-up, single-threaded.
The ra8_lpm HAL owns the HUM citations for these SYSC writes.
Postcondition
LPSCR.LPMD == 0 (the next WFI is a plain CPU Sleep).
PRCR.PRC1 is re-locked.
Note
ra8_emulator routes these SYSC writes to its catch-all (no fault); on silicon they are the real LPM register writes.
Since
0.1.0

Definition at line 570 of file main.c.

References k_ra8_ok, ra8_lpm_init(), ra8_lpm_prcr_relock(), and ra8_lpm_prcr_unlock().

Referenced by main().

◆ m85_wait_turn()

bool m85_wait_turn ( const volatile erm33_mailbox_t * mb,
uint32_t turn )
static

Park in Sleep-mode WFI until the M33 requests page turn turn.

Each iteration checks the mailbox turn_req and, if the requested turn has not yet arrived, issues a wfi. The M33's page-turn poke of IPC0ISET0 raises the armed IPC0 receive interrupt (see arm_ipc_wake), which wakes the core; the loop then observes the turn_req the M33 ordered ahead of the poke. The bounded count is the NASA Rule 2 backstop for a missed wake.

Parameters
[in]mbPointer to the shared mailbox (never NULL).
[in]turnThe page-turn number this park is waiting for (1-based).
Returns
Whether turn_req reached turn within budget.
Return values
trueturn_req >= turn within k_m85_done_poll_budget iterations.
falsePoll budget exhausted before the request arrived.
Precondition
mb is the fixed-address mailbox pointer.
arm_ipc_wake armed the IPC0 receive IRQ and enabled interrupts.
Postcondition
No mailbox field is modified.
Iteration count bounded by k_m85_done_poll_budget (NASA Rule 2).
Note
The M85 sleeps in WFI between wakes – this is the low-power yield point.
Since
0.1.0

Definition at line 637 of file main.c.

References k_m85_done_poll_budget, RA8_LOOP_BOUND, and erm33_mailbox_t::turn_req.

Referenced by run_handoff_cycle().

◆ m85_wait_turn_done()

bool m85_wait_turn_done ( const volatile erm33_mailbox_t * mb,
uint32_t turn )
static

Bounded-poll the mailbox until the M33 republishes through turn.

After the M85 acknowledges the final turn the M33 re-renders and sets turn_done; the M85 reads that back to narrate the cycle verdict. The M33 does not poke IPC for turn_done (only for turn_req), so this is a plain bounded poll, not a WFI wait – the M33 is actively re-rendering, so it settles quickly.

Parameters
[in]mbPointer to the shared mailbox (never NULL).
[in]turnThe re-render generation to wait for (1-based).
Returns
Whether turn_done reached turn within budget.
Return values
trueturn_done >= turn within k_m85_done_poll_budget iterations.
falsePoll budget exhausted before the re-render published.
Precondition
mb is the fixed-address mailbox pointer.
The M85 has acknowledged turn via turn_ack.
Postcondition
No mailbox field is modified.
Iteration count bounded by k_m85_done_poll_budget (NASA Rule 2).
Note
Not thread-safe; single-threaded main context.
Since
0.1.0

Definition at line 705 of file main.c.

References k_m85_done_poll_budget, RA8_LOOP_BOUND, and erm33_mailbox_t::turn_done.

Referenced by run_mode_switch().

◆ main()

void main ( void )

CPU0 (Cortex-M85) application entry.

The application entry point Reset_Handler hands control to.

Publishes the mailbox, arms the IPC0 wake and configures the LPM block, releases the Cortex-M33 into the reader, waits for the first held page, logs the page-0 verdict, then runs the #150 mode-switch cycle – parking in low-power WFI and waking on the M33's page-turn pokes – before logging the handoff verdict and parking for good. See the file header for the narrative.

Precondition
SystemInit has completed core bring-up.
The M33 is held inactive by hardware until released here.
Postcondition
The M33 has rendered + re-rendered the held page and the M85 is parked.
This function never returns to its caller.
Note
Single-threaded; no RTOS on the M85 in this example.
Since
0.1.0

Definition at line 901 of file main.c.

References arm_ipc_wake(), emit_verdict(), erm33_mailbox(), erm33_mailbox_t::fb_base, erm33_mailbox_t::fb_crc, g_ra8_ls_cpu1_mram_start, g_ra8_ls_cpu1_stack_top, erm33_mailbox_t::glyph_count, k_ra8_ok, m85_lpm_configure(), park_forever(), park_low_power(), prep_mailbox(), ra8_cpu1_release(), ra8_log_info, ra8_log_info_val, ra8_log_init(), run_mode_switch(), verify_page(), wait_for_done(), and wait_for_m33_sig().

◆ park_forever()

void park_forever ( void )
static

Park the M85 forever after an unrecoverable startup failure.

Returns
This function never returns.
Note
The core spins in place.
Precondition
A fatal error (e.g. CPU1 release failure) has occurred and been logged.
Postcondition
The M85 makes no further forward progress.
No mailbox state changes.
Note
Distinct from park_low_power: this is an error halt, not low power.
Since
0.1.0

Definition at line 877 of file main.c.

◆ park_low_power()

void park_low_power ( void )
static

Park the M85 in low-power WFI after the M33 owns the page.

Returns
This function never returns.
Note
The M85 sleeps until power-off (or a future M33 wake IRQ).
Precondition
The handoff cycle has completed and the verdict was logged.
The verdict banner has already been emitted.
Postcondition
The HOCO is gated and the M85 spends its time in WFI (the power win).
No mailbox field is modified.
Note
The final park gates the clock once and WFIs for good; the held page now lives on the M33 with no further page turns scripted.
Since
0.1.0

Definition at line 855 of file main.c.

References m85_gate_hoco(), and ra8_log_info.

Referenced by main().

◆ prep_mailbox()

void prep_mailbox ( volatile erm33_mailbox_t * mb)
static

Publish the shared mailbox and stamp its magic before release.

Parameters
[out]mbPointer to the shared mailbox (never NULL).
Returns
Nothing.
Precondition
mb is the fixed-address mailbox pointer.
Called before ra8_cpu1_release so the M33 sees a live mailbox.
Postcondition
All progress fields read back as 0 and status is running.
magic holds k_erm33_magic after a dsb published the zeros first.
Note
Single owner (M85) at this point; no concurrency.
Since
0.1.0

Definition at line 276 of file main.c.

References erm33_mailbox_t::done, erm33_mailbox_t::fb_base, erm33_mailbox_t::fb_crc, erm33_mailbox_t::fb_format, erm33_mailbox_t::fb_height, erm33_mailbox_t::fb_stride, erm33_mailbox_t::fb_width, erm33_mailbox_t::glyph_count, k_erm33_magic, k_erm33_status_running, erm33_mailbox_t::m33_sig, erm33_mailbox_t::magic, erm33_mailbox_t::status, erm33_mailbox_t::turn_ack, erm33_mailbox_t::turn_done, and erm33_mailbox_t::turn_req.

◆ run_handoff_cycle()

bool run_handoff_cycle ( volatile erm33_mailbox_t * mb)
static

Run the #150 mode-switch cycle: park, wake on a page turn, repeat.

For each of k_erm33_max_turns turns the M85 gates the HOCO and parks in Sleep-mode WFI (m85_wait_turn), wakes on the M33's IPC poke, restores the HOCO, does the heavy next-page work (m85_heavy_work), and acknowledges by writing turn_ack behind a dsb so the M33 sees a settled ack before it re-renders. A wake-timeout aborts the cycle. The outer loop is bounded by k_erm33_max_turns (NASA Rule 2).

Parameters
[in,out]mbPointer to the shared mailbox (never NULL).
Returns
Whether every page turn was serviced and acknowledged.
Return values
trueAll k_erm33_max_turns turns were woken and acked.
falsemb was NULL, or a park timed out before a request arrived.
Precondition
mb is the fixed-address mailbox pointer with the first page held.
arm_ipc_wake and m85_lpm_configure have run.
Postcondition
On true, turn_ack == k_erm33_max_turns.
The HOCO is restored (un-gated) on return.
Note
Single-threaded; the WFI inside m85_wait_turn is the yield point.
Since
0.1.0

Definition at line 740 of file main.c.

References k_erm33_max_turns, m85_gate_hoco(), m85_heavy_work(), m85_wait_turn(), ra8_log_info_val, RA8_LOOP_BOUND, and erm33_mailbox_t::turn_ack.

Referenced by run_mode_switch().

◆ run_mode_switch()

void run_mode_switch ( volatile erm33_mailbox_t * mb)
static

Run the #150 mode-switch and log its verdict.

Drives the park / wake / re-render cycle (run_handoff_cycle), waits for the M33's final re-render (m85_wait_turn_done), and emits the handoff verdict. Each guard is its own if (no compound boolean decision, so no MC/DC obligation); the verdict is true only when every turn completed and the M33 republished a non-zero CRC.

Parameters
[in,out]mbPointer to the shared mailbox (never NULL).
Returns
Nothing.
Precondition
mb is the fixed-address mailbox pointer with the first page held.
arm_ipc_wake and m85_lpm_configure have run.
Postcondition
Exactly one handoff verdict banner is emitted.
On a full cycle, turn_done == k_erm33_max_turns.
Note
Single-threaded; the WFI inside the cycle is the low-power yield point.
Since
0.1.0

Definition at line 820 of file main.c.

References emit_cycle_verdict(), erm33_mailbox_t::fb_crc, k_erm33_max_turns, m85_wait_turn_done(), ra8_log_info, and run_handoff_cycle().

Referenced by main().

◆ verify_page()

bool verify_page ( const volatile erm33_mailbox_t * mb)
static

Validate the M33's published held-page descriptor.

Confirms the render succeeded and that every published field is self-consistent: the framebuffer base lies inside the SDRAM window, the geometry equals erm33_fb_geom_t, the format is RGB565, and the glyph count and CRC are non-zero (a blank or absent render publishes neither).

Parameters
[in]mbPointer to the shared mailbox (never NULL).
Returns
Whether the M33 published a valid held page.
Return values
truestatus ok and every descriptor field is consistent.
falseAny check failed.
Precondition
mb is the fixed-address mailbox pointer and done == 1.
A dsb has ordered the M33's publish before the M85's read.
Postcondition
No mailbox field is modified.
The return value gates the PASS / FAIL banner.
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 375 of file main.c.

References erm33_mailbox_t::fb_base, erm33_mailbox_t::fb_crc, erm33_mailbox_t::fb_format, erm33_mailbox_t::fb_height, erm33_mailbox_t::fb_stride, erm33_mailbox_t::fb_width, erm33_mailbox_t::glyph_count, k_erm33_fb_format_rgb565, k_erm33_fb_height, k_erm33_fb_stride, k_erm33_fb_width, k_erm33_sdram_base, k_erm33_sdram_end, k_erm33_status_ok, and erm33_mailbox_t::status.

Referenced by main().

◆ wait_for_done()

bool wait_for_done ( const volatile erm33_mailbox_t * mb)
static

Poll the mailbox until the M33 publishes its held page (done).

Parameters
[in]mbPointer to the shared mailbox (never NULL).
Returns
Whether done reached 1 within budget.
Return values
truedone == 1 within k_m85_done_poll_budget iterations.
falsePoll budget exhausted before done was set.
Precondition
mb is the fixed-address mailbox pointer.
The M33 has been confirmed alive via wait_for_m33_sig.
Postcondition
No mailbox field is modified.
Iteration count bounded by k_m85_done_poll_budget (NASA Rule 2).
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 342 of file main.c.

References erm33_mailbox_t::done, k_m85_done_poll_budget, and RA8_LOOP_BOUND.

◆ wait_for_m33_sig()

bool wait_for_m33_sig ( const volatile erm33_mailbox_t * mb)
static

Poll the mailbox until the M33 stamps its boot signature.

Parameters
[in]mbPointer to the shared mailbox (never NULL).
Returns
Whether the M33 boot signature appeared within budget.
Return values
truem33_sig == k_erm33_m33_sig within k_m85_sig_poll_budget.
falsePoll budget exhausted before the signature appeared.
Precondition
mb is the fixed-address mailbox pointer.
The M85 has already called ra8_cpu1_release.
Postcondition
No mailbox field is modified.
Iteration count bounded by k_m85_sig_poll_budget (NASA Rule 2).
Note
Not thread-safe; single-threaded boot context.
Since
0.1.0

Definition at line 314 of file main.c.

References k_erm33_m33_sig, k_m85_sig_poll_budget, erm33_mailbox_t::m33_sig, and RA8_LOOP_BOUND.

Variable Documentation

◆ 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_m33_woke

volatile bool s_m33_woke
static

Set by the IPC0 receive callback when the M33 signals a page turn.

Diagnostic wake hint only; the authoritative exit condition for the WFI wait remains the mailbox turn_req field, which the M33 orders (with a dsb) ahead of its IPC poke, so a wake always observes a settled request.

Note
Written from IPC IRQ context, read in thread context – hence volatile.
Warning
Not the completion signal; it only proves the wake fired.
Since
0.1.0

Definition at line 450 of file main.c.