ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches

Arm Ethos-U55 NPU command/queue driver foundation (RA8P1-only). More...

#include <stdint.h>
#include "ra8_device.h"
#include "ra8_err.h"
#include "ra8_npu_regs.h"
Include dependency graph for ra8_npu.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_npu_job_t
 One Ethos-U55 inference job: a command stream plus its tensor arenas. More...
struct  ra8_npu_status_t
 Decoded snapshot of the NPU_STATUS register. More...

Functions

ra8_err_t ra8_npu_init (void)
 Bring the NPU out of module-stop and soft-reset it.
ra8_err_t ra8_npu_deinit (void)
 Gate the NPU back into module-stop.
ra8_err_t ra8_npu_reset (void)
 Soft-reset an already-initialized NPU.
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_submit (const ra8_npu_job_t *job)
 Program the command queue and tensor region base pointers for a job.
ra8_err_t ra8_npu_run (void)
 Kick the currently-submitted job (transition the NPU to running).
ra8_err_t ra8_npu_poll (bool *out_done)
 Non-blocking completion / fault poll of a running job.
ra8_err_t ra8_npu_wait (void)
 Bounded busy-wait until the running job completes or faults.
ra8_err_t ra8_npu_read_status (ra8_npu_status_t *out)
 Read and decode the NPU_STATUS register.
ra8_err_t ra8_npu_clear_irq (void)
 Acknowledge (clear) a raised NPU interrupt.
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_wait_irq (void)
 Block on the NPU interrupt until the armed job completes or faults.

Detailed Description

Arm Ethos-U55 NPU command/queue driver foundation (RA8P1-only).

Tag
[Ring 3 / HAL] {World: S}

Public API of the Ethos-U55 micro-NPU driver on the Renesas RA8P1 (R7KA8P1KFLCAC). This is the DRIVER FOUNDATION: it brings the NPU out of module-stop, soft-resets the block, and models the Ethos-U55 command-stream submission protocol – program the command-queue base/size (QBASE/QSIZE), program the per-tensor AXI region bases (BASEPn), kick the job (CMD.transition_to_running_state), then poll or take the IRQ for completion and read STATUS for faults.

It is deliberately NOT a Vela compiler and NOT a TFLite-micro runtime: it consumes a pre-compiled command stream (produced offline by Vela) plus the input/output/scratch tensors already resident in shared system SRAM, and runs one inference job. Building the command stream and the tensor-arena layout is the caller's (or a future runtime's) responsibility – see the follow-ups filed against the RA8P1 epic.

Sourcing / status

The register interface is the Arm Ethos-U55 architectural APB map (see ra8_npu_regs.h for the primary-source transcription). There is no RA8P1 board yet, so the command/queue construction is host-tested for the exact register write sequence only; a real on-silicon inference is a follow-up.

Threading

Not thread-safe. The NPU is a single-job engine; the caller owns serialisation. Call from a single-threaded context or with the NPU IRQ masked.

Since
0.1.0

Definition in file ra8_npu.h.

Function Documentation

◆ ra8_npu_clear_irq()

ra8_err_t ra8_npu_clear_irq ( void )
nodiscard

Acknowledge (clear) a raised NPU interrupt.

Writes CMD.clear_irq. Call from the NPU ISR (or after an IRQ-driven completion) so the line de-asserts and the next job can raise it.

Returns
ra8_err_t error code.
Return values
k_ra8_okClear-IRQ request issued.
k_ra8_err_not_initializedra8_npu_init() had not run.
Precondition
ra8_npu_init() previously succeeded.
An NPU interrupt was raised (or this is a defensive pre-clear).
Postcondition
On success CMD.clear_irq has been written.
STATUS.irq_raised de-asserts once the write takes effect.
Note
ISR-safe: performs a single register write, no logging on the hot path.
See also
ra8_npu_poll
Since
0.1.0

◆ ra8_npu_deinit()

ra8_err_t ra8_npu_deinit ( void )
nodiscard

Gate the NPU back into module-stop.

Clears the driver's initialized flag and releases the NPU MSTP reference. Any in-flight job should be stopped first; the foundation does not force-stop a running stream.

Returns
ra8_err_t error code.
Return values
k_ra8_okNPU gated (or still referenced by another user).
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_hw_timeoutMSTP bit did not read back as set within budget.
Precondition
ra8_npu_init() previously succeeded.
No inference job is currently running.
Postcondition
On success the NPU MSTP reference is released.
The driver's initialized flag is clear.
Note
Not thread-safe.
See also
ra8_npu_init
Since
0.1.0

◆ ra8_npu_init()

ra8_err_t ra8_npu_init ( void )
nodiscard

Bring the NPU out of module-stop and soft-reset it.

Ungates the NPU via the ref-counted ra8_mstp substrate (MSTPCRA bit 16 on the RA8P1), then issues a soft reset and polls STATUS.reset until the block reports ready or a bounded budget expires. NPUCLK is supplied by the CGC clock tree configured at system-clock init; this driver assumes it is running.

Returns
ra8_err_t error code.
Return values
k_ra8_okNPU clocked, reset complete, ready for a job.
k_ra8_err_hw_timeoutReset did not complete within the spin budget.
k_ra8_err_hw_errorAn MSTP read-back or NPU fault bit was observed.
Precondition
The build targets the RA8P1 (RA8_HAS_NPU defined).
NPUCLK is running (CGC clock tree already configured).
Postcondition
On success the NPU is out of module-stop and idle (STATUS.state == 0).
On success the driver's internal initialized flag is set.
Note
Not thread-safe. Call from single-threaded init or with IRQs masked.
See also
ra8_npu_deinit
ra8_npu_reset
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 5: 2 preconditions, 2 postconditions
  • Rule 7: returns ra8_err_t, marked [[nodiscard]]

Referenced by internal_npu_infer_execute(), and main().

◆ ra8_npu_irq_arm()

ra8_err_t ra8_npu_irq_arm ( void )
nodiscard

Arm the interrupt-driven completion latch for the submitted job.

Resets the internal completion state to "waiting" so ra8_npu_wait_irq can block until ra8_npu_irq_handler observes the job finish. Call it AFTER ra8_npu_submit and BEFORE ra8_npu_run when the caller intends to take the NPU interrupt instead of busy-polling. The interrupt itself must already be routed to ra8_npu_irq_handler via ra8_isr_register(k_ra8_npu_event_irq, ...).

Returns
ra8_err_t error code.
Return values
k_ra8_okCompletion latch armed; the IRQ path may now be used.
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_invalid_stateNo job has been submitted since init/reset.
Precondition
ra8_npu_submit() programmed a job since the last init/reset.
The NPU interrupt is (or is about to be) routed to ra8_npu_irq_handler.
Postcondition
On success the completion latch reads "armed" (not done, not faulted).
No hardware register is modified.
Note
Not thread-safe.
See also
ra8_npu_wait_irq
ra8_npu_irq_handler
Since
0.1.0

Referenced by internal_npu_infer_run_job_irq().

◆ ra8_npu_irq_handler()

void ra8_npu_irq_handler ( void * ctx)

NPU interrupt service routine: latch completion / fault, ack the IRQ.

Register this with ra8_isr_register(k_ra8_npu_event_irq, ra8_npu_irq_handler, nullptr, priority, ...). On entry it reads STATUS, latches the internal completion state to "done" (command stream fully consumed) or "faulted" (any bus / parse / weight-decoder / ECC fault), then writes CMD.clear_irq so the line de-asserts. It performs no logging on the hot path and touches the NPU only through the already-cited ra8_npu_read_status / ra8_npu_clear_irq accessors, so it adds no new register citation. A waiter unblocks via ra8_npu_wait_irq.

Parameters
[in]ctxUnused registration cookie (kept for ra8_isr_handler_t ABI).
Returns
None (void).
Note
This function returns no value.
Precondition
ra8_npu_init() previously succeeded.
Invoked from the NPU interrupt vector (or an equivalent test driver).
Postcondition
The completion latch reflects the observed STATUS (done or fault).
CMD.clear_irq has been written, so STATUS.irq_raised de-asserts.
Note
ISR-safe: single status read + single command write, no logging.
See also
ra8_npu_wait_irq
ra8_npu_irq_arm
Since
0.1.0

Referenced by internal_npu_infer_execute().

◆ ra8_npu_poll()

ra8_err_t ra8_npu_poll ( bool * out_done)
nodiscard

Non-blocking completion / fault poll of a running job.

Reads STATUS once. Reports completion when the command stream end has been reached, and reports a hardware fault when any bus / parse / weight-decoder / ECC fault bit is latched.

Parameters
[out]out_doneOn k_ra8_ok, true when the job has finished, else false.
Returns
ra8_err_t error code.
Return values
k_ra8_okPoll succeeded; *out_done set accordingly.
k_ra8_err_null_ptrout_done was nullptr.
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_hw_errorA STATUS fault bit is set.
Precondition
out_done is non-NULL.
ra8_npu_run() has been issued for the job being polled.
Postcondition
On k_ra8_ok *out_done reflects command-stream completion.
No hardware state is modified.
Note
Not thread-safe.
See also
ra8_npu_wait
Since
0.1.0

◆ ra8_npu_read_id()

ra8_err_t ra8_npu_read_id ( uint32_t * out_id)
nodiscard

Read the Ethos-U55 NPU_ID (architecture / product revision) register.

Presence/revision probe. The value encodes the Arm architecture and product revision fields; a driver typically reads it once after ra8_npu_init() to confirm the block responds.

Parameters
[out]out_idOn success, the raw 32-bit NPU_ID value.
Returns
ra8_err_t error code.
Return values
k_ra8_ok*out_id holds the NPU_ID value.
k_ra8_err_null_ptrout_id was nullptr.
k_ra8_err_not_initializedra8_npu_init() had not run.
Precondition
out_id is non-NULL.
ra8_npu_init() previously succeeded.
Postcondition
On success *out_id holds the register value.
No hardware state is modified.
Note
Not thread-safe.
See also
ra8_npu_init
Since
0.1.0

Referenced by internal_npu_infer_execute(), and main().

◆ ra8_npu_read_status()

ra8_err_t ra8_npu_read_status ( ra8_npu_status_t * out)
nodiscard

Read and decode the NPU_STATUS register.

Parameters
[out]outOn success, the decoded status snapshot.
Returns
ra8_err_t error code.
Return values
k_ra8_ok*out holds the decoded status.
k_ra8_err_null_ptrout was nullptr.
k_ra8_err_not_initializedra8_npu_init() had not run.
Precondition
out is non-NULL.
ra8_npu_init() previously succeeded.
Postcondition
On success *out reflects the live STATUS register.
No hardware state is modified.
Note
Not thread-safe.
See also
ra8_npu_status_t
Since
0.1.0

Referenced by main().

◆ ra8_npu_reset()

ra8_err_t ra8_npu_reset ( void )
nodiscard

Soft-reset an already-initialized NPU.

Issues an NPU_RESET and polls STATUS.reset until the block is ready, returning the engine to the idle/stopped state. Use between jobs to clear a latched fault.

Returns
ra8_err_t error code.
Return values
k_ra8_okReset complete; NPU idle.
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_hw_timeoutReset did not complete within the spin budget.
Precondition
ra8_npu_init() previously succeeded.
No inference job result is still needed (reset discards NPU state).
Postcondition
On success STATUS.reset reads 0 (reset finished).
On success the NPU is stopped (STATUS.state == 0).
Note
Not thread-safe.
See also
ra8_npu_init
Since
0.1.0

◆ ra8_npu_run()

ra8_err_t ra8_npu_run ( void )
nodiscard

Kick the currently-submitted job (transition the NPU to running).

Sets CMD.transition_to_running_state, after which the NPU parses the command queue programmed by ra8_npu_submit(). Completion is observed via ra8_npu_poll() / ra8_npu_wait() or the NPU IRQ.

Returns
ra8_err_t error code.
Return values
k_ra8_okRun request issued.
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_invalid_stateNo job has been submitted since init/reset.
Precondition
ra8_npu_submit() programmed a job since the last init/reset.
ra8_npu_init() previously succeeded.
Postcondition
On success CMD.transition_to_running_state has been written.
The NPU begins (or is about to begin) consuming the command queue.
Note
Not thread-safe.
See also
ra8_npu_submit
ra8_npu_wait
Since
0.1.0

Referenced by internal_npu_infer_run_job_irq(), internal_npu_smoke_run_job(), and internal_npu_vela_run_job().

◆ ra8_npu_submit()

ra8_err_t ra8_npu_submit ( const ra8_npu_job_t * job)
nodiscard

Program the command queue and tensor region base pointers for a job.

Writes QBASE (64-bit, split lo/hi) to the job's command-stream address and QSIZE to its byte length, then writes each in-use BASEPn pair to the corresponding tensor-arena AXI base. Does NOT start the job – call ra8_npu_run() afterwards. Programming is idempotent: re-submitting overwrites the previous descriptor.

Parameters
[in]jobJob descriptor (command stream + region bases). Not retained.
Returns
ra8_err_t error code.
Return values
k_ra8_okQueue and region pointers programmed.
k_ra8_err_null_ptrjob or job->cmd_stream was nullptr.
k_ra8_err_invalid_sizejob->cmd_stream_bytes was 0.
k_ra8_err_invalid_argjob->region_count exceeds k_ra8_npu_region_count.
k_ra8_err_not_initializedra8_npu_init() had not run.
Precondition
ra8_npu_init() previously succeeded.
job describes a valid command stream resident in NPU-visible SRAM.
Postcondition
On success QBASE/QSIZE and the used BASEPn registers hold job's values.
The NPU is armed but not yet running (no CMD write performed).
Note
Not thread-safe.
See also
ra8_npu_run
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 5: 2 preconditions, 2 postconditions
  • Rule 7: returns ra8_err_t, marked [[nodiscard]]

Referenced by internal_npu_infer_run_job_irq(), internal_npu_smoke_run_job(), and internal_npu_vela_run_job().

◆ ra8_npu_wait()

ra8_err_t ra8_npu_wait ( void )
nodiscard

Bounded busy-wait until the running job completes or faults.

Spins ra8_npu_poll() up to a fixed iteration budget (NASA Rule 2). Returns as soon as the job completes, a fault is latched, or the budget is exhausted.

Returns
ra8_err_t error code.
Return values
k_ra8_okJob completed (command stream fully consumed).
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_hw_errorA STATUS fault bit was observed.
k_ra8_err_hw_timeoutJob did not complete within the spin budget.
Precondition
ra8_npu_run() has been issued for the job being awaited.
ra8_npu_init() previously succeeded.
Postcondition
On k_ra8_ok the command stream has been fully consumed.
No hardware state is modified beyond the NPU's own progress.
Note
Not thread-safe. Prefer the IRQ path for long-running inferences.
See also
ra8_npu_poll
Since
0.1.0

Referenced by internal_npu_smoke_run_job(), and internal_npu_vela_run_job().

◆ ra8_npu_wait_irq()

ra8_err_t ra8_npu_wait_irq ( void )
nodiscard

Block on the NPU interrupt until the armed job completes or faults.

The interrupt-driven alternative to the busy-wait ra8_npu_wait. Spins a bounded budget (NASA Rule 2), issuing a WFI on the target between checks so the core sleeps until ra8_npu_irq_handler latches a result. On the unit-test host WFI compiles away and the test drives ra8_npu_irq_handler directly. Requires ra8_npu_irq_arm to have armed the latch first.

Returns
ra8_err_t error code.
Return values
k_ra8_okThe ISR observed completion (command stream consumed).
k_ra8_err_not_initializedra8_npu_init() had not run.
k_ra8_err_invalid_stateThe completion latch was not armed.
k_ra8_err_hw_errorThe ISR latched a STATUS fault.
k_ra8_err_hw_timeoutNo completion latched within the spin budget.
Precondition
ra8_npu_irq_arm() armed the latch and ra8_npu_run() kicked the job.
The NPU interrupt is routed to ra8_npu_irq_handler and IRQs are enabled.
Postcondition
On k_ra8_ok the command stream has been fully consumed.
No hardware register is modified by the wait itself.
Note
Not thread-safe. Prefer this over ra8_npu_wait for long inferences.
See also
ra8_npu_irq_arm
ra8_npu_wait
Since
0.1.0

Referenced by internal_npu_infer_run_job_irq().