|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
IPC HAL – hardware semaphores, NMI surface, and ring buffers. More...
#include <stdint.h>#include "ra8_attributes.h"#include "ra8_check.h"#include "ra8_err.h"#include "ra8_hw_err.h"#include "ra8_ipc.h"#include "ra8_ipc_regs.h"Go to the source code of this file.
Functions | |
| static volatile r_ipc_nmi_regs_t * | internal_ra8_ipc_get_nmi (uint8_t unit) |
| Validate NMI unit id and return the NMI reg pointer. | |
| static uint32_t | internal_ra8_ipc_sem_read_take (volatile uint32_t *sem) |
| Test-and-set on IPCSEMn – a 32-bit read takes the lock and returns the previous LOCK value. | |
| static void | internal_ra8_ipc_sem_release_write (volatile uint32_t *sem) |
| Write the IPCSEMn write-1-to-clear release command. | |
| ra8_err_t | ra8_ipc_sem_try_take (uint8_t sem_id) |
| Test-and-set acquire on one IPC hardware semaphore. | |
| ra8_err_t | ra8_ipc_sem_take_timeout (uint8_t sem_id, uint16_t max_spins) |
| Bounded-spin take on one IPC hardware semaphore. | |
| ra8_err_t | ra8_ipc_sem_release (uint8_t sem_id) |
| Release one IPC hardware semaphore. | |
| ra8_err_t | ra8_ipc_sem_is_locked (uint8_t sem_id, bool *out_locked) |
| Predicate: is the semaphore currently locked? | |
| ra8_err_t | ra8_ipc_nmi_send (uint8_t unit) |
| Issue an inter-processor NMI to the peer core. | |
| ra8_err_t | ra8_ipc_nmi_clear (uint8_t unit) |
| Acknowledge an inter-processor NMI on the local core. | |
| ra8_err_t | ra8_ipc_nmi_get_status (uint8_t unit, bool *out_pending) |
| Read NMISTA.NMI for one IPC NMI unit. | |
| ra8_err_t | ra8_ipc_attach_nmi_handler (ra8_ipc_nmi_fn_t fn, void *ctx) |
| Attach a callback for inter-processor NMI dispatch. | |
| void | ra8_ipc_dispatch_nmi (uint8_t unit) |
| Drive the NMI dispatch path for one unit. | |
| static ra8_err_t | internal_ra8_ipc_ring_validate (const ra8_ipc_ring_t *ring) |
| Validate the scalar fields of an ra8_ipc_ring_t descriptor. | |
| ra8_err_t | ra8_ipc_ring_init (ra8_ipc_ring_t *ring) |
| Initialise a producer/consumer ring backed by shared SRAM. | |
| ra8_err_t | ra8_ipc_ring_produce (ra8_ipc_ring_t *ring, uint32_t payload) |
| Push one word into the shared-memory ring (producer side). | |
| ra8_err_t | ra8_ipc_ring_consume (ra8_ipc_ring_t *ring, uint32_t *out_payload) |
| Pop one word from the shared-memory ring (consumer side). | |
| ra8_err_t | ra8_ipc_ring_is_empty (const ra8_ipc_ring_t *ring, bool *out_empty) |
| Predicate: ring empty? | |
| ra8_err_t | ra8_ipc_ring_is_full (const ra8_ipc_ring_t *ring, bool *out_full) |
| Predicate: ring full? | |
Variables | |
| static const char * | s_tag = "IPC" |
| static ra8_ipc_nmi_fn_t | s_ipc_nmi_callback |
| static void * | s_ipc_nmi_context |
IPC HAL – hardware semaphores, NMI surface, and ring buffers.
Sibling translation unit of ra8_ipc.c carrying the cohesive lower-level IPC surfaces that compose into cross-core synchronization: the IPCSEM0..15 hardware-semaphore wrappers (test-and-set + bounded spin take), the NMI surface (IPC0NMI* / IPC1NMI*), and the producer/consumer ring-buffer protocol that uses an IPCSEM for mutual exclusion plus the FIFO IRQ lines for cross-core notification. See ra8_ipc.h for the public API surface. Each register access carries a HUM Ch 3 citation – IPC is not power-gated by MSTPCR so the driver does not call ra8_mstp_*.
Definition in file ra8_ipc_sem_ring.c.
|
static |
Validate NMI unit id and return the NMI reg pointer.
Definition at line 47 of file ra8_ipc_sem_ring.c.
References k_ra8_ipc_nmi_unit_count, and ra8_ipc_nmi().
Referenced by ra8_ipc_dispatch_nmi(), ra8_ipc_nmi_clear(), ra8_ipc_nmi_get_status(), and ra8_ipc_nmi_send().
|
static |
Validate the scalar fields of an ra8_ipc_ring_t descriptor.
| [in] | ring | Caller-supplied, null-checked ring descriptor. |
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 319 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::channel, k_ra8_err_invalid_arg, k_ra8_ipc_channel_count, k_ra8_ipc_irq_event_count, k_ra8_ipc_sem_count, k_ra8_ok, ra8_ipc_ring_t::notify_id, and ra8_ipc_ring_t::sem_id.
Referenced by ra8_ipc_ring_init().
|
static |
Test-and-set on IPCSEMn – a 32-bit read takes the lock and returns the previous LOCK value.
On silicon the read itself is the take: HUM Ch 3.2.3 "IPCSEMn" p 210 documents "Set condition: Reading this register", and the read data report the LOCK state from before the set. The host unit-test register file is dumb RAM with no read side effects, so the host test build routes the same read through the ra8_fake_mmio read-to-set model, which performs the read and then latches LOCK in the backing RAM exactly as the silicon set condition does. A test models a peer core releasing the semaphore mid-spin with ra8_fake_mmio_set_poll_hook.
| [in] | sem | Mapped IPCSEMn register. Must not be NULL (callers null-check the accessor result before calling). |
| 0 | The semaphore was free – the caller now owns it. |
| k_ra8_ipc_sem_mask_lock | It was already owned by another core. |
Definition at line 85 of file ra8_ipc_sem_ring.c.
References k_ra8_ipc_sem_mask_lock.
Referenced by ra8_ipc_sem_is_locked(), ra8_ipc_sem_take_timeout(), and ra8_ipc_sem_try_take().
|
static |
Write the IPCSEMn write-1-to-clear release command.
HUM Ch 3.2.3 "IPCSEMn" p 210: "Clear condition: Writing 1 to this bit" – silicon clears LOCK when the command lands. The host unit-test register file is dumb RAM that would store the literal 1 (leaving the register file claiming "locked" after a release), so the host test build routes the same write through the ra8_fake_mmio write-1-to-clear model, which leaves LOCK cleared exactly as silicon does.
| [in] | sem | Mapped IPCSEMn register. Must not be NULL (callers null-check the accessor result before calling). |
Definition at line 124 of file ra8_ipc_sem_ring.c.
References k_ra8_ipc_sem_mask_lock.
Referenced by ra8_ipc_sem_is_locked(), and ra8_ipc_sem_release().
|
nodiscard |
Attach a callback for inter-processor NMI dispatch.
Single global callback shared by both NMI units; unit is passed back as a parameter so the callback can demux IPC0NMI vs IPC1NMI. Pass NULL to detach.
| [in] | fn | Callback fired by ra8_ipc_dispatch_nmi. |
| [in] | ctx | Opaque context forwarded to fn. |
| k_ra8_ok | Always. |
Definition at line 267 of file ra8_ipc_sem_ring.c.
References k_ra8_ok, s_ipc_nmi_callback, and s_ipc_nmi_context.
| void ra8_ipc_dispatch_nmi | ( | uint8_t | unit | ) |
Drive the NMI dispatch path for one unit.
Reads NMISTA.NMI; if set, calls the registered NMI callback and writes NMICLR.CLR to acknowledge. Safe to call when no NMI is pending (becomes a no-op).
| [in] | unit | NMI unit id 0..1. |
Definition at line 274 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_ipc_nmi_mask_bit, r_ipc_nmi_regs_t::NMICLR, r_ipc_nmi_regs_t::NMISTA, s_ipc_nmi_callback, and s_ipc_nmi_context.
|
nodiscard |
Acknowledge an inter-processor NMI on the local core.
| [in] | unit | NMI unit id 0..1. |
| k_ra8_ok | CLR written. |
| k_ra8_err_invalid_arg | unit >= 2. |
Definition at line 243 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_err_invalid_arg, k_ra8_ipc_nmi_mask_bit, k_ra8_ok, and r_ipc_nmi_regs_t::NMICLR.
|
nodiscard |
Read NMISTA.NMI for one IPC NMI unit.
| [in] | unit | NMI unit id 0..1. |
| [out] | out_pending | Receives true if NMI is currently asserted. |
| k_ra8_ok | Status read. |
| k_ra8_err_invalid_arg | unit >= 2. |
| k_ra8_err_null_ptr | out_pending was NULL. |
Definition at line 255 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_err_invalid_arg, k_ra8_ipc_nmi_mask_bit, k_ra8_ok, r_ipc_nmi_regs_t::NMISTA, RA8_CHECK_NULL_PTR, and s_tag.
|
nodiscard |
Issue an inter-processor NMI to the peer core.
Writes 1 to IPCnNMISET.SET (HUM Ch 3.2.5 p 211 / Ch 3.2.8 p 213). The peer core observes IPCnNMISTA.NMI = 1 and (if the ICU has the IPCNMIn line enabled) takes the NMI exception.
| [in] | unit | NMI unit id (k_ra8_ipc_unit_ipc0 or k_ra8_ipc_unit_ipc1). |
| k_ra8_ok | SET written. |
| k_ra8_err_invalid_arg | unit >= 2. |
Definition at line 231 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_get_nmi(), k_ra8_err_invalid_arg, k_ra8_ipc_nmi_mask_bit, k_ra8_ok, and r_ipc_nmi_regs_t::NMISET.
|
nodiscard |
Pop one word from the shared-memory ring (consumer side).
Acquires the semaphore, samples head/tail, copies slots[tail % capacity] into out_payload if non-empty, advances tail, releases the semaphore.
| [in] | ring | Non-NULL initialized descriptor. |
| [out] | out_payload | Receives the popped word. |
| k_ra8_ok | Word dequeued. |
| k_ra8_err_null_ptr | ring or out_payload was NULL. |
| k_ra8_err_busy | Semaphore not available. |
| k_ra8_err_no_data | Ring was empty. |
Definition at line 380 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::head, k_ra8_err_no_data, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_sem_release(), ra8_ipc_sem_try_take(), s_tag, ra8_ipc_ring_t::sem_id, ra8_ipc_ring_t::slots, and ra8_ipc_ring_t::tail.
|
nodiscard |
Initialise a producer/consumer ring backed by shared SRAM.
Zeroes the head/tail counters and stores the descriptor for later ra8_ipc_ring_produce / ra8_ipc_ring_consume calls. Does not touch the underlying slots array; the caller is responsible for placing it in shared SRAM that both cores can see.
| [in] | ring | Non-NULL descriptor (caller-allocated). |
| k_ra8_ok | Initialized. |
| k_ra8_err_null_ptr | ring or one of its required pointer fields was NULL. |
| k_ra8_err_invalid_arg | capacity == 0 or non-power-of-two. |
Definition at line 340 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::head, internal_ra8_ipc_ring_validate(), k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, ra8_ipc_ring_t::slots, and ra8_ipc_ring_t::tail.
|
nodiscard |
Predicate: ring empty?
| [in] | ring | Non-NULL descriptor. |
| [out] | out_empty | true when head == tail. |
| k_ra8_ok | Predicate evaluated. |
| k_ra8_err_null_ptr | ring or out_empty was NULL. |
Definition at line 399 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::head, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, and ra8_ipc_ring_t::tail.
|
nodiscard |
Predicate: ring full?
| [in] | ring | Non-NULL descriptor. |
| [out] | out_full | true when (head - tail) == capacity. |
| k_ra8_ok | Predicate evaluated. |
| k_ra8_err_null_ptr | ring or out_full was NULL. |
Definition at line 407 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::head, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, and ra8_ipc_ring_t::tail.
|
nodiscard |
Push one word into the shared-memory ring (producer side).
Acquires ring->sem_id via ra8_ipc_sem_try_take, writes payload into slots[head % capacity], advances head, releases the semaphore, then signals the consumer through ra8_ipc_send_event(ring->channel, ring->notify_id).
| [in] | ring | Non-NULL initialized descriptor. |
| [in] | payload | 32-bit word to enqueue. |
| k_ra8_ok | Word enqueued and notification sent. |
| k_ra8_err_null_ptr | ring was NULL. |
| k_ra8_err_busy | Ring full or semaphore not available. |
Definition at line 355 of file ra8_ipc_sem_ring.c.
References ra8_ipc_ring_t::capacity, ra8_ipc_ring_t::channel, ra8_ipc_ring_t::head, k_ra8_err_busy, k_ra8_ok, ra8_ipc_ring_t::notify_id, RA8_CHECK_NULL_PTR, ra8_ipc_sem_release(), ra8_ipc_sem_try_take(), ra8_ipc_send_event(), s_tag, ra8_ipc_ring_t::sem_id, ra8_ipc_ring_t::slots, and ra8_ipc_ring_t::tail.
|
nodiscard |
Predicate: is the semaphore currently locked?
Note that simply reading IPCSEMn through a 32-bit access takes the semaphore (HUM Ch 3.2.3 p 210 NOTE). This API therefore samples the LOCK bit by reading and, if the read observed "unlocked", undoes the probe's own take with the write-1-to-clear release command so the register reads back 0 again.
Only safe to call when the caller already owns the lock or knows the peer is quiescent. Most users should treat this as a debug-only helper and stick to ra8_ipc_sem_try_take for real acquisition.
| [in] | sem_id | Semaphore index 0..15. |
| [out] | out_locked | Receives true if the semaphore was already locked. |
| k_ra8_ok | Predicate evaluated. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
| k_ra8_err_null_ptr | out_locked was NULL. |
Definition at line 204 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_read_take(), internal_ra8_ipc_sem_release_write(), k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_sem(), and s_tag.
|
nodiscard |
Release one IPC hardware semaphore.
| [in] | sem_id | Semaphore index 0..15. |
| k_ra8_ok | Released. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
Definition at line 190 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_release_write(), k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_barrier(), ra8_ipc_sem(), and s_tag.
Referenced by ra8_ipc_ring_consume(), and ra8_ipc_ring_produce().
|
nodiscard |
Bounded-spin take on one IPC hardware semaphore.
| [in] | sem_id | Semaphore index 0..15. |
| [in] | max_spins | Iteration cap (<= k_ra8_ipc_sem_take_max). |
| k_ra8_ok | Acquired before the budget ran out. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
| k_ra8_err_hw_timeout | Budget expired without acquiring. |
Definition at line 163 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_read_take(), k_ra8_err_hw_timeout, k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ipc_sem_take_max, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_barrier(), ra8_ipc_sem(), and s_tag.
|
nodiscard |
Test-and-set acquire on one IPC hardware semaphore.
IPCSEMn implements test-and-set semantics: a 32-bit read sets the LOCK bit and returns the previous value. A return of 0 means the caller acquired the lock (it was previously unlocked). A return of 1 means another core owned it.
| [in] | sem_id | Semaphore index 0..15. |
| k_ra8_ok | Lock acquired. |
| k_ra8_err_busy | Lock already held by another core. |
| k_ra8_err_invalid_arg | sem_id >= 16. |
Definition at line 143 of file ra8_ipc_sem_ring.c.
References internal_ra8_ipc_sem_read_take(), k_ra8_err_busy, k_ra8_err_invalid_arg, k_ra8_ipc_sem_count, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_ipc_barrier(), ra8_ipc_sem(), and s_tag.
Referenced by ra8_ipc_ring_consume(), and ra8_ipc_ring_produce().
|
static |
Definition at line 35 of file ra8_ipc_sem_ring.c.
Referenced by ra8_ipc_attach_nmi_handler(), and ra8_ipc_dispatch_nmi().
|
static |
Definition at line 36 of file ra8_ipc_sem_ring.c.
Referenced by ra8_ipc_attach_nmi_handler(), and ra8_ipc_dispatch_nmi().
|
static |
Definition at line 33 of file ra8_ipc_sem_ring.c.