mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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:
65 files changed
+4271
-649
No files matched your search
@@ -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"},
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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)®_i2s_txdata, 0U, 512U) != RS_OK) ||
|
||||
if ((rs_dma_config(RS_DMA_MODE_I2S_TX, 0x40000000U, 1U, (uintptr_t)®_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)®_i2s_rxdata, 0U, 0x41000000U, 1U, 180U) != RS_OK) ||
|
||||
reg_i2s_stream_ctrl = 2U;
|
||||
if ((rs_dma_config(RS_DMA_MODE_I2S_RX, (uintptr_t)®_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
@@ -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)®_i2s_txdata, 0U,
|
||||
(rs_dma_config(RS_DMA_MODE_I2S_TX, start_address + info.data_offset, 1U,
|
||||
(uintptr_t)®_i2s_txdata, 0U,
|
||||
info.data_size / sizeof(uint32_t)) != RS_OK)) {
|
||||
printf("wav file parse/configuration error\n");
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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"];
|
||||
}
|
||||
+427
-373
File diff suppressed because it is too large.
Load diff
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 65 KiB |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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)
|
||||
);
|
||||
|
||||
|
||||
@@ -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 #(
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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 #(
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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"),
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in new issue
Block a user