ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
47
48#include <stdint.h>
49
50#include "ra8_attributes.h"
51#include "ra8_board_ek_ra8d2.h"
52#include "ra8_boot_entry.h"
53#include "ra8_cgc.h"
54#include "ra8_device.h"
55#include "ra8_err.h"
56#include "ra8_ethosu_kernel.h"
57#include "ra8_isr.h"
58#include "ra8_npu.h"
59#include "ra8_npu_fake_cmd.h"
60#include "ra8_npu_quant.h"
61#include "ra8_npu_regs.h"
62
63/*
64 * Compile-time proof that the RA8P1 toolchain selection reached this TU: the NPU
65 * driver + TFLite-micro Ethos-U kernel only exist when RA8_HAS_NPU is defined
66 * (RA8_DEVICE_RA8P1). Building this app with the RA8D2 toolchain fails loudly here.
67 */
68#ifndef RA8_HAS_NPU
69#error "npu_infer must be built with cmake/toolchain-ra8p1.cmake (RA8_DEVICE_RA8P1)."
70#endif
71
84
95
106
111typedef enum : uint32_t {
113 k_npu_infer_fnv_prime = 0x01000193U,
115
123static const float s_infer_scale = 0.5F;
124
133static const float s_infer_deq_tol = 0.001F;
134
143
152
161
170
179
188
196volatile uint32_t g_npu_infer_pass = 0U;
197
213{
214 while (1) {
215 __asm__ volatile("wfi");
216 }
217}
218
234{
235 while (1) {
236 __asm__ volatile("wfi");
237 }
238}
239
265
287
304{
305 for (uint32_t i = 0U; i < (uint32_t)k_npu_infer_arena_bytes; i++) {
306 s_infer_input_f[i] = s_infer_scale * (float)((int32_t)i & (int32_t)k_npu_infer_seed_mask);
307 s_npu_output[i] = 0U;
308 }
313 (int32_t)k_npu_infer_zero_point);
314}
315
332{
333 ra8_npu_job_t job = {};
335 job.cmd_stream_bytes = (uint32_t)sizeof(s_npu_cmd_stream);
337 job.region_base[k_npu_infer_region_weights] = (uint64_t)(uintptr_t)s_npu_weights;
338 job.region_base[k_npu_infer_region_input] = (uint64_t)(uintptr_t)s_npu_input;
339 job.region_base[k_npu_infer_region_output] = (uint64_t)(uintptr_t)s_npu_output;
340
341 const ra8_err_t sub = ra8_npu_submit(&job);
342 if (sub != k_ra8_ok) {
343 return sub;
344 }
345 const ra8_err_t arm = ra8_npu_irq_arm();
346 if (arm != k_ra8_ok) {
347 return arm;
348 }
349 const ra8_err_t run = ra8_npu_run();
350 if (run != k_ra8_ok) {
351 return run;
352 }
353 return ra8_npu_wait_irq();
354}
355
373RA8_INTERNAL static bool internal_npu_infer_verify(uint32_t* out_check)
374{
375 uint32_t check = (uint32_t)k_npu_infer_fnv_offset;
376 bool ok = true;
377 for (uint32_t i = 0U; i < (uint32_t)k_npu_infer_arena_bytes; i++) {
378 const int32_t expect_q =
379 ((int32_t)i & (int32_t)k_npu_infer_seed_mask) + (int32_t)k_npu_infer_zero_point;
380 const int32_t expect_out =
381 (expect_q + (int32_t)k_npu_infer_addk) & (int32_t)k_npu_infer_byte_mask;
382 const float expect_f =
383 s_infer_scale * (float)((int32_t)s_npu_output[i] - (int32_t)k_npu_infer_zero_point);
384 const float diff = (s_infer_output_f[i] > expect_f) ? (s_infer_output_f[i] - expect_f)
385 : (expect_f - s_infer_output_f[i]);
386 if ((int32_t)s_npu_input[i] != expect_q) {
387 ok = false; /* quantize stage */
388 }
389 if ((int32_t)s_npu_output[i] != expect_out) {
390 ok = false; /* NPU op stage (IRQ completion) */
391 }
392 if (diff > s_infer_deq_tol) {
393 ok = false; /* dequantize stage */
394 }
395 check = (check ^ (uint32_t)s_npu_output[i]) * (uint32_t)k_npu_infer_fnv_prime;
396 }
397 *out_check = check;
398 return ok;
399}
400
401RA8_INTERNAL static void internal_npu_infer_write(const uint8_t* data, size_t len)
402{
403 (void)ra8_board_uart_console_write(data, len);
404}
405
407{
408 static const uint8_t k_hex[] = "0123456789ABCDEF";
409 uint8_t digits[k_npu_infer_hex_digits] = {};
410 for (uint8_t i = 0U; i < (uint8_t)k_npu_infer_hex_digits; ++i) {
411 const uint8_t shift =
412 (uint8_t)(((uint8_t)k_npu_infer_hex_digits - 1U - i) * (uint8_t)k_npu_infer_hex_shift);
413 digits[i] = k_hex[(value >> shift) & (uint32_t)k_npu_infer_hex_mask];
414 }
416}
417
419{
420 const uint8_t* text = ok ? (const uint8_t*)"OK" : (const uint8_t*)"FAIL";
421 const size_t len = ok ? 2U : 4U;
422 internal_npu_infer_write(text, len);
423}
424
426{
427 const uint8_t* text = pass ? (const uint8_t*)"PASS" : (const uint8_t*)"FAIL";
428 internal_npu_infer_write(text, 4U);
429}
430
451RA8_INTERNAL static void
452internal_npu_infer_emit(uint32_t id, bool tflm_ok, bool run_ok, uint32_t check, bool pass)
453{
454 internal_npu_infer_write((const uint8_t*)"npu-infer: id=0x", sizeof("npu-infer: id=0x") - 1U);
456 internal_npu_infer_write((const uint8_t*)" tflm=", sizeof(" tflm=") - 1U);
458 internal_npu_infer_write((const uint8_t*)" irq=", sizeof(" irq=") - 1U);
460 internal_npu_infer_write((const uint8_t*)" out=0x", sizeof(" out=0x") - 1U);
462 internal_npu_infer_write((const uint8_t*)" verdict=", sizeof(" verdict=") - 1U);
464 internal_npu_infer_write((const uint8_t*)"\r\n", sizeof("\r\n") - 1U);
466}
467
488RA8_INTERNAL static bool
489internal_npu_infer_execute(uint32_t* out_id, bool* out_tflm, uint32_t* out_check)
490{
491 *out_id = 0U;
492 *out_tflm = (ra8_ethosu_kernel_available() == 1);
493 *out_check = 0U;
494
495 if (ra8_npu_init() != k_ra8_ok) {
496 return false;
497 }
498 (void)ra8_npu_read_id(out_id);
499
502 nullptr,
503 (uint8_t)k_ra8_isr_prio_default,
504 nullptr);
505 if (reg != k_ra8_ok) {
506 return false;
507 }
509
512 return false;
513 }
515 return false;
516 }
521 (int32_t)k_npu_infer_zero_point) != k_ra8_ok) {
522 return false;
523 }
524 return internal_npu_infer_verify(out_check);
525}
526
534void main(void)
535{
537
538 uint32_t id = 0U;
539 bool tflm = false;
540 uint32_t check = 0U;
541 /* run_ok = init + IRQ-driven quantize/op/dequantize pipeline all matched. The
542 * TFLite-micro registration (tflm) is a separate leg reported on its own field;
543 * the verdict is PASS only when every leg holds. */
544 const bool run_ok = internal_npu_infer_execute(&id, &tflm, &check);
545 const bool pass = run_ok && tflm && (id != 0U);
546
547 g_npu_infer_pass = pass ? 1U : 0U;
548 internal_npu_infer_emit(id, tflm, run_ok, check, pass);
549
551}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static uint8_t s_npu_input[k_npu_infer_arena_bytes]
Region 1 UINT8 input tensor (quantized s_infer_input_f).
Definition main.c:169
static const float s_infer_scale
Quantization scale (const float; enums cannot carry a float).
Definition main.c:123
volatile uint32_t g_npu_infer_pass
Final verdict (1 = PASS, 0 = FAIL), for external (J-Link) inspection.
Definition main.c:196
static void internal_npu_infer_emit(uint32_t id, bool tflm_ok, bool run_ok, uint32_t check, bool pass)
Print the one-line verdict banner over the SCI8 console.
Definition main.c:452
static void internal_npu_infer_write_hex32(uint32_t value)
Definition main.c:406
static bool internal_npu_infer_execute(uint32_t *out_id, bool *out_tflm, uint32_t *out_check)
Bring up the NPU, register its completion IRQ, and run one inference.
Definition main.c:489
static const float s_infer_deq_tol
Absolute tolerance for the dequantized float comparison.
Definition main.c:133
static void internal_npu_infer_setup_or_halt(void)
Bring up CGC, the SCI8 console, and the ra8_isr substrate.
Definition main.c:253
static uint8_t s_npu_output[k_npu_infer_arena_bytes]
Region 2 UINT8 output tensor: zeroed pre-run, holds the NPU result.
Definition main.c:178
static void internal_npu_infer_build_stream(void)
Fill the command stream (add-constant op) per the stand-in convention.
Definition main.c:278
static void internal_npu_infer_panic_halt(void)
Park the CPU forever in WFI after a fatal init error (a real panic).
Definition main.c:212
npu_infer_quant_t
Deterministic quantization parameters + the add-constant the op applies.
Definition main.c:100
@ k_npu_infer_addk
Constant the NPU add-const op adds (16).
Definition main.c:102
@ k_npu_infer_seed_mask
Input pattern wrap: in_f[i] uses (i & 15).
Definition main.c:103
@ k_npu_infer_zero_point
UINT8 zero-point (non-zero to exercise it).
Definition main.c:101
@ k_npu_infer_byte_mask
8-bit element wrap (matches the op).
Definition main.c:104
static uint32_t s_npu_cmd_stream[k_npu_infer_cmd_words]
Stand-in command stream in SRAM (ra8_npu_fake_cmd.h layout; add-constant op).
Definition main.c:142
static void internal_npu_infer_write(const uint8_t *data, size_t len)
Definition main.c:401
static bool internal_npu_infer_verify(uint32_t *out_check)
Verify quantize + NPU op + dequantize, folding the output to a checkword.
Definition main.c:373
static void internal_npu_infer_write_status(bool ok)
Definition main.c:418
static void internal_npu_infer_park(void)
Park the CPU forever in WFI after the verdict banner (a clean stop).
Definition main.c:233
npu_infer_region_t
Tensor-region indices the job programs into BASEPn.
Definition main.c:89
@ k_npu_infer_region_output
Region 2: op destination (quantized output).
Definition main.c:92
@ k_npu_infer_region_count
Regions programmed (BASEP0..2).
Definition main.c:93
@ k_npu_infer_region_weights
Region 0: Vela weight arena (unused by op).
Definition main.c:90
@ k_npu_infer_region_input
Region 1: op source (quantized input).
Definition main.c:91
npu_infer_size_t
Command-stream / tensor-arena sizes and the console baud.
Definition main.c:76
@ k_npu_infer_hex_shift
Bits per hex nibble.
Definition main.c:81
@ k_npu_infer_hex_digits
Fixed-width hex word digits.
Definition main.c:80
@ k_npu_infer_cmd_words
Command-stream word count.
Definition main.c:79
@ k_npu_infer_hex_mask
Mask for one hex nibble.
Definition main.c:82
@ k_npu_infer_baud
SCI8 J-Link OB console baud.
Definition main.c:77
@ k_npu_infer_arena_bytes
Tensor-arena length (bytes).
Definition main.c:78
static void internal_npu_infer_write_verdict(bool pass)
Definition main.c:425
npu_infer_fnv_t
FNV-1a 32-bit constants for the displayed output checkword.
Definition main.c:111
@ k_npu_infer_fnv_offset
FNV-1a 32-bit offset basis.
Definition main.c:112
@ k_npu_infer_fnv_prime
FNV-1a 32-bit prime.
Definition main.c:113
static ra8_err_t internal_npu_infer_run_job_irq(void)
Submit the job, arm the IRQ latch, kick it, and await the NPU interrupt.
Definition main.c:331
static uint8_t s_npu_weights[k_npu_infer_arena_bytes]
Region 0 weight arena (present by Vela convention; unused by this op).
Definition main.c:151
static float s_infer_output_f[k_npu_infer_arena_bytes]
Float output arena, dequantized from s_npu_output after the run.
Definition main.c:187
static ra8_err_t internal_npu_infer_prepare_input(void)
Seed the float input, quantize it to UINT8, and zero the output arenas.
Definition main.c:303
static float s_infer_input_f[k_npu_infer_arena_bytes]
Float input arena, seeded with a deterministic pattern before quantize.
Definition main.c:160
-copyright
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
ra8_err_t ra8_board_uart_console_init(uint32_t baud)
Configure SCI8 + PD02/PD03 as the debug-console UART.
ra8_err_t ra8_board_uart_console_flush(void)
Block until every byte queued on the J-Link OB VCOM console has finished clocking out on the wire.
Boot entry points shared between a vector table and its startup code.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
Compile-time device selection for the RA8 multi-chip build (RA8D2 / RA8P1).
ra8_elc_event_t
Partial list of ELC events (populate as drivers need them).
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
First-party TFLite-micro Ethos-U custom-op registration probe (RA8P1-only).
NVIC + ICU IELSR allocator.
@ k_ra8_isr_prio_default
Middle priority.
Definition ra8_isr.h:107
ra8_err_t ra8_isr_init(void)
Initialise the ra8_isr table.
Definition ra8_isr.c:229
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
ra8_err_t ra8_isr_register(ra8_elc_event_t event, ra8_isr_handler_t handler, void *ctx, uint8_t priority, uint16_t *out_slot)
Allocate an IELSR slot for an ELC event + handler.
Definition ra8_isr.c:296
Arm Ethos-U55 NPU command/queue driver foundation (RA8P1-only).
ra8_err_t ra8_npu_submit(const ra8_npu_job_t *job)
Program the command queue and tensor region base pointers for a job.
ra8_err_t ra8_npu_wait_irq(void)
Block on the NPU interrupt until the armed job completes or faults.
ra8_err_t ra8_npu_irq_arm(void)
Arm the interrupt-driven completion latch for the submitted job.
void ra8_npu_irq_handler(void *ctx)
NPU interrupt service routine: latch completion / fault, ack the IRQ.
ra8_err_t ra8_npu_run(void)
Kick the currently-submitted job (transition the NPU to running).
ra8_err_t ra8_npu_read_id(uint32_t *out_id)
Read the Ethos-U55 NPU_ID (architecture / product revision) register.
ra8_err_t ra8_npu_init(void)
Bring the NPU out of module-stop and soft-reset it.
ra8_emulator / host-test command-stream convention for the Ethos-U55 model
@ k_ra8_npu_fake_op_addk
dst[i] = (src[i] + constant) & 0xFF.
@ k_ra8_npu_fake_word_dst
Destination region index (0 .
@ k_ra8_npu_fake_word_count
Byte count to process.
@ k_ra8_npu_fake_word_num
Header word count (populated words).
@ k_ra8_npu_fake_word_src
Source region index (0 .
@ k_ra8_npu_fake_word_op
magic | opcode.
@ k_ra8_npu_fake_word_const
Constant addend (add-constant op).
@ k_ra8_npu_fake_magic
Emu-Ethos-U55 marker in bits [31:16].
Affine (scale + zero-point) tensor quantization for the NPU runtime.
ra8_err_t ra8_npu_dequantize_u8(const uint8_t *in, float *out, size_t count, float scale, int32_t zero_point)
Dequantize a UINT8 tensor into a float arena (affine).
ra8_err_t ra8_npu_quantize_u8(const float *in, uint8_t *out, size_t count, float scale, int32_t zero_point)
Quantize a float arena into a UINT8 tensor (affine, saturating).
Arm Ethos-U55 NPU register window on the Renesas RA8P1 (RA8P1-only).
@ k_ra8_npu_event_irq
NPU_IRQ event (RA8P1 elc_event_t).
One Ethos-U55 inference job: a command stream plus its tensor arenas.
Definition ra8_npu.h:87
uint8_t region_count
Number of region_base[] entries in use.
Definition ra8_npu.h:90
uint32_t cmd_stream_bytes
Command stream length in bytes (> 0).
Definition ra8_npu.h:89
uint64_t region_base[k_ra8_npu_region_count]
AXI base of each BASEPn arena.
Definition ra8_npu.h:91
const void * cmd_stream
Vela command stream base in SRAM.
Definition ra8_npu.h:88