ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_canfd.c
Go to the documentation of this file.
1
36
37#include <stdint.h>
38#include <stdio.h>
39#include <string.h>
40
41#include "board_console.h"
42#include "board_periph_block.h"
44
46typedef enum : uint64_t {
47 k_canfd0_base = 0x40380000UL,
48 k_canfd1_base = 0x40382000UL,
49 k_canfd_span = 0x1920UL,
51 k_canfd_words = 0x1920UL / 4UL,
54 k_canfd_off_gctr = 0x018UL,
55 k_canfd_off_gsts = 0x01CUL,
58 k_canfd_off_tmc0 = 0x070UL,
60 k_canfd_off_rf0 = 0x520UL,
61 k_canfd_off_tm0 = 0x604UL,
62 k_canfd_frame_words = 0x4CUL / 4UL,
63 k_canfd_off_afl = 0x120UL,
67
69typedef enum : uint32_t {
70 k_gsts_grststs = 1UL << 0U,
71 k_gsts_ghltsts = 1UL << 1U,
72 k_gsts_graminit = 1UL << 3U,
74
76typedef enum : uint32_t {
77 k_cnsts_crstst = 1UL << 0U,
78 k_cnsts_chltst = 1UL << 1U,
80
82typedef enum : uint32_t {
83 k_canfd_id_std = 0x000007FFUL,
84 k_canfd_id_ext = 0x1FFFFFFFUL,
86
88typedef enum : uint32_t {
93
95typedef enum : uint32_t {
96 k_mode_mask = 0x3UL,
98 k_mode_reset = 0x1UL,
99 k_mode_halt = 0x2UL,
101
103typedef enum : uint32_t {
104 k_rfsts_empty = 1UL << 0U,
105 k_rfsts_if = 1UL << 3U,
107
109typedef enum : uint8_t {
110 k_tmc_txreq = 1U << 0U,
111 k_tmsts_done = 0x04U,
113
127typedef enum : uint16_t {
130
132typedef struct {
133 uint32_t reg[k_canfd_words];
134 uint32_t loopbacks;
136
138
150RA8_INTERNAL static uint32_t internal_canfd_instance(uint64_t addr)
151{
152 if ((addr >= (uint64_t)k_canfd0_base) &&
153 (addr < (uint64_t)k_canfd0_base + (uint64_t)k_canfd_span)) {
154 return 0U;
155 }
156 if ((addr >= (uint64_t)k_canfd1_base) &&
157 (addr < (uint64_t)k_canfd1_base + (uint64_t)k_canfd_span)) {
158 return 1U;
159 }
160 return (uint32_t)k_canfd_count;
161}
162
175RA8_INTERNAL static uint64_t internal_canfd_offset(uint32_t inst, uint64_t addr)
176{
177 const uint64_t base = (inst == 0U) ? (uint64_t)k_canfd0_base : (uint64_t)k_canfd1_base;
178 return addr - base;
179}
180
192RA8_INTERNAL static uint32_t internal_canfd_word(uint64_t off)
193{
194 return (uint32_t)(off >> 2U);
195}
196
208{
209 uint32_t gsts = c->reg[internal_canfd_word((uint64_t)k_canfd_off_gsts)];
210 gsts &= ~(uint32_t)(k_gsts_grststs | k_gsts_ghltsts | k_gsts_graminit);
211 const uint32_t mode = gctr & (uint32_t)k_mode_mask;
212 if (mode == (uint32_t)k_mode_reset) {
213 gsts |= (uint32_t)k_gsts_grststs;
214 } else if (mode == (uint32_t)k_mode_halt) {
215 gsts |= (uint32_t)k_gsts_ghltsts;
216 }
217 c->reg[internal_canfd_word((uint64_t)k_canfd_off_gsts)] = gsts;
218}
219
231{
232 uint32_t sts = c->reg[internal_canfd_word((uint64_t)k_canfd_off_cnsts)];
233 sts &= ~(uint32_t)(k_cnsts_crstst | k_cnsts_chltst);
234 const uint32_t mode = ctr & (uint32_t)k_mode_mask;
235 if (mode == (uint32_t)k_mode_reset) {
236 sts |= (uint32_t)k_cnsts_crstst;
237 } else if (mode == (uint32_t)k_mode_halt) {
238 sts |= (uint32_t)k_cnsts_chltst;
239 }
240 c->reg[internal_canfd_word((uint64_t)k_canfd_off_cnsts)] = sts;
241}
242
264RA8_INTERNAL static bool internal_canfd_frame_accepted(const canfd_inst_t* c, uint32_t tx_id)
265{
266 bool any_active = false;
267 for (uint32_t slot = 0U; slot < (uint32_t)k_canfd_afl_count; slot++) {
268 const uint64_t ent =
269 (uint64_t)k_canfd_off_afl + ((uint64_t)slot * (uint64_t)k_canfd_afl_stride);
270 const uint32_t mask = c->reg[internal_canfd_word(ent + 4UL)] & (uint32_t)k_canfd_id_ext;
271 if (mask == 0U) {
272 continue; /* unprogrammed slot */
273 }
274 any_active = true;
275 const uint32_t accept_id = c->reg[internal_canfd_word(ent)] & (uint32_t)k_canfd_id_ext;
276 if ((tx_id & mask) == (accept_id & mask)) {
277 return true;
278 }
279 }
280 return !any_active;
281}
282
307RA8_INTERNAL static void
308internal_canfd_console_frame(uint32_t inst, uint32_t tx_id, uint32_t dlc, const char* outcome)
309{
310 enum : uint8_t {
311 k_canfd_console_line_cap = 64U,
312 };
313 char ln[k_canfd_console_line_cap];
314 (void)snprintf(ln, sizeof(ln), "CANFD%u TX id=0x%X dlc=%u %s", inst, tx_id, dlc, outcome);
316}
317
328RA8_INTERNAL static void internal_canfd_loopback_deliver(uc_engine* uc, uint32_t inst)
329{
330 canfd_inst_t* c = &s_canfd[inst];
331 const uint32_t tm = internal_canfd_word((uint64_t)k_canfd_off_tm0);
332 const uint32_t rf = internal_canfd_word((uint64_t)k_canfd_off_rf0);
333 const uint32_t tx_id = c->reg[tm] & (uint32_t)k_canfd_id_ext;
334 const uint32_t ptr = c->reg[tm + (uint32_t)k_canfd_ptr_word];
335 const uint32_t dlc = (ptr >> (uint32_t)k_canfd_ptr_dlc_shift) & (uint32_t)k_canfd_ptr_dlc_mask;
336 /* The frame is transmitted regardless of the filter; mark TX complete.
337 * CFDTMSTS[0] is a byte at a word-aligned offset, so its low byte carries
338 * TMTRF = 10b ("transmission complete"). */
339 c->reg[internal_canfd_word((uint64_t)k_canfd_off_tmsts0)] = (uint32_t)k_tmsts_done;
340 if (!internal_canfd_frame_accepted(c, tx_id)) {
341 if (board_periph_trace()) {
342 (void)priv_emu_io_errf(" [trace] CANFD%u loopback: TX id=0x%X filtered (no AFL match)\n",
343 inst,
344 tx_id);
345 }
346 internal_canfd_console_frame(inst, tx_id, dlc, "filtered");
347 return; /* filtered out: transmitted but not received */
348 }
349 for (uint32_t w = 0U; w < (uint32_t)k_canfd_frame_words; w++) {
350 c->reg[rf + w] = c->reg[tm + w];
351 }
352 /* RX FIFO 0 now holds one frame: clear empty, raise the RX flag. */
353 uint32_t rfsts = c->reg[internal_canfd_word((uint64_t)k_canfd_off_rfsts0)];
354 rfsts &= ~(uint32_t)k_rfsts_empty;
355 rfsts |= (uint32_t)k_rfsts_if;
356 c->reg[internal_canfd_word((uint64_t)k_canfd_off_rfsts0)] = rfsts;
357 c->loopbacks++;
358 if (inst == 0U) {
360 }
361 if (board_periph_trace()) {
362 (void)priv_emu_io_errf(" [trace] CANFD%u loopback: TX MB0 -> RX FIFO0 (id=0x%X)\n",
363 inst,
364 c->reg[rf] & (uint32_t)k_canfd_id_ext);
365 }
366 internal_canfd_console_frame(inst, tx_id, dlc, "-> RXF0");
367}
368
382RA8_INTERNAL static uint64_t internal_canfd_read(uc_engine* uc, uint64_t addr, unsigned size)
383{
384 (void)uc;
385 (void)size;
386 const uint32_t inst = internal_canfd_instance(addr);
387 if (inst >= (uint32_t)k_canfd_count) {
388 return 0U;
389 }
390 const uint64_t off = internal_canfd_offset(inst, addr);
391 if (off >= (uint64_t)k_canfd_span) {
392 return 0U;
393 }
394 return s_canfd[inst].reg[internal_canfd_word(off)];
395}
396
409RA8_INTERNAL static void
410internal_canfd_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
411{
412 (void)size;
413 const uint32_t inst = internal_canfd_instance(addr);
414 if (inst >= (uint32_t)k_canfd_count) {
415 return;
416 }
417 const uint64_t off = internal_canfd_offset(inst, addr);
418 if (off >= (uint64_t)k_canfd_span) {
419 return;
420 }
421 canfd_inst_t* c = &s_canfd[inst];
422 /* CFDTMC[0] is a byte register; a TMTR request triggers the loopback. */
423 if (off == (uint64_t)k_canfd_off_tmc0) {
424 c->reg[internal_canfd_word(off)] = (uint32_t)value;
425 if (((uint8_t)value & (uint8_t)k_tmc_txreq) != 0U) {
427 }
428 return;
429 }
430 /* Popping RX FIFO 0 (CFDRFPCTR write) returns it to the empty state. */
431 if (off == (uint64_t)k_canfd_off_rfpctr0) {
432 c->reg[internal_canfd_word(off)] = (uint32_t)value;
433 uint32_t rfsts = c->reg[internal_canfd_word((uint64_t)k_canfd_off_rfsts0)];
434 rfsts |= (uint32_t)k_rfsts_empty;
435 rfsts &= ~(uint32_t)k_rfsts_if;
436 c->reg[internal_canfd_word((uint64_t)k_canfd_off_rfsts0)] = rfsts;
437 return;
438 }
439 c->reg[internal_canfd_word(off)] = (uint32_t)value;
440 if (off == (uint64_t)k_canfd_off_gctr) {
441 internal_canfd_apply_global_mode(c, (uint32_t)value);
442 } else if (off == (uint64_t)k_canfd_off_cnctr) {
443 internal_canfd_apply_channel_mode(c, (uint32_t)value);
444 }
445}
446
456{
457 for (uint32_t i = 0U; i < (uint32_t)k_canfd_count; i++) {
458 (void)memset(&s_canfd[i], 0, sizeof(s_canfd[i]));
459 /* RX FIFO 0 powers up empty; GRAMINIT powers up already-clear (0). */
460 s_canfd[i].reg[internal_canfd_word((uint64_t)k_canfd_off_rfsts0)] = (uint32_t)k_rfsts_empty;
461 }
462}
463
473{
474 for (uint32_t i = 0U; i < (uint32_t)k_canfd_count; i++) {
475 if (s_canfd[i].loopbacks == 0U) {
476 continue;
477 }
478 const uint32_t rf = internal_canfd_word((uint64_t)k_canfd_off_rf0);
479 (void)priv_emu_io_errf(" CANFD%u : loopback frames=%u last_rx_id=0x%03X\n",
480 i,
481 s_canfd[i].loopbacks,
482 s_canfd[i].reg[rf] & (uint32_t)k_canfd_id_std);
483 }
484}
485
488 .base = (uint64_t)k_canfd0_base,
489 .span = (uint64_t)k_canfd_span,
490 .order = (uint32_t)k_block_order_i2c, /* After the timers/UART; no tick. */
491 .read = internal_canfd_read,
493 .tick = nullptr,
494 .reset = internal_canfd_reset,
495 .report = internal_canfd_report,
496 .name = "CANFD0",
497};
498
501 .base = (uint64_t)k_canfd1_base,
502 .span = (uint64_t)k_canfd_span,
503 .order = (uint32_t)k_block_order_i2c,
504 .read = internal_canfd_read,
506 .tick = nullptr,
507 .reset = nullptr,
508 .report = nullptr,
509 .name = "CANFD1",
510};
511
Multi-channel console log store backing the board view's tabbed console.
void board_console_push(board_console_ch_t ch, const char *line)
Append one completed line to a channel ring and the ALL ring.
@ k_board_console_ch_can
CAN-FD frame summaries.
Decentralized peripheral-block registry for the board emulator core.
void board_periph_icu_raise_event(uc_engine *uc, uint16_t event)
Raise a peripheral ELC event through the core's ICU -> NVIC path.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
@ k_block_order_i2c
I3C/I2C + GT911 (no tick today).
bool board_periph_trace(void)
Whether –trace is active (blocks log transitions when true).
static RA8_INTERNAL uint64_t internal_canfd_offset(uint32_t inst, uint64_t addr)
In-window byte offset of addr for instance inst.
static const board_periph_block_t s_k_canfd1_block
CANFD1 register window (reset / report handled by the CANFD0 block).
canfd_rfsts_t
RX FIFO status (CFDRFSTS[0]) bit masks.
@ k_rfsts_empty
RFEMP: FIFO empty flag.
@ k_rfsts_if
RFIF: RX interrupt flag.
static RA8_INTERNAL uint32_t internal_canfd_instance(uint64_t addr)
Resolve an absolute address to its instance index (0/1) or count.
static RA8_INTERNAL void internal_canfd_apply_channel_mode(canfd_inst_t *c, uint32_t ctr)
Apply a channel mode-control write to its matching status bits.
canfd_elc_event_t
CANFD0 RX-FIFO (RXF) ELC event the model pends on loopback delivery.
@ k_event_can0_rxf
CANFD0 RXF RX-FIFO event (best-effort).
static RA8_INTERNAL void internal_canfd_report(void)
Print one line per CANFD instance that looped a frame back.
canfd_map_t
CANFD block geometry (ra8_canfd_regs.h, FSP R_CANFD_Type).
@ k_canfd_span
Full FSP R_CANFD_Type window size.
@ k_canfd_off_gsts
CFDGSTS global status.
@ k_canfd_off_tmc0
CFDTMC[0] TX MB 0 control byte.
@ k_canfd_words
CANFD words.
@ k_canfd_off_rfsts0
CFDRFSTS[0] RX FIFO 0 status.
@ k_canfd0_base
CANFD0 channel-window base.
@ k_canfd_off_tm0
CFDTM[0] TX MB 0 access window.
@ k_canfd_afl_stride
Bytes per CFDGAFL entry (ID/M/P0/P1).
@ k_canfd_off_cnctr
CFDC[0].CTR channel control.
@ k_canfd_count
CANFD0 / CANFD1.
@ k_canfd_off_gctr
CFDGCTR global control.
@ k_canfd_frame_words
ID+PTR+FDSTS+DF[64] = 19 words.
@ k_canfd_off_rfpctr0
CFDRFPCTR[0] RX FIFO 0 pointer ctrl.
@ k_canfd_off_afl
CFDGAFL[] acceptance-filter window.
@ k_canfd_off_tmsts0
CFDTMSTS[0] TX MB 0 status byte.
@ k_canfd_off_rf0
CFDRF[0] RX FIFO 0 access window.
@ k_canfd_afl_count
Entries in one CFDGAFL page window.
@ k_canfd_off_cnsts
CFDC[0].STS channel status.
@ k_canfd1_base
CANFD1 channel-window base.
canfd_gsts_t
Global status (CFDGSTS) bit masks the model drives.
@ k_gsts_graminit
Global RAM-init in progress.
@ k_gsts_ghltsts
Global halt status.
@ k_gsts_grststs
Global reset status.
static const board_periph_block_t s_k_canfd0_block
CANFD0 register window + the shared loopback reset / report.
static canfd_inst_t s_canfd[k_canfd_count]
static RA8_INTERNAL void internal_board_periph_canfd_register(void)
Self-register both CANFD windows before main runs (decentralized).
canfd_tmc_t
TX MB control / status byte bits.
@ k_tmc_txreq
CFDTMC.TMTR transmit request.
@ k_tmsts_done
CFDTMSTS.TMTRF = 10b complete.
static RA8_INTERNAL void internal_canfd_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
Handle a write to a CANFD register with side effects, else latch it.
static RA8_INTERNAL void internal_canfd_apply_global_mode(canfd_inst_t *c, uint32_t gctr)
Apply a mode-control write to its matching status register bits.
static RA8_INTERNAL void internal_canfd_console_frame(uint32_t inst, uint32_t tx_id, uint32_t dlc, const char *outcome)
Push a one-line CAN-FD frame summary to the board console CAN lane.
static RA8_INTERNAL uint64_t internal_canfd_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside a CANFD window: read back the latched register.
canfd_id_mask_t
Message-ID field masks (CFDRF.ID / CFDTM.ID), for trace + report.
@ k_canfd_id_std
11-bit standard ID.
@ k_canfd_id_ext
29-bit extended ID.
canfd_cnsts_t
Channel status (CFDC[0].STS) bit masks the model drives.
@ k_cnsts_chltst
Channel halt status.
@ k_cnsts_crstst
Channel reset status.
canfd_ptr_t
CFDTM/CFDRF.PTR frame fields (PTR layout: [15:0] timestamp, [31:28] DLC).
@ k_canfd_ptr_word
PTR is the 2nd word of a frame window.
@ k_canfd_ptr_dlc_shift
DLC occupies PTR bits [31:28].
@ k_canfd_ptr_dlc_mask
4-bit DLC code mask (0..15).
static RA8_INTERNAL uint32_t internal_canfd_word(uint64_t off)
Word index into the backing store for an in-window offset.
canfd_mode_t
Global / channel mode-control field (GMDC / CHMDC, bits [1:0]).
@ k_mode_operation
Operation mode.
@ k_mode_halt
Halt mode.
@ k_mode_mask
2-bit mode field.
@ k_mode_reset
Reset mode.
static RA8_INTERNAL bool internal_canfd_frame_accepted(const canfd_inst_t *c, uint32_t tx_id)
Decide whether tx_id passes the programmed acceptance filter.
static RA8_INTERNAL void internal_canfd_loopback_deliver(uc_engine *uc, uint32_t inst)
Copy TX MB 0 into RX FIFO 0 and flag the frame available.
static RA8_INTERNAL void internal_canfd_reset(void)
Reset both CANFD instances to a coherent power-on state.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
-proof
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
A modelled peripheral block's self-description for the core registry.
One CANFD instance: flat register backing store.
uint32_t reg[k_canfd_words]
Word-addressed register backing.
uint32_t loopbacks
Frames delivered TX -> RX FIFO.