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

SPI_B (Type-B SPI) controller peripheral-block model for ra8_emulator. More...

#include <stdint.h>
#include <stdio.h>
#include "board_console.h"
#include "board_periph_block.h"
#include "board_periph_eink.h"
#include "board_periph_sd.h"
#include "emu_host_io_internal.h"
Include dependency graph for board_periph_spi.c:

Go to the source code of this file.

Data Structures

struct  spi_state_t
 One SPI_B channel: register shadow + a single-frame echo engine. More...

Enumerations

enum  spi_map_t : uint64_t {
  k_spi_base = 0x4035C000UL ,
  k_spi_stride = 0x100UL ,
  k_spi_count = 2UL ,
  k_spi_span = 0x100UL * 2UL ,
  k_spi_off_spdr = 0x00UL ,
  k_spi_off_spcr = 0x08UL ,
  k_spi_off_spcr2 = 0x0CUL ,
  k_spi_off_spsr = 0x50UL ,
  k_spi_off_spsrc = 0x68UL ,
  k_spi_reg_words = 0x70UL / 4UL
}
 SPI_B block geometry (ra8_spi_regs.h, 32-bit register file). More...
enum  spi_spcr_bit_t : uint32_t { k_spi_spcr_spe = 0x00000001U }
 SPCR (control 1) bits the model observes (ra8_spi_regs.h). More...
enum  spi_spcr2_bit_t : uint32_t {
  k_spi_spcr2_splp = 0x00010000U ,
  k_spi_spcr2_splp2 = 0x00020000U
}
 SPCR2 (control 2) loopback bits (ra8_spi_regs.h). More...
enum  spi_spsr_bit_t : uint32_t {
  k_spi_spsr_spdrf = 0x00800000U ,
  k_spi_spsr_sptef = 0x20000000U ,
  k_spi_spsr_cendf = 0x40000000U ,
  k_spi_spsr_sprf = 0x80000000U
}
 SPSR (status) flags the driver polls (ra8_spi_regs.h). More...
enum  spi_data_t : uint32_t { k_spi_byte_mask = 0xFFU }
 One-byte / one-word masks used by the echo path. More...
enum  spi_console_dim_t : uint32_t { k_spi_console_line_cap = 64U }
 Sizing for the board-console SPI transfer-summary line. More...

Functions

static RA8_INTERNAL uint32_t internal_spi_word (uint64_t off)
 Index of the shadow word for off within a channel (range-checked).
static RA8_INTERNAL void internal_spi_spcr_write (spi_state_t *s, uint32_t value)
 Apply an SPCR write: SPE gates the channel and arms TX-empty.
static RA8_INTERNAL void internal_spi_spcr2_write (spi_state_t *s, uint32_t value)
 Apply an SPCR2 write: latch whether internal loopback is engaged.
static RA8_INTERNAL void internal_spi_spdr_write (spi_state_t *s, uint32_t value)
 Handle a write to SPDR: echo the frame and assert receive-full.
static RA8_INTERNAL void internal_spi_spsrc_write (spi_state_t *s, uint32_t value)
 Handle an SPSRC write (write-1-to-clear the matching SPSR flags).
static RA8_INTERNAL uint64_t internal_spi_reg_read (spi_state_t *s, uint64_t off)
 Read a register from one modelled SPI_B channel.
static RA8_INTERNAL void internal_spi_reg_write (spi_state_t *s, uint64_t off, uint32_t value)
 Write a register on one modelled SPI_B channel.
static RA8_INTERNAL uint64_t internal_spi_read (uc_engine *uc, uint64_t addr, unsigned size)
 MMIO read inside the SPI_B window: route to the addressed channel.
static RA8_INTERNAL void internal_spi_write (uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
 MMIO write inside the SPI_B window: route to the addressed channel.
static RA8_INTERNAL void internal_spi_reset (void)
 Clear all SPI_B channel state to power-on.
static RA8_INTERNAL void internal_spi_report (void)
 Print one line per SPI channel that echoed any frame.
static RA8_INTERNAL void internal_board_periph_spi_register (void)
 Self-register the SPI_B block before main runs (decentralized).

Variables

static spi_state_t s_spi [k_spi_count]
 The modelled SPI_B channels (SPI0 + SPI1).
static const board_periph_block_t s_k_spi_block
 This block's descriptor (static lifetime; the core keeps the pointer).

Detailed Description

SPI_B (Type-B SPI) controller peripheral-block model for ra8_emulator.

Models the RA8D2 SPI_B controller the ra8_spi_b.c polling driver drives, so the spi_loopback example exercises the genuine ra8_spi_init -> ra8_spi_xfer8 code path instead of the sparse ready-bit fallback. Two channels (SPI0 / SPI1) share one window at 0x4035C000 with a 0x100 stride; the register offsets match the r_spi_regs_t struct in ra8_spi_regs.h.

Loopback semantics: the example calls ra8_spi_init with cfg.loopback=true, which sets SPCR2.SPLP2 (non-inverting internal tie, rx = tx) while SPE is still 0; the silicon then feeds the controller's outgoing line straight back into its receive shifter with no external wiring. The model reproduces that by echoing each word written to SPDR back into the receive holding register and driving the SPSR flags the driver polls:

  • SPSR.SPTEF (transmit-buffer empty) stays asserted once SPE is set, so the driver's "wait for TX empty" poll falls through (the model drains TX immediately).
  • A write to SPDR latches the word, echoes it into the receive holding register when loopback is engaged (else an idle 0), and asserts SPSR.SPRF (receive-buffer full) so the driver's "wait for RX full" poll completes and the subsequent SPDR read returns the echoed word.
  • SPSRC (write-1-to-clear) clears the matching SPSR flags, mirroring the driver's SPTEFC / SPRFC clears between frames.

Self-registers its descriptor (address range + read / write / reset / report) with the board_periph core from a file-scope constructor.

Since
0.1.0

Definition in file board_periph_spi.c.

Enumeration Type Documentation

◆ spi_console_dim_t

enum spi_console_dim_t : uint32_t

Sizing for the board-console SPI transfer-summary line.

Enumerator
k_spi_console_line_cap 

Max chars in one SPI console summary line.

Definition at line 94 of file board_periph_spi.c.

◆ spi_data_t

enum spi_data_t : uint32_t

One-byte / one-word masks used by the echo path.

Enumerator
k_spi_byte_mask 

Low data byte of an 8-bit frame.

Definition at line 89 of file board_periph_spi.c.

◆ spi_map_t

enum spi_map_t : uint64_t

SPI_B block geometry (ra8_spi_regs.h, 32-bit register file).

The RA8D2 has two SPI_B channels at 0x4035C000 (SPI0) and 0x4035C100 (SPI1), each a 0x70-byte register block inside a 0x100 stride. The polling driver (libs/ra8_hal/src/ra8_spi_b.c) only touches the registers named here; everything else in the window reflects writes through the shadow. Offsets match the r_spi_regs_t struct in ra8_spi_regs.h.

Enumerator
k_spi_base 

SPI0 base.

k_spi_stride 

Bytes per SPI channel.

k_spi_count 

SPI0 + SPI1.

k_spi_span 

Both channel windows.

k_spi_off_spdr 

SPDR data register (FIFO front).

k_spi_off_spcr 

SPCR control 1 (SPE/MSTR).

k_spi_off_spcr2 

SPCR2 control 2 (loopback bits).

k_spi_off_spsr 

SPSR status (SPTEF/SPRF/...).

k_spi_off_spsrc 

SPSRC status clear (write-1).

k_spi_reg_words 

Shadow word count for one channel.

Definition at line 56 of file board_periph_spi.c.

◆ spi_spcr2_bit_t

enum spi_spcr2_bit_t : uint32_t

SPCR2 (control 2) loopback bits (ra8_spi_regs.h).

Enumerator
k_spi_spcr2_splp 

SPLP: inverting loopback (rx=~tx).

k_spi_spcr2_splp2 

SPLP2: non-inverting loopback.

Definition at line 75 of file board_periph_spi.c.

◆ spi_spcr_bit_t

enum spi_spcr_bit_t : uint32_t

SPCR (control 1) bits the model observes (ra8_spi_regs.h).

Enumerator
k_spi_spcr_spe 

SPE: SPI function enable (bit 0).

Definition at line 70 of file board_periph_spi.c.

◆ spi_spsr_bit_t

enum spi_spsr_bit_t : uint32_t

SPSR (status) flags the driver polls (ra8_spi_regs.h).

Enumerator
k_spi_spsr_spdrf 

SPDRF: receive data ready (bit 23).

k_spi_spsr_sptef 

SPTEF: transmit empty (bit 29).

k_spi_spsr_cendf 

CENDF: communication end (bit 30).

k_spi_spsr_sprf 

SPRF: receive full (bit 31).

Definition at line 81 of file board_periph_spi.c.

Function Documentation

◆ internal_board_periph_spi_register()

RA8_INTERNAL void internal_board_periph_spi_register ( void )
static

Self-register the SPI_B block before main runs (decentralized).

Definition at line 395 of file board_periph_spi.c.

References board_periph_register_block(), RA8_INTERNAL, and s_k_spi_block.

◆ internal_spi_read()

RA8_INTERNAL uint64_t internal_spi_read ( uc_engine * uc,
uint64_t addr,
unsigned size )
static

MMIO read inside the SPI_B window: route to the addressed channel.

MMIO read inside the spi_b window: route to the addressed channel; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]addrGuest address involved in the operation.
[in]sizeSize of the requested region or access in bytes.
Returns
The SPI read result produced by the board periph SPI model.
Return values
valueThe operation-specific SPI read value.
Precondition
Arguments satisfy the ranges documented for SPI read.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 297 of file board_periph_spi.c.

References internal_spi_reg_read(), k_spi_base, k_spi_stride, RA8_INTERNAL, and s_spi.

◆ internal_spi_reg_read()

RA8_INTERNAL uint64_t internal_spi_reg_read ( spi_state_t * s,
uint64_t off )
static

Read a register from one modelled SPI_B channel.

Read a register from one modelled spi_b channel; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]sModule state instance processed by the operation.
[in]offRegister or byte offset addressed by the operation.
Returns
The SPI reg read result produced by the board periph SPI model.
Return values
valueThe operation-specific SPI reg read value.
Precondition
Arguments satisfy the ranges documented for SPI reg read.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 248 of file board_periph_spi.c.

References internal_spi_word(), k_spi_off_spdr, k_spi_off_spsr, RA8_INTERNAL, spi_state_t::reg, spi_state_t::rx, and spi_state_t::spsr.

Referenced by internal_spi_read().

◆ internal_spi_reg_write()

RA8_INTERNAL void internal_spi_reg_write ( spi_state_t * s,
uint64_t off,
uint32_t value )
static

Write a register on one modelled SPI_B channel.

Write a register on one modelled spi_b channel; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]sModule state instance processed by the operation.
[in]offRegister or byte offset addressed by the operation.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for SPI reg write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 270 of file board_periph_spi.c.

References internal_spi_spcr2_write(), internal_spi_spcr_write(), internal_spi_spdr_write(), internal_spi_spsrc_write(), internal_spi_word(), k_spi_off_spcr, k_spi_off_spcr2, k_spi_off_spdr, k_spi_off_spsrc, RA8_INTERNAL, and spi_state_t::reg.

Referenced by internal_spi_write().

◆ internal_spi_report()

RA8_INTERNAL void internal_spi_report ( void )
static

Print one line per SPI channel that echoed any frame.

Also mirrors each active channel's transfer summary into the board view's SPI console tab (k_board_console_ch_spi). This single end-of-run push is the model's coalesced transfer-completion point: the polling driver clocks one 8-bit frame per SPDR write inside an unbounded loop and the model exposes no per-transaction / CS-deassert boundary, so a per-frame push would flood the 64-deep ring. The push is in-memory only and never touches injected output sink, so the smoke / golden gates stay byte-identical.

Precondition
Arguments satisfy the ranges documented for SPI report.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 360 of file board_periph_spi.c.

References board_console_push(), board_eink_report(), k_board_console_ch_spi, k_spi_console_line_cap, k_spi_count, priv_emu_io_errf(), RA8_INTERNAL, and s_spi.

◆ internal_spi_reset()

RA8_INTERNAL void internal_spi_reset ( void )
static

Clear all SPI_B channel state to power-on.

Clear all spi_b channel state to power-on; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Precondition
Arguments satisfy the ranges documented for SPI reset.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 336 of file board_periph_spi.c.

References board_eink_reset(), board_sd_reset(), k_spi_count, RA8_INTERNAL, and s_spi.

◆ internal_spi_spcr2_write()

RA8_INTERNAL void internal_spi_spcr2_write ( spi_state_t * s,
uint32_t value )
static

Apply an SPCR2 write: latch whether internal loopback is engaged.

Apply an spcr2 write: latch whether internal loopback is engaged; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]sModule state instance processed by the operation.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for SPI spcr2 write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 176 of file board_periph_spi.c.

References k_spi_spcr2_splp, k_spi_spcr2_splp2, spi_state_t::loopback, and RA8_INTERNAL.

Referenced by internal_spi_reg_write().

◆ internal_spi_spcr_write()

RA8_INTERNAL void internal_spi_spcr_write ( spi_state_t * s,
uint32_t value )
static

Apply an SPCR write: SPE gates the channel and arms TX-empty.

Apply an spcr write: spe gates the channel and arms tx-empty; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]sModule state instance processed by the operation.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for SPI spcr write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 153 of file board_periph_spi.c.

References spi_state_t::enabled, k_spi_spcr_spe, k_spi_spsr_sprf, k_spi_spsr_sptef, RA8_INTERNAL, and spi_state_t::spsr.

Referenced by internal_spi_reg_write().

◆ internal_spi_spdr_write()

RA8_INTERNAL void internal_spi_spdr_write ( spi_state_t * s,
uint32_t value )
static

Handle a write to SPDR: echo the frame and assert receive-full.

Handle a write to spdr: echo the frame and assert receive-full; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]sModule state instance processed by the operation.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for SPI spdr write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 191 of file board_periph_spi.c.

References board_eink_attached(), board_eink_exchange(), board_sd_attached(), board_sd_exchange(), spi_state_t::frames, internal_spi_word(), k_spi_byte_mask, k_spi_off_spcr2, k_spi_spcr2_splp, k_spi_spsr_spdrf, k_spi_spsr_sprf, k_spi_spsr_sptef, spi_state_t::loopback, RA8_INTERNAL, spi_state_t::reg, spi_state_t::rx, and spi_state_t::spsr.

Referenced by internal_spi_reg_write().

◆ internal_spi_spsrc_write()

RA8_INTERNAL void internal_spi_spsrc_write ( spi_state_t * s,
uint32_t value )
static

Handle an SPSRC write (write-1-to-clear the matching SPSR flags).

Handle an spsrc write (write-1-to-clear the matching spsr flags); this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]sModule state instance processed by the operation.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for SPI spsrc write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 225 of file board_periph_spi.c.

References spi_state_t::enabled, k_spi_spsr_sptef, RA8_INTERNAL, and spi_state_t::spsr.

Referenced by internal_spi_reg_write().

◆ internal_spi_word()

RA8_INTERNAL uint32_t internal_spi_word ( uint64_t off)
static

Index of the shadow word for off within a channel (range-checked).

Index of the shadow word for off within a channel (range-checked); this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in]offRegister or byte offset addressed by the operation.
Returns
The SPI word result produced by the board periph SPI model.
Return values
valueThe operation-specific SPI word value.
Precondition
Arguments satisfy the ranges documented for SPI word.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 138 of file board_periph_spi.c.

References RA8_INTERNAL.

Referenced by internal_spi_reg_read(), internal_spi_reg_write(), and internal_spi_spdr_write().

◆ internal_spi_write()

RA8_INTERNAL void internal_spi_write ( uc_engine * uc,
uint64_t addr,
unsigned size,
uint64_t value )
static

MMIO write inside the SPI_B window: route to the addressed channel.

MMIO write inside the spi_b window: route to the addressed channel; this step is contained within the board periph SPI model and uses bounded caller or module-owned storage.

Parameters
[in,out]ucUnicorn engine whose emulated state is read or updated.
[in]addrGuest address involved in the operation.
[in]sizeSize of the requested region or access in bytes.
[in]valueRegister or payload value involved in the operation.
Precondition
Arguments satisfy the ranges documented for SPI write.
The call executes on the emulator's single owning thread.
Postcondition
State changes remain confined to the board periph SPI model and documented output objects.
Ownership of caller-supplied storage is unchanged.
Note
The operation is synchronous and does not transfer heap ownership.
Since
0.1.0

Definition at line 319 of file board_periph_spi.c.

References internal_spi_reg_write(), k_spi_base, k_spi_stride, and s_spi.

Variable Documentation

◆ s_k_spi_block

const board_periph_block_t s_k_spi_block
static
Initial value:
= {
.base = (uint64_t)k_spi_base,
.span = (uint64_t)k_spi_span,
.order = (uint32_t)k_block_order_sci,
.tick = nullptr,
.name = "SPI_B",
}
@ k_block_order_sci
SCI_B UART.
@ k_spi_span
Both channel windows.
@ k_spi_base
SPI0 base.
static RA8_INTERNAL uint64_t internal_spi_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside the SPI_B window: route to the addressed channel.
static RA8_INTERNAL void internal_spi_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write inside the SPI_B window: route to the addressed channel.
static RA8_INTERNAL void internal_spi_report(void)
Print one line per SPI channel that echoed any frame.
static RA8_INTERNAL void internal_spi_reset(void)
Clear all SPI_B channel state to power-on.
-proof

This block's descriptor (static lifetime; the core keeps the pointer).

Definition at line 382 of file board_periph_spi.c.

Referenced by internal_board_periph_spi_register().

◆ s_spi

spi_state_t s_spi[k_spi_count]
static

The modelled SPI_B channels (SPI0 + SPI1).

Definition at line 119 of file board_periph_spi.c.

Referenced by internal_spi_read(), internal_spi_report(), internal_spi_reset(), and internal_spi_write().