Files
retroSoC/rtl/ip/serial/apb4_spi.sv
T
maksyuki 31daf3e84c feat(spi): implement SPI-P3 Tiny GPIO RCU and SDK integration
Integrate the SPI-P2 shared-DMA ABI into the Tiny product: SPI0 at
0x1001D000 with IRQ25 and RCU target16, the four frozen Gen1 ALT routes,
latched four-bit source qualification through the fabric and APB CDC, GPIO
readiness/ownership guard, and the bounded rs_spi_* HAL with the
TINY_SPI_P3_ACCEPTANCE ci_smoke image. Tiny DMA enables V2.2 requests 16/17
with exact fixed FIFO MMIO checks; Mini remains default-disabled and
unchanged. Review closure: the DMA AXI4 master stages the origin channel with
each burst so final and contended SPI alias bursts stay qualified, the RCU
spare feedback bit is tied off for four-state simulators, and the
clock-switch quiescence now includes the SPI session.

Validation: full Pytest 2097 passed, 0 failed, 1 skipped (optional pypdf);
both Tiny profiles pass the SPI-P3 Verilator acceptance (SIM_TEST_PASS
cycles=1030088); R2-P7 Verilator acceptance, Mini DMA formal prove and
cover, Mini/Tiny lint, Tiny Yosys synthesis, netsim-boot and OpenSTA pass;
C format/policy/host tests and RTL format/style checks clean. Evidence and
remaining obligations are recorded in docs/ip/spi-verification.md.

Tiny Icarus behavioral remains blocked by the pre-existing observer/sv2v
defect (routed to the R2 DV owners); Mini smoke synthesis host timeout is
skipped per maintainer decision. Human phase acceptance and SPI-P4/P5
remain outstanding; phase_accepted stays false.
2026-10-22 11:57:29 +08:00

124 lines
4.5 KiB
Systemverilog

// Standalone SPI shell. DMA pacing is local; product route and fabric origin remain external.
module apb4_spi #(
parameter bit EnableDma = 1'b1
) (
input logic clk_i,
rst_n_i,
input logic [31:0] clock_hz_i,
input logic [ 1:0] origin_i,
input logic [ 4:0] request_i,
input logic [ 2:0] channel_i,
input logic [ 1:0] credit_valid_i,
credit_retire_i,
input logic [ 3:0] dma_status_i,
input logic [ 1:0] dma_start_pending_i,
input logic dma_error_i,
input logic [31:0] user_select_i,
handoff_i,
alt_enable_i,
alt_select_i,
input logic [31:0] output_enable_i,
open_drain_i,
input logic gpio_ready_i,
miso_i,
output logic sck_o,
mosi_o,
cs_n_o,
output_enable_o,
irq_o,
session_owned_o,
lifecycle_idle_o,
output logic [ 1:0] credit_commit_o,
apb4_if.slave apb4
);
spi_ctrl_if u_ctrl ();
spi_pkg::configuration_t s_cfg;
spi_pkg::status_t s_stat;
logic [31:0] s_claim, s_ready;
logic s_handback, s_credit_fault, s_reg_credit_fault, s_pacing_fault;
logic s_fifo_pending;
logic [1:0] s_credit_pending, s_pacing_pending, s_reg_credit_pending;
logic [1:0] s_credit_valid, s_credit_retire, s_credit_commit;
logic [3:0] s_dma_stat;
logic s_unused;
assign s_cfg = u_ctrl.cfg;
assign s_stat = u_ctrl.stat;
// Only personality bits feed the GPIO guard; other fields feed the core/reg blocks.
assign s_unused = ^s_cfg;
assign s_credit_fault = s_reg_credit_fault | s_pacing_fault;
assign s_credit_pending = s_pacing_pending | s_reg_credit_pending;
spi_dma_pacing u_dma_pacing (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.enable_i (EnableDma),
.tx_binding_i (s_cfg.tx_binding),
.rx_binding_i (s_cfg.rx_binding),
.dma_start_pending_i(dma_start_pending_i),
.dma_status_i (dma_status_i),
.dma_error_i (dma_error_i),
.credit_valid_i (credit_valid_i),
.credit_retire_i (credit_retire_i),
.credit_commit_i (s_credit_commit),
.credit_valid_o (s_credit_valid),
.credit_retire_o (s_credit_retire),
.credit_pending_o (s_pacing_pending),
.dma_status_o (s_dma_stat),
.credit_fault_o (s_pacing_fault),
.busy_o ()
);
spi_gpio_guard u_gpio_guard (
.session_i (s_cfg.session),
.user_select_i (user_select_i),
.handoff_i (handoff_i),
.alt_enable_i (alt_enable_i),
.alt_select_i (alt_select_i),
.output_enable_i(output_enable_i),
.open_drain_i (open_drain_i),
.gpio_ready_i (gpio_ready_i),
.claim_o (s_claim),
.ready_o (s_ready),
.handback_o (s_handback)
);
spi_reg u_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clock_hz_i (clock_hz_i),
.origin_i (origin_i),
.request_i (request_i),
.channel_i (channel_i),
.credit_valid_i (s_credit_valid),
.credit_retire_i (s_credit_retire),
.dma_status_i (s_dma_stat),
.dma_start_pending_i(dma_start_pending_i),
.credit_commit_o (s_credit_commit),
.credit_pending_o (s_reg_credit_pending),
.fifo_pending_o (s_fifo_pending),
.credit_fault_o (s_reg_credit_fault),
.irq_o (irq_o),
.apb4 (apb4),
.ctrl (u_ctrl)
);
assign credit_commit_o = s_credit_commit;
assign session_owned_o = s_stat.status[5];
assign lifecycle_idle_o = s_stat.status[10] && s_stat.status[11] && !s_stat.status[5];
spi_master_core u_master_core (
.apb_pending_i (s_fifo_pending),
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.claim_i (s_claim),
.ready_pins_i (s_ready),
.gpio_ready_i (gpio_ready_i),
.handback_i (s_handback),
.dma_status_i (s_dma_stat),
.dma_start_pending_i(dma_start_pending_i),
.dma_error_i (dma_error_i),
.credit_fault_i (s_credit_fault),
.miso_i (miso_i),
.sck_o (sck_o),
.mosi_o (mosi_o),
.cs_n_o (cs_n_o),
.output_enable_o (output_enable_o),
.ctrl (u_ctrl)
);
endmodule