|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
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"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. | |
CPU0 (Cortex-M85 primary core) driver for the e-reader-on-M33 demo.
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:
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.
Definition in file main.c.
| enum m85_banner_t : uint32_t |
| enum m85_dec_t : uint8_t |
| enum m85_hex_t : uint8_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.
| Enumerator | |
|---|---|
| k_ipc_wake_channel | IPC0 channel 0 (CPU1 -> CPU0 receive side). |
| 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.
| Enumerator | |
|---|---|
| k_m85_sig_poll_budget | Max iters waiting for M33 signature. |
| k_m85_done_poll_budget | Max iters waiting for M33 done flag. |
| 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.
| Enumerator | |
|---|---|
| k_heavy_work_iters | Iterations of the placeholder next-page fold. |
|
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).
| true | IPC0 RX IRQ is routed, attached, and interrupts are enabled. |
| false | A setup stage failed; the caller falls back to a bounded poll. |
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().
|
static |
Append a NUL-terminated string into a bounded banner buffer.
| [in,out] | dst | Destination buffer (never NULL). |
| [in,out] | off | In/out write offset; advanced by the bytes copied. |
| [in] | cap | Capacity of dst (one byte reserved for the final NUL). |
| [in] | src | Source string (never NULL). |
dst, off and src are non-NULL; *off < cap. cap is the true size of dst. cap (NASA Rule 2).Definition at line 144 of file main.c.
References k_banner_cap, and RA8_LOOP_BOUND.
Referenced by emit_cycle_verdict(), and emit_verdict().
|
static |
Append value as 8 uppercase hex digits into the banner buffer.
| [in,out] | dst | Destination buffer (never NULL). |
| [in,out] | off | In/out write offset; advanced by up to 8. |
| [in] | cap | Capacity of dst. |
| [in] | value | 32-bit value to format big-endian (MSB nibble first). |
dst and off are non-NULL; *off < cap. cap is the true size of dst. 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().
|
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).
| [in,out] | dst | Destination buffer (never NULL). |
| [in,out] | off | In/out write offset; advanced by the digits copied. |
| [in] | cap | Capacity of dst. |
| [in] | value | 32-bit value to format in base 10. |
dst and off are non-NULL; *off < cap. cap is the true size of dst. 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().
|
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.
| [in] | mb | Pointer to the shared mailbox (never NULL). |
| [in] | pass | Whether the full cycle completed and the re-render published. |
mb is the fixed-address mailbox pointer. 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().
|
static |
Assemble and log the single deterministic verdict banner.
| [in] | crc | The CRC-32 the M33 published over its rendered pixels. |
| [in] | pass | Whether verify_page accepted the held page. |
crc is the value read from the mailbox. Definition at line 416 of file main.c.
References banner_append(), banner_append_hex(), k_banner_cap, and ra8_log_info.
Referenced by main().
|
static |
IPC0 receive ISR trampoline: decode the channel's pending events.
| [in] | ctx | Unused registration context. |
Definition at line 492 of file main.c.
References k_ipc_wake_channel, and ra8_ipc_dispatch().
|
static |
IPC0 receive event callback: record that a page-turn poke arrived.
| [in] | ctx | Unused registration context. |
| [in] | channel | Channel that fired (always k_ipc_wake_channel here). |
| [in] | event_id | IRQ line that fired (always line 0 here). |
Definition at line 469 of file main.c.
References s_m33_woke.
|
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.
| [in] | stop | true – gate the HOCO (park); false – restore it (wake). |
stop. 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().
|
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.
| [in] | turn | The page-turn number being serviced (the work seed). |
turn (logged as proof the work ran). | (value) | turn + sum(0 .. k_heavy_work_iters-1). |
turn is a 1-based page-turn index. Definition at line 672 of file main.c.
References k_heavy_work_iters, and RA8_LOOP_BOUND.
Referenced by run_handoff_cycle().
|
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.
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().
|
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.
| [in] | mb | Pointer to the shared mailbox (never NULL). |
| [in] | turn | The page-turn number this park is waiting for (1-based). |
turn within budget. | true | turn_req >= turn within k_m85_done_poll_budget iterations. |
| false | Poll budget exhausted before the request arrived. |
mb is the fixed-address mailbox pointer. 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().
|
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.
| [in] | mb | Pointer to the shared mailbox (never NULL). |
| [in] | turn | The re-render generation to wait for (1-based). |
turn within budget. | true | turn_done >= turn within k_m85_done_poll_budget iterations. |
| false | Poll budget exhausted before the re-render published. |
mb is the fixed-address mailbox pointer. turn via turn_ack. 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().
| 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.
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().
|
static |
Park the M85 forever after an unrecoverable startup failure.
|
static |
Park the M85 in low-power WFI after the M33 owns the page.
Definition at line 855 of file main.c.
References m85_gate_hoco(), and ra8_log_info.
Referenced by main().
|
static |
Publish the shared mailbox and stamp its magic before release.
| [out] | mb | Pointer to the shared mailbox (never NULL). |
mb is the fixed-address mailbox pointer. 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.
|
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).
| [in,out] | mb | Pointer to the shared mailbox (never NULL). |
| true | All k_erm33_max_turns turns were woken and acked. |
| false | mb was NULL, or a park timed out before a request arrived. |
mb is the fixed-address mailbox pointer with the first page held. 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().
|
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.
| [in,out] | mb | Pointer to the shared mailbox (never NULL). |
mb is the fixed-address mailbox pointer with the first page held. 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().
|
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).
| [in] | mb | Pointer to the shared mailbox (never NULL). |
| true | status ok and every descriptor field is consistent. |
| false | Any check failed. |
mb is the fixed-address mailbox pointer and done == 1. 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().
|
static |
Poll the mailbox until the M33 publishes its held page (done).
| [in] | mb | Pointer to the shared mailbox (never NULL). |
| true | done == 1 within k_m85_done_poll_budget iterations. |
| false | Poll budget exhausted before done was set. |
mb is the fixed-address mailbox pointer. Definition at line 342 of file main.c.
References erm33_mailbox_t::done, k_m85_done_poll_budget, and RA8_LOOP_BOUND.
|
static |
Poll the mailbox until the M33 stamps its boot signature.
| [in] | mb | Pointer to the shared mailbox (never NULL). |
| true | m33_sig == k_erm33_m33_sig within k_m85_sig_poll_budget. |
| false | Poll budget exhausted before the signature appeared. |
mb is the fixed-address mailbox pointer. 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.
|
extern |
Base of the embedded M33 image / its vector table (MRAM_CPU1).
|
extern |
Initial stack pointer handed to the M33 at release.
|
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.