|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
CPU1 (Cortex-M33 secondary core) image: render a held e-reader page. More...
#include <stdint.h>#include "book.h"#include "ereader_m33.h"#include "ra8_attributes.h"#include "ra8_gfx.h"#include "ra8_ipc.h"#include "rabook_fixture.h"Go to the source code of this file.
Data Structures | |
| struct | m33_walk_stack_t |
| Explicit DOM-walk stack (NASA Rule 1: iteration, never recursion). More... | |
Enumerations | |
| enum | m33_walk_bound_t : uint32_t { k_walk_iter_max = 4096U , k_max_run_len = 1024U } |
| Static iteration bounds for the M33 DOM walk (NASA Rule 2). More... | |
| enum | m33_walk_size_t : uint16_t { k_walk_stack_depth = 64U , k_max_chapters = 32U , k_max_nodes = 4096U , k_magic_len = 7U } |
| Small table / validation sizes for the M33 reader. More... | |
| enum | m33_render_t : uint32_t { k_erm33_glyph_h = 16U , k_erm33_paper = 0xFFFFFFU , k_erm33_ink = 0x000000U } |
| Glyph cell height and page colours for the ra8_gfx blit. More... | |
| enum | m33_crc_t : uint32_t { k_crc32_init = 0xFFFFFFFFU , k_crc32_poly = 0xEDB88320U } |
| Constants for the standard reflected CRC-32 over the rendered plane. More... | |
| enum | m33_crc_bits_t : uint8_t { k_crc32_bits = 8U } |
| Bit-fold count for the bitwise CRC-32 inner loop. More... | |
| enum | cpu1_ipc_t : uint8_t { k_cpu1_ipc_wake_channel = 0U } |
| IPC channel the M33 pokes to wake the parked M85 on a page turn. More... | |
| enum | m33_cycle_bound_t : uint32_t { k_m33_ack_budget = 50000000UL } |
| Static bound for the M33's wait-for-ack poll (NASA Rule 2). More... | |
Functions | |
| void | cpu1_reset_handler (void) |
| CPU1 reset handler: minimal C-runtime init, then run the reader. | |
| static void | append_run (char *out, uint32_t *plen, uint32_t cap, const char *txt) |
| Append one NUL-terminated text run into the page accumulator. | |
| static void | walk_push (m33_walk_stack_t *st, uint32_t node) |
| Push a node index onto the DOM-walk stack if it fits. | |
| static uint32_t | collect_chapter_text (const void *base, uint32_t root, uint32_t node_count, char *out, uint32_t cap) |
| Collect a chapter's opening text into the page accumulator. | |
| static bool | render_page (uint8_t *fb, const char *text, uint32_t len) |
| Render the collected page text into the SDRAM framebuffer via ra8_gfx. | |
| static uint32_t | fb_crc32 (const uint8_t *fb, uint32_t len) |
| Fold a reflected CRC-32 over the rendered framebuffer pixels. | |
| static void | publish_page (volatile erm33_mailbox_t *mb, uint32_t crc, uint32_t glyphs) |
| Publish the rendered page's base, geometry, format and CRC. | |
| static bool | book_is_valid (const void *base, uint32_t size) |
| Validate the baked RABOOK1 flat blob before walking it. | |
| static bool | render_held_page (const void *base, uint32_t *out_crc, uint32_t *out_glyphs) |
| Re-render the held page from the validated book and fold its CRC. | |
| static void | notify_m85 (void) |
| Poke the M85's IPC0 receive line to wake it from a page-turn park. | |
| static void | simulate_touch_dwell (void) |
| Spin a bounded page-dwell that stands in for a touch-poll latency. | |
| static bool | wait_for_ack (volatile const erm33_mailbox_t *mb, uint32_t turn) |
Poll the mailbox until the M85 acks page turn turn (heavy work done). | |
| static void | run_page_turns (volatile erm33_mailbox_t *mb, const void *base) |
| Hold the page and run the #150 page-turn handoff loop for the M85. | |
| static void | cpu1_park (void) |
| Park the M33 forever once the held page has been published. | |
| static void | cpu1_fail (volatile erm33_mailbox_t *mb, uint32_t status) |
| Mark a failure status, publish done, and park the M33. | |
| static void | cpu1_run_reader (void) |
| CPU1 reader entry: validate the book, render the held page, publish. | |
| static void | cpu1_fault_handler (void) |
| CPU1 default fault handler: park the core. | |
Variables | |
| uint32_t | g_ra8_ls_cpu1_stack_top |
| CPU1 stack top (slot 0 of the M33 vector table). | |
| uint32_t | g_ra8_ls_cpu1_data_start |
| CPU1 .data run-region start (in SRAM_CPU1). | |
| uint32_t | g_ra8_ls_cpu1_data_end |
| CPU1 .data run-region end. | |
| uint32_t | g_ra8_ls_cpu1_data_load |
| CPU1 .data load image (in MRAM_CPU1). | |
| uint32_t | g_ra8_ls_cpu1_bss_start |
| CPU1 .bss start (in SRAM_CPU1). | |
| uint32_t | g_ra8_ls_cpu1_bss_end |
| CPU1 .bss end. | |
| static uint8_t | s_framebuffer [k_erm33_fb_bytes] |
| The M33's RGB565 page framebuffer, resident in external SDRAM. | |
| const uintptr_t | g_cpu1_vector_table [] |
CPU1 (Cortex-M33 secondary core) image: render a held e-reader page.
This is the firmware that runs on the RA8D2's second core, the Cortex-M33, for the #150 power-saving demo. It is compiled as a wholly separate ELF (-mcpu=cortex-m33) and embedded into the M85 ELF as a .cpu1_image blob; the M85 hands the reader to this core via ra8_cpu1_release (HUM Ch 2.9.1) and PARKS. From then on the M33 is the live core holding the page.
The M33 runs the reader's data path AND renders one page to real pixels through the production ra8_gfx text stack – the same scalar (no-Helium) renderer the M85 e-reader uses, here driving a framebuffer that lives in external SDRAM:
Definition in file cpu1_main.c.
| enum cpu1_ipc_t : uint8_t |
IPC channel the M33 pokes to wake the parked M85 on a page turn.
IPC0 channel 0 is the CPU1 -> CPU0 direction; writing its IPC0ISET0 raises the IPC0 receive interrupt the M85 armed before release, so the M85 leaves WFI as soon as a page-turn request is published.
| Enumerator | |
|---|---|
| k_cpu1_ipc_wake_channel | IPC0 channel 0 (CPU1 -> CPU0). |
Definition at line 176 of file cpu1_main.c.
| enum m33_crc_bits_t : uint8_t |
Bit-fold count for the bitwise CRC-32 inner loop.
| Enumerator | |
|---|---|
| k_crc32_bits | Bits folded per input byte. |
Definition at line 164 of file cpu1_main.c.
| enum m33_crc_t : uint32_t |
Constants for the standard reflected CRC-32 over the rendered plane.
The M33 folds every byte of its SDRAM framebuffer through the IEEE 802.3 / zlib CRC-32 (reflected polynomial, pre/post-inverted), so the published value is a stable fingerprint of the exact pixels drawn.
| Enumerator | |
|---|---|
| k_crc32_init | Pre/post-inversion seed. |
| k_crc32_poly | Reflected CRC-32 polynomial. |
Definition at line 154 of file cpu1_main.c.
| enum m33_cycle_bound_t : uint32_t |
Static bound for the M33's wait-for-ack poll (NASA Rule 2).
The M85 acknowledges a page turn within a few ra8_emulator interleaves; this bound is the backstop so a never-arriving ack still terminates the loop instead of hanging the held-page cycle.
| Enumerator | |
|---|---|
| k_m33_ack_budget | Max iters waiting for the M85's turn_ack. |
Definition at line 188 of file cpu1_main.c.
| enum m33_render_t : uint32_t |
Glyph cell height and page colours for the ra8_gfx blit.
The bundled ra8_gfx font is 8x16, so glyph rows advance by 16 px. The page is rendered as black ink on a white paper background, the conventional e-reader palette.
| Enumerator | |
|---|---|
| k_erm33_glyph_h | ra8_gfx 8x16 font cell height, pixels. |
| k_erm33_paper | Page background colour (white). |
| k_erm33_ink | Glyph foreground colour (black). |
Definition at line 140 of file cpu1_main.c.
| enum m33_walk_bound_t : uint32_t |
Static iteration bounds for the M33 DOM walk (NASA Rule 2).
Each loop in the reader is bounded by one of these compile-time constants so the M33 can never run unbounded on a corrupt blob.
| Enumerator | |
|---|---|
| k_walk_iter_max | Max DOM-walk pops in the chapter. |
| k_max_run_len | Bounded text-run length cap, bytes. |
Definition at line 113 of file cpu1_main.c.
| enum m33_walk_size_t : uint16_t |
Small table / validation sizes for the M33 reader.
The DOM-walk stack depth and the validation caps that reject an implausible blob before the walk begins.
| Enumerator | |
|---|---|
| k_walk_stack_depth | Explicit DOM-walk stack depth. |
| k_max_chapters | Validation cap on chapter_count. |
| k_max_nodes | Validation cap on node_count. |
| k_magic_len | "RABOOK1" magic length (no NUL). |
Definition at line 125 of file cpu1_main.c.
|
static |
Append one NUL-terminated text run into the page accumulator.
Scans txt up to its NUL or the static k_max_run_len cap, copying each character into out until out reaches cap. A run that would overflow the page is truncated, never wrapped past the buffer.
| [in,out] | out | Page accumulator (never NULL). |
| [in,out] | plen | In/out count of characters already buffered (never NULL). |
| [in] | cap | Capacity of out in characters. |
| [in] | txt | NUL-terminated run from the validated blob (may be NULL). |
out and plen are non-NULL; *plen <= cap. txt, when non-NULL, points inside the validated blob's string pool. Definition at line 214 of file cpu1_main.c.
References k_max_run_len, and RA8_LOOP_BOUND.
Referenced by collect_chapter_text().
|
static |
Validate the baked RABOOK1 flat blob before walking it.
Checks the "RABOOK1" magic, the format version, that the header's total_size matches the baked length, and that the chapter / node counts are non-zero and within sane caps. Mirrors the real loader's gate so the M33 never walks a malformed blob (the inline accessors do no bounds checking).
| [in] | base | Candidate blob base (never NULL in this app). |
| [in] | size | Baked blob length in bytes (k_rabook_fixture_len). |
| true | Magic, version, size and table counts are all plausible. |
| false | Any check failed; the caller must not walk the blob. |
base points at the baked fixture rodata. size is the true baked length. base.Definition at line 522 of file cpu1_main.c.
References book_header(), book_header_t::chapter_count, book_header_t::format_version, k_book_format_version, k_book_sizeof_header, k_magic_len, k_max_chapters, k_max_nodes, book_header_t::magic, book_header_t::node_count, RA8_LOOP_BOUND, and book_header_t::total_size.
Referenced by cpu1_run_reader().
|
static |
Collect a chapter's opening text into the page accumulator.
Iterative pre-order walk (NASA Rule 1: an explicit index stack, no recursion) rooted at root. The root's own siblings are never followed, so the walk stays inside this chapter. Each text node's run is appended via append_run; the walk stops once cap characters are buffered. The pop loop is bounded by k_walk_iter_max.
| [in] | base | Validated RABOOK1 blob base (never NULL). |
| [in] | root | Chapter root node index, or k_book_nil. |
| [in] | node_count | Node-table length (an out-of-range index is dropped). |
| [out] | out | Page accumulator (never NULL). |
| [in] | cap | Capacity of out in characters. |
| 0 | base or out was NULL, or the chapter held no text. |
base was accepted by book_is_valid. out has room for cap characters. Definition at line 309 of file cpu1_main.c.
References append_run(), book_node_text(), book_nodes(), book_node_t::first_child, m33_walk_stack_t::items, k_book_nil, k_book_node_text, k_walk_iter_max, book_node_t::kind, book_node_t::next_sibling, RA8_LOOP_BOUND, m33_walk_stack_t::sp, and walk_push().
Referenced by render_held_page().
|
static |
Mark a failure status, publish done, and park the M33.
| [out] | mb | Shared mailbox (never NULL). |
| [in] | status | Failure status code (erm33_const_t). |
mb is the fixed-address mailbox pointer. Definition at line 785 of file cpu1_main.c.
References cpu1_park(), erm33_mailbox_t::done, and erm33_mailbox_t::status.
Referenced by cpu1_run_reader().
|
static |
CPU1 default fault handler: park the core.
Every M33 exception slot routes here. The core stops making forward progress; on hardware a watchdog (if enabled) eventually resets.
Definition at line 905 of file cpu1_main.c.
|
static |
Park the M33 forever once the held page has been published.
Definition at line 761 of file cpu1_main.c.
| void cpu1_reset_handler | ( | void | ) |
CPU1 reset handler: minimal C-runtime init, then run the reader.
The M33 boots with uninitialised RAM, so before any C code runs this copies .data from its MRAM_CPU1 load image into SRAM_CPU1 and zeroes .bss. The linker exports the region bounds as g_ra8_ls_cpu1_* symbols. The SDRAM framebuffer is in a NOLOAD section and is painted by ra8_gfx_clear, so it is deliberately left out of this init.
Definition at line 868 of file cpu1_main.c.
References cpu1_run_reader(), g_ra8_ls_cpu1_bss_end, g_ra8_ls_cpu1_bss_start, g_ra8_ls_cpu1_data_end, g_ra8_ls_cpu1_data_load, and g_ra8_ls_cpu1_data_start.
|
static |
CPU1 reader entry: validate the book, render the held page, publish.
Stamps the boot signature, validates the baked RABOOK1 blob, renders chapter 0's opening page into the SDRAM framebuffer (render_held_page), publishes the descriptor, and sets status = ok, done = 1. It then becomes the live core for the #150 mode-switch: it runs the page-turn hold loop (run_page_turns) – holding the page, waking the parked M85 on each scripted touch, and re-rendering – before holding for good. A failure at any step publishes the matching failure status and parks.
Definition at line 818 of file cpu1_main.c.
References book_is_valid(), cpu1_fail(), cpu1_park(), erm33_mailbox_t::done, erm33_mailbox(), k_erm33_m33_sig, k_erm33_status_bad_book, k_erm33_status_ok, k_erm33_status_render_fail, k_rabook_fixture, k_rabook_fixture_len, erm33_mailbox_t::m33_sig, publish_page(), render_held_page(), run_page_turns(), and erm33_mailbox_t::status.
Referenced by cpu1_reset_handler().
|
static |
Fold a reflected CRC-32 over the rendered framebuffer pixels.
Standard table-less reflected CRC-32: seed all-ones, fold each byte LSB-first through k_crc32_poly, post-invert. Reading every byte back out of SDRAM is what proves the M33's pixels actually landed; a blank plane hashes to one fixed value, so a different CRC demonstrates genuine rendering.
| [in] | fb | Framebuffer base (never NULL). |
| [in] | len | Bytes to hash; expected to equal k_erm33_fb_bytes. |
len bytes at fb. | 0 | fb is NULL or len is 0 (no pixels to hash). |
fb addresses the rendered SDRAM framebuffer. Definition at line 439 of file cpu1_main.c.
References k_crc32_bits, k_crc32_init, k_crc32_poly, k_erm33_fb_bytes, and RA8_LOOP_BOUND.
Referenced by render_held_page().
|
static |
Poke the M85's IPC0 receive line to wake it from a page-turn park.
Writes IPC0ISET0 for the wake channel (HUM Ch 3.2.11 "IPC0ISET0" p 215), asserting IRQ line 0 on the primary core. turn_req is already published and dsb-ordered ahead of this call, so the woken M85 observes a settled request. The HAL return value is intentionally discarded: a failed poke only costs the M85 a fall-through to its bounded poll, never correctness.
Definition at line 626 of file cpu1_main.c.
References k_cpu1_ipc_wake_channel, k_ra8_ipc_irq_event_0, and ra8_ipc_send_event().
|
static |
Publish the rendered page's base, geometry, format and CRC.
Writes the SDRAM framebuffer address, the agreed RGB565 geometry, the glyph count and the freshly-folded CRC into the shared mailbox, each behind a dsb so the parked M85 observes a fully-formed descriptor.
| [out] | mb | Shared mailbox (never NULL). |
| [in] | crc | CRC-32 the M33 folded over the framebuffer. |
| [in] | glyphs | Characters laid onto the held page. |
mb is the fixed-address mailbox pointer. Definition at line 484 of file cpu1_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, and s_framebuffer.
Referenced by cpu1_run_reader(), and run_page_turns().
|
static |
Re-render the held page from the validated book and fold its CRC.
Re-collects chapter 0's opening text, renders it into the SDRAM framebuffer via ra8_gfx, drains the writes with a dsb, then folds the CRC-32 over the rendered pixels. Pure of the mailbox and fully deterministic – the same immutable blob renders the same bytes – so every call (the first render and each page-turn re-render) yields the identical CRC, keeping the ra8_emulator gate's golden stable.
| [in] | base | Validated RABOOK1 blob base (never NULL). |
| [out] | out_crc | Receives the CRC-32 of the rendered framebuffer. |
| [out] | out_glyphs | Receives the count of characters laid onto the page. |
| true | The page rendered and out_crc / out_glyphs are set. |
| false | base / out_crc / out_glyphs was NULL, or ra8_gfx failed. |
base was accepted by book_is_valid. out_crc and out_glyphs are writable. Definition at line 579 of file cpu1_main.c.
References book_chapters(), book_header(), collect_chapter_text(), fb_crc32(), k_erm33_fb_bytes, k_erm33_page_chars, book_header_t::node_count, render_page(), and s_framebuffer.
Referenced by cpu1_run_reader(), and run_page_turns().
|
static |
Render the collected page text into the SDRAM framebuffer via ra8_gfx.
Binds fb as an RGB565 canvas, clears it to paper white, then lays the len buffered characters out left-to-right, wrapping to the next glyph row every k_erm33_fb_cols cells, blitting each row string with one ra8_gfx_text_out. The row loop is bounded by k_erm33_fb_rows.
| [out] | fb | SDRAM framebuffer base (never NULL). |
| [in] | text | Collected page text (never NULL). |
| [in] | len | Count of valid characters in text. |
| true | The plane holds the page over a paper-white background. |
| false | A NULL argument or an ra8_gfx error; the plane is undefined. |
fb is k_erm33_fb_bytes bytes of SDRAM. text holds at least len characters. Definition at line 370 of file cpu1_main.c.
References k_erm33_fb_cols, k_erm33_fb_height, k_erm33_fb_rows, k_erm33_fb_width, k_erm33_glyph_h, k_erm33_ink, k_erm33_paper, k_ra8_gfx_format_rgb565, k_ra8_ok, ra8_gfx_clear(), ra8_gfx_font_8x16, ra8_gfx_init(), ra8_gfx_text_out(), and RA8_LOOP_BOUND.
Referenced by render_held_page().
|
static |
Hold the page and run the #150 page-turn handoff loop for the M85.
For each of k_erm33_max_turns turns the M33 dwells on the held page (simulate_touch_dwell), publishes the page-turn request (turn_req) behind a dsb, pokes the parked M85 (notify_m85), waits for the M85's heavy-work ack (wait_for_ack), RE-RENDERS the held page (render_held_page – same content, same CRC), republishes the descriptor, and sets turn_done. A missed ack ends the loop. The outer loop is bounded by k_erm33_max_turns (NASA Rule 2).
| [in,out] | mb | Shared mailbox (never NULL). |
| [in] | base | Validated RABOOK1 blob base (never NULL). |
mb is the fixed-address mailbox pointer with the first page published. base was accepted by book_is_valid. Definition at line 720 of file cpu1_main.c.
References k_erm33_max_turns, notify_m85(), publish_page(), RA8_LOOP_BOUND, render_held_page(), simulate_touch_dwell(), erm33_mailbox_t::turn_done, erm33_mailbox_t::turn_req, and wait_for_ack().
Referenced by cpu1_run_reader().
|
static |
Spin a bounded page-dwell that stands in for a touch-poll latency.
The real e-reader would poll the GT911 touch controller while holding the page; here the M33 spins k_erm33_touch_dwell times on a volatile counter so ra8_emulator interleaves the cores a few times before the synthetic page turn fires. Deterministic and bounded (NASA Rule 2); replaced by a real touch poll on hardware (a HIL follow-up).
Definition at line 650 of file cpu1_main.c.
References k_erm33_touch_dwell, and RA8_LOOP_BOUND.
Referenced by run_page_turns().
|
static |
Poll the mailbox until the M85 acks page turn turn (heavy work done).
After the M33 requests a page turn and pokes the M85, the woken M85 does its heavy next-page work and writes turn_ack. This bounded poll waits for that ack across ra8_emulator's core interleaves; the bound is the NASA Rule 2 backstop for an ack that never arrives.
| [in] | mb | Shared mailbox (never NULL). |
| [in] | turn | The page-turn number being acknowledged (1-based). |
turn within budget. | true | turn_ack >= turn within k_m33_ack_budget iterations. |
| false | mb was NULL or the budget was exhausted first. |
mb is the fixed-address mailbox pointer; turn_req == turn published. Definition at line 683 of file cpu1_main.c.
References k_m33_ack_budget, RA8_LOOP_BOUND, and erm33_mailbox_t::turn_ack.
Referenced by run_page_turns().
|
static |
Push a node index onto the DOM-walk stack if it fits.
| [in,out] | st | Walk stack (never NULL). |
| [in] | node | Node index to push, or k_book_nil to ignore. |
st is non-NULL with sp <= k_walk_stack_depth. node is a node index or the nil sentinel. node is pushed unless the stack is full (then dropped). Definition at line 268 of file cpu1_main.c.
References m33_walk_stack_t::items, k_book_nil, k_walk_stack_depth, and m33_walk_stack_t::sp.
Referenced by collect_chapter_text().
| const uintptr_t g_cpu1_vector_table[] |
Definition at line 926 of file cpu1_main.c.
|
extern |
CPU1 .bss end.
|
extern |
CPU1 .bss start (in SRAM_CPU1).
|
extern |
CPU1 .data run-region end.
|
extern |
CPU1 .data load image (in MRAM_CPU1).
|
extern |
CPU1 .data run-region start (in SRAM_CPU1).
|
extern |
CPU1 stack top (slot 0 of the M33 vector table).
|
static |
The M33's RGB565 page framebuffer, resident in external SDRAM.
Placed in the .sdram_bss (NOLOAD) section the CPU1 linker script pins at the SDRAM base (0x68000000); ra8_gfx_clear paints every byte before the page is published, so it needs no startup zeroing. The M33 publishes its address (&s_framebuffer) in the mailbox's fb_base.
Definition at line 104 of file cpu1_main.c.