mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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.
59 lines
3.3 KiB
Python
59 lines
3.3 KiB
Python
"""Independent frozen SPI APB 1.0 constants and handwritten mirror checks."""
|
|
from pathlib import Path
|
|
import re
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
REGISTERS = """IP_ID IP_VERSION CAPABILITY FIFO_CAPABILITY CLOCK_HZ ROUTABLE_MASK
|
|
COMMAND STATUS SESSION_CFG DIV CS_SETUP CS_HOLD CS_INACTIVE SEG_CONFIG FRAME_COUNT
|
|
DUMMY TX_BIND RX_BIND WATERMARKS CPU_TXDATA CPU_RXDATA DMA_TXDATA DMA_RXDATA
|
|
FIFO_LEVELS IRQ_STATE IRQ_ENABLE IRQ_STATUS FAULT_CODE FAULT_FRAME FRAMES_DONE
|
|
TRANSPORT_WORDS TX_WORDS_ACCEPTED RX_WORDS_PRODUCED RX_WORDS_REMOVED TX_STALL_CYCLES
|
|
RX_STALL_CYCLES SESSION_PINS DMA_STATUS PINS_READY PAYLOAD_BYTES""".split()
|
|
|
|
|
|
def test_frozen_spi_register_mirrors():
|
|
sv = (ROOT / "rtl/ip/serial/spi_define.svh").read_text()
|
|
header = (ROOT / "crt/include/retrosoc/hal/spi_regs.h").read_text()
|
|
rtl = {}
|
|
for name, width, hexadecimal, decimal in re.findall(
|
|
r"^`define\s+APB4_SPI__(\w+)\s+(?:(\d+)'h([0-9a-f]+)|(\d+))\s*$", sv, re.M):
|
|
rtl[name] = int(hexadecimal, 16) if width else int(decimal)
|
|
c = {name: int(hexa, 16) if hexa else int(decimal)
|
|
for name, hexa, decimal in re.findall(
|
|
r"^#define\s+RS_SPI_ABI_(\w+)\s+(?:UINT32_C\((0x[0-9a-f]+)\)|(\d+)U)\s*$", header, re.M)}
|
|
assert rtl == c
|
|
assert {name: rtl[name] for name in REGISTERS} == {
|
|
name: index * 4 for index, name in enumerate(REGISTERS)}
|
|
assert rtl['ID_VALUE'] == 0x53504930
|
|
assert rtl['VERSION_VALUE'] == 0x10000
|
|
assert rtl['CAPABILITY_VALUE'] == 0x3f7f
|
|
assert rtl['FIFO_VALUE'] == 0x200808
|
|
assert rtl['ROUTES_VALUE'] == 0xd8000000
|
|
for bit, name in enumerate('ENABLE DISABLE ARM START END ABORT RECOVER RELEASE RESET'.split()):
|
|
assert rtl[name] == bit
|
|
assert rtl['TIMING_RESET'] == 1 and rtl['DUMMY_RESET'] == 0xffff
|
|
assert rtl['WATERMARK_RESET'] == 0x100
|
|
for bit, name in enumerate('CPOL CPHA LSB_FIRST MISO_ENABLE DISPLAY_DC'.split()):
|
|
assert rtl[name] == bit
|
|
for number, name in enumerate('DISABLED IDLE ARMED SETUP SHIFT HOLD HELD GAP CLOSING'.split()):
|
|
assert rtl['STATE_' + name] == number
|
|
for number, name in enumerate('NONE ROUTE READINESS DMA CREDIT QUOTA'.split()):
|
|
assert rtl['FAULT_' + name] == number
|
|
for bit, name in enumerate('SEGMENT_DONE DONE ABORTED FAULT TX_STALL RX_STALL'.split()):
|
|
assert rtl['IRQ_' + name] == bit
|
|
for bit, name in enumerate(('CS_ACTIVE SESSION_OWNED SEGMENT_PENDING SEGMENT_CLEAN '
|
|
'TX_WAIT RX_WAIT BUS_IDLE TRANSPORT_IDLE GPIO_READY').split(), 4):
|
|
assert rtl['STATUS_' + name] == bit
|
|
assert [rtl[name] for name in ('TX_ONLY', 'FULL_DUPLEX', 'RX_ONLY')] == [0, 1, 2]
|
|
assert [rtl[name] for name in ('FRAME16', 'DIRECTION', 'HOLD_CS', 'BIND_ENABLE')] == [0, 1, 3, 31]
|
|
assert rtl['IRQ_TX_LEVEL'] == 8 and rtl['IRQ_RX_LEVEL'] == 9
|
|
|
|
|
|
def test_spi_is_advertised_only_by_tiny_product_integration():
|
|
assert any('/serial/apb4_spi.sv' in path.read_text()
|
|
for path in (ROOT / 'rtl/tiny/filelist').glob('*.fl'))
|
|
assert all('/serial/apb4_spi.sv' not in path.read_text()
|
|
for path in (ROOT / 'rtl/mini/filelist').glob('*.fl'))
|
|
assert 'spi' in [row['name'] for row in __import__('json').loads(
|
|
(ROOT / 'rtl/tiny/integration/soc_topology.json').read_text())['apb_targets']]
|