feat: add AXI4 interconnect testbench and enhance existing tests

- Introduced a new testbench for the AXI4 interconnect () to validate fault classification for decode and access errors.
- Updated  and  to reflect changes in bus naming conventions.
- Enhanced  to include AXI4-Stream interface checks and validate stream data transfers.
- Modified  to integrate AXI4-Stream interfaces for improved DMA testing.
- Added new Python tests () to verify AXI4 to RIBP burst bridge functionality and interconnect fault classification.
- Updated existing tests to include AXI4 interfaces and ensure proper error handling and response validation.
- Adjusted memory map generation and test setups to accommodate new AXI4 interface requirements.
This commit is contained in:
maksyuki committed 2026-08-12 12:30:12 +08:00
1 parent 9314b5950f
commit de32aa2979
65 files changed
+4271 -649

No files matched your search

+1 -1
View File
@@ -62,7 +62,7 @@
},
"cluster_archinfo": {"url": "https://github.com/retroSoC/archinfo.git", "revision": "78505969a0afdbc887cdd9b36eda228b4afb616e", "destination": "rtl/managed/clusterip/archinfo", "license": "MulanPSL-2.0"},
"cluster_clint": {"url": "https://github.com/retroSoC/clint.git", "revision": "ce49f1a5501c0a9f18c0e3f358417648f3f2fb18", "destination": "rtl/managed/clusterip/clint", "license": "NOASSERTION"},
"cluster_common": {"url": "https://github.com/retroSoC/common.git", "revision": "6c318bf06570a2d195afb1708853ee921a058e5c", "destination": "rtl/managed/clusterip/common", "license": "NOASSERTION"},
"cluster_common": {"url": "https://github.com/retroSoC/common.git", "revision": "e08b474b2b25584055785378e611f805e4756e46", "destination": "rtl/managed/clusterip/common", "license": "NOASSERTION"},
"cluster_crc": {"url": "https://github.com/retroSoC/crc.git", "revision": "8c1a5664c4d23d005c1afad432372a13ca967cc8", "destination": "rtl/managed/clusterip/crc", "license": "MulanPSL-2.0"},
"cluster_i2c": {"url": "https://github.com/retroSoC/i2c.git", "revision": "73b024547c5cd70fb8bf801cc7757db2536c604f", "destination": "rtl/managed/clusterip/i2c", "license": "NOASSERTION"},
"cluster_i2s": {"url": "https://github.com/retroSoC/i2s.git", "revision": "bd0978e8b45e4cf4c1335a1fa7311385d2a4e805", "destination": "rtl/managed/clusterip/i2s", "license": "NOASSERTION"},
+2
View File
@@ -52,6 +52,7 @@
#define reg_i2s_txdata RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x14))
#define reg_i2s_rxdata RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x18))
#define reg_i2s_status RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x1C))
#define reg_i2s_stream_ctrl RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x20))
// ws2812
#define reg_ws2812_bit_cycles RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x00))
#define reg_ws2812_t0h_cycles RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x04))
@@ -186,6 +187,7 @@
#define reg_dvp_recven RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x00))
#define reg_dvp_rxdata RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x04))
#define reg_dvp_status RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x08))
#define reg_dvp_stream_ctrl RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x0C))
#define reg_user_ip_reg0 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x00))
#define reg_user_ip_reg1 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x04))
#define reg_user_ip_reg2 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x08))
+1
View File
@@ -21,6 +21,7 @@ typedef struct {
#define RS_DMA_MODE_I2C0_RX UINT32_C(8)
#define RS_DMA_MODE_I2C1_TX UINT32_C(9)
#define RS_DMA_MODE_I2C1_RX UINT32_C(10)
#define RS_DMA_MODE_DVP_RX UINT32_C(11)
rs_status_t rs_dma_config(uint32_t mode, uintptr_t source, uint32_t source_increment,
uintptr_t destination, uint32_t destination_increment,
+9 -3
View File
@@ -6,7 +6,7 @@
rs_status_t rs_dma_config(uint32_t mode, uintptr_t source, uint32_t source_increment,
uintptr_t destination, uint32_t destination_increment,
uint32_t transfer_words) {
if ((mode > RS_DMA_MODE_I2C1_RX) || (source == 0U) || (destination == 0U) ||
if ((mode > RS_DMA_MODE_DVP_RX) || (source == 0U) || (destination == 0U) ||
(transfer_words == 0U) || (source_increment > 1U) || (destination_increment > 1U)) {
return RS_EINVAL;
}
@@ -74,20 +74,26 @@ void ip_dma_test(void) {
reg_i2s_upbound = 120U;
reg_i2s_lowbound = 32U;
reg_i2s_recven = 0U;
reg_i2s_stream_ctrl = 1U;
if ((rs_dma_config(1U, 0x40000000U, 1U, (uintptr_t)&reg_i2s_txdata, 0U, 512U) != RS_OK) ||
if ((rs_dma_config(RS_DMA_MODE_I2S_TX, 0x40000000U, 1U, (uintptr_t)&reg_i2s_txdata, 0U, 512U) !=
RS_OK) ||
(rs_dma_start() != RS_OK) || (rs_dma_wait(RS_TIMEOUT_DEFAULT) != RS_OK)) {
printf("dma transmit failed\n");
return;
}
reg_i2s_recven = 1U;
if ((rs_dma_config(2U, (uintptr_t)&reg_i2s_rxdata, 0U, 0x41000000U, 1U, 180U) != RS_OK) ||
reg_i2s_stream_ctrl = 2U;
if ((rs_dma_config(RS_DMA_MODE_I2S_RX, (uintptr_t)&reg_i2s_rxdata, 0U, 0x41000000U, 1U, 180U) !=
RS_OK) ||
(rs_dma_start() != RS_OK) || (rs_dma_wait(RS_TIMEOUT_DEFAULT) != RS_OK)) {
printf("dma receive failed\n");
reg_i2s_recven = 0U;
reg_i2s_stream_ctrl = 0U;
return;
}
reg_i2s_recven = 0U;
reg_i2s_stream_ctrl = 0U;
printf("dma test passed\n");
}
+3 -1
View File
@@ -12,6 +12,7 @@ static uint32_t audio_idx;
static void i2s_init(uint32_t mode) {
reg_i2s_mode = (uint32_t)mode;
reg_i2s_stream_ctrl = (mode == 0U) ? 0U : 1U;
reg_i2s_upbound = (uint32_t)120;
// NOTE: larger than 'clk/clk_aud 'size of i2x tx fifo
reg_i2s_lowbound = (uint32_t)80;
@@ -28,7 +29,8 @@ static void i2s_audio_load(void) {
if ((available_size == 0U) ||
(rs_wav_parse_spisd(start_address, available_size, &info) != RS_OK) ||
((info.data_size % sizeof(uint32_t)) != 0U) ||
(rs_dma_config(1U, start_address + info.data_offset, 1U, (uintptr_t)&reg_i2s_txdata, 0U,
(rs_dma_config(RS_DMA_MODE_I2S_TX, start_address + info.data_offset, 1U,
(uintptr_t)&reg_i2s_txdata, 0U,
info.data_size / sizeof(uint32_t)) != RS_OK)) {
printf("wav file parse/configuration error\n");
}
+4
View File
@@ -20,6 +20,10 @@ the root README and subsystem guides.
planned product targets, claim gates, and commercial reference points.
- [rib-interconnect.md](rib-interconnect.md) defines the RIB v1 linear-burst
contract, compatibility boundaries, target status, and verification.
- [axi4-interconnect.md](axi4-interconnect.md) defines the active Mini SoC AXI4
subset, arbitration, target, access-control, error, and performance contract.
- [axi4-stream.md](axi4-stream.md) defines the DMA, I2S, and DVP AXI4-Stream
data paths, PIO fallback, register controls, and backpressure contract.
- [ip/ws2812.md](ip/ws2812.md) defines the WS2812 transmitter register ABI,
timing, FIFO, interrupt, DMA, and integration contracts.
- [ip/timer.md](ip/timer.md) defines the dual general timer register ABI,
+66
View File
@@ -0,0 +1,66 @@
# AXI4 Interconnect Contract
AXI4 is the active Mini SoC system interconnect. The Common `axi4_if`
declaration, `memory_map.json`, and `axi4_interconnect.sv` are the executable
sources of truth. RIB remains documented and verified as an independent legacy
protocol; it is not an active Mini SoC fabric link.
## Supported Subset
The interconnect has 32-bit addresses and 32-bit data. It supports only linear
`INCR` transfers with one through sixteen beats (`AxLEN` 0 through 15), natural
1-, 2-, or 4-byte alignment, and no 4 KiB boundary crossing. `FIXED`, `WRAP`,
locked, wider, misaligned, and cross-target transactions receive `SLVERR`.
Unmapped addresses receive `DECERR`.
Each master may own at most one read or write transaction. IDs and user fields
are one bit because no outstanding or out-of-order completion is supported.
Read and write ordering is therefore program order at each master. Different
masters may use different targets concurrently; requests to one target use a
Common round-robin arbiter and retain ownership through `B` or `RLAST`.
The three masters are the Hazard3 management core, the selected user core, and
DMA. Hazard3 AHB-Lite and the current user-core RIBP ABI issue single-beat AXI4
transactions through adapters. DMA converts its existing four-word chunks to
AXI4 `INCR4`, so non-burst masters remain compatible while burst-capable masters
can use the wider contract.
## Targets and Access Control
The fixed targets are the RIBP configuration plane, APB, SRAM, SDRAM, PSRAM,
XPI/Flash, SPI-SD, `DECERR`, and `SLVERR`. RIBP and APB accept only single-beat
transactions. SRAM uses a direct AXI4 target with pipelined synchronous reads
and response buffering. External-memory data windows accept up to sixteen
beats; their current compatibility bridge serializes each beat into the
existing controller data engine. Register configuration remains on RIBP.
The user-core firewall validates both the first and last byte before target
arbitration. User access to SYSCTRL, CLINT, DMA configuration, and other
management-only regions is rejected with `SLVERR`. SYSCTRL records the address,
master, write strobes, reserved/access classification, and response code for a
terminal error. The internal fault classification maps an unmapped address to
`DECERR`, a malformed or unsupported burst to `BURSTERR`, and a firewall or
access-control rejection to `PROTERR`.
## Integration Rules
- Instantiate every Mini SoC AXI4 link with `ADDR_WIDTH=32`, `DATA_WIDTH=32`,
`ID_WIDTH=1`, and `USER_WIDTH=1`; do not rely on Common defaults.
- Hold address/control and response payload stable while `VALID` is asserted
without `READY`. Write data must assert `WLAST` on the declared final beat.
- Keep RIBP configuration and AXI4 data apertures separate in the canonical
address map. An IP may arbitrate the two internally, but a data address must
not be routed through the global configuration decoder.
- Add controller-native command/data queues before claiming physical burst
coalescing. The compatibility bridges establish protocol correctness, not
SDRAM row, serial chip-select, or media-sector amortization.
## Verification and Performance Gates
`tests/test_axi4.py` covers a four-beat write/read, response backpressure, and
rejection of a seventeen-beat request without touching the RIBP target. The
IHP130 `ci_smoke` regression is the end-to-end boot and configuration check.
CoreMark uses SRAM and must not regress more than five percent from the recorded
7,620,324-cycle baseline. A controller may be promoted to a native burst target
only after aligned sixteen-word tests show at least twenty percent improvement
and cover partial writes, backpressure, device timing, and error termination.
+44
View File
@@ -0,0 +1,44 @@
# AXI4-Stream Peripheral Data Paths
The Mini SoC uses 32-bit AXI4-Stream links for high-rate peripheral data that
does not need an address on every word. RIBP remains the register configuration
plane. The active stream endpoints are DMA to I2S TX, I2S RX to DMA, and DVP RX
to DMA. UART, I2C, and WS2812 retain their existing RIBP FIFO data registers.
## Interface Contract
All three links use `DATA_WIDTH=32`, one-bit ID, destination, and user fields,
and the system clock/reset. `TKEEP` and `TSTRB` are `4'hF`; the current I2S and
DVP data paths always transfer complete words. DMA holds `TDATA`, `TKEEP`,
`TSTRB`, and `TLAST` stable while `TVALID` is high and `TREADY` is low. A word
is consumed only on a `TVALID && TREADY` clock edge.
DMA asserts `TLAST` on the final programmed I2S TX word. I2S RX and DVP do not
currently provide a packet boundary to DMA, so DMA terminates their transfers
using its programmed `XFERLEN`; incoming `TLAST` is informational and ignored.
IDs, destinations, and user sidebands are currently zero.
## Configuration and PIO Fallback
I2S register offset `0x20` is `STREAM_CTRL`: bit 0 selects AXI4-Stream as the
TX FIFO producer and bit 1 selects AXI4-Stream as the RX FIFO consumer. A clear
bit preserves the existing `TXDATA` or `RXDATA` PIO behavior. Software must not
change a stream-select bit while that direction is active.
DVP register offset `0x0C` is `STREAM_CTRL`: bit 0 selects AXI4-Stream as the
RX FIFO consumer. When clear, reads of `RXDATA` retain the existing pop
behavior. When set, `RXDATA` reads do not pop the FIFO.
DMA modes 1 and 2 use the I2S TX and RX stream links. Mode 11 uses DVP RX. The
source address is unused for stream RX modes, and the destination address is
unused for I2S TX, but the current software API still requires valid nonzero
addresses for a uniform descriptor contract. DMA writes received stream words
to AXI4 memory and reads I2S TX words from AXI4 memory.
## Verification Boundary
The DMA directed test covers stream TX backpressure, two-word stream RX to
memory, exact transfer length, bus errors, and retained RIB burst behavior. The
I2S and DVP FIFO tests continue to cover PIO mode. Physical audio and camera
clock-domain behavior remains controller-specific and must be verified with
board-level timing and device models.
+2 -2
View File
@@ -10,7 +10,7 @@ default JTAG ID code is `0xDEADBEEF`. Set
The Debug Module (DM) controls only the management Hazard3 hart. It supports
abstract register and memory commands and has `HAVE_SBA=0`, so it never becomes
a second SoC bus master. Debugger memory operations execute through the halted
hart and remain subject to the existing RIB access policy. User cores,
hart and remain subject to the AXI4 interconnect access policy. User cores,
peripherals, clocks, and pad control stay outside the debug-reset scope.
PicoRV32 is available as software-selected user core C5 through mini-ver-mpw;
@@ -23,7 +23,7 @@ transactions into the system-clock DM domain. The canonical clock/reset map
constrains TCK at 10 MHz and declares the JTAG/system clock groups asynchronous.
The DM `ndmreset` and hart-reset requests pass through `mgmt_debug_reset`.
It waits until the management AHB-Lite-to-RIBP bridge is idle, then resets only
It waits until the management AHB-Lite-to-AXI4 bridge is idle, then resets only
that bridge and the management hart. The DTM, DM, RCU, user cores, and all
peripherals remain live. Reset release is synchronized with the common
`rst_sync` cell and acknowledged only after the local reset is released.
+1 -1
View File
@@ -15,7 +15,7 @@ retroSoC RIBP target protocol.
| RTL hart parameter range | 1 through 4095 |
| Timebase frequency | 1 MHz |
| Management-core interrupts | software IRQ 0, timer IRQ 1 |
| User-core access | denied by the RIB access policy |
| User-core access | denied by the AXI4 interconnect access policy |
| User-core interrupt visibility | masked |
The timebase divider runs from the buffered external reference clock, not the
+29 -16
View File
@@ -87,7 +87,7 @@ digraph mini_soc_block_diagram {
];
mgmt_adapter [
fillcolor="#E5E7EB",
label="RIBP2RIB"
label="AHB-Lite2AXI4\nsingle-beat adapter"
];
user_core [
fillcolor="#DDF2E3",
@@ -95,11 +95,11 @@ digraph mini_soc_block_diagram {
];
dma [
fillcolor="#DDF2E3",
label="DMA\nRIB master and RIBP target"
label="DMA\nAXI4 burst master and RIBP target"
];
fabric [
fillcolor="#DCECF8",
label="RIB fabric\n3-master round-robin arbitration\nINCR1 / INCR4, access policy, fault reporting",
label="AXI4 fabric\n3 masters / 9 targets, per-target round robin\nINCR1-16, access policy, fault reporting",
shape=hexagon
];
fault [
@@ -108,15 +108,15 @@ digraph mini_soc_block_diagram {
];
sram [
fillcolor="#FFF3C9",
label="On-chip SRAM\noptional RIB2RAM path"
label="On-chip SRAM\noptional pipelined AXI42RAM path"
];
ribp_adapter [
fillcolor="#E5E7EB",
label="RIB2RIBP"
label="AXI42RIBP\nconfiguration plane"
];
apb_adapter [
fillcolor="#E5E7EB",
label="RIB2APB\ndirect APB bridge"
label="AXI42APB\ndirect APB bridge"
];
sysctrl [
fillcolor="#F9E1E7",
@@ -128,7 +128,15 @@ digraph mini_soc_block_diagram {
];
ribp_targets [
fillcolor="#F9E1E7",
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nI2S"
label="RIBP configuration targets\nXPI, SDRAM, PSRAM, SPI-SD, DVP and I2S"
];
memory_targets [
fillcolor="#FFF3C9",
label="AXI4 data targets\nXPI/Flash, SDRAM, PSRAM and SPI-SD\nINCR1-16 compatibility engines"
];
stream_io [
fillcolor="#FFF3C9",
label="AXI4-Stream data endpoints\nI2S TX/RX and DVP RX\nRIBP configuration with PIO fallback"
];
uart0 [
fillcolor="#F9E1E7",
@@ -197,7 +205,7 @@ digraph mini_soc_block_diagram {
{ rank=same; user_core; dma; }
{ rank=same; fault; fabric; sram; }
{ rank=same; ribp_adapter; apb_adapter; }
{ rank=same; sysctrl; clint; ribp_targets; uart0; i2c_controllers; gpio_controller; timers; ws2812; archinfo; rng; ps2; rtc; wdg; crc; pwm; apb_targets; }
{ rank=same; sysctrl; clint; ribp_targets; memory_targets; stream_io; uart0; i2c_controllers; gpio_controller; timers; ws2812; archinfo; rng; ps2; rtc; wdg; crc; pwm; apb_targets; }
{ rank=same; gpio_bridge; irq; }
ext_clock -> rcu [label="clock / reset"];
@@ -210,15 +218,17 @@ digraph mini_soc_block_diagram {
debug_module -> timers [label="halted", style=dashed];
rcu -> clint [label="1 MHz tick", style=dashed];
mgmt_core -> mgmt_adapter [label="RIBP"];
mgmt_adapter -> fabric [label="RIB"];
user_core -> fabric [label="RIB"];
dma -> fabric [label="RIB"];
mgmt_core -> mgmt_adapter [label="AHB-Lite"];
mgmt_adapter -> fabric [label="AXI4"];
user_core -> fabric [label="RIBP2AXI4"];
dma -> fabric [label="AXI4"];
dma -> stream_io [dir=both, label="AXI4-Stream"];
fabric -> fault [label="invalid / denied", dir=both];
fabric -> sram [label="RIB"];
fabric -> ribp_adapter [label="RIB"];
fabric -> apb_adapter [label="RIB"];
fabric -> sram [label="AXI4"];
fabric -> memory_targets [label="AXI4 data"];
fabric -> ribp_adapter [label="AXI4 config"];
fabric -> apb_adapter [label="AXI4"];
ribp_adapter -> sysctrl [label="RIBP"];
ribp_adapter -> clint [label="RIBP"];
ribp_adapter -> ribp_targets [label="RIBP"];
@@ -262,7 +272,10 @@ digraph mini_soc_block_diagram {
wdg -> irq [label="early warning IRQ14"];
wdg -> rcu [label="system reset request", color="#B91C1C", penwidth=2];
apb_targets -> gpio_controller [label="user_gpio"];
ribp_targets -> ext_io [dir=both, label="device interfaces"];
ribp_targets -> memory_targets [label="RIBP configuration", style=dashed];
ribp_targets -> stream_io [label="RIBP configuration", style=dashed];
memory_targets -> ext_io [dir=both, label="device interfaces"];
stream_io -> ext_io [dir=both, label="I2S / DVP signals"];
uart0 -> ext_io [dir=both, label="UART pads"];
gpio_bridge -> ext_io [dir=both, label="pad control"];
}
File diff suppressed because it is too large. Load diff

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 65 KiB

+7 -4
View File
@@ -1,6 +1,8 @@
# RIB Family Protocols
retroSoC uses a scalar peripheral protocol and a native burst interconnect.
retroSoC retains a scalar peripheral protocol and the RIB burst protocol as an
independently verified compatibility family. AXI4 is now the active Mini SoC
interconnect; see [AXI4 Interconnect Contract](axi4-interconnect.md).
The interface declarations and generated address map are the executable source
of truth; this document fixes the ownership, ordering, and adaptation rules at
each boundary.
@@ -59,9 +61,10 @@ ordered RIB responses. An asserted RIBP `resp_err` is mapped to native RIB
## Targets and Performance
Management and current user cores use RIBP through the SoC adapters. Future
user cores can select native RIB in `user_extensions.json`. DMA is a native
RIB master and uses the common four-entry FIFO for each chunk.
The active Mini SoC no longer selects RIB as a fabric link. Current user cores
retain their RIBP ABI and use a RIBP-to-AXI4 adapter. DMA retains its proven RIB
chunk engine behind a RIB-to-AXI4 adapter. The RIB modules, protocol tests, and
formal targets remain available for independent reuse and maintenance.
`rib2ram` is the native RIB SRAM target. It pipelines synchronous reads
and uses the Common two-entry spill register for response backpressure. The
+10 -8
View File
@@ -134,15 +134,17 @@ capabilities:
- The canonical address map exposes 128 KiB of on-chip SRAM, a 32 MiB SDRAM
window, and an 8 MiB PSRAM window. Address-window capacity does not guarantee
that every implementation includes the corresponding physical memory.
- RIB v1 is a 32-bit interconnect with `INCR1` and aligned four-word `INCR4`
transfers and one outstanding transaction per master.
- Current external-memory targets serialize an accepted RIB burst into ordered
scalar RIBP accesses. They do not yet combine an `INCR4` request into a native
SDRAM, PSRAM, or flash streaming transaction.
- AXI4 is the active 32-bit interconnect. It supports linear one- through
sixteen-beat transfers, one transaction per master, and concurrent accesses
to different targets.
- Current external-memory targets serialize accepted AXI4 bursts into ordered
scalar engine accesses. They do not yet combine a burst into a native SDRAM,
PSRAM, flash, or SPI-SD physical transaction.
The generated address map, user-extension map, and
[RIB protocol contract](rib-interconnect.md) remain the executable sources of
truth for the implemented baseline.
The generated address map, user-extension map,
[AXI4 contract](axi4-interconnect.md), and retained
[RIB protocol contract](rib-interconnect.md) remain the integration references
for the implemented baseline.
### Planned Linux Configuration
+5 -1
View File
@@ -77,10 +77,14 @@ management-core interrupt 17. The data pin is forced low while idle, during
reset/latch time, after abort, and after underflow.
The RIBP TX FIFO is also a fixed-address target for the generic DMA engine.
DMA remains a normal RIB master and receives RIBP backpressure when the FIFO
DMA is an AXI4 master and receives RIBP backpressure when the FIFO
is full; the transmitter does not own a private DMA request channel. See
[ws2812.md](ip/ws2812.md) for the register and transfer contract.
I2S and DVP use dedicated 32-bit AXI4-Stream data links to DMA while retaining
RIBP for configuration and PIO fallback. Their stream selection, backpressure,
and transfer-boundary rules are defined in [axi4-stream.md](axi4-stream.md).
## Management JTAG
The fixed Hazard3 management core always exposes five ASIC pads:
+38 -12
View File
@@ -11,9 +11,12 @@
`ifndef RIBP_DVP_DEF_SV
`define RIBP_DVP_DEF_SV
`define RIBP_DVP_RECVEN 8'h00
`define RIBP_DVP_RXDATA 8'h04
`define RIBP_DVP_STATUS 8'h08
// verilog_format: off
`define RIBP_DVP_RECVEN 8'h00
`define RIBP_DVP_RXDATA 8'h04
`define RIBP_DVP_STATUS 8'h08
`define RIBP_DVP_STREAM_CTRL 8'h0C
// verilog_format: on
`endif
@@ -28,10 +31,11 @@ endinterface
module ribp_dvp (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
dvp_if.dut dvp
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
axi4_stream_if.source rx_axis,
dvp_if.dut dvp
// verilog_format: on
);
// ribp
@@ -43,6 +47,8 @@ module ribp_dvp (
logic s_dvp_recven_en;
logic s_dvp_recven_d, s_dvp_recven_q;
logic s_dvp_status_d, s_dvp_status_q;
logic s_dvp_stream_en;
logic s_dvp_stream_d, s_dvp_stream_q;
// dvp clk
logic s_dvp_pclk_buf;
logic s_dvp_pclk_rst_n_sync;
@@ -71,6 +77,16 @@ module ribp_dvp (
s_dvp_recven_q
);
assign s_dvp_stream_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DVP_STREAM_CTRL;
assign s_dvp_stream_d = ribp.wdata[0];
dffer #(1) u_dvp_stream_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_dvp_stream_en),
.dat_i (s_dvp_stream_d),
.dat_o (s_dvp_stream_q)
);
assign s_dvp_status_d = s_rx_empty;
dffr #(1) u_dvp_status_dffr (
clk_i,
@@ -89,19 +105,20 @@ module ribp_dvp (
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
always_comb begin
s_rx_pop_valid = '0;
s_rx_pop_valid = s_dvp_stream_q && rx_axis.tvalid && rx_axis.tready;
s_ribp_rdata_d = s_ribp_rdata_q;
unique case (ribp.addr[7:0])
`RIBP_DVP_RECVEN: s_ribp_rdata_d = {31'd0, s_dvp_recven_q};
`RIBP_DVP_RECVEN: s_ribp_rdata_d = {31'd0, s_dvp_recven_q};
`RIBP_DVP_RXDATA: begin
if (s_ribp_rd_hdshk) begin
if (s_ribp_rd_hdshk && !s_dvp_stream_q) begin
s_rx_pop_valid = 1'b1;
if (!s_rx_empty) s_ribp_rdata_d = s_rx_pop_data;
else s_ribp_rdata_d = '0;
end
end
`RIBP_DVP_STATUS: s_ribp_rdata_d = {31'd0, s_dvp_status_q};
default: s_ribp_rdata_d = s_ribp_rdata_q;
`RIBP_DVP_STATUS: s_ribp_rdata_d = {31'd0, s_dvp_status_q};
`RIBP_DVP_STREAM_CTRL: s_ribp_rdata_d = {31'd0, s_dvp_stream_q};
default: s_ribp_rdata_d = s_ribp_rdata_q;
endcase
end
dffer #(32) u_ribp_rdata_dffer (
@@ -112,6 +129,15 @@ module ribp_dvp (
s_ribp_rdata_q
);
assign rx_axis.tdata = s_rx_pop_data;
assign rx_axis.tkeep = '1;
assign rx_axis.tstrb = '1;
assign rx_axis.tlast = 1'b0;
assign rx_axis.tid = '0;
assign rx_axis.tdest = '0;
assign rx_axis.tuser = '0;
assign rx_axis.tvalid = s_dvp_stream_q && !s_rx_empty;
// clk buffer
tc_clk_buf u_dvp_pclk_clk_buf (
+13 -7
View File
@@ -57,12 +57,15 @@ endinterface
module ribp_dma (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
output logic dma_xfer_done_o,
dma_hw_trg_if.dut hw_trg,
ribp_if.slave ribp,
rib_if.master rib
input logic clk_i,
input logic rst_n_i,
output logic dma_xfer_done_o,
dma_hw_trg_if.dut hw_trg,
ribp_if.slave ribp,
rib_if.master rib,
axi4_stream_if.source i2s_tx_axis,
axi4_stream_if.sink i2s_rx_axis,
axi4_stream_if.sink dvp_rx_axis
// verilog_format: on
);
@@ -291,7 +294,10 @@ module ribp_dma (
.error_addr_o(s_xfer_error_addr),
.fsm_o (s_xfer_fsm),
.hw_trg (hw_trg),
.rib (rib)
.rib (rib),
.i2s_tx_axis (i2s_tx_axis),
.i2s_rx_axis (i2s_rx_axis),
.dvp_rx_axis (dvp_rx_axis)
);
endmodule
+78 -35
View File
@@ -13,24 +13,27 @@
module dma_core (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic [3:0] mode_i,
input logic [31:0] srcaddr_i,
input logic srcincr_i,
input logic [31:0] dstaddr_i,
input logic dstincr_i,
input logic [31:0] xferlen_i,
input logic start_i,
input logic stop_i,
input logic reset_i,
output logic done_o,
output logic error_o,
output logic [2:0] error_code_o,
output logic [31:0] error_addr_o,
output logic [1:0] fsm_o,
dma_hw_trg_if.dut hw_trg,
rib_if.master rib
input logic clk_i,
input logic rst_n_i,
input logic [3:0] mode_i,
input logic [31:0] srcaddr_i,
input logic srcincr_i,
input logic [31:0] dstaddr_i,
input logic dstincr_i,
input logic [31:0] xferlen_i,
input logic start_i,
input logic stop_i,
input logic reset_i,
output logic done_o,
output logic error_o,
output logic [2:0] error_code_o,
output logic [31:0] error_addr_o,
output logic [1:0] fsm_o,
dma_hw_trg_if.dut hw_trg,
rib_if.master rib,
axi4_stream_if.source i2s_tx_axis,
axi4_stream_if.sink i2s_rx_axis,
axi4_stream_if.sink dvp_rx_axis
// verilog_format: on
);
@@ -45,6 +48,7 @@ module dma_core (
localparam logic [3:0] HWT_I2C0_RX_TRG = 4'd8;
localparam logic [3:0] HWT_I2C1_TX_TRG = 4'd9;
localparam logic [3:0] HWT_I2C1_RX_TRG = 4'd10;
localparam logic [3:0] HWT_DVP_RX_TRG = 4'd11;
localparam logic [2:0] FSM_IDLE = 3'd0;
localparam logic [2:0] FSM_RD_CMD = 3'd1;
@@ -72,6 +76,11 @@ module dma_core (
logic [ 2:0] s_fifo_count;
logic [31:0] s_fifo_rdata;
logic s_rsp_error;
logic s_i2s_tx_stream;
logic s_i2s_rx_stream;
logic s_dvp_rx_stream;
logic s_stream_rx_hdshk;
logic s_stream_tx_hdshk;
assign s_remaining_words = xferlen_i - s_xfer_cnt_q;
// verilog_format: off
@@ -86,6 +95,26 @@ module dma_core (
// verilog_format: on
assign s_chunk_len = s_use_burst ? `RIB_LEN_INCR4 : `RIB_LEN_INCR1;
assign s_chunk_words = s_use_burst ? 32'd4 : 32'd1;
assign s_i2s_tx_stream = mode_i == HWT_I2S_TX_TRG;
assign s_i2s_rx_stream = mode_i == HWT_I2S_RX_TRG;
assign s_dvp_rx_stream = mode_i == HWT_DVP_RX_TRG;
assign i2s_tx_axis.tdata = s_fifo_rdata;
assign i2s_tx_axis.tkeep = '1;
assign i2s_tx_axis.tstrb = '1;
assign i2s_tx_axis.tlast = (s_xfer_cnt_q + 1'b1) >= xferlen_i;
assign i2s_tx_axis.tid = '0;
assign i2s_tx_axis.tdest = '0;
assign i2s_tx_axis.tuser = '0;
assign i2s_tx_axis.tvalid = (s_fsm_q == FSM_WR_DATA) && s_i2s_tx_stream &&
!s_fifo_empty;
assign i2s_rx_axis.tready = (s_fsm_q == FSM_RD_RESP) && s_i2s_rx_stream &&
!s_fifo_full;
assign dvp_rx_axis.tready = (s_fsm_q == FSM_RD_RESP) && s_dvp_rx_stream &&
!s_fifo_full;
assign s_stream_tx_hdshk = i2s_tx_axis.tvalid && i2s_tx_axis.tready;
assign s_stream_rx_hdshk = (i2s_rx_axis.tvalid && i2s_rx_axis.tready) ||
(dvp_rx_axis.tvalid && dvp_rx_axis.tready);
always_comb begin
s_read_trigger = 1'b1;
@@ -117,11 +146,12 @@ module dma_core (
assign rib.cmd_addr = s_fsm_q == FSM_WR_CMD ? s_dst_addr_q : s_src_addr_q;
assign rib.cmd_write = s_fsm_q == FSM_WR_CMD;
assign rib.cmd_len = s_chunk_len;
assign rib.w_valid = (s_fsm_q == FSM_WR_DATA) && ~s_fifo_empty && (s_fifo_count != 3'd0);
assign rib.w_valid = (s_fsm_q == FSM_WR_DATA) && !s_i2s_tx_stream &&
~s_fifo_empty && (s_fifo_count != 3'd0);
assign rib.wdata = s_fifo_rdata;
assign rib.wstrb = '1;
assign rib.wlast = s_wr_beat_q == s_chunk_len;
assign rib.rsp_ready = (s_fsm_q == FSM_RD_RESP) ?
assign rib.rsp_ready = (s_fsm_q == FSM_RD_RESP) && !(s_i2s_rx_stream || s_dvp_rx_stream) ?
(~s_fifo_full && (s_fifo_count != 3'd4)) :
(s_fsm_q == FSM_WR_RESP);
@@ -131,23 +161,24 @@ module dma_core (
assign s_rsp_error = s_rsp_hdshk && rib.resp_err;
assign s_fifo_flush = reset_i || start_i || s_rsp_error;
assign s_fifo_push = (s_fsm_q == FSM_RD_RESP) && s_rsp_hdshk && ~rib.resp_err;
assign s_fifo_pop = (s_fsm_q == FSM_WR_DATA) && s_w_hdshk;
assign s_fifo_push = (s_i2s_rx_stream || s_dvp_rx_stream) ? s_stream_rx_hdshk :
((s_fsm_q == FSM_RD_RESP) && s_rsp_hdshk && ~rib.resp_err);
assign s_fifo_pop = s_i2s_tx_stream ? s_stream_tx_hdshk : ((s_fsm_q == FSM_WR_DATA) && s_w_hdshk);
fifo #(
.DATA_WIDTH (32),
.BUFFER_DEPTH(4)
) u_data_fifo (
.clk_i (clk_i),
.clk_i(clk_i),
.rst_n_i(rst_n_i),
.flush_i(s_fifo_flush),
.push_i (s_fifo_push),
.full_o (s_fifo_full),
.dat_i (rib.rdata),
.pop_i (s_fifo_pop),
.push_i(s_fifo_push),
.full_o(s_fifo_full),
.dat_i(s_i2s_rx_stream ? i2s_rx_axis.tdata : s_dvp_rx_stream ? dvp_rx_axis.tdata : rib.rdata),
.pop_i(s_fifo_pop),
.empty_o(s_fifo_empty),
.dat_o (s_fifo_rdata),
.cnt_o (s_fifo_count)
.dat_o(s_fifo_rdata),
.cnt_o(s_fifo_count)
);
assign fsm_o = s_fsm_q == FSM_IDLE ? 2'd0 : s_fsm_q == FSM_DONE ? 2'd2 : 2'd1;
@@ -174,8 +205,9 @@ module dma_core (
s_src_addr_d = srcaddr_i;
s_dst_addr_d = dstaddr_i;
s_xfer_cnt_d = '0;
s_wr_beat_d = '0;
s_fsm_d = xferlen_i == 32'd0 ? FSM_DONE : FSM_RD_CMD;
s_wr_beat_d = '0;
s_fsm_d = xferlen_i == 32'd0 ? FSM_DONE :
(s_i2s_rx_stream || s_dvp_rx_stream) ? FSM_RD_RESP : FSM_RD_CMD;
end
end
FSM_RD_CMD: begin
@@ -184,7 +216,10 @@ module dma_core (
end
end
FSM_RD_RESP: begin
if (s_rsp_hdshk) begin
if ((s_i2s_rx_stream || s_dvp_rx_stream) && s_stream_rx_hdshk) begin
s_wr_beat_d = '0;
s_fsm_d = FSM_WR_CMD;
end else if (s_rsp_hdshk) begin
if (rib.resp_err) begin
s_fsm_d = FSM_IDLE;
error_o = 1'b1;
@@ -192,7 +227,7 @@ module dma_core (
error_addr_o = s_src_addr_q + {28'd0, rib.rsp_beat, 2'b00};
end else if (rib.rsp_last) begin
s_wr_beat_d = '0;
s_fsm_d = FSM_WR_CMD;
s_fsm_d = s_i2s_tx_stream ? FSM_WR_DATA : FSM_WR_CMD;
end
end
end
@@ -202,7 +237,15 @@ module dma_core (
end
end
FSM_WR_DATA: begin
if (s_w_hdshk) begin
if (s_i2s_tx_stream && s_stream_tx_hdshk) begin
s_xfer_cnt_d = s_xfer_cnt_q + 1'b1;
if (srcincr_i) s_src_addr_d = s_src_addr_q + 32'd4;
if ((s_xfer_cnt_q + 1'b1) >= xferlen_i) begin
s_fsm_d = FSM_DONE;
end else begin
s_fsm_d = FSM_RD_CMD;
end
end else if (s_w_hdshk) begin
if (rib.wlast) begin
s_fsm_d = FSM_WR_RESP;
end else begin
@@ -224,7 +267,7 @@ module dma_core (
if ((s_xfer_cnt_q + s_chunk_words) >= xferlen_i) begin
s_fsm_d = FSM_DONE;
end else begin
s_fsm_d = FSM_RD_CMD;
s_fsm_d = (s_i2s_rx_stream || s_dvp_rx_stream) ? FSM_RD_RESP : FSM_RD_CMD;
end
end
end
+49 -27
View File
@@ -31,51 +31,73 @@ endinterface
module ribp_i2s (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic clk_aud_i,
input logic rst_aud_n_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o,
ribp_if.slave ribp,
i2s_if.dut i2s
input logic clk_i,
input logic rst_n_i,
input logic clk_aud_i,
input logic rst_aud_n_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o,
ribp_if.slave ribp,
axi4_stream_if.sink tx_axis,
axi4_stream_if.source rx_axis,
i2s_if.dut i2s
// verilog_format: on
);
logic s_i2s_mode;
logic [1:0] s_i2s_format;
logic s_i2s_recven;
logic s_i2s_stream_tx_enable;
logic s_i2s_stream_rx_enable;
// tx fifo
logic s_tx_push_valid, s_tx_full, s_tx_empty;
logic s_tx_push_valid, s_tx_pio_push_valid, s_tx_full, s_tx_empty;
logic s_tx_pop_valid, s_tx_pop_ready;
logic [31:0] s_tx_push_data, s_tx_pop_data;
logic [31:0] s_tx_push_data, s_tx_pio_push_data, s_tx_pop_data;
logic [7:0] s_tx_elem_num;
// rx fifo
logic s_rx_push_valid, s_rx_full, s_rx_empty;
logic s_rx_pop_valid, s_rx_pop_ready;
logic s_rx_pop_valid, s_rx_pio_pop_valid, s_rx_pop_ready;
logic [31:0] s_rx_push_data, s_rx_pop_data;
logic [7:0] s_rx_elem_num;
i2s_reg u_i2s_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.mode_o (s_i2s_mode),
.format_o (s_i2s_format),
.recven_o (s_i2s_recven),
.tx_push_valid_o(s_tx_push_valid),
.tx_push_data_o (s_tx_push_data),
.tx_full_i (s_tx_full),
.tx_elem_num_i (s_tx_elem_num),
.rx_pop_valid_o (s_rx_pop_valid),
.rx_pop_data_i (s_rx_pop_data),
.rx_empty_i (s_rx_empty),
.rx_elem_num_i (s_rx_elem_num),
.dma_tx_stall_o (dma_tx_stall_o),
.dma_rx_stall_o (dma_rx_stall_o)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.mode_o (s_i2s_mode),
.format_o (s_i2s_format),
.recven_o (s_i2s_recven),
.stream_tx_enable_o(s_i2s_stream_tx_enable),
.stream_rx_enable_o(s_i2s_stream_rx_enable),
.tx_push_valid_o (s_tx_pio_push_valid),
.tx_push_data_o (s_tx_pio_push_data),
.tx_full_i (s_tx_full),
.tx_elem_num_i (s_tx_elem_num),
.rx_pop_valid_o (s_rx_pio_pop_valid),
.rx_pop_data_i (s_rx_pop_data),
.rx_empty_i (s_rx_empty),
.rx_elem_num_i (s_rx_elem_num),
.dma_tx_stall_o (dma_tx_stall_o),
.dma_rx_stall_o (dma_rx_stall_o)
);
assign tx_axis.tready = s_i2s_stream_tx_enable && !s_tx_full;
assign s_tx_push_valid = s_i2s_stream_tx_enable ?
(tx_axis.tvalid && tx_axis.tready) : s_tx_pio_push_valid;
assign s_tx_push_data = s_i2s_stream_tx_enable ? tx_axis.tdata : s_tx_pio_push_data;
assign rx_axis.tdata = s_rx_pop_data;
assign rx_axis.tkeep = '1;
assign rx_axis.tstrb = '1;
assign rx_axis.tlast = 1'b0;
assign rx_axis.tid = '0;
assign rx_axis.tdest = '0;
assign rx_axis.tuser = '0;
assign rx_axis.tvalid = s_i2s_stream_rx_enable && !s_rx_empty;
assign s_rx_pop_valid = s_i2s_stream_rx_enable ?
(rx_axis.tvalid && rx_axis.tready) : s_rx_pio_pop_valid;
async_fifo #(
.DATA_WIDTH (32),
+9 -8
View File
@@ -12,14 +12,15 @@
`define RIBP_I2S_DEF_SV
// verilog_format: off
`define RIBP_I2S_MODE 8'h00
`define RIBP_I2S_FORMAT 8'h04
`define RIBP_I2S_UPBOUND 8'h08
`define RIBP_I2S_LOWBOUND 8'h0C
`define RIBP_I2S_RECVEN 8'h10
`define RIBP_I2S_TXDATA 8'h14
`define RIBP_I2S_RXDATA 8'h18
`define RIBP_I2S_STATUS 8'h1C
`define RIBP_I2S_MODE 8'h00
`define RIBP_I2S_FORMAT 8'h04
`define RIBP_I2S_UPBOUND 8'h08
`define RIBP_I2S_LOWBOUND 8'h0C
`define RIBP_I2S_RECVEN 8'h10
`define RIBP_I2S_TXDATA 8'h14
`define RIBP_I2S_RXDATA 8'h18
`define RIBP_I2S_STATUS 8'h1C
`define RIBP_I2S_STREAM_CTRL 8'h20
// verilog_format: on
`define I2S_16b_48K 2'd0
+33 -16
View File
@@ -18,6 +18,8 @@ module i2s_reg (
output logic mode_o,
output logic [ 1:0] format_o,
output logic recven_o,
output logic stream_tx_enable_o,
output logic stream_rx_enable_o,
output logic tx_push_valid_o,
output logic [31:0] tx_push_data_o,
input logic tx_full_i,
@@ -48,28 +50,32 @@ module i2s_reg (
logic s_i2s_recven_en;
logic s_i2s_recven_d, s_i2s_recven_q;
logic [1:0] s_i2s_status_d, s_i2s_status_q;
logic s_i2s_stream_en;
logic [1:0] s_i2s_stream_d, s_i2s_stream_q;
// common
logic s_tx_fifo_stall_d, s_tx_fifo_stall_q;
logic s_rx_fifo_stall_d, s_rx_fifo_stall_q;
// ribp
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && (|ribp.wstrb);
assign s_ribp_rd_hdshk = ribp.valid && (~s_ribp_ready_q) && (~(|ribp.wstrb));
assign ribp.ready = s_ribp_ready_q;
assign ribp.resp_err = 1'b0;
assign ribp.rdata = s_ribp_rdata_q;
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && (|ribp.wstrb);
assign s_ribp_rd_hdshk = ribp.valid && (~s_ribp_ready_q) && (~(|ribp.wstrb));
assign ribp.ready = s_ribp_ready_q;
assign ribp.resp_err = 1'b0;
assign ribp.rdata = s_ribp_rdata_q;
// reg
assign mode_o = s_i2s_mode_q;
assign format_o = s_i2s_format_q;
assign recven_o = s_i2s_recven_q;
assign mode_o = s_i2s_mode_q;
assign format_o = s_i2s_format_q;
assign recven_o = s_i2s_recven_q;
assign stream_tx_enable_o = s_i2s_stream_q[0];
assign stream_rx_enable_o = s_i2s_stream_q[1];
// dma
assign dma_tx_stall_o = s_tx_fifo_stall_q;
assign dma_rx_stall_o = s_rx_fifo_stall_q;
assign dma_tx_stall_o = s_tx_fifo_stall_q;
assign dma_rx_stall_o = s_rx_fifo_stall_q;
assign s_i2s_mode_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2S_MODE;
assign s_i2s_mode_d = ribp.wdata[0];
assign s_i2s_mode_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2S_MODE;
assign s_i2s_mode_d = ribp.wdata[0];
dffer #(1) u_i2s_mode_dffer (
clk_i,
rst_n_i,
@@ -122,6 +128,16 @@ module i2s_reg (
s_i2s_recven_q
);
assign s_i2s_stream_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2S_STREAM_CTRL;
assign s_i2s_stream_d = ribp.wdata[1:0];
dffer #(2) u_i2s_stream_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_i2s_stream_en),
.dat_i (s_i2s_stream_d),
.dat_o (s_i2s_stream_q)
);
always_comb begin
s_tx_fifo_stall_d = s_tx_fifo_stall_q;
@@ -193,8 +209,8 @@ module i2s_reg (
rx_pop_valid_o = 1'b0;
s_ribp_rdata_d = s_ribp_rdata_q;
unique case (ribp.addr[7:0])
`RIBP_I2S_MODE: s_ribp_rdata_d = {31'd0, s_i2s_mode_q};
`RIBP_I2S_FORMAT: s_ribp_rdata_d = {30'd0, s_i2s_format_q};
`RIBP_I2S_MODE: s_ribp_rdata_d = {31'd0, s_i2s_mode_q};
`RIBP_I2S_FORMAT: s_ribp_rdata_d = {30'd0, s_i2s_format_q};
`RIBP_I2S_RXDATA: begin
if (s_ribp_rd_hdshk) begin
rx_pop_valid_o = 1'b1;
@@ -202,8 +218,9 @@ module i2s_reg (
else s_ribp_rdata_d = '0;
end
end
`RIBP_I2S_STATUS: s_ribp_rdata_d = {30'd0, s_i2s_status_q};
default: s_ribp_rdata_d = s_ribp_rdata_q;
`RIBP_I2S_STATUS: s_ribp_rdata_d = {30'd0, s_i2s_status_q};
`RIBP_I2S_STREAM_CTRL: s_ribp_rdata_d = {30'd0, s_i2s_stream_q};
default: s_ribp_rdata_d = s_ribp_rdata_q;
endcase
end
dffer #(32) u_ribp_rdata_dffer (
+21 -7
View File
@@ -12,10 +12,10 @@ from typing import Any
MAX_ADDRESS = 1 << 32
VALID_ROUTES = {"ribp", "apb", "ram", "reserved"}
VALID_ROUTES = {"ribp", "axi4", "apb", "ram", "reserved"}
VALID_KINDS = {"active", "reserved"}
VALID_USER_ACCESS = {"none", "ro", "rw"}
VALID_BURST = {"incr1", "incr4"}
VALID_BURST = {"incr1", "incr4", "incr16"}
def parse_integer(value: Any, field: str) -> int:
@@ -32,8 +32,8 @@ def parse_integer(value: Any, field: str) -> int:
def read_map(path: Path) -> tuple[int, list[dict[str, Any]], list[dict[str, Any]]]:
with path.open(encoding="utf-8") as source:
document = json.load(source)
if document.get("schema_version") != 1:
raise ValueError("schema_version must be 1")
if document.get("schema_version") != 2:
raise ValueError("schema_version must be 2")
cpu_reset = parse_integer(document.get("cpu_reset"), "cpu_reset")
registers = document.get("sysctrl_registers")
if not isinstance(registers, list) or not registers:
@@ -86,7 +86,7 @@ def read_map(path: Path) -> tuple[int, list[dict[str, Any]], list[dict[str, Any]
if burst not in VALID_BURST:
raise ValueError(f"regions[{index}].burst must be one of {sorted(VALID_BURST)}")
if kind == "reserved" and burst != "incr1":
raise ValueError(f"regions[{index}] reserved regions cannot support INCR4")
raise ValueError(f"regions[{index}] reserved regions cannot support bursts")
base = parse_integer(region.get("base"), f"regions[{index}].base")
size = parse_integer(region.get("size"), f"regions[{index}].size")
if base < 0 or size <= 0 or base + size > MAX_ADDRESS:
@@ -160,13 +160,21 @@ def render_rtl(
f"{range_expression(symbol, region['base'], region['end'])}",
]
lines.append("")
for route in ("ribp", "apb", "ram", "reserved"):
for route in ("ribp", "axi4", "apb", "ram", "reserved"):
selected = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
if region["route"] == route
]
lines.append(f"`define SOC_ADDR_IS_{route.upper()}(addr) ({join_or(selected)})")
legacy_rib_targets = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
if region["route"] in {"ribp", "axi4"}
]
lines.append(
f"`define SOC_ADDR_IS_RIB_LEGACY_TARGET(addr) ({join_or(legacy_rib_targets)})"
)
user_readable = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
@@ -185,9 +193,15 @@ def render_rtl(
incr4_regions = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
if region["burst"] == "incr4"
if region["burst"] in {"incr4", "incr16"}
]
lines.append(f"`define SOC_ADDR_SUPPORTS_INCR4(addr) ({join_or(incr4_regions)})")
incr16_regions = [
f"`SOC_ADDR_IS_{region['symbol']}(addr)"
for region in regions
if region["burst"] == "incr16"
]
lines.append(f"`define SOC_ADDR_SUPPORTS_INCR16(addr) ({join_or(incr16_regions)})")
lines.append("")
for register in sysctrl_registers:
macro = f"SOC_SYSCTRL_{register['symbol']}_OFFSET"
+7 -7
View File
@@ -1,5 +1,5 @@
{
"schema_version": 1,
"schema_version": 2,
"cpu_reset": "0x00000000",
"sysctrl_registers": [
{"symbol": "CORESEL", "offset": "0x00"},
@@ -35,7 +35,7 @@
{"symbol": "RTC_WAKE_STATUS", "offset": "0x88"}
],
"regions": [
{"symbol": "FLASH", "base": "0x00000000", "size": "0x01000000", "route": "ribp", "kind": "active", "public": true, "linker": "FLASH", "user_access": "ro", "burst": "incr4"},
{"symbol": "FLASH", "base": "0x00000000", "size": "0x01000000", "route": "axi4", "kind": "active", "public": true, "linker": "FLASH", "user_access": "ro", "burst": "incr16"},
{"symbol": "RIBP_GPIO", "base": "0x10000000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "RIBP_UART0", "base": "0x10001000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "RIBP_TIM0", "base": "0x10002000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
@@ -65,11 +65,11 @@
{"symbol": "APB_WDG", "base": "0x20005000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "APB_CRC", "base": "0x20006000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "APB_USER_IP", "base": "0x20007000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "SRAM", "base": "0x30000000", "size": "0x00020000", "route": "ram", "kind": "active", "public": true, "linker": "SRAM", "user_access": "rw", "burst": "incr4"},
{"symbol": "SDRAM", "base": "0x38000000", "size": "0x02000000", "route": "ribp", "kind": "active", "public": true, "linker": "SDRAM", "user_access": "rw", "burst": "incr4"},
{"symbol": "PSRAM", "base": "0x40000000", "size": "0x00800000", "route": "ribp", "kind": "active", "public": true, "linker": "PSRAM", "user_access": "rw", "burst": "incr4"},
{"symbol": "SRAM", "base": "0x30000000", "size": "0x00020000", "route": "ram", "kind": "active", "public": true, "linker": "SRAM", "user_access": "rw", "burst": "incr16"},
{"symbol": "SDRAM", "base": "0x38000000", "size": "0x02000000", "route": "axi4", "kind": "active", "public": true, "linker": "SDRAM", "user_access": "rw", "burst": "incr16"},
{"symbol": "PSRAM", "base": "0x40000000", "size": "0x00800000", "route": "axi4", "kind": "active", "public": true, "linker": "PSRAM", "user_access": "rw", "burst": "incr16"},
{"symbol": "OPIPSRAM", "base": "0x48000000", "size": "0x08000000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
{"symbol": "XPI", "base": "0x50000000", "size": "0x10000000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw", "burst": "incr4"},
{"symbol": "SPISD", "base": "0x60000000", "size": "0x40000000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw", "burst": "incr4"}
{"symbol": "XPI", "base": "0x50000000", "size": "0x10000000", "route": "axi4", "kind": "active", "public": true, "user_access": "rw", "burst": "incr16"},
{"symbol": "SPISD", "base": "0x60000000", "size": "0x40000000", "route": "axi4", "kind": "active", "public": true, "user_access": "rw", "burst": "incr16"}
]
}
+71
View File
@@ -0,0 +1,71 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`ifndef SV_ASSRT_DISABLE
`ifndef SYNTHESIS
// The design uses rst_n_i asynchronously in state registers while SVA samples
// it synchronously in disable iff. This is intentional assertion semantics.
/* verilator lint_off SYNCASYNCNET */
module axi4_interconnect_sva #(
parameter int NUM_MASTERS = 3,
parameter int NUM_TARGETS = 9,
parameter int MASTER_WIDTH = $clog2(NUM_MASTERS),
parameter int TARGET_WIDTH = $clog2(NUM_TARGETS)
) (
input logic clk_i,
input logic rst_n_i,
input logic [NUM_MASTERS-1:0][ 1:0] master_state_i,
input logic [NUM_MASTERS-1:0][TARGET_WIDTH-1:0] master_target_i,
input logic [NUM_TARGETS-1:0] target_valid_i,
input logic [NUM_TARGETS-1:0] target_addr_sent_i,
input logic [NUM_TARGETS-1:0][MASTER_WIDTH-1:0] target_owner_i,
input logic user_bus_enable_i,
input logic user_awready_i,
input logic user_arready_i
);
localparam logic [1:0] MASTER_IDLE = 2'd0;
localparam logic [1:0] MASTER_ACTIVE = 2'd2;
for (genvar target = 0; target < NUM_TARGETS; target++) begin : GEN_TARGET_OWNERSHIP
assert property (@(posedge clk_i) disable iff (!rst_n_i)
target_addr_sent_i[target] |-> target_valid_i[target]);
assert property (@(posedge clk_i) disable iff (!rst_n_i)
target_valid_i[target] |->
master_state_i[target_owner_i[target]] == MASTER_ACTIVE &&
master_target_i[target_owner_i[target]] == TARGET_WIDTH'(target));
for (genvar other = target + 1; other < NUM_TARGETS; other++) begin : GEN_UNIQUE_OWNER
assert property (@(posedge clk_i) disable iff (!rst_n_i)
target_valid_i[target] && target_valid_i[other] |->
target_owner_i[target] != target_owner_i[other]);
end
end
assert property (@(posedge clk_i) disable iff (!rst_n_i)
!user_bus_enable_i && master_state_i[1] == MASTER_IDLE |->
!user_awready_i && !user_arready_i);
endmodule
bind axi4_interconnect axi4_interconnect_sva #(
.NUM_MASTERS(NUM_MASTERS),
.NUM_TARGETS(NUM_TARGETS)
) u_axi4_interconnect_sva (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.master_state_i (r_master_state),
.master_target_i (r_master_target),
.target_valid_i (r_target_valid),
.target_addr_sent_i(r_target_addr_sent),
.target_owner_i (r_target_owner),
.user_bus_enable_i (user_bus_enable_i),
.user_awready_i (m_awready[1]),
.user_arready_i (m_arready[1])
);
/* verilator lint_on SYNCASYNCNET */
`endif
`endif
+1 -1
View File
@@ -40,7 +40,7 @@ module rib_bus_sva (
endmodule
bind bus rib_bus_sva u_rib_bus_sva (
bind rib_bus rib_bus_sva u_rib_bus_sva (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.fault_cmd_accept_i(s_fault_cmd_hdshk),
+3
View File
@@ -1,12 +1,15 @@
/clusterip/common/rtl/interface/apb4_if.sv
/clusterip/common/rtl/interface/apb4_pure_if.sv
/clusterip/common/rtl/interface/ahbl_if.sv
/clusterip/common/rtl/interface/axi4_if.sv
/clusterip/common/rtl/interface/axi4_stream_if.sv
/clusterip/common/rtl/interface/ribp_if.sv
/clusterip/common/rtl/interface/ram_if.sv
/top/rib_if.sv
/clusterip/common/rtl/utils/register.sv
/top/soc_common_fifo.sv
/clusterip/common/rtl/utils/spill_register.sv
/clusterip/common/rtl/stream/round_robin_arbiter.sv
/clusterip/common/rtl/utils/lfsr.sv
/clusterip/common/rtl/utils/gray2bin.sv
/clusterip/common/rtl/utils/edge_det.sv
+12
View File
@@ -3,6 +3,17 @@
/top/ribp2rib.sv
/top/rib2ribp.sv
/top/rib2apb.sv
/top/axi4_connector.sv
/top/axi4_interconnect.sv
/top/axi4_error_slave.sv
/top/axi42ribp.sv
/top/axi42ribp_burst.sv
/top/ribp2axi4.sv
/top/rib2axi4.sv
/top/ahbl2axi4.sv
/top/axi42apb.sv
/top/axi42ram.sv
/top/ribp_arbiter2.sv
/top/rib_error_slave.sv
/top/rib2ram.sv
/top/core_wrapper.sv
@@ -22,3 +33,4 @@
/top/user_ip_top.sv
/top/user_ip_wrapper.sv
/sva/rib_protocol_sva.sv
/sva/axi4_protocol_sva.sv
+1 -1
View File
@@ -188,7 +188,7 @@ module bus_formal_design (
assign rib_cmd_len = rib.cmd_len;
assign apb_valid = apb_rib.cmd_valid;
bus u_dut (
rib_bus u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.mgmt_ribp (mgmt_ribp),
@@ -29,6 +29,7 @@ def target_defines(target: str) -> list[str]:
def source_files(target: str) -> list[Path]:
common = [
COMMON_RTL / "interface/axi4_if.sv",
COMMON_RTL / "interface/ribp_if.sv",
COMMON_RTL / "interface/ram_if.sv",
COMMON_RTL / "utils/register.sv",
+9 -7
View File
@@ -3,11 +3,12 @@
`soc_topology.json` is the source of truth for internal Mini SoC integration
that is not part of the software address-map ABI or the package pad map.
The topology generator validates rib RIB and APB target ownership against
The topology generator validates RIBP configuration and APB target ownership against
`../address_map/memory_map.json` and emits generated SystemVerilog include
files for `ip_ribp_wrapper.sv`, `ip_apb_wrapper.sv`, `rib2apb.sv`, and
`retrosoc.sv`. The output retains scalar interface instances and ports, so it
does not depend on interface-array support in FPGA or netlist simulation tools.
files for `ip_ribp_wrapper.sv`, `ip_apb_wrapper.sv`, `axi42apb.sv`, and
`retrosoc.sv`. Generated fabric links are explicit 32-bit AXI4 interfaces.
Interface arrays are confined to the AXI4 bus implementation and flattened by
the existing synthesis/export flow before FPGA or netlist simulation.
The `ribp_targets` list uses stable response slots. Every active RIBP
memory-map region must appear exactly once. Disabled targets keep their slot
@@ -41,9 +42,10 @@ design IDs, module names, slots, and reset type. `scripts/generate_mpw.py`
verifies that both descriptions agree before RTL generation.
`generate_user_extensions.py` then creates isolated default routing and one
explicit instance per selected slot for `user_core_top.sv` and `user_ip_top.sv`.
User cores use `ribp_if.master ribp`; user IPs use `user_gpio_if.user_ip gpio`
and APB4. This prevents legacy RIB/NMI and electrical pad-control contracts
from entering the SoC muxes.
User cores keep `ribp_if.master ribp` at the extension ABI and are converted to
AXI4 after selection; user IPs use `user_gpio_if.user_ip gpio` and APB4. This
prevents system-fabric and electrical pad-control contracts from entering the
extension muxes.
`clock_reset_domains.json` is the checked inventory of root clock domains,
reset synchronizers, and RCU PLL control crossings. It records the primitive,
+31 -23
View File
@@ -16,14 +16,8 @@ from typing import Any
SV_IDENTIFIER_RE = re.compile(r"[A-Za-z_][A-Za-z0-9_]*$")
SV_REFERENCE_RE = re.compile(r"[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*(?:\[[0-9]+\])?$")
SV_CONSTANT_RE = re.compile(r"(?:1'[bB][01]|'[01])$")
FABRIC_LINK_NAMES = ("mgmt", "user", "dma", "rib", "apb")
FABRIC_PROTOCOLS = {
"mgmt": "ribp",
"user": "rib",
"dma": "rib",
"rib": "rib",
"apb": "rib",
}
FABRIC_LINK_NAMES = ("mgmt", "user", "dma", "cfg", "apb")
FABRIC_PROTOCOLS = {name: "axi4" for name in FABRIC_LINK_NAMES}
IRQ_GROUP_NAMES = ("ribp", "apb")
IRQ_VECTOR_WIDTH = 32
COMPATIBILITY_IRQ_BINDINGS = (
@@ -691,7 +685,7 @@ def render_apb_request_routes(targets: list[ApbTarget]) -> str:
def render_apb_select_routes(targets: list[ApbTarget]) -> str:
lines = ["// Generated by rtl/mini/integration/generate_soc_topology.py; do not edit."]
lines.extend(
f" assign s_psel_comb[{target.slot}] = `SOC_ADDR_IS_{target.region}(rib.cmd_addr);"
f" assign s_psel_comb[{target.slot}] = `SOC_ADDR_IS_{target.region}(s_decode_addr);"
for target in targets
)
return "\n".join(lines) + "\n"
@@ -718,11 +712,25 @@ def render_fabric_interfaces(links: list[FabricLink]) -> str:
interface_types = {
"ribp": "ribp_if",
"rib": "rib_if",
"axi4": "axi4_if",
}
lines.extend(
f" {interface_types[link.protocol]} {link.interface} ();"
for link in links
)
for link in links:
if link.protocol == "axi4":
lines.extend(
[
" axi4_if #(",
" .ADDR_WIDTH(32),",
" .DATA_WIDTH(32),",
" .ID_WIDTH (1),",
" .USER_WIDTH(1)",
f" ) {link.interface} (",
" .aclk (clk_i),",
" .aresetn(rst_n_i)",
" );",
]
)
else:
lines.append(f" {interface_types[link.protocol]} {link.interface} ();")
return "\n".join(lines) + "\n"
@@ -739,11 +747,11 @@ def render_fabric_connection(links: list[FabricLink], name: str, port: str) -> s
def render_bus_fabric_connections(links: list[FabricLink]) -> str:
port_names = {
"mgmt": "mgmt_ribp",
"user": "user_rib",
"dma": "dma_rib",
"rib": "rib",
"apb": "apb_rib",
"mgmt": "mgmt_axi4",
"user": "user_axi4",
"dma": "dma_axi4",
"cfg": "cfg_axi4",
"apb": "apb_axi4",
}
interfaces = {link.name: link.interface for link in links}
lines = ["// Generated by rtl/mini/integration/generate_soc_topology.py; do not edit."]
@@ -904,21 +912,21 @@ def generate(topology_path: Path, memory_map_path: Path, output_dir: Path) -> No
atomic_write(rtl_dir / "soc_fabric_interfaces.svh", render_fabric_interfaces(fabric_links))
atomic_write(
rtl_dir / "soc_mgmt_core_wrapper_fabric.svh",
render_fabric_connection(fabric_links, "mgmt", "ribp"),
render_fabric_connection(fabric_links, "mgmt", "axi4"),
)
atomic_write(
rtl_dir / "soc_user_core_fabric.svh",
render_fabric_connection(fabric_links, "user", "rib"),
render_fabric_connection(fabric_links, "user", "axi4"),
)
atomic_write(rtl_dir / "soc_bus_fabric.svh", render_bus_fabric_connections(fabric_links))
atomic_write(
rtl_dir / "ip_ribp_wrapper_fabric.svh",
render_fabric_connection(fabric_links, "rib", "rib")
+ render_fabric_connection(fabric_links, "dma", "dma_rib"),
render_fabric_connection(fabric_links, "cfg", "cfg_axi4")
+ render_fabric_connection(fabric_links, "dma", "dma_axi4"),
)
atomic_write(
rtl_dir / "soc_ip_apb_wrapper_fabric.svh",
render_fabric_connection(fabric_links, "apb", "rib"),
render_fabric_connection(fabric_links, "apb", "axi4"),
)
atomic_write(rtl_dir / "soc_gpio_alt_bindings.svh", render_gpio_bindings(gpio_functions))
atomic_write(
+9 -9
View File
@@ -34,27 +34,27 @@
{"slot": 1, "name": "gpio", "interface": "u_gpio_ribp_if", "regions": ["RIBP_GPIO", "RIBP_GPIO_ADMIN"]},
{"slot": 2, "name": "tim0", "interface": "u_tim0_ribp_if", "regions": ["RIBP_TIM0"]},
{"slot": 3, "name": "tim1", "interface": "u_tim1_ribp_if", "regions": ["RIBP_TIM1"]},
{"slot": 4, "name": "psram", "interface": "u_psram_ribp_if", "regions": ["RIBP_PSRAM", "PSRAM"]},
{"slot": 5, "name": "spisd", "interface": "u_spisd_ribp_if", "regions": ["RIBP_SPISD", "SPISD"]},
{"slot": 4, "name": "psram", "interface": "u_psram_ribp_if", "regions": ["RIBP_PSRAM"]},
{"slot": 5, "name": "spisd", "interface": "u_spisd_ribp_if", "regions": ["RIBP_SPISD"]},
{"slot": 6, "name": "i2c0", "interface": "u_i2c0_ribp_if", "regions": ["RIBP_I2C0"]},
{"slot": 7, "name": "i2s", "interface": "u_i2s_ribp_if", "regions": ["RIBP_I2S"]},
{"slot": 8, "name": "ws2812", "interface": "u_ws2812_ribp_if", "regions": ["RIBP_WS2812"]},
{"slot": 9, "name": "xpi", "interface": "u_xpi_ribp_if", "regions": ["RIBP_XPI", "FLASH", "XPI"]},
{"slot": 9, "name": "xpi", "interface": "u_xpi_ribp_if", "regions": ["RIBP_XPI"]},
{"slot": 10, "name": "dma", "interface": "u_dma_ribp_if", "regions": ["RIBP_DMA"]},
{"slot": 11, "name": "sysctrl", "interface": "u_sysctrl_ribp_if", "regions": ["RIBP_SYSCTRL"]},
{"slot": 12, "name": "clint", "interface": "u_clint_ribp_if", "regions": ["RIBP_CLINT"]},
{"slot": 13, "name": "sdram", "interface": "u_sdram_ribp_if", "regions": ["RIBP_SDRAM", "SDRAM"]},
{"slot": 13, "name": "sdram", "interface": "u_sdram_ribp_if", "regions": ["RIBP_SDRAM"]},
{"slot": 14, "name": "dvp", "interface": "u_dvp_ribp_if", "regions": ["RIBP_DVP"]},
{"slot": 15, "name": "sdio", "interface": "u_sdio_ribp_if", "disabled": true},
{"slot": 16, "name": "opipsram", "interface": "u_opipsram_ribp_if", "disabled": true},
{"slot": 17, "name": "i2c1", "interface": "u_i2c1_ribp_if", "regions": ["RIBP_I2C1"]}
],
"fabric_links": [
{"name": "mgmt", "interface": "u_mgmt_ribp_if", "protocol": "ribp"},
{"name": "user", "interface": "u_user_rib_if", "protocol": "rib"},
{"name": "dma", "interface": "u_dma_rib_if", "protocol": "rib"},
{"name": "rib", "interface": "u_rib_if", "protocol": "rib"},
{"name": "apb", "interface": "u_apb_rib_if", "protocol": "rib"}
{"name": "mgmt", "interface": "u_mgmt_axi4_if", "protocol": "axi4"},
{"name": "user", "interface": "u_user_axi4_if", "protocol": "axi4"},
{"name": "dma", "interface": "u_dma_axi4_if", "protocol": "axi4"},
{"name": "cfg", "interface": "u_cfg_axi4_if", "protocol": "axi4"},
{"name": "apb", "interface": "u_apb_axi4_if", "protocol": "axi4"}
],
"apb_targets": [
{"slot": 0, "name": "archinfo", "timed_interface": "u_archinfo_apb_if", "pure_interface": "u_archinfo_apb_pure_if", "region": "APB_ARCHINFO"},
+193
View File
@@ -0,0 +1,193 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
module ahbl2axi4 (
ahbl_if.slave ahbl,
axi4_if.master axi4,
output logic idle_o
);
localparam logic [1:0] AHBL_TRANS_NSEQ = 2'b10;
localparam logic [2:0] AHBL_SIZE_BYTE = 3'b000;
localparam logic [2:0] AHBL_SIZE_HWRD = 3'b001;
localparam logic AHBL_RESP_OKAY = 1'b0;
localparam logic AHBL_RESP_ERROR = 1'b1;
localparam logic [2:0] FSM_IDLE = 3'd0;
localparam logic [2:0] FSM_WRITE = 3'd1;
localparam logic [2:0] FSM_WRITE_RESP = 3'd2;
localparam logic [2:0] FSM_READ = 3'd3;
localparam logic [2:0] FSM_READ_RESP = 3'd4;
logic [2:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_d, s_addr_q;
logic s_write_d, s_write_q;
logic [2:0] s_size_d, s_size_q;
logic s_aw_done_d, s_aw_done_q;
logic s_w_done_d, s_w_done_q;
logic [ 3:0] s_wstrb;
logic [31:0] s_wdata;
logic s_terminal;
assign idle_o = s_fsm_q == FSM_IDLE;
assign s_terminal = ((s_fsm_q == FSM_WRITE_RESP) && axi4.bvalid) ||
((s_fsm_q == FSM_READ_RESP) && axi4.rvalid);
assign ahbl.hready = (s_fsm_q == FSM_IDLE) || s_terminal;
assign ahbl.hresp = s_terminal &&
(((s_fsm_q == FSM_WRITE_RESP) && (axi4.bresp != `AXI4_RESP_OKAY)) ||
((s_fsm_q == FSM_READ_RESP) && (axi4.rresp != `AXI4_RESP_OKAY))) ?
AHBL_RESP_ERROR : AHBL_RESP_OKAY;
assign ahbl.hrdata = axi4.rdata;
always_comb begin
s_wstrb = '0;
s_wdata = '0;
if (s_write_q) begin
unique case (s_size_q)
AHBL_SIZE_BYTE: begin
unique case (s_addr_q[1:0])
2'd0: begin
s_wstrb = 4'b0001;
s_wdata = {24'd0, ahbl.hwdata[7:0]};
end
2'd1: begin
s_wstrb = 4'b0010;
s_wdata = {16'd0, ahbl.hwdata[7:0], 8'd0};
end
2'd2: begin
s_wstrb = 4'b0100;
s_wdata = {8'd0, ahbl.hwdata[7:0], 16'd0};
end
default: begin
s_wstrb = 4'b1000;
s_wdata = {ahbl.hwdata[7:0], 24'd0};
end
endcase
end
AHBL_SIZE_HWRD: begin
if (s_addr_q[1]) begin
s_wstrb = 4'b1100;
s_wdata = {ahbl.hwdata[15:0], 16'd0};
end else begin
s_wstrb = 4'b0011;
s_wdata = {16'd0, ahbl.hwdata[15:0]};
end
end
default: begin
s_wstrb = 4'b1111;
s_wdata = ahbl.hwdata;
end
endcase
end
end
assign axi4.awid = '0;
assign axi4.awaddr = {s_addr_q[31:2], 2'b00};
assign axi4.awlen = 8'd0;
assign axi4.awsize = `AXI4_BURST_SIZE_4BYTES;
assign axi4.awburst = `AXI4_BURST_TYPE_INCR;
assign axi4.awlock = `AXI4_LOCK_NORM;
assign axi4.awcache = `AXI4_CACHE_NO_BUF;
assign axi4.awprot = `AXI4_PROT_PRIVILEGED | `AXI4_PROT_DATA;
assign axi4.awqos = `AXI4_QOS_NORMAL;
assign axi4.awregion = `AXI4_REGION_NORMAL;
assign axi4.awuser = '0;
assign axi4.awvalid = (s_fsm_q == FSM_WRITE) && !s_aw_done_q;
assign axi4.wdata = s_wdata;
assign axi4.wstrb = s_wstrb;
assign axi4.wlast = 1'b1;
assign axi4.wuser = '0;
assign axi4.wvalid = (s_fsm_q == FSM_WRITE) && !s_w_done_q;
assign axi4.bready = (s_fsm_q == FSM_WRITE_RESP);
assign axi4.arid = '0;
assign axi4.araddr = {s_addr_q[31:2], 2'b00};
assign axi4.arlen = 8'd0;
assign axi4.arsize = `AXI4_BURST_SIZE_4BYTES;
assign axi4.arburst = `AXI4_BURST_TYPE_INCR;
assign axi4.arlock = `AXI4_LOCK_NORM;
assign axi4.arcache = `AXI4_CACHE_NO_BUF;
assign axi4.arprot = `AXI4_PROT_PRIVILEGED | `AXI4_PROT_DATA;
assign axi4.arqos = `AXI4_QOS_NORMAL;
assign axi4.arregion = `AXI4_REGION_NORMAL;
assign axi4.aruser = '0;
assign axi4.arvalid = (s_fsm_q == FSM_READ);
assign axi4.rready = (s_fsm_q == FSM_READ_RESP);
always_comb begin
s_fsm_d = s_fsm_q;
s_addr_d = s_addr_q;
s_write_d = s_write_q;
s_size_d = s_size_q;
s_aw_done_d = s_aw_done_q;
s_w_done_d = s_w_done_q;
if (s_fsm_q == FSM_IDLE || s_terminal) begin
s_aw_done_d = 1'b0;
s_w_done_d = 1'b0;
if (ahbl.htrans == AHBL_TRANS_NSEQ) begin
s_addr_d = ahbl.haddr;
s_write_d = ahbl.hwrite;
s_size_d = ahbl.hsize;
s_fsm_d = ahbl.hwrite ? FSM_WRITE : FSM_READ;
end else begin
s_fsm_d = FSM_IDLE;
end
end else begin
unique case (s_fsm_q)
FSM_WRITE: begin
if (axi4.awvalid && axi4.awready) s_aw_done_d = 1'b1;
if (axi4.wvalid && axi4.wready) s_w_done_d = 1'b1;
if ((s_aw_done_q || (axi4.awvalid && axi4.awready)) &&
(s_w_done_q || (axi4.wvalid && axi4.wready))) begin
s_fsm_d = FSM_WRITE_RESP;
end
end
FSM_READ: begin
if (axi4.arvalid && axi4.arready) s_fsm_d = FSM_READ_RESP;
end
default: begin
end
endcase
end
end
dffr #(3) u_fsm_dffr (
.clk_i (ahbl.hclk),
.rst_n_i(ahbl.hresetn),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(32) u_addr_dffr (
.clk_i (ahbl.hclk),
.rst_n_i(ahbl.hresetn),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(1) u_write_dffr (
.clk_i (ahbl.hclk),
.rst_n_i(ahbl.hresetn),
.dat_i (s_write_d),
.dat_o (s_write_q)
);
dffr #(3) u_size_dffr (
.clk_i (ahbl.hclk),
.rst_n_i(ahbl.hresetn),
.dat_i (s_size_d),
.dat_o (s_size_q)
);
dffr #(1) u_aw_done_dffr (
.clk_i (ahbl.hclk),
.rst_n_i(ahbl.hresetn),
.dat_i (s_aw_done_d),
.dat_o (s_aw_done_q)
);
dffr #(1) u_w_done_dffr (
.clk_i (ahbl.hclk),
.rst_n_i(ahbl.hresetn),
.dat_i (s_w_done_d),
.dat_o (s_w_done_q)
);
endmodule
+232
View File
@@ -0,0 +1,232 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
`include "mmap_define.svh"
module axi42apb (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave axi4,
`include "soc_apb_ports.svh"
);
localparam logic [3:0] FSM_IDLE = 4'd0;
localparam logic [3:0] FSM_DECODE = 4'd1;
localparam logic [3:0] FSM_WR_DATA = 4'd2;
localparam logic [3:0] FSM_SETP = 4'd3;
localparam logic [3:0] FSM_ENAB = 4'd4;
localparam logic [3:0] FSM_WR_RESP = 4'd5;
localparam logic [3:0] FSM_RD_RESP = 4'd6;
localparam logic [3:0] FSM_ERR_WR_DATA = 4'd7;
localparam logic [3:0] FSM_ERR_WR_RESP = 4'd8;
localparam logic [3:0] FSM_ERR_RD_RESP = 4'd9;
logic [3:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_d, s_addr_q, s_decode_addr;
logic [31:0] s_wdata_d, s_wdata_q;
logic [3:0] s_wstrb_d, s_wstrb_q;
logic s_write_d, s_write_q;
logic s_id_d, s_id_q;
logic [7:0] s_len_d, s_len_q;
logic [7:0] s_beat_d, s_beat_q;
logic [31:0] s_rdata_d, s_rdata_q;
logic [1:0] s_resp_d, s_resp_q;
logic [31:0] s_rd_data;
logic s_xfer_valid, s_xfer_ready, s_xfer_error;
logic s_psel_valid;
`include "soc_apb_declarations.svh"
assign s_decode_addr = s_addr_q;
assign s_xfer_valid = (s_fsm_q == FSM_SETP) || (s_fsm_q == FSM_ENAB);
`include "soc_apb_request_routes.svh"
`include "soc_apb_select_routes.svh"
`include "soc_apb_response_mux.svh"
assign s_psel_valid = |s_psel_comb;
assign axi4.awready = (s_fsm_q == FSM_IDLE) && !axi4.arvalid;
assign axi4.arready = (s_fsm_q == FSM_IDLE);
assign axi4.wready = (s_fsm_q == FSM_WR_DATA) || (s_fsm_q == FSM_ERR_WR_DATA);
assign axi4.bid = s_id_q;
assign axi4.bresp = s_resp_q;
assign axi4.buser = '0;
assign axi4.bvalid = (s_fsm_q == FSM_WR_RESP) || (s_fsm_q == FSM_ERR_WR_RESP);
assign axi4.rid = s_id_q;
assign axi4.rdata = (s_fsm_q == FSM_RD_RESP) ? s_rdata_q : '0;
assign axi4.rresp = s_resp_q;
assign axi4.rlast = (s_fsm_q == FSM_RD_RESP) ||
((s_fsm_q == FSM_ERR_RD_RESP) && (s_beat_q == s_len_q));
assign axi4.ruser = '0;
assign axi4.rvalid = (s_fsm_q == FSM_RD_RESP) || (s_fsm_q == FSM_ERR_RD_RESP);
always_comb begin
s_fsm_d = s_fsm_q;
s_addr_d = s_addr_q;
s_wdata_d = s_wdata_q;
s_wstrb_d = s_wstrb_q;
s_write_d = s_write_q;
s_id_d = s_id_q;
s_len_d = s_len_q;
s_beat_d = s_beat_q;
s_rdata_d = s_rdata_q;
s_resp_d = s_resp_q;
unique case (s_fsm_q)
FSM_IDLE: begin
s_beat_d = '0;
s_resp_d = `AXI4_RESP_OKAY;
if (axi4.arvalid && axi4.arready) begin
s_addr_d = axi4.araddr;
s_write_d = 1'b0;
s_id_d = axi4.arid;
s_len_d = axi4.arlen;
if ((axi4.arlen != 8'd0) || (axi4.arburst != `AXI4_BURST_TYPE_INCR) || axi4.arlock) begin
s_resp_d = `AXI4_RESP_SLAVE_ERROR;
s_fsm_d = FSM_ERR_RD_RESP;
end else begin
s_fsm_d = FSM_DECODE;
end
end else if (axi4.awvalid && axi4.awready) begin
s_addr_d = axi4.awaddr;
s_write_d = 1'b1;
s_id_d = axi4.awid;
s_len_d = axi4.awlen;
if ((axi4.awlen != 8'd0) || (axi4.awburst != `AXI4_BURST_TYPE_INCR) || axi4.awlock) begin
s_resp_d = `AXI4_RESP_SLAVE_ERROR;
s_fsm_d = FSM_ERR_WR_DATA;
end else begin
s_fsm_d = FSM_DECODE;
end
end
end
FSM_DECODE: begin
if (!s_psel_valid) begin
s_resp_d = `AXI4_RESP_DECODE_ERROR;
s_fsm_d = s_write_q ? FSM_ERR_WR_DATA : FSM_ERR_RD_RESP;
end else begin
s_fsm_d = s_write_q ? FSM_WR_DATA : FSM_SETP;
end
end
FSM_WR_DATA: begin
if (axi4.wvalid && axi4.wready) begin
s_wdata_d = axi4.wdata;
s_wstrb_d = axi4.wstrb;
if (axi4.wlast) begin
s_fsm_d = FSM_SETP;
end else begin
s_resp_d = `AXI4_RESP_SLAVE_ERROR;
s_fsm_d = FSM_ERR_WR_DATA;
end
end
end
FSM_SETP: s_fsm_d = FSM_ENAB;
FSM_ENAB: begin
if (s_xfer_ready) begin
s_resp_d = s_xfer_error ? `AXI4_RESP_SLAVE_ERROR : `AXI4_RESP_OKAY;
if (s_write_q) begin
s_fsm_d = FSM_WR_RESP;
end else begin
s_rdata_d = s_rd_data;
s_fsm_d = FSM_RD_RESP;
end
end
end
FSM_WR_RESP: begin
if (axi4.bvalid && axi4.bready) s_fsm_d = FSM_IDLE;
end
FSM_RD_RESP: begin
if (axi4.rvalid && axi4.rready) s_fsm_d = FSM_IDLE;
end
FSM_ERR_WR_DATA: begin
if (axi4.wvalid && axi4.wready) begin
if ((s_beat_q == s_len_q) || axi4.wlast) begin
s_fsm_d = FSM_ERR_WR_RESP;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
FSM_ERR_WR_RESP: begin
if (axi4.bvalid && axi4.bready) s_fsm_d = FSM_IDLE;
end
FSM_ERR_RD_RESP: begin
if (axi4.rvalid && axi4.rready) begin
if (s_beat_q == s_len_q) begin
s_fsm_d = FSM_IDLE;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
default: s_fsm_d = FSM_IDLE;
endcase
end
dffr #(4) u_fsm_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(32) u_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(32) u_wdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wdata_d),
.dat_o (s_wdata_q)
);
dffr #(4) u_wstrb_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wstrb_d),
.dat_o (s_wstrb_q)
);
dffr #(1) u_write_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_write_d),
.dat_o (s_write_q)
);
dffr #(1) u_id_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_id_d),
.dat_o (s_id_q)
);
dffr #(8) u_len_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_len_d),
.dat_o (s_len_q)
);
dffr #(8) u_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_beat_d),
.dat_o (s_beat_q)
);
dffr #(32) u_rdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rdata_d),
.dat_o (s_rdata_q)
);
dffr #(2) u_resp_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_resp_d),
.dat_o (s_resp_q)
);
dffr #(NSLV) u_psel_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i ((s_fsm_q == FSM_DECODE) ? s_psel_comb : s_psel_q),
.dat_o (s_psel_q)
);
endmodule
+238
View File
@@ -0,0 +1,238 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
module axi42ram (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave axi4,
ram_if.master ram
);
localparam int RSP_WIDTH = 37;
logic s_active_d, s_active_q;
logic s_write_d, s_write_q;
logic s_id_d, s_id_q;
logic [31:0] s_addr_d, s_addr_q;
logic [7:0] s_len_d, s_len_q;
logic [2:0] s_size_d, s_size_q;
logic [7:0] s_issue_beat_d, s_issue_beat_q;
logic s_issue_valid_d, s_issue_valid_q;
logic [7:0] s_write_beat_d, s_write_beat_q;
logic s_bvalid_d, s_bvalid_q;
logic [1:0] s_bresp_d, s_bresp_q;
logic s_read_pending_d, s_read_pending_q;
logic [7:0] s_read_beat_d, s_read_beat_q;
logic s_read_last_d, s_read_last_q;
logic [14:0] s_read_addr;
logic [31:0] s_read_issue_addr, s_read_hold_addr, s_write_addr;
logic s_read_issue, s_write_hdshk;
logic s_rsp_input_valid, s_rsp_input_ready;
logic [RSP_WIDTH-1:0] s_rsp_input_data, s_rsp_output_data;
assign axi4.awready = !s_active_q && !axi4.arvalid;
assign axi4.arready = !s_active_q;
assign axi4.wready = s_active_q && s_write_q && !s_bvalid_q;
assign axi4.bid = s_id_q;
assign axi4.bresp = s_bresp_q;
assign axi4.buser = '0;
assign axi4.bvalid = s_bvalid_q;
assign axi4.rid = s_rsp_output_data[36];
assign axi4.rdata = s_rsp_output_data[35:4];
assign axi4.rresp = s_rsp_output_data[3:2];
assign axi4.rlast = s_rsp_output_data[1];
assign axi4.ruser = s_rsp_output_data[0];
assign s_write_hdshk = axi4.wvalid && axi4.wready;
assign s_read_issue = s_active_q && !s_write_q && s_issue_valid_q &&
(!s_read_pending_q || s_rsp_input_ready);
assign s_read_issue_addr = s_addr_q + (32'(s_issue_beat_q) << s_size_q);
assign s_read_hold_addr = s_addr_q + (32'(s_read_beat_q) << s_size_q);
assign s_write_addr = s_addr_q + (32'(s_write_beat_q) << s_size_q);
always_comb begin
s_read_addr = s_read_issue_addr[16:2];
if (s_read_pending_q && !s_rsp_input_ready) begin
s_read_addr = s_read_hold_addr[16:2];
end
end
assign ram.addr = s_write_q ? s_write_addr[16:2] : s_read_addr;
assign ram.wdata = axi4.wdata;
assign ram.wstrb = s_write_hdshk ? axi4.wstrb : '0;
assign s_rsp_input_valid = s_read_pending_q;
assign s_rsp_input_data = {s_id_q, ram.rdata, `AXI4_RESP_OKAY, s_read_last_q, 1'b0};
spill_register #(
.DATA_WIDTH(RSP_WIDTH),
.BYPASS (1'b0)
) u_rsp_spill_register (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.flush_i(1'b0),
.valid_i(s_rsp_input_valid),
.ready_o(s_rsp_input_ready),
.data_i (s_rsp_input_data),
.valid_o(axi4.rvalid),
.ready_i(axi4.rready),
.data_o (s_rsp_output_data)
);
always_comb begin
s_active_d = s_active_q;
s_write_d = s_write_q;
s_id_d = s_id_q;
s_addr_d = s_addr_q;
s_len_d = s_len_q;
s_size_d = s_size_q;
s_issue_beat_d = s_issue_beat_q;
s_issue_valid_d = s_issue_valid_q;
s_write_beat_d = s_write_beat_q;
s_bvalid_d = s_bvalid_q;
s_bresp_d = s_bresp_q;
s_read_pending_d = s_read_pending_q;
s_read_beat_d = s_read_beat_q;
s_read_last_d = s_read_last_q;
if (axi4.arvalid && axi4.arready) begin
s_active_d = 1'b1;
s_write_d = 1'b0;
s_id_d = axi4.arid;
s_addr_d = axi4.araddr;
s_len_d = axi4.arlen;
s_size_d = axi4.arsize;
s_issue_beat_d = '0;
s_issue_valid_d = 1'b1;
s_read_pending_d = 1'b0;
end else if (axi4.awvalid && axi4.awready) begin
s_active_d = 1'b1;
s_write_d = 1'b1;
s_id_d = axi4.awid;
s_addr_d = axi4.awaddr;
s_len_d = axi4.awlen;
s_size_d = axi4.awsize;
s_write_beat_d = '0;
s_bvalid_d = 1'b0;
s_bresp_d = `AXI4_RESP_OKAY;
end
if (s_read_pending_q && s_rsp_input_ready) s_read_pending_d = 1'b0;
if (s_read_issue) begin
s_read_pending_d = 1'b1;
s_read_beat_d = s_issue_beat_q;
s_read_last_d = s_issue_beat_q == s_len_q;
if (s_issue_beat_q == s_len_q) begin
s_issue_valid_d = 1'b0;
end else begin
s_issue_beat_d = s_issue_beat_q + 1'b1;
end
end
if (s_write_hdshk) begin
if ((s_write_beat_q == s_len_q) || axi4.wlast) begin
s_bvalid_d = 1'b1;
s_bresp_d = (axi4.wlast == (s_write_beat_q == s_len_q)) ?
`AXI4_RESP_OKAY : `AXI4_RESP_SLAVE_ERROR;
end else begin
s_write_beat_d = s_write_beat_q + 1'b1;
end
end
if (axi4.bvalid && axi4.bready) begin
s_active_d = 1'b0;
s_bvalid_d = 1'b0;
end
if (axi4.rvalid && axi4.rready && axi4.rlast) begin
s_active_d = 1'b0;
s_issue_valid_d = 1'b0;
s_read_pending_d = 1'b0;
end
end
dffr #(1) u_active_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_active_d),
.dat_o (s_active_q)
);
dffr #(1) u_write_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_write_d),
.dat_o (s_write_q)
);
dffr #(1) u_id_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_id_d),
.dat_o (s_id_q)
);
dffr #(32) u_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(8) u_len_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_len_d),
.dat_o (s_len_q)
);
dffr #(3) u_size_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_size_d),
.dat_o (s_size_q)
);
dffr #(8) u_issue_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_issue_beat_d),
.dat_o (s_issue_beat_q)
);
dffr #(1) u_issue_valid_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_issue_valid_d),
.dat_o (s_issue_valid_q)
);
dffr #(8) u_write_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_write_beat_d),
.dat_o (s_write_beat_q)
);
dffr #(1) u_bvalid_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_bvalid_d),
.dat_o (s_bvalid_q)
);
dffr #(2) u_bresp_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_bresp_d),
.dat_o (s_bresp_q)
);
dffr #(1) u_read_pending_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_read_pending_d),
.dat_o (s_read_pending_q)
);
dffr #(8) u_read_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_read_beat_d),
.dat_o (s_read_beat_q)
);
dffr #(1) u_read_last_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_read_last_d),
.dat_o (s_read_last_q)
);
endmodule
+212
View File
@@ -0,0 +1,212 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND.
`include "axi4_define.svh"
module axi42ribp (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave axi4,
ribp_if.master ribp
);
localparam logic [3:0] FSM_IDLE = 4'd0;
localparam logic [3:0] FSM_WR_DATA = 4'd1;
localparam logic [3:0] FSM_WR_REQ = 4'd2;
localparam logic [3:0] FSM_WR_RESP = 4'd3;
localparam logic [3:0] FSM_RD_REQ = 4'd4;
localparam logic [3:0] FSM_RD_RESP = 4'd5;
localparam logic [3:0] FSM_ERR_WR_DATA = 4'd6;
localparam logic [3:0] FSM_ERR_WR_RESP = 4'd7;
localparam logic [3:0] FSM_ERR_RD_RESP = 4'd8;
logic [3:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_d, s_addr_q;
logic [31:0] s_wdata_d, s_wdata_q;
logic [3:0] s_wstrb_d, s_wstrb_q;
logic s_id_d, s_id_q;
logic [7:0] s_len_d, s_len_q;
logic [7:0] s_beat_d, s_beat_q;
logic [31:0] s_rdata_d, s_rdata_q;
logic [1:0] s_resp_d, s_resp_q;
logic s_write_legal, s_read_legal;
logic s_aw_hdshk, s_w_hdshk, s_b_hdshk, s_ar_hdshk, s_r_hdshk;
assign s_write_legal = (axi4.awlen == 8'd0) &&
(axi4.awburst == `AXI4_BURST_TYPE_INCR) && !axi4.awlock &&
(axi4.awsize <= `AXI4_BURST_SIZE_4BYTES) &&
((axi4.awaddr & ((32'd1 << axi4.awsize) - 1'b1)) == '0);
assign s_read_legal = (axi4.arlen == 8'd0) &&
(axi4.arburst == `AXI4_BURST_TYPE_INCR) && !axi4.arlock &&
(axi4.arsize <= `AXI4_BURST_SIZE_4BYTES) &&
((axi4.araddr & ((32'd1 << axi4.arsize) - 1'b1)) == '0);
assign axi4.awready = (s_fsm_q == FSM_IDLE) && !axi4.arvalid;
assign axi4.arready = (s_fsm_q == FSM_IDLE);
assign axi4.wready = (s_fsm_q == FSM_WR_DATA) || (s_fsm_q == FSM_ERR_WR_DATA);
assign axi4.bid = s_id_q;
assign axi4.bresp = s_resp_q;
assign axi4.buser = '0;
assign axi4.bvalid = (s_fsm_q == FSM_WR_RESP) || (s_fsm_q == FSM_ERR_WR_RESP);
assign axi4.rid = s_id_q;
assign axi4.rdata = (s_fsm_q == FSM_RD_RESP) ? s_rdata_q : '0;
assign axi4.rresp = s_resp_q;
assign axi4.rlast = (s_fsm_q == FSM_RD_RESP) ||
((s_fsm_q == FSM_ERR_RD_RESP) && (s_beat_q == s_len_q));
assign axi4.ruser = '0;
assign axi4.rvalid = (s_fsm_q == FSM_RD_RESP) || (s_fsm_q == FSM_ERR_RD_RESP);
assign s_aw_hdshk = axi4.awvalid && axi4.awready;
assign s_w_hdshk = axi4.wvalid && axi4.wready;
assign s_b_hdshk = axi4.bvalid && axi4.bready;
assign s_ar_hdshk = axi4.arvalid && axi4.arready;
assign s_r_hdshk = axi4.rvalid && axi4.rready;
assign ribp.valid = (s_fsm_q == FSM_WR_REQ) || (s_fsm_q == FSM_RD_REQ);
assign ribp.addr = {s_addr_q[31:2], 2'b00};
assign ribp.wdata = s_wdata_q;
assign ribp.wstrb = (s_fsm_q == FSM_WR_REQ) ? s_wstrb_q : '0;
always_comb begin
s_fsm_d = s_fsm_q;
s_addr_d = s_addr_q;
s_wdata_d = s_wdata_q;
s_wstrb_d = s_wstrb_q;
s_id_d = s_id_q;
s_len_d = s_len_q;
s_beat_d = s_beat_q;
s_rdata_d = s_rdata_q;
s_resp_d = s_resp_q;
unique case (s_fsm_q)
FSM_IDLE: begin
s_beat_d = '0;
s_resp_d = `AXI4_RESP_OKAY;
if (s_ar_hdshk) begin
s_addr_d = axi4.araddr;
s_id_d = axi4.arid;
s_len_d = axi4.arlen;
s_fsm_d = s_read_legal ? FSM_RD_REQ : FSM_ERR_RD_RESP;
if (!s_read_legal) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
end else if (s_aw_hdshk) begin
s_addr_d = axi4.awaddr;
s_id_d = axi4.awid;
s_len_d = axi4.awlen;
s_fsm_d = s_write_legal ? FSM_WR_DATA : FSM_ERR_WR_DATA;
if (!s_write_legal) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
end
end
FSM_WR_DATA: begin
if (s_w_hdshk) begin
s_wdata_d = axi4.wdata;
s_wstrb_d = axi4.wstrb;
if (axi4.wlast) begin
s_fsm_d = FSM_WR_REQ;
end else begin
s_resp_d = `AXI4_RESP_SLAVE_ERROR;
s_fsm_d = FSM_ERR_WR_DATA;
end
end
end
FSM_WR_REQ: begin
if (ribp.ready) begin
s_resp_d = ribp.resp_err ? `AXI4_RESP_SLAVE_ERROR : `AXI4_RESP_OKAY;
s_fsm_d = FSM_WR_RESP;
end
end
FSM_WR_RESP: begin
if (s_b_hdshk) s_fsm_d = FSM_IDLE;
end
FSM_RD_REQ: begin
if (ribp.ready) begin
s_rdata_d = ribp.rdata;
s_resp_d = ribp.resp_err ? `AXI4_RESP_SLAVE_ERROR : `AXI4_RESP_OKAY;
s_fsm_d = FSM_RD_RESP;
end
end
FSM_RD_RESP: begin
if (s_r_hdshk) s_fsm_d = FSM_IDLE;
end
FSM_ERR_WR_DATA: begin
if (s_w_hdshk) begin
if ((s_beat_q == s_len_q) || axi4.wlast) begin
s_fsm_d = FSM_ERR_WR_RESP;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
FSM_ERR_WR_RESP: begin
if (s_b_hdshk) s_fsm_d = FSM_IDLE;
end
FSM_ERR_RD_RESP: begin
if (s_r_hdshk) begin
if (s_beat_q == s_len_q) begin
s_fsm_d = FSM_IDLE;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
default: s_fsm_d = FSM_IDLE;
endcase
end
dffr #(4) u_fsm_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(32) u_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(32) u_wdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wdata_d),
.dat_o (s_wdata_q)
);
dffr #(4) u_wstrb_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wstrb_d),
.dat_o (s_wstrb_q)
);
dffr #(1) u_id_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_id_d),
.dat_o (s_id_q)
);
dffr #(8) u_len_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_len_d),
.dat_o (s_len_q)
);
dffr #(8) u_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_beat_d),
.dat_o (s_beat_q)
);
dffr #(32) u_rdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rdata_d),
.dat_o (s_rdata_q)
);
dffr #(2) u_resp_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_resp_d),
.dat_o (s_resp_q)
);
endmodule
+222
View File
@@ -0,0 +1,222 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
module axi42ribp_burst (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave axi4,
ribp_if.master ribp
);
localparam logic [3:0] FSM_IDLE = 4'd0;
localparam logic [3:0] FSM_WR_DATA = 4'd1;
localparam logic [3:0] FSM_WR_REQ = 4'd2;
localparam logic [3:0] FSM_WR_RESP = 4'd3;
localparam logic [3:0] FSM_RD_REQ = 4'd4;
localparam logic [3:0] FSM_RD_RESP = 4'd5;
localparam logic [3:0] FSM_ERR_WR_DRAIN = 4'd6;
localparam logic [3:0] FSM_ERR_WR_RESP = 4'd7;
localparam logic [3:0] FSM_ERR_RD_RESP = 4'd8;
logic [3:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_d, s_addr_q;
logic [31:0] s_wdata_d, s_wdata_q;
logic [3:0] s_wstrb_d, s_wstrb_q;
logic [7:0] s_len_d, s_len_q;
logic [7:0] s_beat_d, s_beat_q;
logic [2:0] s_size_d, s_size_q;
logic s_id_d, s_id_q;
logic [31:0] s_rdata_d, s_rdata_q;
logic [1:0] s_resp_d, s_resp_q;
logic s_legal_write, s_legal_read;
logic [32:0] s_write_last_addr, s_read_last_addr;
assign s_write_last_addr = {1'b0, axi4.awaddr} + ((33'(axi4.awlen) + 1'b1) << axi4.awsize) - 1'b1;
assign s_read_last_addr = {1'b0, axi4.araddr} + ((33'(axi4.arlen) + 1'b1) << axi4.arsize) - 1'b1;
assign s_legal_write = (axi4.awlen <= 8'd15) &&
(axi4.awburst == `AXI4_BURST_TYPE_INCR) && !axi4.awlock &&
(axi4.awsize <= `AXI4_BURST_SIZE_4BYTES) &&
((axi4.awaddr & ((32'd1 << axi4.awsize) - 1'b1)) == '0) &&
!s_write_last_addr[32] &&
(axi4.awaddr[31:12] == s_write_last_addr[31:12]);
assign s_legal_read = (axi4.arlen <= 8'd15) &&
(axi4.arburst == `AXI4_BURST_TYPE_INCR) && !axi4.arlock &&
(axi4.arsize <= `AXI4_BURST_SIZE_4BYTES) &&
((axi4.araddr & ((32'd1 << axi4.arsize) - 1'b1)) == '0) &&
!s_read_last_addr[32] &&
(axi4.araddr[31:12] == s_read_last_addr[31:12]);
assign axi4.awready = (s_fsm_q == FSM_IDLE) && !axi4.arvalid;
assign axi4.arready = s_fsm_q == FSM_IDLE;
assign axi4.wready = (s_fsm_q == FSM_WR_DATA) || (s_fsm_q == FSM_ERR_WR_DRAIN);
assign axi4.bid = s_id_q;
assign axi4.bresp = s_resp_q;
assign axi4.buser = '0;
assign axi4.bvalid = (s_fsm_q == FSM_WR_RESP) || (s_fsm_q == FSM_ERR_WR_RESP);
assign axi4.rid = s_id_q;
assign axi4.rdata = s_rdata_q;
assign axi4.rresp = s_resp_q;
assign axi4.rlast = s_beat_q == s_len_q;
assign axi4.ruser = '0;
assign axi4.rvalid = (s_fsm_q == FSM_RD_RESP) || (s_fsm_q == FSM_ERR_RD_RESP);
assign ribp.valid = (s_fsm_q == FSM_WR_REQ) || (s_fsm_q == FSM_RD_REQ);
assign ribp.addr = s_addr_q;
assign ribp.wdata = s_wdata_q;
assign ribp.wstrb = (s_fsm_q == FSM_WR_REQ) ? s_wstrb_q : '0;
always_comb begin
s_fsm_d = s_fsm_q;
s_addr_d = s_addr_q;
s_wdata_d = s_wdata_q;
s_wstrb_d = s_wstrb_q;
s_len_d = s_len_q;
s_beat_d = s_beat_q;
s_size_d = s_size_q;
s_id_d = s_id_q;
s_rdata_d = s_rdata_q;
s_resp_d = s_resp_q;
unique case (s_fsm_q)
FSM_IDLE: begin
s_beat_d = '0;
s_resp_d = `AXI4_RESP_OKAY;
if (axi4.arvalid && axi4.arready) begin
s_addr_d = axi4.araddr;
s_len_d = axi4.arlen;
s_size_d = axi4.arsize;
s_id_d = axi4.arid;
s_fsm_d = s_legal_read ? FSM_RD_REQ : FSM_ERR_RD_RESP;
if (!s_legal_read) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
end else if (axi4.awvalid && axi4.awready) begin
s_addr_d = axi4.awaddr;
s_len_d = axi4.awlen;
s_size_d = axi4.awsize;
s_id_d = axi4.awid;
s_fsm_d = s_legal_write ? FSM_WR_DATA : FSM_ERR_WR_DRAIN;
if (!s_legal_write) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
end
end
FSM_WR_DATA: begin
if (axi4.wvalid && axi4.wready) begin
s_wdata_d = axi4.wdata;
s_wstrb_d = axi4.wstrb;
s_fsm_d = FSM_WR_REQ;
if (axi4.wlast != (s_beat_q == s_len_q)) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
end
end
FSM_WR_REQ: begin
if (ribp.ready) begin
if (ribp.resp_err) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
if ((s_beat_q == s_len_q) || (s_resp_q != `AXI4_RESP_OKAY)) begin
s_fsm_d = FSM_WR_RESP;
end else begin
s_addr_d = s_addr_q + (32'd1 << s_size_q);
s_beat_d = s_beat_q + 1'b1;
s_fsm_d = FSM_WR_DATA;
end
end
end
FSM_WR_RESP: begin
if (axi4.bvalid && axi4.bready) s_fsm_d = FSM_IDLE;
end
FSM_RD_REQ: begin
if (ribp.ready) begin
s_rdata_d = ribp.rdata;
if (ribp.resp_err) s_resp_d = `AXI4_RESP_SLAVE_ERROR;
s_fsm_d = FSM_RD_RESP;
end
end
FSM_RD_RESP: begin
if (axi4.rvalid && axi4.rready) begin
if (s_beat_q == s_len_q) begin
s_fsm_d = FSM_IDLE;
end else begin
s_addr_d = s_addr_q + (32'd1 << s_size_q);
s_beat_d = s_beat_q + 1'b1;
s_fsm_d = FSM_RD_REQ;
end
end
end
FSM_ERR_WR_DRAIN: begin
if (axi4.wvalid && axi4.wready && axi4.wlast) s_fsm_d = FSM_ERR_WR_RESP;
end
FSM_ERR_WR_RESP: begin
if (axi4.bvalid && axi4.bready) s_fsm_d = FSM_IDLE;
end
FSM_ERR_RD_RESP: begin
if (axi4.rvalid && axi4.rready) begin
if (s_beat_q == s_len_q) begin
s_fsm_d = FSM_IDLE;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
default: s_fsm_d = FSM_IDLE;
endcase
end
dffr #(4) u_fsm_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(32) u_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(32) u_wdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wdata_d),
.dat_o (s_wdata_q)
);
dffr #(4) u_wstrb_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wstrb_d),
.dat_o (s_wstrb_q)
);
dffr #(8) u_len_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_len_d),
.dat_o (s_len_q)
);
dffr #(8) u_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_beat_d),
.dat_o (s_beat_q)
);
dffr #(3) u_size_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_size_d),
.dat_o (s_size_q)
);
dffr #(1) u_id_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_id_d),
.dat_o (s_id_q)
);
dffr #(32) u_rdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rdata_d),
.dat_o (s_rdata_q)
);
dffr #(2) u_resp_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_resp_d),
.dat_o (s_resp_q)
);
endmodule
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
module axi4_connector (
axi4_if.slave source,
axi4_if.master sink
);
assign sink.awid = source.awid;
assign sink.awaddr = source.awaddr;
assign sink.awlen = source.awlen;
assign sink.awsize = source.awsize;
assign sink.awburst = source.awburst;
assign sink.awlock = source.awlock;
assign sink.awcache = source.awcache;
assign sink.awprot = source.awprot;
assign sink.awqos = source.awqos;
assign sink.awregion = source.awregion;
assign sink.awuser = source.awuser;
assign sink.awvalid = source.awvalid;
assign source.awready = sink.awready;
assign sink.wdata = source.wdata;
assign sink.wstrb = source.wstrb;
assign sink.wlast = source.wlast;
assign sink.wuser = source.wuser;
assign sink.wvalid = source.wvalid;
assign source.wready = sink.wready;
assign source.bid = sink.bid;
assign source.bresp = sink.bresp;
assign source.buser = sink.buser;
assign source.bvalid = sink.bvalid;
assign sink.bready = source.bready;
assign sink.arid = source.arid;
assign sink.araddr = source.araddr;
assign sink.arlen = source.arlen;
assign sink.arsize = source.arsize;
assign sink.arburst = source.arburst;
assign sink.arlock = source.arlock;
assign sink.arcache = source.arcache;
assign sink.arprot = source.arprot;
assign sink.arqos = source.arqos;
assign sink.arregion = source.arregion;
assign sink.aruser = source.aruser;
assign sink.arvalid = source.arvalid;
assign source.arready = sink.arready;
assign source.rid = sink.rid;
assign source.rdata = sink.rdata;
assign source.rresp = sink.rresp;
assign source.rlast = sink.rlast;
assign source.ruser = sink.ruser;
assign source.rvalid = sink.rvalid;
assign sink.rready = source.rready;
endmodule
+105
View File
@@ -0,0 +1,105 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
module axi4_error_slave #(
parameter logic [1:0] RESPONSE = `AXI4_RESP_DECODE_ERROR
) (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave axi4
);
localparam logic [1:0] FSM_IDLE = 2'd0;
localparam logic [1:0] FSM_WRITE = 2'd1;
localparam logic [1:0] FSM_WRITE_RESP = 2'd2;
localparam logic [1:0] FSM_READ_RESP = 2'd3;
logic [1:0] s_fsm_d, s_fsm_q;
logic s_id_d, s_id_q;
logic [7:0] s_len_d, s_len_q;
logic [7:0] s_beat_d, s_beat_q;
assign axi4.awready = (s_fsm_q == FSM_IDLE) && !axi4.arvalid;
assign axi4.arready = (s_fsm_q == FSM_IDLE);
assign axi4.wready = (s_fsm_q == FSM_WRITE);
assign axi4.bid = s_id_q;
assign axi4.bresp = RESPONSE;
assign axi4.buser = '0;
assign axi4.bvalid = (s_fsm_q == FSM_WRITE_RESP);
assign axi4.rid = s_id_q;
assign axi4.rdata = '0;
assign axi4.rresp = RESPONSE;
assign axi4.rlast = (s_beat_q == s_len_q);
assign axi4.ruser = '0;
assign axi4.rvalid = (s_fsm_q == FSM_READ_RESP);
always_comb begin
s_fsm_d = s_fsm_q;
s_id_d = s_id_q;
s_len_d = s_len_q;
s_beat_d = s_beat_q;
unique case (s_fsm_q)
FSM_IDLE: begin
s_beat_d = '0;
if (axi4.arvalid && axi4.arready) begin
s_id_d = axi4.arid;
s_len_d = axi4.arlen;
s_fsm_d = FSM_READ_RESP;
end else if (axi4.awvalid && axi4.awready) begin
s_id_d = axi4.awid;
s_len_d = axi4.awlen;
s_fsm_d = FSM_WRITE;
end
end
FSM_WRITE: begin
if (axi4.wvalid && axi4.wready) begin
if ((s_beat_q == s_len_q) || axi4.wlast) begin
s_fsm_d = FSM_WRITE_RESP;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
FSM_WRITE_RESP: begin
if (axi4.bvalid && axi4.bready) s_fsm_d = FSM_IDLE;
end
FSM_READ_RESP: begin
if (axi4.rvalid && axi4.rready) begin
if (s_beat_q == s_len_q) begin
s_fsm_d = FSM_IDLE;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
default: s_fsm_d = FSM_IDLE;
endcase
end
dffr #(2) u_fsm_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(1) u_id_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_id_d),
.dat_o (s_id_q)
);
dffr #(8) u_len_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_len_d),
.dat_o (s_len_q)
);
dffr #(8) u_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_beat_d),
.dat_o (s_beat_q)
);
endmodule
+569
View File
@@ -0,0 +1,569 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
`include "mmap_define.svh"
`include "rib_defs.svh"
module axi4_interconnect #(
parameter int NUM_MASTERS = 3,
parameter int NUM_TARGETS = 9
) (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave masters [NUM_MASTERS],
axi4_if.master targets [NUM_TARGETS],
input logic user_bus_enable_i,
output logic user_bus_idle_o,
input logic perf_enable_i,
input logic perf_clear_i,
output logic fault_valid_o,
output logic [31:0] fault_addr_o,
output logic [ 3:0] fault_wstrb_o,
output logic fault_reserved_o,
output logic fault_access_o,
output logic [ 1:0] fault_master_o,
output logic [ 2:0] fault_code_o,
output logic [63:0] perf_mgmt_wait_o,
output logic [63:0] perf_user_wait_o,
output logic [63:0] perf_dma_wait_o,
output logic [63:0] perf_ribp_wait_o,
output logic [63:0] perf_apb_wait_o,
output logic [63:0] perf_sdram_wait_o,
output logic [63:0] perf_psram_wait_o,
output logic [63:0] perf_flash_wait_o
);
localparam int MASTER_WIDTH = $clog2(NUM_MASTERS);
localparam int TARGET_WIDTH = $clog2(NUM_TARGETS);
localparam logic [TARGET_WIDTH-1:0] TARGET_CFG = TARGET_WIDTH'(0);
localparam logic [TARGET_WIDTH-1:0] TARGET_APB = TARGET_WIDTH'(1);
localparam logic [TARGET_WIDTH-1:0] TARGET_RAM = TARGET_WIDTH'(2);
localparam logic [TARGET_WIDTH-1:0] TARGET_SDRAM = TARGET_WIDTH'(3);
localparam logic [TARGET_WIDTH-1:0] TARGET_PSRAM = TARGET_WIDTH'(4);
localparam logic [TARGET_WIDTH-1:0] TARGET_XPI = TARGET_WIDTH'(5);
localparam logic [TARGET_WIDTH-1:0] TARGET_SPISD = TARGET_WIDTH'(6);
localparam logic [TARGET_WIDTH-1:0] TARGET_DECERR = TARGET_WIDTH'(7);
localparam logic [TARGET_WIDTH-1:0] TARGET_SLVERR = TARGET_WIDTH'(8);
localparam logic [1:0] MASTER_IDLE = 2'd0;
localparam logic [1:0] MASTER_PENDING = 2'd1;
localparam logic [1:0] MASTER_ACTIVE = 2'd2;
logic [NUM_MASTERS-1:0] m_awvalid, m_awready;
logic [NUM_MASTERS-1:0][31:0] m_awaddr;
logic [NUM_MASTERS-1:0][ 7:0] m_awlen;
logic [NUM_MASTERS-1:0][ 2:0] m_awsize;
logic [NUM_MASTERS-1:0][ 1:0] m_awburst;
logic [NUM_MASTERS-1:0] m_awlock;
logic [NUM_MASTERS-1:0][ 3:0] m_awcache;
logic [NUM_MASTERS-1:0][ 2:0] m_awprot;
logic [NUM_MASTERS-1:0][3:0] m_awqos, m_awregion;
logic [NUM_MASTERS-1:0] m_awid, m_awuser;
logic [NUM_MASTERS-1:0] m_wvalid, m_wready, m_wlast;
logic [NUM_MASTERS-1:0][31:0] m_wdata;
logic [NUM_MASTERS-1:0][ 3:0] m_wstrb;
logic [NUM_MASTERS-1:0] m_wuser;
logic [NUM_MASTERS-1:0] m_bvalid, m_bready, m_bid, m_buser;
logic [NUM_MASTERS-1:0][1:0] m_bresp;
logic [NUM_MASTERS-1:0] m_arvalid, m_arready;
logic [NUM_MASTERS-1:0][31:0] m_araddr;
logic [NUM_MASTERS-1:0][ 7:0] m_arlen;
logic [NUM_MASTERS-1:0][ 2:0] m_arsize;
logic [NUM_MASTERS-1:0][ 1:0] m_arburst;
logic [NUM_MASTERS-1:0] m_arlock;
logic [NUM_MASTERS-1:0][ 3:0] m_arcache;
logic [NUM_MASTERS-1:0][ 2:0] m_arprot;
logic [NUM_MASTERS-1:0][3:0] m_arqos, m_arregion;
logic [NUM_MASTERS-1:0] m_arid, m_aruser;
logic [NUM_MASTERS-1:0] m_rvalid, m_rready, m_rid, m_rlast, m_ruser;
logic [NUM_MASTERS-1:0][31:0] m_rdata;
logic [NUM_MASTERS-1:0][ 1:0] m_rresp;
logic [NUM_TARGETS-1:0] t_awvalid, t_awready;
logic [NUM_TARGETS-1:0][31:0] t_awaddr;
logic [NUM_TARGETS-1:0][ 7:0] t_awlen;
logic [NUM_TARGETS-1:0][ 2:0] t_awsize;
logic [NUM_TARGETS-1:0][ 1:0] t_awburst;
logic [NUM_TARGETS-1:0] t_awlock;
logic [NUM_TARGETS-1:0][ 3:0] t_awcache;
logic [NUM_TARGETS-1:0][ 2:0] t_awprot;
logic [NUM_TARGETS-1:0][3:0] t_awqos, t_awregion;
logic [NUM_TARGETS-1:0] t_awid, t_awuser;
logic [NUM_TARGETS-1:0] t_wvalid, t_wready, t_wlast;
logic [NUM_TARGETS-1:0][31:0] t_wdata;
logic [NUM_TARGETS-1:0][ 3:0] t_wstrb;
logic [NUM_TARGETS-1:0] t_wuser;
logic [NUM_TARGETS-1:0] t_bvalid, t_bready, t_bid, t_buser;
logic [NUM_TARGETS-1:0][1:0] t_bresp;
logic [NUM_TARGETS-1:0] t_arvalid, t_arready;
logic [NUM_TARGETS-1:0][31:0] t_araddr;
logic [NUM_TARGETS-1:0][ 7:0] t_arlen;
logic [NUM_TARGETS-1:0][ 2:0] t_arsize;
logic [NUM_TARGETS-1:0][ 1:0] t_arburst;
logic [NUM_TARGETS-1:0] t_arlock;
logic [NUM_TARGETS-1:0][ 3:0] t_arcache;
logic [NUM_TARGETS-1:0][ 2:0] t_arprot;
logic [NUM_TARGETS-1:0][3:0] t_arqos, t_arregion;
logic [NUM_TARGETS-1:0] t_arid, t_aruser;
logic [NUM_TARGETS-1:0] t_rvalid, t_rready, t_rid, t_rlast, t_ruser;
logic [NUM_TARGETS-1:0][ 31:0] t_rdata;
logic [NUM_TARGETS-1:0][ 1:0] t_rresp;
logic [NUM_MASTERS-1:0][ 1:0] r_master_state;
logic [NUM_MASTERS-1:0] r_master_write;
logic [NUM_MASTERS-1:0][TARGET_WIDTH-1:0] r_master_target;
logic [NUM_MASTERS-1:0][ 31:0] r_master_addr;
logic [NUM_MASTERS-1:0][ 7:0] r_master_len;
logic [NUM_MASTERS-1:0][ 2:0] r_master_size;
logic [NUM_MASTERS-1:0][ 1:0] r_master_burst;
logic [NUM_MASTERS-1:0] r_master_lock;
logic [NUM_MASTERS-1:0][ 3:0] r_master_cache;
logic [NUM_MASTERS-1:0][ 2:0] r_master_prot;
logic [NUM_MASTERS-1:0][3:0] r_master_qos, r_master_region;
logic [NUM_MASTERS-1:0] r_master_id, r_master_user;
logic [NUM_MASTERS-1:0] r_master_access_error;
logic [NUM_MASTERS-1:0][3:0] r_master_first_wstrb;
logic [NUM_TARGETS-1:0] r_target_valid, r_target_addr_sent;
logic [NUM_TARGETS-1:0][MASTER_WIDTH-1:0] r_target_owner;
logic [NUM_TARGETS-1:0][ NUM_MASTERS-1:0] s_target_request;
logic [NUM_TARGETS-1:0][ NUM_MASTERS-1:0] s_target_grant;
logic [NUM_TARGETS-1:0][MASTER_WIDTH-1:0] s_target_selected;
logic [NUM_TARGETS-1:0] s_target_grant_valid, s_target_advance;
logic [NUM_TARGETS-1:0] s_target_terminal;
logic [NUM_MASTERS-1:0] s_master_terminal, s_master_fault;
logic [NUM_MASTERS-1:0][ 2:0] s_master_fault_code;
logic [NUM_MASTERS-1:0][32:0] s_last_addr;
logic [NUM_MASTERS-1:0] s_protocol_legal, s_access_allowed;
logic [NUM_MASTERS-1:0][TARGET_WIDTH-1:0] s_capture_target;
logic [ 63:0] r_perf_master_wait[NUM_MASTERS];
logic [ 63:0] r_perf_target_wait[NUM_TARGETS];
function automatic logic [TARGET_WIDTH-1:0] decode_target(input logic [31:0] addr);
if (`SOC_ADDR_IS_SDRAM(addr)) return TARGET_SDRAM;
if (`SOC_ADDR_IS_PSRAM(addr)) return TARGET_PSRAM;
if (`SOC_ADDR_IS_FLASH(addr) || `SOC_ADDR_IS_XPI(addr)) return TARGET_XPI;
if (`SOC_ADDR_IS_SPISD(addr)) return TARGET_SPISD;
if (`SOC_ADDR_IS_APB(addr)) return TARGET_APB;
if (`SOC_ADDR_IS_RAM(addr)) return TARGET_RAM;
if (`SOC_ADDR_IS_RIBP(addr)) return TARGET_CFG;
return TARGET_DECERR;
endfunction
for (genvar master = 0; master < NUM_MASTERS; master++) begin : GEN_MASTER_PORTS
assign m_awvalid[master] = masters[master].awvalid;
assign m_awaddr[master] = masters[master].awaddr;
assign m_awlen[master] = masters[master].awlen;
assign m_awsize[master] = masters[master].awsize;
assign m_awburst[master] = masters[master].awburst;
assign m_awlock[master] = masters[master].awlock;
assign m_awcache[master] = masters[master].awcache;
assign m_awprot[master] = masters[master].awprot;
assign m_awqos[master] = masters[master].awqos;
assign m_awregion[master] = masters[master].awregion;
assign m_awid[master] = masters[master].awid;
assign m_awuser[master] = masters[master].awuser;
assign masters[master].awready = m_awready[master];
assign m_wvalid[master] = masters[master].wvalid;
assign m_wdata[master] = masters[master].wdata;
assign m_wstrb[master] = masters[master].wstrb;
assign m_wlast[master] = masters[master].wlast;
assign m_wuser[master] = masters[master].wuser;
assign masters[master].wready = m_wready[master];
assign masters[master].bid = m_bid[master];
assign masters[master].bresp = m_bresp[master];
assign masters[master].buser = m_buser[master];
assign masters[master].bvalid = m_bvalid[master];
assign m_bready[master] = masters[master].bready;
assign m_arvalid[master] = masters[master].arvalid;
assign m_araddr[master] = masters[master].araddr;
assign m_arlen[master] = masters[master].arlen;
assign m_arsize[master] = masters[master].arsize;
assign m_arburst[master] = masters[master].arburst;
assign m_arlock[master] = masters[master].arlock;
assign m_arcache[master] = masters[master].arcache;
assign m_arprot[master] = masters[master].arprot;
assign m_arqos[master] = masters[master].arqos;
assign m_arregion[master] = masters[master].arregion;
assign m_arid[master] = masters[master].arid;
assign m_aruser[master] = masters[master].aruser;
assign masters[master].arready = m_arready[master];
assign masters[master].rid = m_rid[master];
assign masters[master].rdata = m_rdata[master];
assign masters[master].rresp = m_rresp[master];
assign masters[master].rlast = m_rlast[master];
assign masters[master].ruser = m_ruser[master];
assign masters[master].rvalid = m_rvalid[master];
assign m_rready[master] = masters[master].rready;
end
for (genvar target = 0; target < NUM_TARGETS; target++) begin : GEN_TARGET_PORTS
assign targets[target].awid = t_awid[target];
assign targets[target].awaddr = t_awaddr[target];
assign targets[target].awlen = t_awlen[target];
assign targets[target].awsize = t_awsize[target];
assign targets[target].awburst = t_awburst[target];
assign targets[target].awlock = t_awlock[target];
assign targets[target].awcache = t_awcache[target];
assign targets[target].awprot = t_awprot[target];
assign targets[target].awqos = t_awqos[target];
assign targets[target].awregion = t_awregion[target];
assign targets[target].awuser = t_awuser[target];
assign targets[target].awvalid = t_awvalid[target];
assign t_awready[target] = targets[target].awready;
assign targets[target].wdata = t_wdata[target];
assign targets[target].wstrb = t_wstrb[target];
assign targets[target].wlast = t_wlast[target];
assign targets[target].wuser = t_wuser[target];
assign targets[target].wvalid = t_wvalid[target];
assign t_wready[target] = targets[target].wready;
assign t_bid[target] = targets[target].bid;
assign t_bresp[target] = targets[target].bresp;
assign t_buser[target] = targets[target].buser;
assign t_bvalid[target] = targets[target].bvalid;
assign targets[target].bready = t_bready[target];
assign targets[target].arid = t_arid[target];
assign targets[target].araddr = t_araddr[target];
assign targets[target].arlen = t_arlen[target];
assign targets[target].arsize = t_arsize[target];
assign targets[target].arburst = t_arburst[target];
assign targets[target].arlock = t_arlock[target];
assign targets[target].arcache = t_arcache[target];
assign targets[target].arprot = t_arprot[target];
assign targets[target].arqos = t_arqos[target];
assign targets[target].arregion = t_arregion[target];
assign targets[target].aruser = t_aruser[target];
assign targets[target].arvalid = t_arvalid[target];
assign t_arready[target] = targets[target].arready;
assign t_rid[target] = targets[target].rid;
assign t_rdata[target] = targets[target].rdata;
assign t_rresp[target] = targets[target].rresp;
assign t_rlast[target] = targets[target].rlast;
assign t_ruser[target] = targets[target].ruser;
assign t_rvalid[target] = targets[target].rvalid;
assign targets[target].rready = t_rready[target];
round_robin_arbiter #(
.CLIENTS(NUM_MASTERS)
) u_target_arbiter (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.advance_i (s_target_advance[target]),
.request_i (s_target_request[target]),
.grant_o (s_target_grant[target]),
.selected_o(s_target_selected[target]),
.valid_o (s_target_grant_valid[target])
);
end
always_comb begin
m_awready = '0;
m_wready = '0;
m_bid = '0;
m_bresp = '0;
m_buser = '0;
m_bvalid = '0;
m_arready = '0;
m_rid = '0;
m_rdata = '0;
m_rresp = '0;
m_rlast = '0;
m_ruser = '0;
m_rvalid = '0;
t_awvalid = '0;
t_awaddr = '0;
t_awlen = '0;
t_awsize = '0;
t_awburst = '0;
t_awlock = '0;
t_awcache = '0;
t_awprot = '0;
t_awqos = '0;
t_awregion = '0;
t_awid = '0;
t_awuser = '0;
t_wvalid = '0;
t_wdata = '0;
t_wstrb = '0;
t_wlast = '0;
t_wuser = '0;
t_bready = '0;
t_arvalid = '0;
t_araddr = '0;
t_arlen = '0;
t_arsize = '0;
t_arburst = '0;
t_arlock = '0;
t_arcache = '0;
t_arprot = '0;
t_arqos = '0;
t_arregion = '0;
t_arid = '0;
t_aruser = '0;
t_rready = '0;
s_target_request = '0;
s_target_advance = '0;
s_target_terminal = '0;
s_master_terminal = '0;
s_master_fault = '0;
s_master_fault_code = '0;
for (int master = 0; master < NUM_MASTERS; master++) begin
if (r_master_state[master] == MASTER_IDLE) begin
m_arready[master] = (master != 1) || user_bus_enable_i;
m_awready[master] = ((master != 1) || user_bus_enable_i) && !m_arvalid[master];
if ((m_arvalid[master] && m_arready[master]) ||
(m_awvalid[master] && m_awready[master])) begin
s_target_request[s_capture_target[master]][master] = 1'b1;
end
end
if (r_master_state[master] == MASTER_PENDING) begin
s_target_request[r_master_target[master]][master] = 1'b1;
end
end
for (int target = 0; target < NUM_TARGETS; target++) begin
s_target_advance[target] = !r_target_valid[target] && s_target_grant_valid[target];
if (r_target_valid[target]) begin
automatic logic [MASTER_WIDTH-1:0] owner = r_target_owner[target];
if (!r_target_addr_sent[target]) begin
if (r_master_write[owner]) begin
t_awvalid[target] = 1'b1;
t_awaddr[target] = r_master_addr[owner];
t_awlen[target] = r_master_len[owner];
t_awsize[target] = r_master_size[owner];
t_awburst[target] = r_master_burst[owner];
t_awlock[target] = r_master_lock[owner];
t_awcache[target] = r_master_cache[owner];
t_awprot[target] = r_master_prot[owner];
t_awqos[target] = r_master_qos[owner];
t_awregion[target] = r_master_region[owner];
t_awid[target] = r_master_id[owner];
t_awuser[target] = r_master_user[owner];
end else begin
t_arvalid[target] = 1'b1;
t_araddr[target] = r_master_addr[owner];
t_arlen[target] = r_master_len[owner];
t_arsize[target] = r_master_size[owner];
t_arburst[target] = r_master_burst[owner];
t_arlock[target] = r_master_lock[owner];
t_arcache[target] = r_master_cache[owner];
t_arprot[target] = r_master_prot[owner];
t_arqos[target] = r_master_qos[owner];
t_arregion[target] = r_master_region[owner];
t_arid[target] = r_master_id[owner];
t_aruser[target] = r_master_user[owner];
end
end else if (r_master_write[owner]) begin
t_wvalid[target] = m_wvalid[owner];
t_wdata[target] = m_wdata[owner];
t_wstrb[target] = m_wstrb[owner];
t_wlast[target] = m_wlast[owner];
t_wuser[target] = m_wuser[owner];
m_wready[owner] = t_wready[target];
t_bready[target] = m_bready[owner];
m_bid[owner] = t_bid[target];
m_bresp[owner] = t_bresp[target];
m_buser[owner] = t_buser[target];
m_bvalid[owner] = t_bvalid[target];
s_target_terminal[target] = t_bvalid[target] && t_bready[target];
end else begin
t_rready[target] = m_rready[owner];
m_rid[owner] = t_rid[target];
m_rdata[owner] = t_rdata[target];
m_rresp[owner] = t_rresp[target];
m_rlast[owner] = t_rlast[target];
m_ruser[owner] = t_ruser[target];
m_rvalid[owner] = t_rvalid[target];
s_target_terminal[target] = t_rvalid[target] && t_rready[target] && t_rlast[target];
end
if (s_target_terminal[target]) begin
s_master_terminal[owner] = 1'b1;
if ((r_master_write[owner] && (t_bresp[target] != `AXI4_RESP_OKAY)) ||
(!r_master_write[owner] && (t_rresp[target] != `AXI4_RESP_OKAY))) begin
s_master_fault[owner] = 1'b1;
s_master_fault_code[owner] =
(TARGET_WIDTH'(target) == TARGET_DECERR) ? `RIB_RESP_DECERR :
(TARGET_WIDTH'(target) == TARGET_SLVERR) ?
(r_master_access_error[owner] ? `RIB_RESP_PROTERR : `RIB_RESP_BURSTERR) :
`RIB_RESP_SLVERR;
end
end
end
end
end
always_comb begin
for (int master = 0; master < NUM_MASTERS; master++) begin
automatic logic read_request = m_arvalid[master];
automatic logic write_request = !read_request && m_awvalid[master];
automatic logic [31:0] address = read_request ? m_araddr[master] : m_awaddr[master];
automatic logic [ 7:0] length = read_request ? m_arlen[master] : m_awlen[master];
automatic logic [ 2:0] size = read_request ? m_arsize[master] : m_awsize[master];
automatic logic [ 1:0] burst = read_request ? m_arburst[master] : m_awburst[master];
automatic logic lock = read_request ? m_arlock[master] : m_awlock[master];
automatic logic [32:0] bytes = 33'(length + 1'b1) << size;
s_last_addr[master] = {1'b0, address} + bytes - 1'b1;
s_protocol_legal[master] = (length <= 8'd15) &&
(burst == `AXI4_BURST_TYPE_INCR) && !lock && (size <= 3'd2) &&
((address & ((32'd1 << size) - 1'b1)) == '0) &&
(s_last_addr[master][32] == 1'b0) &&
(address[31:12] == s_last_addr[master][31:12]) &&
(decode_target(address) ==
decode_target(s_last_addr[master][31:0]));
s_access_allowed[master] = (master != 1) || ((read_request &&
`SOC_USER_ADDR_READABLE(address)
&&
`SOC_USER_ADDR_READABLE(s_last_addr[master][31:0])
) || (write_request &&
`SOC_USER_ADDR_WRITABLE(address)
&&
`SOC_USER_ADDR_WRITABLE(s_last_addr[master][31:0])
));
s_capture_target[master] = decode_target(address);
if (!s_protocol_legal[master] ||
((s_capture_target[master] == TARGET_CFG || s_capture_target[master] == TARGET_APB) &&
(length != 8'd0))) begin
s_capture_target[master] = TARGET_SLVERR;
end else if (!s_access_allowed[master]) begin
s_capture_target[master] = TARGET_SLVERR;
end
end
end
assign user_bus_idle_o = r_master_state[1] == MASTER_IDLE;
always_comb begin
fault_valid_o = 1'b0;
fault_addr_o = '0;
fault_wstrb_o = '0;
fault_reserved_o = 1'b0;
fault_access_o = 1'b0;
fault_master_o = '0;
fault_code_o = `RIB_RESP_OK;
for (int master = NUM_MASTERS - 1; master >= 0; master--) begin
if (s_master_fault[master]) begin
fault_valid_o = 1'b1;
fault_addr_o = r_master_addr[master];
fault_wstrb_o = r_master_first_wstrb[master];
fault_reserved_o = `SOC_ADDR_IS_RESERVED(r_master_addr[master]);
fault_access_o = r_master_access_error[master];
fault_master_o = 2'(master);
fault_code_o = s_master_fault_code[master];
end
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
r_master_state <= '0;
r_master_write <= '0;
r_master_target <= '0;
r_master_addr <= '0;
r_master_len <= '0;
r_master_size <= '0;
r_master_burst <= '0;
r_master_lock <= '0;
r_master_cache <= '0;
r_master_prot <= '0;
r_master_qos <= '0;
r_master_region <= '0;
r_master_id <= '0;
r_master_user <= '0;
r_master_access_error <= '0;
r_master_first_wstrb <= '0;
r_target_valid <= '0;
r_target_addr_sent <= '0;
r_target_owner <= '0;
end else begin
for (int master = 0; master < NUM_MASTERS; master++) begin
if (r_master_state[master] == MASTER_IDLE &&
((m_arvalid[master] && m_arready[master]) ||
(m_awvalid[master] && m_awready[master]))) begin
automatic logic read_request = m_arvalid[master] && m_arready[master];
r_master_state[master] <= MASTER_PENDING;
r_master_write[master] <= !read_request;
r_master_target[master] <= s_capture_target[master];
r_master_addr[master] <= read_request ? m_araddr[master] : m_awaddr[master];
r_master_len[master] <= read_request ? m_arlen[master] : m_awlen[master];
r_master_size[master] <= read_request ? m_arsize[master] : m_awsize[master];
r_master_burst[master] <= read_request ? m_arburst[master] : m_awburst[master];
r_master_lock[master] <= read_request ? m_arlock[master] : m_awlock[master];
r_master_cache[master] <= read_request ? m_arcache[master] : m_awcache[master];
r_master_prot[master] <= read_request ? m_arprot[master] : m_awprot[master];
r_master_qos[master] <= read_request ? m_arqos[master] : m_awqos[master];
r_master_region[master] <= read_request ? m_arregion[master] : m_awregion[master];
r_master_id[master] <= read_request ? m_arid[master] : m_awid[master];
r_master_user[master] <= read_request ? m_aruser[master] : m_awuser[master];
r_master_access_error[master] <= !s_access_allowed[master];
r_master_first_wstrb[master] <= '0;
end
if ((r_master_state[master] == MASTER_ACTIVE) && r_master_write[master] &&
m_wvalid[master] && m_wready[master] && (r_master_first_wstrb[master] == '0)) begin
r_master_first_wstrb[master] <= m_wstrb[master];
end
if (s_master_terminal[master]) r_master_state[master] <= MASTER_IDLE;
end
for (int target = 0; target < NUM_TARGETS; target++) begin
if (!r_target_valid[target] && s_target_grant_valid[target]) begin
r_target_valid[target] <= 1'b1;
r_target_addr_sent[target] <= 1'b0;
r_target_owner[target] <= s_target_selected[target];
r_master_state[s_target_selected[target]] <= MASTER_ACTIVE;
end else if (r_target_valid[target] && !r_target_addr_sent[target]) begin
automatic logic [MASTER_WIDTH-1:0] owner = r_target_owner[target];
if ((r_master_write[owner] && t_awvalid[target] && t_awready[target]) ||
(!r_master_write[owner] && t_arvalid[target] && t_arready[target])) begin
r_target_addr_sent[target] <= 1'b1;
end
end
if (s_target_terminal[target]) begin
r_target_valid[target] <= 1'b0;
r_target_addr_sent[target] <= 1'b0;
end
end
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
for (int master = 0; master < NUM_MASTERS; master++) r_perf_master_wait[master] <= '0;
for (int target = 0; target < NUM_TARGETS; target++) r_perf_target_wait[target] <= '0;
end else if (perf_clear_i) begin
for (int master = 0; master < NUM_MASTERS; master++) r_perf_master_wait[master] <= '0;
for (int target = 0; target < NUM_TARGETS; target++) r_perf_target_wait[target] <= '0;
end else if (perf_enable_i) begin
for (int master = 0; master < NUM_MASTERS; master++) begin
if ((r_master_state[master] != MASTER_IDLE) && !s_master_terminal[master] &&
!(&r_perf_master_wait[master])) begin
r_perf_master_wait[master] <= r_perf_master_wait[master] + 1'b1;
end
end
for (int target = 0; target < NUM_TARGETS; target++) begin
if (r_target_valid[target] && !s_target_terminal[target] &&
!(&r_perf_target_wait[target])) begin
r_perf_target_wait[target] <= r_perf_target_wait[target] + 1'b1;
end
end
end
end
assign perf_mgmt_wait_o = r_perf_master_wait[0];
assign perf_user_wait_o = r_perf_master_wait[1];
assign perf_dma_wait_o = r_perf_master_wait[2];
assign perf_ribp_wait_o = r_perf_target_wait[TARGET_CFG];
assign perf_apb_wait_o = r_perf_target_wait[TARGET_APB];
assign perf_sdram_wait_o = r_perf_target_wait[TARGET_SDRAM];
assign perf_psram_wait_o = r_perf_target_wait[TARGET_PSRAM];
assign perf_flash_wait_o = r_perf_target_wait[TARGET_XPI];
initial begin
if (NUM_MASTERS != 3 || NUM_TARGETS != 9) begin
$fatal(1, "axi4_interconnect: retroSoC topology requires three masters and nine targets");
end
end
endmodule
+186 -3
View File
@@ -11,7 +11,7 @@
`include "mmap_define.svh"
`include "rib_defs.svh"
module bus (
module rib_bus (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
@@ -323,7 +323,7 @@ module bus (
// verilog_format: off
assign s_ribp_sel = u_mstr_rib_if.cmd_valid && ~s_cmd_accepted_q && ~s_access_denied &&
s_burst_legal && `SOC_ADDR_IS_RIBP(u_mstr_rib_if.cmd_addr);
s_burst_legal && `SOC_ADDR_IS_RIB_LEGACY_TARGET(u_mstr_rib_if.cmd_addr);
assign s_apb_sel = u_mstr_rib_if.cmd_valid && ~s_cmd_accepted_q && ~s_access_denied &&
(u_mstr_rib_if.cmd_len == `RIB_LEN_INCR1) &&
`SOC_ADDR_IS_APB(u_mstr_rib_if.cmd_addr);
@@ -344,7 +344,7 @@ module bus (
end else if (`SOC_ADDR_IS_RESERVED(u_mstr_rib_if.cmd_addr)) begin
s_fault_code = `RIB_RESP_RESERVED;
// verilog_format: off
end else if ((`SOC_ADDR_IS_RIBP(u_mstr_rib_if.cmd_addr) ||
end else if ((`SOC_ADDR_IS_RIB_LEGACY_TARGET(u_mstr_rib_if.cmd_addr) ||
`SOC_ADDR_IS_APB(u_mstr_rib_if.cmd_addr) ||
`SOC_ADDR_IS_RAM(u_mstr_rib_if.cmd_addr)) &&
(~s_burst_legal ||
@@ -650,3 +650,186 @@ module bus (
assign perf_flash_wait_o = s_perf_flash_wait_q;
endmodule
module axi4_bus (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
axi4_if.slave mgmt_axi4,
axi4_if.slave user_axi4,
axi4_if.slave dma_axi4,
axi4_if.master cfg_axi4,
axi4_if.master apb_axi4,
`ifdef HAVE_SRAM_IF
ram_if.master ram,
`endif
axi4_if.master sdram_axi4,
axi4_if.master psram_axi4,
axi4_if.master xpi_axi4,
axi4_if.master spisd_axi4,
input logic user_bus_enable_i,
output logic user_bus_idle_o,
input logic perf_enable_i,
input logic perf_clear_i,
output logic fault_valid_o,
output logic [31:0] fault_addr_o,
output logic [3:0] fault_wstrb_o,
output logic fault_reserved_o,
output logic fault_access_o,
output logic [1:0] fault_master_o,
output logic [2:0] fault_code_o,
output logic [63:0] perf_mgmt_wait_o,
output logic [63:0] perf_user_wait_o,
output logic [63:0] perf_dma_wait_o,
output logic [63:0] perf_ribp_wait_o,
output logic [63:0] perf_apb_wait_o,
output logic [63:0] perf_sdram_wait_o,
output logic [63:0] perf_psram_wait_o,
output logic [63:0] perf_flash_wait_o
// verilog_format: on
);
localparam int NUM_MASTERS = 3;
localparam int NUM_TARGETS = 9;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) u_master_axi4_if[NUM_MASTERS] (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) u_target_axi4_if[NUM_TARGETS] (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) u_ram_axi4_if (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_connector u_mgmt_connector (
.source(mgmt_axi4),
.sink (u_master_axi4_if[0])
);
axi4_connector u_user_connector (
.source(user_axi4),
.sink (u_master_axi4_if[1])
);
axi4_connector u_dma_connector (
.source(dma_axi4),
.sink (u_master_axi4_if[2])
);
axi4_connector u_cfg_connector (
.source(u_target_axi4_if[0]),
.sink (cfg_axi4)
);
axi4_connector u_apb_connector (
.source(u_target_axi4_if[1]),
.sink (apb_axi4)
);
axi4_connector u_ram_connector (
.source(u_target_axi4_if[2]),
.sink (u_ram_axi4_if)
);
axi4_connector u_sdram_connector (
.source(u_target_axi4_if[3]),
.sink (sdram_axi4)
);
axi4_connector u_psram_connector (
.source(u_target_axi4_if[4]),
.sink (psram_axi4)
);
axi4_connector u_xpi_connector (
.source(u_target_axi4_if[5]),
.sink (xpi_axi4)
);
axi4_connector u_spisd_connector (
.source(u_target_axi4_if[6]),
.sink (spisd_axi4)
);
axi4_interconnect #(
.NUM_MASTERS(NUM_MASTERS),
.NUM_TARGETS(NUM_TARGETS)
) u_axi4_interconnect (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.masters (u_master_axi4_if),
.targets (u_target_axi4_if),
.user_bus_enable_i(user_bus_enable_i),
.user_bus_idle_o (user_bus_idle_o),
.perf_enable_i (perf_enable_i),
.perf_clear_i (perf_clear_i),
.fault_valid_o (fault_valid_o),
.fault_addr_o (fault_addr_o),
.fault_wstrb_o (fault_wstrb_o),
.fault_reserved_o (fault_reserved_o),
.fault_access_o (fault_access_o),
.fault_master_o (fault_master_o),
.fault_code_o (fault_code_o),
.perf_mgmt_wait_o (perf_mgmt_wait_o),
.perf_user_wait_o (perf_user_wait_o),
.perf_dma_wait_o (perf_dma_wait_o),
.perf_ribp_wait_o (perf_ribp_wait_o),
.perf_apb_wait_o (perf_apb_wait_o),
.perf_sdram_wait_o(perf_sdram_wait_o),
.perf_psram_wait_o(perf_psram_wait_o),
.perf_flash_wait_o(perf_flash_wait_o)
);
`ifdef HAVE_SRAM_IF
axi42ram u_axi42ram (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (u_ram_axi4_if),
.ram (ram)
);
`else
axi4_error_slave #(
.RESPONSE(2'b11)
) u_ram_error_slave (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (u_ram_axi4_if)
);
`endif
axi4_error_slave #(
.RESPONSE(2'b11)
) u_decode_error_slave (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (u_target_axi4_if[7])
);
axi4_error_slave #(
.RESPONSE(2'b10)
) u_slave_error_slave (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (u_target_axi4_if[8])
);
endmodule
+11 -11
View File
@@ -10,16 +10,16 @@
module core_wrapper (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic [31:0] irq_i,
input logic jtag_tck_i,
input logic jtag_tms_i,
input logic jtag_tdi_i,
input logic jtag_trst_n_i,
output logic jtag_tdo_o,
output logic debug_halted_o,
ribp_if.master ribp
input logic clk_i,
input logic rst_n_i,
input logic [31:0] irq_i,
input logic jtag_tck_i,
input logic jtag_tms_i,
input logic jtag_tdi_i,
input logic jtag_trst_n_i,
output logic jtag_tdo_o,
output logic debug_halted_o,
axi4_if.master axi4
// verilog_format: on
);
@@ -33,7 +33,7 @@ module core_wrapper (
.jtag_trst_n_i (jtag_trst_n_i),
.jtag_tdo_o (jtag_tdo_o),
.debug_halted_o(debug_halted_o),
.ribp (ribp)
.axi4 (axi4)
);
endmodule
+10 -10
View File
@@ -17,14 +17,14 @@
module ip_apb_wrapper (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic clk_aud_i,
input logic rst_aud_n_i,
input logic debug_halted_i,
rib_if.slave rib,
pwm_if.dut pwm,
ps2_if.dut ps2,
input logic clk_i,
input logic rst_n_i,
input logic clk_aud_i,
input logic rst_aud_n_i,
input logic debug_halted_i,
axi4_if.slave axi4,
pwm_if.dut pwm,
ps2_if.dut ps2,
input logic [`USER_IPSEL_WIDTH-1:0] ip_sel_i,
user_gpio_if.user_ip user_gpio,
output logic rtc_wake_o,
@@ -183,10 +183,10 @@ module ip_apb_wrapper (
// Generated IRQ ownership and core-vector bit assignments are topology checked.
`include "soc_apb_irq_bindings.svh"
rib2apb u_rib2apb (
axi42apb u_axi42apb (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.rib (rib),
.axi4 (axi4),
`include "soc_apb_connections.svh"
);
+103 -11
View File
@@ -20,7 +20,11 @@ module ip_ribp_wrapper (
input logic rst_aud_n_i,
input logic debug_halted_i,
input logic timebase_tick_i,
rib_if.slave rib,
axi4_if.slave cfg_axi4,
axi4_if.slave sdram_axi4,
axi4_if.slave psram_axi4,
axi4_if.slave xpi_axi4,
axi4_if.slave spisd_axi4,
gpio_if.dut gpio,
user_gpio_if.padctrl user_gpio,
uart_if.dut uart,
@@ -30,7 +34,7 @@ module ip_ribp_wrapper (
i2s_if.dut i2s,
ws2812_if.dut ws2812,
xpi_if.dut xpi,
rib_if.master dma_rib,
axi4_if.master dma_axi4,
sysctrl_if.dut sysctrl,
pll_ctrl_if.sysctrl pll_ctrl,
sdram_if.dut sdram,
@@ -51,6 +55,21 @@ module ip_ribp_wrapper (
`include "ribp_interfaces.svh"
ribp_if ribp ();
ribp_if u_sdram_data_ribp_if ();
ribp_if u_sdram_target_ribp_if ();
ribp_if u_psram_data_ribp_if ();
ribp_if u_psram_target_ribp_if ();
ribp_if u_xpi_data_ribp_if ();
ribp_if u_xpi_target_ribp_if ();
ribp_if u_spisd_data_ribp_if ();
ribp_if u_spisd_target_ribp_if ();
rib_if u_dma_rib_if ();
axi4_stream_if #(.DATA_WIDTH(32), .ID_WIDTH(1), .DEST_WIDTH(1), .USER_WIDTH(1))
u_i2s_tx_axis_if (.aclk(clk_i), .aresetn(rst_n_i));
axi4_stream_if #(.DATA_WIDTH(32), .ID_WIDTH(1), .DEST_WIDTH(1), .USER_WIDTH(1))
u_i2s_rx_axis_if (.aclk(clk_i), .aresetn(rst_n_i));
axi4_stream_if #(.DATA_WIDTH(32), .ID_WIDTH(1), .DEST_WIDTH(1), .USER_WIDTH(1))
u_dvp_rx_axis_if (.aclk(clk_i), .aresetn(rst_n_i));
// verilog_format: on
clint_if u_clint_if ();
@@ -82,15 +101,82 @@ module ip_ribp_wrapper (
localparam bit GPIO_HAS_PULL_DOWN = 1'b0;
`endif
rib2ribp u_rib2ribp (
axi42ribp u_axi42ribp (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.rib (rib),
.axi4 (cfg_axi4),
.ribp (ribp)
);
// Generated target routing operates on the RIBP boundary behind the RIB
// adapter. Register targets therefore remain INCR1-only.
axi42ribp_burst u_sdram_axi42ribp (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (sdram_axi4),
.ribp (u_sdram_data_ribp_if)
);
axi42ribp_burst u_psram_axi42ribp (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (psram_axi4),
.ribp (u_psram_data_ribp_if)
);
axi42ribp_burst u_xpi_axi42ribp (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (xpi_axi4),
.ribp (u_xpi_data_ribp_if)
);
axi42ribp_burst u_spisd_axi42ribp (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (spisd_axi4),
.ribp (u_spisd_data_ribp_if)
);
ribp_arbiter2 u_sdram_ribp_arbiter (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.cfg (u_sdram_ribp_if),
.data (u_sdram_data_ribp_if),
.target (u_sdram_target_ribp_if)
);
ribp_arbiter2 u_psram_ribp_arbiter (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.cfg (u_psram_ribp_if),
.data (u_psram_data_ribp_if),
.target (u_psram_target_ribp_if)
);
ribp_arbiter2 u_xpi_ribp_arbiter (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.cfg (u_xpi_ribp_if),
.data (u_xpi_data_ribp_if),
.target (u_xpi_target_ribp_if)
);
ribp_arbiter2 u_spisd_ribp_arbiter (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.cfg (u_spisd_ribp_if),
.data (u_spisd_data_ribp_if),
.target (u_spisd_target_ribp_if)
);
rib2axi4 u_dma_rib2axi4 (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.rib (u_dma_rib_if),
.axi4 (dma_axi4)
);
// Generated target routing operates on the RIBP configuration boundary
// behind the AXI4 adapter. Register targets therefore remain INCR1-only.
assign u_dma_hw_trg_if.i2s_tx_proc = ~s_dma_i2s_tx_stall;
assign u_dma_hw_trg_if.i2s_rx_proc = ~s_dma_i2s_rx_stall;
@@ -153,14 +239,14 @@ module ip_ribp_wrapper (
ribp_psram u_rib_psram (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (u_psram_ribp_if),
.ribp (u_psram_target_ribp_if),
.psram (psram)
);
ribp_spisd u_rib_spisd (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (u_spisd_ribp_if),
.ribp (u_spisd_target_ribp_if),
.spi (spisd)
);
@@ -181,6 +267,8 @@ module ip_ribp_wrapper (
.dma_tx_stall_o(s_dma_i2s_tx_stall),
.dma_rx_stall_o(s_dma_i2s_rx_stall),
.ribp (u_i2s_ribp_if),
.tx_axis (u_i2s_tx_axis_if),
.rx_axis (u_i2s_rx_axis_if),
.i2s (i2s)
);
@@ -197,7 +285,7 @@ module ip_ribp_wrapper (
.dma_xfer_done_i(s_dma_xfer_done),
.dma_tx_stall_o (s_dma_xpi_tx_stall),
.dma_rx_stall_o (s_dma_xpi_rx_stall),
.ribp (u_xpi_ribp_if),
.ribp (u_xpi_target_ribp_if),
.xpi (xpi)
);
@@ -207,7 +295,10 @@ module ip_ribp_wrapper (
.dma_xfer_done_o(s_dma_xfer_done),
.hw_trg (u_dma_hw_trg_if),
.ribp (u_dma_ribp_if),
.rib (dma_rib)
.rib (u_dma_rib_if),
.i2s_tx_axis (u_i2s_tx_axis_if),
.i2s_rx_axis (u_i2s_rx_axis_if),
.dvp_rx_axis (u_dvp_rx_axis_if)
);
ribp_sysctrl u_rib_sysctrl (
@@ -233,7 +324,7 @@ module ip_ribp_wrapper (
ribp_sdram u_rib_sdram (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (u_sdram_ribp_if),
.ribp (u_sdram_target_ribp_if),
.sdram (sdram)
);
@@ -241,6 +332,7 @@ module ip_ribp_wrapper (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (u_dvp_ribp_if),
.rx_axis(u_dvp_rx_axis_if),
.dvp (dvp)
);
+6 -2
View File
@@ -21,7 +21,7 @@ module mgmt_core_wrapper (
input logic jtag_trst_n_i,
output logic jtag_tdo_o,
output logic debug_halted_o,
ribp_if.master ribp
axi4_if.master axi4
// verilog_format: on
);
@@ -53,7 +53,11 @@ module mgmt_core_wrapper (
assign debug_halted_o = s_dbg_halted;
// verilog_format: off
ahbl_if u_ahbl_if (clk_i, s_core_rst_n);
ahbl2ribp u_ahbl2ribp (u_ahbl_if, ribp, s_ahbl_idle);
ahbl2axi4 u_ahbl2axi4 (
.ahbl (u_ahbl_if),
.axi4 (axi4),
.idle_o(s_ahbl_idle)
);
// verilog_format: on
mgmt_debug_wrapper #(
+18 -2
View File
@@ -42,8 +42,16 @@ module retrosoc (
);
// verilog_format: off
// Generated fabric links reuse the common ribp_if contract.
// Generated fabric links use the common 32-bit AXI4 contract.
`include "soc_fabric_interfaces.svh"
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_sdram_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_psram_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_xpi_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_spisd_axi4_if (.aclk(clk_i), .aresetn(rst_n_i));
user_gpio_if u_user_gpio_if ();
// ip interface
gpio_if u_gpio_if ();
@@ -140,7 +148,7 @@ core_wrapper u_core_wrapper (
.core_reset_i(u_sysctrl_if.core_reset_o)
);
bus u_bus (
axi4_bus u_bus (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
`ifdef HAVE_SRAM_IF
@@ -149,6 +157,10 @@ core_wrapper u_core_wrapper (
.user_bus_enable_i(u_sysctrl_if.user_bus_enable_o),
.user_bus_idle_o (u_sysctrl_if.user_bus_idle_i),
`include "soc_bus_fabric.svh"
.sdram_axi4 (u_sdram_axi4_if),
.psram_axi4 (u_psram_axi4_if),
.xpi_axi4 (u_xpi_axi4_if),
.spisd_axi4 (u_spisd_axi4_if),
.perf_enable_i (s_perf_enable),
.perf_clear_i (s_perf_clear),
.fault_valid_o (s_bus_fault_valid),
@@ -176,6 +188,10 @@ core_wrapper u_core_wrapper (
.debug_halted_i (s_mgmt_debug_halted),
.timebase_tick_i (timebase_tick_i),
`include "ip_ribp_wrapper_fabric.svh"
.sdram_axi4 (u_sdram_axi4_if),
.psram_axi4 (u_psram_axi4_if),
.xpi_axi4 (u_xpi_axi4_if),
.spisd_axi4 (u_spisd_axi4_if),
.gpio (u_gpio_if),
.user_gpio (u_user_gpio_if),
.uart (u_uart0_if),
+4 -2
View File
@@ -32,8 +32,9 @@ module rib2apb (
logic s_xfer_valid, s_xfer_ready, s_xfer_error;
logic [2:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_q, s_wdata_q;
logic [3:0] s_wstrb_q;
logic s_write_q;
logic [31:0] s_decode_addr;
logic [ 3:0] s_wstrb_q;
logic s_write_q;
logic [2:0] s_error_code_d, s_error_code_q;
logic s_cmd_hdshk, s_w_hdshk, s_rsp_hdshk;
logic s_psel_valid;
@@ -44,6 +45,7 @@ module rib2apb (
`include "soc_apb_declarations.svh"
assign s_cmd_hdshk = rib.cmd_valid && rib.cmd_ready;
assign s_decode_addr = rib.cmd_addr;
assign s_w_hdshk = rib.w_valid && rib.w_ready;
assign rib.cmd_ready = (s_fsm_q == FSM_CMD) && !rib.rsp_valid;
+157
View File
@@ -0,0 +1,157 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
`include "rib_defs.svh"
module rib2axi4 (
input logic clk_i,
input logic rst_n_i,
rib_if.slave rib,
axi4_if.master axi4
);
localparam logic [2:0] FSM_IDLE = 3'd0;
localparam logic [2:0] FSM_WR_ADDR = 3'd1;
localparam logic [2:0] FSM_WR_DATA = 3'd2;
localparam logic [2:0] FSM_WR_RESP = 3'd3;
localparam logic [2:0] FSM_RD_ADDR = 3'd4;
localparam logic [2:0] FSM_RD_RESP = 3'd5;
logic [2:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_d, s_addr_q;
logic [1:0] s_len_d, s_len_q;
logic [1:0] s_beat_d, s_beat_q;
logic s_aw_done_d, s_aw_done_q;
assign rib.cmd_ready = s_fsm_q == FSM_IDLE;
assign rib.w_ready = (s_fsm_q == FSM_WR_DATA) && axi4.wready;
assign rib.rsp_valid = ((s_fsm_q == FSM_WR_RESP) && axi4.bvalid) ||
((s_fsm_q == FSM_RD_RESP) && axi4.rvalid);
assign rib.rdata = axi4.rdata;
assign rib.resp_err = (s_fsm_q == FSM_WR_RESP) ?
(axi4.bresp != `AXI4_RESP_OKAY) :
(axi4.rresp != `AXI4_RESP_OKAY);
assign rib.resp_code = !rib.resp_err ? `RIB_RESP_OK :
((s_fsm_q == FSM_WR_RESP) ? axi4.bresp : axi4.rresp) ==
`AXI4_RESP_DECODE_ERROR ?
`RIB_RESP_DECERR :
`RIB_RESP_SLVERR;
assign rib.rsp_beat = s_beat_q;
assign rib.rsp_last = (s_fsm_q == FSM_WR_RESP) || axi4.rlast;
assign axi4.awid = '0;
assign axi4.awaddr = s_addr_q;
assign axi4.awlen = {6'd0, s_len_q};
assign axi4.awsize = `AXI4_BURST_SIZE_4BYTES;
assign axi4.awburst = `AXI4_BURST_TYPE_INCR;
assign axi4.awlock = `AXI4_LOCK_NORM;
assign axi4.awcache = `AXI4_CACHE_NO_BUF;
assign axi4.awprot = `AXI4_PROT_DATA;
assign axi4.awqos = `AXI4_QOS_NORMAL;
assign axi4.awregion = `AXI4_REGION_NORMAL;
assign axi4.awuser = '0;
assign axi4.awvalid = (s_fsm_q == FSM_WR_ADDR) && !s_aw_done_q;
assign axi4.wdata = rib.wdata;
assign axi4.wstrb = rib.wstrb;
assign axi4.wlast = s_beat_q == s_len_q;
assign axi4.wuser = '0;
assign axi4.wvalid = (s_fsm_q == FSM_WR_DATA) && rib.w_valid;
assign axi4.bready = (s_fsm_q == FSM_WR_RESP) && rib.rsp_ready;
assign axi4.arid = '0;
assign axi4.araddr = s_addr_q;
assign axi4.arlen = {6'd0, s_len_q};
assign axi4.arsize = `AXI4_BURST_SIZE_4BYTES;
assign axi4.arburst = `AXI4_BURST_TYPE_INCR;
assign axi4.arlock = `AXI4_LOCK_NORM;
assign axi4.arcache = `AXI4_CACHE_NO_BUF;
assign axi4.arprot = `AXI4_PROT_DATA;
assign axi4.arqos = `AXI4_QOS_NORMAL;
assign axi4.arregion = `AXI4_REGION_NORMAL;
assign axi4.aruser = '0;
assign axi4.arvalid = s_fsm_q == FSM_RD_ADDR;
assign axi4.rready = (s_fsm_q == FSM_RD_RESP) && rib.rsp_ready;
always_comb begin
s_fsm_d = s_fsm_q;
s_addr_d = s_addr_q;
s_len_d = s_len_q;
s_beat_d = s_beat_q;
s_aw_done_d = s_aw_done_q;
unique case (s_fsm_q)
FSM_IDLE: begin
s_beat_d = '0;
s_aw_done_d = 1'b0;
if (rib.cmd_valid && rib.cmd_ready) begin
s_addr_d = rib.cmd_addr;
s_len_d = rib.cmd_len;
s_fsm_d = rib.cmd_write ? FSM_WR_ADDR : FSM_RD_ADDR;
end
end
FSM_WR_ADDR: begin
if (axi4.awvalid && axi4.awready) begin
s_aw_done_d = 1'b1;
s_fsm_d = FSM_WR_DATA;
end
end
FSM_WR_DATA: begin
if (axi4.wvalid && axi4.wready) begin
if (s_beat_q == s_len_q) begin
s_fsm_d = FSM_WR_RESP;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
FSM_WR_RESP: begin
if (axi4.bvalid && rib.rsp_ready) s_fsm_d = FSM_IDLE;
end
FSM_RD_ADDR: begin
if (axi4.arvalid && axi4.arready) s_fsm_d = FSM_RD_RESP;
end
FSM_RD_RESP: begin
if (axi4.rvalid && rib.rsp_ready) begin
if (axi4.rlast) begin
s_fsm_d = FSM_IDLE;
end else begin
s_beat_d = s_beat_q + 1'b1;
end
end
end
default: s_fsm_d = FSM_IDLE;
endcase
end
dffr #(3) u_fsm_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(32) u_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(2) u_len_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_len_d),
.dat_o (s_len_q)
);
dffr #(2) u_beat_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_beat_d),
.dat_o (s_beat_q)
);
dffr #(1) u_aw_done_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_aw_done_d),
.dat_o (s_aw_done_q)
);
endmodule
+165
View File
@@ -0,0 +1,165 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
`include "axi4_define.svh"
module ribp2axi4 (
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
axi4_if.master axi4
);
localparam logic [2:0] FSM_IDLE = 3'd0;
localparam logic [2:0] FSM_WR_ADDR_DATA = 3'd1;
localparam logic [2:0] FSM_WR_RESP = 3'd2;
localparam logic [2:0] FSM_RD_ADDR = 3'd3;
localparam logic [2:0] FSM_RD_RESP = 3'd4;
logic [2:0] s_fsm_d, s_fsm_q;
logic [31:0] s_addr_d, s_addr_q;
logic [31:0] s_wdata_d, s_wdata_q;
logic [3:0] s_wstrb_d, s_wstrb_q;
logic s_aw_done_d, s_aw_done_q;
logic s_w_done_d, s_w_done_q;
logic [31:0] s_rdata_d, s_rdata_q;
logic s_error_d, s_error_q;
assign ribp.ready = ((s_fsm_q == FSM_WR_RESP) && axi4.bvalid) ||
((s_fsm_q == FSM_RD_RESP) && axi4.rvalid);
assign ribp.rdata = (s_fsm_q == FSM_RD_RESP) ? axi4.rdata : s_rdata_q;
assign ribp.resp_err = ((s_fsm_q == FSM_WR_RESP) && axi4.bvalid) ?
(axi4.bresp != `AXI4_RESP_OKAY) :
((s_fsm_q == FSM_RD_RESP) && axi4.rvalid) ?
(axi4.rresp != `AXI4_RESP_OKAY) : s_error_q;
assign axi4.awid = '0;
assign axi4.awaddr = s_addr_q;
assign axi4.awlen = 8'd0;
assign axi4.awsize = `AXI4_BURST_SIZE_4BYTES;
assign axi4.awburst = `AXI4_BURST_TYPE_INCR;
assign axi4.awlock = `AXI4_LOCK_NORM;
assign axi4.awcache = `AXI4_CACHE_NO_BUF;
assign axi4.awprot = `AXI4_PROT_DATA;
assign axi4.awqos = `AXI4_QOS_NORMAL;
assign axi4.awregion = `AXI4_REGION_NORMAL;
assign axi4.awuser = '0;
assign axi4.awvalid = (s_fsm_q == FSM_WR_ADDR_DATA) && !s_aw_done_q;
assign axi4.wdata = s_wdata_q;
assign axi4.wstrb = s_wstrb_q;
assign axi4.wlast = 1'b1;
assign axi4.wuser = '0;
assign axi4.wvalid = (s_fsm_q == FSM_WR_ADDR_DATA) && !s_w_done_q;
assign axi4.bready = (s_fsm_q == FSM_WR_RESP) && ribp.valid;
assign axi4.arid = '0;
assign axi4.araddr = s_addr_q;
assign axi4.arlen = 8'd0;
assign axi4.arsize = `AXI4_BURST_SIZE_4BYTES;
assign axi4.arburst = `AXI4_BURST_TYPE_INCR;
assign axi4.arlock = `AXI4_LOCK_NORM;
assign axi4.arcache = `AXI4_CACHE_NO_BUF;
assign axi4.arprot = `AXI4_PROT_DATA;
assign axi4.arqos = `AXI4_QOS_NORMAL;
assign axi4.arregion = `AXI4_REGION_NORMAL;
assign axi4.aruser = '0;
assign axi4.arvalid = (s_fsm_q == FSM_RD_ADDR);
assign axi4.rready = (s_fsm_q == FSM_RD_RESP) && ribp.valid;
always_comb begin
s_fsm_d = s_fsm_q;
s_addr_d = s_addr_q;
s_wdata_d = s_wdata_q;
s_wstrb_d = s_wstrb_q;
s_aw_done_d = s_aw_done_q;
s_w_done_d = s_w_done_q;
s_rdata_d = s_rdata_q;
s_error_d = s_error_q;
unique case (s_fsm_q)
FSM_IDLE: begin
s_aw_done_d = 1'b0;
s_w_done_d = 1'b0;
s_error_d = 1'b0;
if (ribp.valid) begin
s_addr_d = {ribp.addr[31:2], 2'b00};
s_wdata_d = ribp.wdata;
s_wstrb_d = ribp.wstrb;
s_fsm_d = (|ribp.wstrb) ? FSM_WR_ADDR_DATA : FSM_RD_ADDR;
end
end
FSM_WR_ADDR_DATA: begin
if (axi4.awvalid && axi4.awready) s_aw_done_d = 1'b1;
if (axi4.wvalid && axi4.wready) s_w_done_d = 1'b1;
if ((s_aw_done_q || (axi4.awvalid && axi4.awready)) &&
(s_w_done_q || (axi4.wvalid && axi4.wready))) begin
s_fsm_d = FSM_WR_RESP;
end
end
FSM_WR_RESP: begin
if (axi4.bvalid && ribp.valid) begin
s_error_d = axi4.bresp != `AXI4_RESP_OKAY;
s_fsm_d = FSM_IDLE;
end
end
FSM_RD_ADDR: begin
if (axi4.arvalid && axi4.arready) s_fsm_d = FSM_RD_RESP;
end
FSM_RD_RESP: begin
if (axi4.rvalid && ribp.valid) begin
s_rdata_d = axi4.rdata;
s_error_d = axi4.rresp != `AXI4_RESP_OKAY;
s_fsm_d = FSM_IDLE;
end
end
default: s_fsm_d = FSM_IDLE;
endcase
end
dffr #(3) u_fsm_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fsm_d),
.dat_o (s_fsm_q)
);
dffr #(32) u_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_addr_d),
.dat_o (s_addr_q)
);
dffr #(32) u_wdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wdata_d),
.dat_o (s_wdata_q)
);
dffr #(4) u_wstrb_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_wstrb_d),
.dat_o (s_wstrb_q)
);
dffr #(1) u_aw_done_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_aw_done_d),
.dat_o (s_aw_done_q)
);
dffr #(1) u_w_done_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_w_done_d),
.dat_o (s_w_done_q)
);
dffr #(32) u_rdata_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rdata_d),
.dat_o (s_rdata_q)
);
dffr #(1) u_error_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_error_d),
.dat_o (s_error_q)
);
endmodule
+54
View File
@@ -0,0 +1,54 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// See LICENSE for the complete license text.
module ribp_arbiter2 (
input logic clk_i,
input logic rst_n_i,
ribp_if.slave cfg,
ribp_if.slave data,
ribp_if.master target
);
logic s_locked_d, s_locked_q;
logic s_owner_d, s_owner_q;
logic s_select_data;
assign s_select_data = s_locked_q ? s_owner_q : (!cfg.valid && data.valid);
assign target.valid = s_select_data ? data.valid : cfg.valid;
assign target.addr = s_select_data ? data.addr : cfg.addr;
assign target.wdata = s_select_data ? data.wdata : cfg.wdata;
assign target.wstrb = s_select_data ? data.wstrb : cfg.wstrb;
assign cfg.ready = !s_select_data && target.ready;
assign cfg.rdata = target.rdata;
assign cfg.resp_err = target.resp_err;
assign data.ready = s_select_data && target.ready;
assign data.rdata = target.rdata;
assign data.resp_err = target.resp_err;
always_comb begin
s_locked_d = s_locked_q;
s_owner_d = s_owner_q;
if (!s_locked_q && target.valid && !target.ready) begin
s_locked_d = 1'b1;
s_owner_d = s_select_data;
end else if (s_locked_q && target.ready) begin
s_locked_d = 1'b0;
end
end
dffr #(1) u_locked_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_locked_d),
.dat_o (s_locked_q)
);
dffr #(1) u_owner_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_owner_d),
.dat_o (s_owner_q)
);
endmodule
+12 -1
View File
@@ -17,11 +17,22 @@ module user_core_top (
input logic [ 31:0] irq_i,
input logic [`USER_CORESEL_WIDTH-1:0] sel_i,
input logic [`USER_CORE_COUNT-1:0] core_reset_i,
rib_if.master rib
axi4_if.master axi4
// verilog_format: on
);
rib_if rib ();
// Generated bindings preserve scalar user-core interfaces and isolation.
`include "user_core_bindings.svh"
// verilog_format: off
rib2axi4 u_rib2axi4 (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.rib (rib),
.axi4 (axi4)
);
// verilog_format: on
endmodule
+263
View File
@@ -0,0 +1,263 @@
`timescale 1ns / 1ps
`include "axi4_define.svh"
module axi42ribp_burst_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [31:0] memory [0:63];
logic [31:0] expected;
integer target_accesses = 0;
integer error_beats;
integer cycle_count = 0;
integer burst_cycles;
integer single_cycles;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
.aclk (clk_i),
.aresetn(rst_n_i)
);
ribp_if ribp ();
always #5 clk_i = ~clk_i;
always @(posedge clk_i) cycle_count <= cycle_count + 1;
axi42ribp_burst u_dut (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (axi4),
.ribp (ribp)
);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
ribp.ready <= 1'b0;
ribp.rdata <= '0;
target_accesses <= 0;
end else begin
ribp.ready <= ribp.valid && !ribp.ready;
if (ribp.valid && !ribp.ready) begin
target_accesses <= target_accesses + 1;
ribp.rdata <= memory[ribp.addr[7:2]];
for (int lane = 0; lane < 4; lane++) begin
if (ribp.wstrb[lane]) begin
memory[ribp.addr[7:2]][lane*8+:8] <= ribp.wdata[lane*8+:8];
end
end
end
end
end
assign ribp.resp_err = 1'b0;
task automatic init_axi4;
begin
axi4.awid = '0;
axi4.awaddr = '0;
axi4.awlen = '0;
axi4.awsize = `AXI4_BURST_SIZE_4BYTES;
axi4.awburst = `AXI4_BURST_TYPE_INCR;
axi4.awlock = `AXI4_LOCK_NORM;
axi4.awcache = `AXI4_CACHE_NO_BUF;
axi4.awprot = `AXI4_PROT_DATA;
axi4.awqos = `AXI4_QOS_NORMAL;
axi4.awregion = `AXI4_REGION_NORMAL;
axi4.awuser = '0;
axi4.awvalid = 1'b0;
axi4.wdata = '0;
axi4.wstrb = '0;
axi4.wlast = 1'b0;
axi4.wuser = '0;
axi4.wvalid = 1'b0;
axi4.bready = 1'b0;
axi4.arid = '0;
axi4.araddr = '0;
axi4.arlen = '0;
axi4.arsize = `AXI4_BURST_SIZE_4BYTES;
axi4.arburst = `AXI4_BURST_TYPE_INCR;
axi4.arlock = `AXI4_LOCK_NORM;
axi4.arcache = `AXI4_CACHE_NO_BUF;
axi4.arprot = `AXI4_PROT_DATA;
axi4.arqos = `AXI4_QOS_NORMAL;
axi4.arregion = `AXI4_REGION_NORMAL;
axi4.aruser = '0;
axi4.arvalid = 1'b0;
axi4.rready = 1'b0;
end
endtask
task automatic issue_write4(input logic [31:0] address);
begin
@(negedge clk_i);
axi4.awaddr = address;
axi4.awlen = 8'd3;
axi4.awvalid = 1'b1;
do @(posedge clk_i); while (!axi4.awready);
@(negedge clk_i);
axi4.awvalid = 1'b0;
for (int beat = 0; beat < 4; beat++) begin
axi4.wdata = 32'hA500_0000 + beat;
axi4.wstrb = 4'hF;
axi4.wlast = beat == 3;
axi4.wvalid = 1'b1;
do @(posedge clk_i); while (!axi4.wready);
@(negedge clk_i);
axi4.wvalid = 1'b0;
end
repeat (2) @(posedge clk_i);
axi4.bready = 1'b1;
do @(posedge clk_i); while (!axi4.bvalid);
if (axi4.bresp != `AXI4_RESP_OKAY) $fatal(1, "write burst returned an error");
@(negedge clk_i);
axi4.bready = 1'b0;
end
endtask
task automatic issue_read4(input logic [31:0] address);
begin
@(negedge clk_i);
axi4.araddr = address;
axi4.arlen = 8'd3;
axi4.arvalid = 1'b1;
do @(posedge clk_i); while (!axi4.arready);
@(negedge clk_i);
axi4.arvalid = 1'b0;
for (int beat = 0; beat < 4; beat++) begin
if (beat == 1) begin
repeat (3) @(posedge clk_i);
@(negedge clk_i);
end
axi4.rready = 1'b1;
do @(posedge clk_i); while (!axi4.rvalid);
expected = 32'hA500_0000 + beat;
if (axi4.rdata != expected || axi4.rresp != `AXI4_RESP_OKAY ||
axi4.rlast != (beat == 3)) begin
$fatal(1, "read beat %0d mismatch: data=%08x expected=%08x resp=%0d last=%0d", beat,
axi4.rdata, expected, axi4.rresp, axi4.rlast);
end
@(negedge clk_i);
axi4.rready = 1'b0;
end
end
endtask
task automatic issue_illegal_read(input logic [31:0] address);
integer accesses_before;
begin
accesses_before = target_accesses;
@(negedge clk_i);
axi4.araddr = address;
axi4.arlen = 8'd16;
axi4.arvalid = 1'b1;
do @(posedge clk_i); while (!axi4.arready);
@(negedge clk_i);
axi4.arvalid = 1'b0;
axi4.rready = 1'b1;
error_beats = 0;
while (error_beats < 17) begin
@(posedge clk_i);
if (axi4.rvalid) begin
if (axi4.rresp != `AXI4_RESP_SLAVE_ERROR || axi4.rlast != (error_beats == 16)) begin
$fatal(1, "illegal burst response mismatch");
end
error_beats = error_beats + 1;
end
end
@(negedge clk_i);
axi4.rready = 1'b0;
if (target_accesses != accesses_before) begin
$fatal(1, "illegal burst reached the RIBP target");
end
end
endtask
task automatic issue_early_last_write(input logic [31:0] address);
integer accesses_before;
begin
accesses_before = target_accesses;
@(negedge clk_i);
axi4.awaddr = address;
axi4.awlen = 8'd3;
axi4.awvalid = 1'b1;
do @(posedge clk_i); while (!axi4.awready);
@(negedge clk_i);
axi4.awvalid = 1'b0;
axi4.wdata = 32'hDEAD_BEEF;
axi4.wstrb = 4'hF;
axi4.wlast = 1'b1;
axi4.wvalid = 1'b1;
do @(posedge clk_i); while (!axi4.wready);
@(negedge clk_i);
axi4.wvalid = 1'b0;
axi4.bready = 1'b1;
do @(posedge clk_i); while (!axi4.bvalid);
if (axi4.bresp != `AXI4_RESP_SLAVE_ERROR) begin
$fatal(1, "early WLAST did not return SLVERR");
end
@(negedge clk_i);
axi4.bready = 1'b0;
axi4.wlast = 1'b0;
if (target_accesses != accesses_before + 1) begin
$fatal(1, "early WLAST must commit exactly one RIBP beat");
end
end
endtask
task automatic issue_read(input logic [31:0] address, input logic [7:0] length);
integer beat;
begin
@(negedge clk_i);
axi4.araddr = address;
axi4.arlen = length;
axi4.arvalid = 1'b1;
do @(posedge clk_i); while (!axi4.arready);
@(negedge clk_i);
axi4.arvalid = 1'b0;
axi4.rready = 1'b1;
beat = 0;
while (beat <= length) begin
@(posedge clk_i);
if (axi4.rvalid) begin
if (axi4.rresp != `AXI4_RESP_OKAY || axi4.rlast != (beat == length)) begin
$fatal(1, "performance read response mismatch");
end
beat = beat + 1;
end
end
@(negedge clk_i);
axi4.rready = 1'b0;
end
endtask
initial begin
init_axi4();
for (int index = 0; index < 64; index++) memory[index] = '0;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
issue_write4(32'h0000_0040);
issue_read4(32'h0000_0040);
issue_illegal_read(32'h0000_0080);
issue_early_last_write(32'h0000_00C0);
burst_cycles = cycle_count;
issue_read(32'h0000_0000, 8'd15);
burst_cycles = cycle_count - burst_cycles;
single_cycles = cycle_count;
for (int index = 0; index < 16; index++) begin
issue_read(32'(index * 4), 8'd0);
end
single_cycles = cycle_count - single_cycles;
if ((burst_cycles * 5) > (single_cycles * 4)) begin
$fatal(1, "16-beat burst improvement is below 20%%: burst=%0d single=%0d", burst_cycles,
single_cycles);
end
if (target_accesses != 41) $fatal(1, "unexpected RIBP access count");
$display("AXI4 to RIBP burst bridge test passed");
$finish;
end
endmodule
+195
View File
@@ -0,0 +1,195 @@
`timescale 1ns / 1ps
`include "axi4_define.svh"
`include "rib_defs.svh"
module axi4_interconnect_tb;
localparam int NUM_MASTERS = 3;
localparam int NUM_TARGETS = 9;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic fault_valid_o;
logic [31:0] fault_addr_o;
logic [ 3:0] fault_wstrb_o;
logic fault_reserved_o;
logic fault_access_o;
logic [ 1:0] fault_master_o;
logic [ 2:0] fault_code_o;
logic user_bus_idle_o;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) masters[NUM_MASTERS] (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) targets[NUM_TARGETS] (
.aclk (clk_i),
.aresetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
axi4_interconnect #(
.NUM_MASTERS(NUM_MASTERS),
.NUM_TARGETS(NUM_TARGETS)
) u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.masters (masters),
.targets (targets),
.user_bus_enable_i(1'b1),
.user_bus_idle_o (user_bus_idle_o),
.perf_enable_i (1'b0),
.perf_clear_i (1'b0),
.fault_valid_o (fault_valid_o),
.fault_addr_o (fault_addr_o),
.fault_wstrb_o (fault_wstrb_o),
.fault_reserved_o (fault_reserved_o),
.fault_access_o (fault_access_o),
.fault_master_o (fault_master_o),
.fault_code_o (fault_code_o),
.perf_mgmt_wait_o (),
.perf_user_wait_o (),
.perf_dma_wait_o (),
.perf_ribp_wait_o (),
.perf_apb_wait_o (),
.perf_sdram_wait_o(),
.perf_psram_wait_o(),
.perf_flash_wait_o()
);
for (genvar target = 0; target < NUM_TARGETS; target++) begin : GEN_TARGETS
localparam logic [1:0] RESPONSE =
(target == 7) ? `AXI4_RESP_DECODE_ERROR :
(target == 8) ? `AXI4_RESP_SLAVE_ERROR : `AXI4_RESP_OKAY;
axi4_error_slave #(
.RESPONSE(RESPONSE)
) u_target (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.axi4 (targets[target])
);
end
`define INIT_MASTER(index) \
masters[index].awid = '0; \
masters[index].awaddr = '0; \
masters[index].awlen = '0; \
masters[index].awsize = `AXI4_BURST_SIZE_4BYTES; \
masters[index].awburst = `AXI4_BURST_TYPE_INCR; \
masters[index].awlock = `AXI4_LOCK_NORM; \
masters[index].awcache = `AXI4_CACHE_NO_BUF; \
masters[index].awprot = `AXI4_PROT_DATA; \
masters[index].awqos = `AXI4_QOS_NORMAL; \
masters[index].awregion = `AXI4_REGION_NORMAL; \
masters[index].awuser = '0; \
masters[index].awvalid = 1'b0; \
masters[index].wdata = '0; \
masters[index].wstrb = '0; \
masters[index].wlast = 1'b0; \
masters[index].wuser = '0; \
masters[index].wvalid = 1'b0; \
masters[index].bready = 1'b0; \
masters[index].arid = '0; \
masters[index].araddr = '0; \
masters[index].arlen = '0; \
masters[index].arsize = `AXI4_BURST_SIZE_4BYTES; \
masters[index].arburst = `AXI4_BURST_TYPE_INCR; \
masters[index].arlock = `AXI4_LOCK_NORM; \
masters[index].arcache = `AXI4_CACHE_NO_BUF; \
masters[index].arprot = `AXI4_PROT_DATA; \
masters[index].arqos = `AXI4_QOS_NORMAL; \
masters[index].arregion = `AXI4_REGION_NORMAL; \
masters[index].aruser = '0; \
masters[index].arvalid = 1'b0; \
masters[index].rready = 1'b0;
task automatic issue_mgmt_error_read(input logic [31:0] address, input logic [7:0] length,
input logic [1:0] response, input logic [2:0] fault_code);
integer beat;
begin
@(negedge clk_i);
masters[0].araddr = address;
masters[0].arlen = length;
masters[0].arvalid = 1'b1;
do @(posedge clk_i); while (!masters[0].arready);
@(negedge clk_i);
masters[0].arvalid = 1'b0;
masters[0].rready = 1'b1;
beat = 0;
while (beat <= length) begin
@(negedge clk_i);
if (masters[0].rvalid) begin
if ((masters[0].rresp != response) || (masters[0].rlast != (beat == int'(length)))) begin
$fatal(1, "management error response mismatch on beat %0d", beat);
end
if ((beat == int'(length)) &&
(!fault_valid_o || (fault_addr_o != address) || fault_access_o ||
(fault_master_o != 2'd0) || (fault_code_o != fault_code))) begin
$fatal(1, "management fault classification mismatch");
end
beat = beat + 1;
end
end
@(negedge clk_i);
masters[0].rready = 1'b0;
end
endtask
task automatic issue_denied_user_write(input logic [31:0] address);
begin
@(negedge clk_i);
masters[1].awaddr = address;
masters[1].awlen = 8'd0;
masters[1].awvalid = 1'b1;
do @(posedge clk_i); while (!masters[1].awready);
@(negedge clk_i);
masters[1].awvalid = 1'b0;
masters[1].wdata = 32'hA5A5_5A5A;
masters[1].wstrb = 4'hF;
masters[1].wlast = 1'b1;
masters[1].wvalid = 1'b1;
do @(posedge clk_i); while (!masters[1].wready);
@(negedge clk_i);
masters[1].wvalid = 1'b0;
while (!masters[1].bvalid) @(negedge clk_i);
masters[1].bready = 1'b1;
#1;
if ((masters[1].bresp != `AXI4_RESP_SLAVE_ERROR) || !fault_valid_o ||
!fault_access_o || (fault_addr_o != address) || (fault_wstrb_o != 4'hF) ||
(fault_master_o != 2'd1) || (fault_code_o != `RIB_RESP_PROTERR)) begin
$fatal(1, "user access fault classification mismatch");
end
@(negedge clk_i);
masters[1].bready = 1'b0;
end
endtask
initial begin
`INIT_MASTER(0)
`INIT_MASTER(1)
`INIT_MASTER(2)
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
issue_mgmt_error_read(32'hA000_0000, 8'd0, `AXI4_RESP_DECODE_ERROR, `RIB_RESP_DECERR);
issue_mgmt_error_read(32'h3000_0000, 8'd16, `AXI4_RESP_SLAVE_ERROR, `RIB_RESP_BURSTERR);
issue_denied_user_write(32'h1000_B000);
$display("AXI4 interconnect fault classification test passed");
$finish;
end
`undef INIT_MASTER
endmodule
+1 -1
View File
@@ -36,7 +36,7 @@ module bus_fault_tb;
assign apb_rib.rsp_beat = '0;
assign apb_rib.rsp_last = 1'b1;
bus u_bus (
rib_bus u_bus (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.mgmt_ribp (mgmt_ribp),
+86 -10
View File
@@ -27,6 +27,10 @@ module dma_error_tb;
integer incr4_write_count = 0;
integer legacy_cycles;
integer burst_cycles;
integer stream_tx_count = 0;
integer stream_rx_count = 0;
logic stream_tx_ready = 1'b0;
logic stream_rx_valid = 1'b0;
logic [ 1:0] model_state_q = MODEL_IDLE;
logic [ 1:0] model_len_q = '0;
logic [ 1:0] model_beat_q = '0;
@@ -34,17 +38,59 @@ module dma_error_tb;
logic model_error_q = 1'b0;
dma_hw_trg_if hw_trg ();
rib_if rib ();
axi4_stream_if i2s_tx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if i2s_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if dvp_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
assign rib.cmd_ready = model_state_q == MODEL_IDLE;
assign rib.w_ready = model_state_q == MODEL_WDATA;
assign rib.rsp_valid = model_state_q == MODEL_RESP;
assign rib.rdata = 32'hA5A5_5A5A + model_beat_q;
assign rib.resp_err = model_error_q;
assign rib.resp_code = model_error_q ? `RIB_RESP_DECERR : `RIB_RESP_OK;
assign rib.rsp_beat = model_beat_q;
assign rib.rsp_last = model_write_q || model_error_q || (model_beat_q == model_len_q);
assign rib.cmd_ready = model_state_q == MODEL_IDLE;
assign rib.w_ready = model_state_q == MODEL_WDATA;
assign rib.rsp_valid = model_state_q == MODEL_RESP;
assign rib.rdata = 32'hA5A5_5A5A + model_beat_q;
assign rib.resp_err = model_error_q;
assign rib.resp_code = model_error_q ? `RIB_RESP_DECERR : `RIB_RESP_OK;
assign rib.rsp_beat = model_beat_q;
assign rib.rsp_last = model_write_q || model_error_q || (model_beat_q == model_len_q);
assign i2s_tx_axis.tready = stream_tx_ready;
assign i2s_rx_axis.tdata = 32'h5100_0000 + stream_rx_count;
assign i2s_rx_axis.tkeep = '1;
assign i2s_rx_axis.tstrb = '1;
assign i2s_rx_axis.tlast = stream_rx_count == 1;
assign i2s_rx_axis.tid = '0;
assign i2s_rx_axis.tdest = '0;
assign i2s_rx_axis.tuser = '0;
assign i2s_rx_axis.tvalid = stream_rx_valid;
assign dvp_rx_axis.tdata = '0;
assign dvp_rx_axis.tkeep = '0;
assign dvp_rx_axis.tstrb = '0;
assign dvp_rx_axis.tlast = 1'b0;
assign dvp_rx_axis.tid = '0;
assign dvp_rx_axis.tdest = '0;
assign dvp_rx_axis.tuser = '0;
assign dvp_rx_axis.tvalid = 1'b0;
always @(posedge clk_i) begin
if (i2s_tx_axis.tvalid && i2s_tx_axis.tready) begin
if (i2s_tx_axis.tdata !== 32'hA5A5_5A5A) begin
$fatal(1, "I2S TX stream data mismatch");
end
stream_tx_count <= stream_tx_count + 1;
end
if (i2s_rx_axis.tvalid && i2s_rx_axis.tready) begin
stream_rx_count <= stream_rx_count + 1;
if (stream_rx_count == 1) stream_rx_valid <= 1'b0;
end
end
always @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
@@ -114,7 +160,10 @@ module dma_error_tb;
.error_addr_o(error_addr_o),
.fsm_o (fsm_o),
.hw_trg (hw_trg),
.rib (rib)
.rib (rib),
.i2s_tx_axis (i2s_tx_axis),
.i2s_rx_axis (i2s_rx_axis),
.dvp_rx_axis (dvp_rx_axis)
);
task automatic start_transfer;
@@ -193,7 +242,34 @@ module dma_error_tb;
$fatal(1, "DMA did not fall back to INCR1 for a register window");
end
$display("dma error and burst performance test passed");
mode_i = 4'd1;
srcaddr_i = 32'h3800_2000;
srcincr_i = 1'b1;
xferlen_i = 32'd2;
stream_tx_ready = 1'b0;
start_transfer();
repeat (3) @(posedge clk_i);
@(negedge clk_i);
stream_tx_ready = 1'b1;
wait (done_o);
@(negedge clk_i);
if (stream_tx_count != 2) begin
$fatal(1, "I2S TX stream transferred %0d words", stream_tx_count);
end
mode_i = 4'd2;
dstaddr_i = 32'h4000_2000;
dstincr_i = 1'b1;
xferlen_i = 32'd2;
stream_rx_valid = 1'b1;
start_transfer();
wait (done_o);
@(negedge clk_i);
if (stream_rx_count != 2) begin
$fatal(1, "I2S RX stream transferred %0d words", stream_rx_count);
end
$display("dma error, burst performance, and AXI4-Stream test passed");
$finish;
end
endmodule
+1 -1
View File
@@ -66,7 +66,7 @@ module rib_bus_tb;
assign apb_rib.rsp_beat = '0;
assign apb_rib.rsp_last = 1'b1;
bus u_bus (
rib_bus u_bus (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.mgmt_ribp (mgmt_ribp),
+2 -2
View File
@@ -141,8 +141,8 @@ module ribp_topology_tb;
expect_route(`SOC_ADDR_RIBP_GPIO_BASE, 1, 32'h1111_1111);
expect_route(`SOC_ADDR_RIBP_GPIO_ADMIN_BASE, 1, 32'h1111_1111);
expect_route(`SOC_ADDR_PSRAM_BASE, 4, 32'h4444_4444);
expect_route(`SOC_ADDR_FLASH_BASE, 9, 32'h9999_9999);
expect_route(`SOC_ADDR_RIBP_PSRAM_BASE, 4, 32'h4444_4444);
expect_route(`SOC_ADDR_RIBP_XPI_BASE, 9, 32'h9999_9999);
expect_route(`SOC_ADDR_RIBP_I2C1_BASE, 17, 32'h1234_5678);
expect_disabled(`SOC_ADDR_RIBP_SDIO_BASE);
u_gpio_ribp_if.resp_err = 1'b1;
+46 -14
View File
@@ -46,6 +46,18 @@ module ws2812_dma_tb;
rib_if dma_rib ();
ribp_if ws_ribp ();
ws2812_if ws2812 ();
axi4_stream_if i2s_tx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if i2s_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if dvp_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
@@ -54,20 +66,37 @@ module ws2812_dma_tb;
$fatal(1, "WS2812 DMA integration test timeout");
end
assign ws_ribp.valid = host_active ? host_valid : dma_ws_valid;
assign ws_ribp.addr = host_active ? host_addr : bus_addr_q;
assign ws_ribp.wdata = host_active ? host_wdata : dma_rib.wdata;
assign ws_ribp.wstrb = host_active ? host_wstrb : dma_rib.wstrb;
assign ws_ribp.valid = host_active ? host_valid : dma_ws_valid;
assign ws_ribp.addr = host_active ? host_addr : bus_addr_q;
assign ws_ribp.wdata = host_active ? host_wdata : dma_rib.wdata;
assign ws_ribp.wstrb = host_active ? host_wstrb : dma_rib.wstrb;
assign dma_rib.cmd_ready = bus_state_q == BUS_IDLE;
assign dma_rib.w_ready = (bus_state_q == BUS_WRITE_DATA) && ws_ribp.ready;
assign dma_rib.rsp_valid = (bus_state_q == BUS_READ_RESP) || (bus_state_q == BUS_WRITE_RESP);
assign dma_rib.rdata = pixels[bus_addr_q[4:2]];
assign dma_rib.resp_err = 1'b0;
assign dma_rib.resp_code = `RIB_RESP_OK;
assign dma_rib.rsp_beat = 2'd0;
assign dma_rib.rsp_last = 1'b1;
assign dma_ws_valid = (bus_state_q == BUS_WRITE_DATA) && dma_rib.w_valid;
assign dma_rib.cmd_ready = bus_state_q == BUS_IDLE;
assign dma_rib.w_ready = (bus_state_q == BUS_WRITE_DATA) && ws_ribp.ready;
assign dma_rib.rsp_valid = (bus_state_q == BUS_READ_RESP) || (bus_state_q == BUS_WRITE_RESP);
assign dma_rib.rdata = pixels[bus_addr_q[4:2]];
assign dma_rib.resp_err = 1'b0;
assign dma_rib.resp_code = `RIB_RESP_OK;
assign dma_rib.rsp_beat = 2'd0;
assign dma_rib.rsp_last = 1'b1;
assign dma_ws_valid = (bus_state_q == BUS_WRITE_DATA) && dma_rib.w_valid;
assign i2s_tx_axis.tready = 1'b0;
assign i2s_rx_axis.tdata = '0;
assign i2s_rx_axis.tkeep = '0;
assign i2s_rx_axis.tstrb = '0;
assign i2s_rx_axis.tlast = 1'b0;
assign i2s_rx_axis.tid = '0;
assign i2s_rx_axis.tdest = '0;
assign i2s_rx_axis.tuser = '0;
assign i2s_rx_axis.tvalid = 1'b0;
assign dvp_rx_axis.tdata = '0;
assign dvp_rx_axis.tkeep = '0;
assign dvp_rx_axis.tstrb = '0;
assign dvp_rx_axis.tlast = 1'b0;
assign dvp_rx_axis.tid = '0;
assign dvp_rx_axis.tdest = '0;
assign dvp_rx_axis.tuser = '0;
assign dvp_rx_axis.tvalid = 1'b0;
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
@@ -142,7 +171,10 @@ module ws2812_dma_tb;
.error_addr_o(dma_error_addr),
.fsm_o (dma_fsm),
.hw_trg (hw_trg),
.rib (dma_rib)
.rib (dma_rib),
.i2s_tx_axis (i2s_tx_axis),
.i2s_rx_axis (i2s_rx_axis),
.dvp_rx_axis (dvp_rx_axis)
);
ribp_ws2812 #(
+113
View File
@@ -0,0 +1,113 @@
"""Directed tests for the active AXI4 fabric adapters."""
from __future__ import annotations
import os
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_axi42ribp_supports_bursts_backpressure_and_errors(tmp_path: Path) -> None:
verilator = shutil.which("verilator")
if verilator is None:
return
output = tmp_path / "axi42ribp_burst_tb"
ccache_tmp = tmp_path / "ccache"
ccache_tmp.mkdir()
subprocess.run(
[
verilator,
"--binary",
"--timing",
"-Wno-fatal",
"--top-module",
"axi42ribp_burst_tb",
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/mini/top/axi42ribp_burst.sv"),
str(ROOT / "tests/rtl/axi42ribp_burst_tb.sv"),
"-Mdir",
str(tmp_path / "obj"),
"-o",
str(output),
],
check=True,
text=True,
capture_output=True,
env={
**os.environ,
"CCACHE_DIR": str(ccache_tmp),
"CCACHE_TEMPDIR": str(ccache_tmp),
},
)
result = subprocess.run([output], check=True, text=True, capture_output=True)
assert "AXI4 to RIBP burst bridge test passed" in result.stdout
def test_axi4_interconnect_classifies_decode_protocol_and_access_errors(
tmp_path: Path,
) -> None:
verilator = shutil.which("verilator")
if verilator is None:
return
memory_map = tmp_path / "memory_map"
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/address_map/generate_memory_map.py"),
"--map",
str(ROOT / "rtl/mini/address_map/memory_map.json"),
"--output-dir",
str(memory_map),
"--have-sram-if",
"NO",
],
check=True,
)
output = tmp_path / "axi4_interconnect_tb"
ccache_tmp = tmp_path / "ccache"
ccache_tmp.mkdir()
subprocess.run(
[
verilator,
"--binary",
"--timing",
"-Wno-fatal",
"--top-module",
"axi4_interconnect_tb",
"-I" + str(memory_map / "rtl"),
"-I" + str(ROOT / "rtl/mini/top"),
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/stream/round_robin_arbiter.sv"),
str(ROOT / "rtl/mini/top/axi4_interconnect.sv"),
str(ROOT / "rtl/mini/top/axi4_error_slave.sv"),
str(ROOT / "tests/rtl/axi4_interconnect_tb.sv"),
"-Mdir",
str(tmp_path / "obj"),
"-o",
str(output),
],
check=True,
text=True,
capture_output=True,
env={
**os.environ,
"CCACHE_DIR": str(ccache_tmp),
"CCACHE_TEMPDIR": str(ccache_tmp),
},
)
result = subprocess.run([output], check=True, text=True, capture_output=True)
assert "AXI4 interconnect fault classification test passed" in result.stdout
+2 -1
View File
@@ -40,6 +40,7 @@ def test_dma_reports_bus_errors_and_transfers_exact_word_count(tmp_path: Path) -
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
f"+incdir+{ROOT / 'rtl/mini/top'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_stream_if.sv"),
str(ROOT / "rtl/mini/top/rib_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv"),
@@ -69,4 +70,4 @@ def test_dma_reports_bus_errors_and_transfers_exact_word_count(tmp_path: Path) -
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "dma error and burst performance test passed" in result.stdout
assert "dma error, burst performance, and AXI4-Stream test passed" in result.stdout
+1
View File
@@ -148,6 +148,7 @@ def test_bus_fault_responder_handles_reserved_and_unmapped_addresses(tmp_path: P
f"+incdir+{tmp_path / 'rtl'}",
f"+incdir+{tmp_path / 'user_extensions' / 'rtl'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ram_if.sv"),
str(ROOT / "rtl/mini/top/rib_if.sv"),
+1
View File
@@ -39,6 +39,7 @@ def test_bus_preserves_incr4_and_rejects_illegal_bursts(tmp_path: Path) -> None:
f"+incdir+{memory_map / 'rtl'}",
f"+incdir+{ROOT / 'rtl/mini/top'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ram_if.sv"),
str(ROOT / "rtl/mini/top/rib_if.sv"),
+1 -1
View File
@@ -737,7 +737,7 @@ def test_management_core_is_fixed_to_hazard3_with_debug() -> None:
assert "CORE_$(CORE)" not in makefile
assert "`ifdef CORE_" not in wrapper
assert "`ifdef HAVE_DEBUG" not in wrapper
assert "ahbl2ribp u_ahbl2ribp" in wrapper
assert "ahbl2axi4 u_ahbl2axi4" in wrapper
assert ".RESET_VECTOR (`SOC_CPU_RESET_ADDR)" in wrapper
assert ".DEBUG_SUPPORT (1)" in wrapper
+7 -7
View File
@@ -79,7 +79,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "assign s_slv_sel_d[17] = u_i2c1_ribp_if.valid;" in routes
assert "assign s_slv_resp_err[17] = u_i2c1_ribp_if.resp_err;" in routes
assert "assign ribp.resp_err = |(s_slv_sel_q & s_slv_ready & s_slv_resp_err);" in routes
assert "assign s_xpi_region_sel[1] = (ribp.addr <= `SOC_ADDR_FLASH_END);" in routes
assert "SOC_ADDR_FLASH" not in routes
assert "assign u_sdio_ribp_if.valid = 1'b0;" in routes
assert gpio.count("// GPIO") == 64
assert "u_uart1_if" not in gpio
@@ -106,12 +106,12 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "assign user_ip.paddr = s_addr_q;" in apb_routes
assert "({32{s_psel_q[7]}} & user_ip.prdata)" in apb_response
assert "localparam int NSLV = 8;" in apb_declarations
assert fabric.count("ribp_if u_") == 1
assert fabric.count("rib_if u_") == 4
assert ".mgmt_ribp(u_mgmt_ribp_if)" in bus_fabric
assert ".user_rib(u_user_rib_if)" in bus_fabric
assert ".apb_rib(u_apb_rib_if)" in bus_fabric
assert ".rib(u_rib_if)" in bus_fabric
assert fabric.count("axi4_if #(") == 5
assert ".mgmt_axi4(u_mgmt_axi4_if)" in bus_fabric
assert ".user_axi4(u_user_axi4_if)" in bus_fabric
assert ".dma_axi4(u_dma_axi4_if)" in bus_fabric
assert ".cfg_axi4(u_cfg_axi4_if)" in bus_fabric
assert ".apb_axi4(u_apb_axi4_if)" in bus_fabric
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
assert "`define SOC_USER_IRQ_MASK 32'h000E7BFC" in irq_config
assert "`define SOC_IRQ_RIBP_WIDTH 13" in irq_config
+1
View File
@@ -96,6 +96,7 @@ def test_ws2812_accepts_dma_fixed_destination_backpressure(tmp_path: Path) -> No
f"+incdir+{ROOT / 'rtl/mini/top'}",
f"+incdir+{serial}",
str(common / "interface/ribp_if.sv"),
str(common / "interface/axi4_stream_if.sv"),
str(ROOT / "rtl/mini/top/rib_if.sv"),
str(common / "utils/register.sv"),
str(common / "utils/fifo.sv"),