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: stage an EPUB, offload its compile to the M33. More...

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "book.h"
#include "compile_on_m33.h"
#include "parity_fixture.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 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 = 50000000UL
}
 Bounded iteration limits for the M85 polling loops. More...
enum  m85_ipc_t : uint8_t { k_ipc_wake_channel = 0U }
 IPC channel the M85 watches for the M33's compile-done wake. More...

Functions

static void ipc_wake_handler (void *ctx, uint8_t channel, ra8_ipc_irq_event_id_t event_id)
 IPC0 receive event callback: record that the M33's wake 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-idle for the M33.
static void prep_mailbox (volatile com33_mailbox_t *mb)
 Publish the mailbox, stage the source .epub, and post the compile job.
static bool wait_for_m33_sig (const volatile com33_mailbox_t *mb)
 Poll the mailbox until the M33 stamps its boot signature.
static bool wait_for_done (const volatile com33_mailbox_t *mb)
 Idle in WFI until the M33's IPC poke signals the done flag.
static bool verify_blob (volatile com33_mailbox_t *mb)
 Validate the M33-emitted blob and cross-check the mailbox report.
static void park_forever (void)
 Park the M85 forever after the verdict (or an unrecoverable 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 compile-done.

Detailed Description

CPU0 (Cortex-M85 primary core) driver: stage an EPUB, offload its compile to the M33.

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

This is the firmware that runs on the RA8D2's primary core, the Cortex-M85, out of reset. It demonstrates the #149 compiler offload: the M85 stages a book and hands the full EPUB->.rabook conversion to the M33 @ 250 MHz, so on a real import the M85 @ 1 GHz stays free to keep the UI live while the slow core grinds.

What the M85 does here:

  1. Publishes the shared mailbox (see compile_on_m33.h), stages the source .epub into shared SRAM, and posts a compile JOB (epub base/len + output buffer) – so the same M33 image compiles whatever the M85 dispatches.
  2. Releases the Cortex-M33 with ra8_cpu1_release (HUM Ch 2.9.1), confirms it booted (signature), then PARKS while the M33 runs the full text/CSS/SVG compile (epub_open -> the pipeline) into the shared output blob.
  3. Once the M33 signals done, the M85 runs book_validate over the blob, cross-checks the reported CRC + chapter count, AND byte-compares it to the desktop/M85 golden – proving the M33 compile is byte-identical. A mismatch traps (bkpt) so ra8_emulator's smoke gate fails the run.

ra8_emulator echoes only the primary core's ITM, so the M85 narrates the whole exchange; the blob it validates can only exist because the M33 ran the compile, so a PASS here proves the conversion ran byte-identically on the second core.

Note
ra8_log_info is compiled to a no-op unless the build defines INFO-level logging (a Debug build). just apps::emulator::run compile_on_m33 builds Debug so the [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_ipc_t

enum m85_ipc_t : uint8_t

IPC channel the M85 watches for the M33's compile-done 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 it can WFI-idle until the poke instead of busy-polling the mailbox.

Since
0.1.0
Enumerator
k_ipc_wake_channel 

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

Definition at line 85 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 finishes the small emit within budget, yet finite so the M85 never hangs if the M33 does not boot. ra8_emulator interleaves the cores in instruction chunks, so the whole emit lands in a few dozen interleaves – far inside these.

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 69 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-idle for the M33.

Initialises the ISR substrate, configures IPC0 channel 0 for the IRQ-line-0 event, attaches ipc_wake_handler to that line, 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 should fall back to polling.
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 170 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().

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 143 of file main.c.

References k_ipc_wake_channel, and ra8_ipc_dispatch().

Referenced by arm_ipc_wake().

◆ 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 the M33's wake 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 120 of file main.c.

References s_m33_woke.

Referenced by arm_ipc_wake().

◆ main()

void main ( void )

CPU0 (Cortex-M85) application entry.

The application entry point Reset_Handler hands control to.

Publishes the mailbox, releases the Cortex-M33 into the emitter, yields until it signals done, validates the blob the M33 built, then logs the PASS/FAIL verdict and the chapter count read back from the blob. See the file header for the offload narrative.

Precondition
SystemInit has completed core bring-up.
The M33 is held inactive by hardware until released here.
Postcondition
The M33 has built a RABOOK1 blob and the M85 has validated it.
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 423 of file main.c.

References arm_ipc_wake(), com33_mailbox_t::blob_len, com33_mailbox_t::chapter_count, com33_mailbox(), g_ra8_ls_cpu1_mram_start, g_ra8_ls_cpu1_stack_top, k_ra8_ok, park_forever(), prep_mailbox(), ra8_cpu1_release(), ra8_log_info, ra8_log_info_val, ra8_log_init(), com33_mailbox_t::status, verify_blob(), wait_for_done(), and wait_for_m33_sig().

◆ park_forever()

void park_forever ( void )
static

Park the M85 forever after the verdict (or an unrecoverable failure).

Returns
This function never returns.
Note
The core spins in place.
Precondition
The verdict (or a fatal error) has already been logged.
Postcondition
The M85 makes no further forward progress.
No shared state changes.
Note
Mirrors the M33 park loop for symmetry.
Since
0.1.0

Definition at line 400 of file main.c.

◆ prep_mailbox()

void prep_mailbox ( volatile com33_mailbox_t * mb)
static

Publish the mailbox, stage the source .epub, and post the compile job.

Zeros the response fields and stamps k_com33_magic, then copies the baked parity fixture .epub into the shared staged-input buffer, fills the request (epub base/len, output base/cap), and stamps k_com33_req_magic LAST behind a dsb so the M33 sees the job only once the staged bytes settle. The M33 compiles whatever is staged, so the same image serves any dispatched book.

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, posted job.
Postcondition
All response fields read back as 0 and status is running.
The staged .epub is in shared SRAM and req_magic holds k_com33_req_magic behind a dsb.
Note
Single owner (M85) at this point; no concurrency.
Since
0.1.0

Definition at line 223 of file main.c.

References com33_mailbox_t::blob_base, com33_mailbox_t::blob_crc, com33_mailbox_t::blob_len, com33_mailbox_t::chapter_count, com33_epub(), com33_mailbox_t::done, com33_mailbox_t::epub_base, com33_mailbox_t::epub_len, k_com33_blob_addr, k_com33_blob_cap, k_com33_epub_addr, k_com33_magic, k_com33_req_magic, k_com33_status_running, k_m33_parity_epub_len, com33_mailbox_t::m33_sig, com33_mailbox_t::magic, memcpy(), com33_mailbox_t::out_base, com33_mailbox_t::out_cap, com33_mailbox_t::req_magic, s_m33_parity_epub, and com33_mailbox_t::status.

Referenced by main().

◆ verify_blob()

bool verify_blob ( volatile com33_mailbox_t * mb)
static

Validate the M33-emitted blob and cross-check the mailbox report.

Confirms the M33 reported success and a plausible blob location, runs book_validate over the shared blob (magic, version, table extents, and the body CRC-32 – an independent recompute that catches any transfer corruption), then cross-checks that the blob header's CRC and chapter count match what the M33 published in the mailbox. Each check is an independent guard (no compound decisions) so the failing condition is unambiguous.

Parameters
[in]mbPointer to the shared mailbox (never NULL, done == 1).
Returns
Whether the M33 produced a well-formed, intact RABOOK1 blob.
Return values
trueStatus ok, blob validated, and CRC + chapter count agree.
falseAny check failed; the blob must not be treated as valid.
Precondition
mb is the fixed-address mailbox pointer and the M33 set done.
The blob bytes are settled (the caller issued a dmb after done).
Postcondition
No mailbox field nor blob byte is modified.
Note
Single-threaded; reads only the immutable published blob.
Since
0.1.0

Definition at line 346 of file main.c.

References com33_mailbox_t::blob_base, com33_mailbox_t::blob_crc, com33_mailbox_t::blob_len, book_header(), book_validate(), book_header_t::chapter_count, com33_mailbox_t::chapter_count, book_header_t::crc32_val, k_com33_blob_addr, k_com33_blob_cap, k_com33_status_ok, k_m33_parity_golden_len, k_ra8_ok, memcmp(), s_m33_parity_golden, and com33_mailbox_t::status.

Referenced by main().

◆ wait_for_done()

bool wait_for_done ( const volatile com33_mailbox_t * mb)
static

Idle in WFI until the M33's IPC poke signals the done flag.

Each iteration checks the mailbox done flag and, if it is not yet set, drops into wfi. The M33's compile-done poke of IPC0ISET0 raises the armed IPC0 receive interrupt (see arm_ipc_wake) which wakes the core; the loop then observes the done 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).
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.
arm_ipc_wake has 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
M85 sleeps in WFI between wakes – this is the yield point.
Since
0.1.0

Definition at line 304 of file main.c.

References com33_mailbox_t::done, k_m85_done_poll_budget, and RA8_LOOP_BOUND.

Referenced by main().

◆ wait_for_m33_sig()

bool wait_for_m33_sig ( const volatile com33_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_com33_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 269 of file main.c.

References k_com33_m33_sig, k_m85_sig_poll_budget, com33_mailbox_t::m33_sig, and RA8_LOOP_BOUND.

Referenced by main().

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 compile-done.

The WFI idle loop reads this only as a diagnostic wake hint; the authoritative exit condition remains the mailbox done flag, which the M33 publishes (and orders with a dsb) before it pokes the IPC, so a wake always observes a settled done.

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

Definition at line 101 of file main.c.

Referenced by ipc_wake_handler().