feat: enhance testbench and system control for GA2D and data plane fault handling

- Updated onchip_ram64_tb to increase ID_WIDTH from 6 to 7 and adjusted related write/read tasks.
- Modified resource_controller_tb to accommodate an expanded resource count from 8 to 9, updating related logic signals.
- Enhanced sysctrl_tb to introduce new fault handling logic for data plane faults, including additional fault validation and delivery mechanisms.
- Added tests for clock and reset domains to ensure proper handling of data plane faults and their reset contracts.
- Introduced new test_ga2d_platform.py to verify GA2D Phase 2 functionality, including lifecycle and recovery processes.
- Updated test_soc_topology.py to ensure proper data master policies and validate GA2D integration within the system.
- Enhanced sysctrl.py to ensure the fault master retains the high bit for data plane faults.
This commit is contained in:
maksyuki committed 2026-09-14 07:19:18 +08:00
1 parent 8dd24e7880
commit e77d7b3299
61 files changed
+2911 -610

No files matched your search

+4 -2
View File
@@ -13,9 +13,11 @@ typedef enum {
RS_FABRIC_MASTER_IO_A = 3,
RS_FABRIC_MASTER_IO_B = 4,
RS_FABRIC_MASTER_LP = 5,
RS_FABRIC_MASTER_RESERVED = 6,
RS_FABRIC_MASTER_JPEG = 6,
RS_FABRIC_MASTER_RESERVED = RS_FABRIC_MASTER_JPEG,
RS_FABRIC_MASTER_EXT_H = 7,
RS_FABRIC_MASTER_COUNT = 8,
RS_FABRIC_MASTER_GA2D = 8,
RS_FABRIC_MASTER_COUNT = 9,
} rs_fabric_master_t;
typedef enum {
+2 -1
View File
@@ -15,7 +15,8 @@ typedef enum {
RS_RESOURCE_EXT_H = 5,
RS_RESOURCE_JPEG = 6,
RS_RESOURCE_APU = 7,
RS_RESOURCE_COUNT = 8,
RS_RESOURCE_GA2D = 8,
RS_RESOURCE_COUNT = 9,
} rs_resource_t;
typedef enum {
+42 -26
View File
@@ -4,35 +4,45 @@
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/fabric_monitor.h>
#define RS_FABRIC_CONTROL_OFFSET UINT32_C(0x00C)
#define RS_FABRIC_STATUS_OFFSET UINT32_C(0x010)
#define RS_FABRIC_FAULT_OFFSET UINT32_C(0x014)
#define RS_FABRIC_FAULT_ADDR_OFFSET UINT32_C(0x018)
#define RS_FABRIC_FLUSH_COUNT_OFFSET UINT32_C(0x01C)
#define RS_FABRIC_FAULT_COUNT_OFFSET UINT32_C(0x020)
#define RS_FABRIC_MASTER_BASE UINT32_C(0x100)
#define RS_FABRIC_TARGET_BASE UINT32_C(0x300)
#define RS_FABRIC_ENTRY_STRIDE UINT32_C(0x020)
#define RS_FABRIC_CONTROL_ENABLE UINT32_C(0x00000001)
#define RS_FABRIC_CONTROL_FREEZE UINT32_C(0x00000002)
#define RS_FABRIC_CONTROL_CLEAR UINT32_C(0x00000004)
#define RS_FABRIC_CONTROL_SNAPSHOT UINT32_C(0x00000008)
#define RS_FABRIC_STATUS_IDLE UINT32_C(0x00000001)
#define RS_FABRIC_STATUS_RECOVERY UINT32_C(0x00000002)
#define RS_FABRIC_STATUS_FLUSH_BUSY UINT32_C(0x00000004)
#define RS_FABRIC_STATUS_READ_SHIFT 8U
#define RS_FABRIC_STATUS_WRITE_SHIFT 16U
#define RS_FABRIC_HIGH_WATER_MASK UINT32_C(0x00000007)
#define RS_FABRIC_WRITE_HIGH_SHIFT 3U
#define RS_FABRIC_FAULT_WRITE UINT32_C(0x00000002)
#define RS_FABRIC_FAULT_MASTER_SHIFT 2U
#define RS_FABRIC_FAULT_TARGET_SHIFT 5U
#define RS_FABRIC_FAULT_REASON_SHIFT 8U
#define RS_FABRIC_FAULT_FIELD_MASK UINT32_C(0x00000007)
#define RS_FABRIC_FAULT_REASON_MASK UINT32_C(0x0000000F)
#define RS_FABRIC_CONTROL_OFFSET UINT32_C(0x00C)
#define RS_FABRIC_STATUS_OFFSET UINT32_C(0x010)
#define RS_FABRIC_FAULT_OFFSET UINT32_C(0x014)
#define RS_FABRIC_IP_VERSION_OFFSET UINT32_C(0x004)
#define RS_FABRIC_FAULT_ADDR_OFFSET UINT32_C(0x018)
#define RS_FABRIC_FLUSH_COUNT_OFFSET UINT32_C(0x01C)
#define RS_FABRIC_FAULT_COUNT_OFFSET UINT32_C(0x020)
#define RS_FABRIC_MASTER_BASE UINT32_C(0x100)
#define RS_FABRIC_TARGET_BASE UINT32_C(0x300)
#define RS_FABRIC_ENTRY_STRIDE UINT32_C(0x020)
#define RS_FABRIC_CONTROL_ENABLE UINT32_C(0x00000001)
#define RS_FABRIC_CONTROL_FREEZE UINT32_C(0x00000002)
#define RS_FABRIC_CONTROL_CLEAR UINT32_C(0x00000004)
#define RS_FABRIC_CONTROL_SNAPSHOT UINT32_C(0x00000008)
#define RS_FABRIC_STATUS_IDLE UINT32_C(0x00000001)
#define RS_FABRIC_STATUS_RECOVERY UINT32_C(0x00000002)
#define RS_FABRIC_STATUS_FLUSH_BUSY UINT32_C(0x00000004)
#define RS_FABRIC_STATUS_READ_SHIFT 8U
#define RS_FABRIC_STATUS_WRITE_SHIFT 16U
#define RS_FABRIC_HIGH_WATER_MASK UINT32_C(0x00000007)
#define RS_FABRIC_WRITE_HIGH_SHIFT 3U
#define RS_FABRIC_FAULT_WRITE UINT32_C(0x00000002)
#define RS_FABRIC_FAULT_MASTER_SHIFT 2U
#define RS_FABRIC_FAULT_TARGET_SHIFT 5U
#define RS_FABRIC_FAULT_REASON_SHIFT 8U
#define RS_FABRIC_FAULT_FIELD_MASK UINT32_C(0x00000007)
#define RS_FABRIC_FAULT_REASON_MASK UINT32_C(0x0000000F)
#define RS_FABRIC_FAULT_MASTER_HIGH UINT32_C(0x00001000)
#define RS_FABRIC_FAULT_MASTER_HIGH_SHIFT 9U
#define RS_FABRIC_IP_VERSION_V1_1 UINT32_C(0x00010001)
static volatile uint32_t *rs_fabric_register(uint32_t offset) {
#if defined(RS_FABRIC_MONITOR_TEST_MMIO)
extern volatile uint32_t rs_fabric_monitor_test_mmio[1024];
return &rs_fabric_monitor_test_mmio[offset / sizeof(uint32_t)];
#else
return (volatile uint32_t *)(RS_SOC_APB4_FABRIC_MONITOR_BASE + (uintptr_t)offset);
#endif
}
static uint32_t rs_fabric_control_value(bool enable, bool freeze) {
@@ -93,14 +103,20 @@ rs_status_t rs_fabric_monitor_get_flush_count(uint32_t *count) {
rs_status_t rs_fabric_monitor_read_fault(rs_fabric_fault_t *fault) {
uint32_t value;
uint32_t version;
if (fault == NULL) {
return RS_EINVAL;
}
version = *rs_fabric_register(RS_FABRIC_IP_VERSION_OFFSET);
value = *rs_fabric_register(RS_FABRIC_FAULT_OFFSET);
fault->address = *rs_fabric_register(RS_FABRIC_FAULT_ADDR_OFFSET);
fault->count = *rs_fabric_register(RS_FABRIC_FAULT_COUNT_OFFSET);
fault->master = (uint8_t)((value >> RS_FABRIC_FAULT_MASTER_SHIFT) & RS_FABRIC_FAULT_FIELD_MASK);
if (version >= RS_FABRIC_IP_VERSION_V1_1) {
fault->master |=
(uint8_t)((value & RS_FABRIC_FAULT_MASTER_HIGH) >> RS_FABRIC_FAULT_MASTER_HIGH_SHIFT);
}
fault->target = (uint8_t)((value >> RS_FABRIC_FAULT_TARGET_SHIFT) & RS_FABRIC_FAULT_FIELD_MASK);
fault->reason =
(uint8_t)((value >> RS_FABRIC_FAULT_REASON_SHIFT) & RS_FABRIC_FAULT_REASON_MASK);
+16 -10
View File
@@ -6,10 +6,13 @@ plane. Common `axi4_if`, `memory_map.json`, and `soc_topology.json` are the
executable protocol, address, and integration sources of truth.
[GA2D Phase 2](ip/ga2d.md#phase-2---expand-axi64-fabric-and-resource-integration)
is the approved, pending expansion to nine native masters and seven-bit global
IDs. It adds master 8 and preserves all existing identities, target policy,
and timeout behavior. The GA2D specification also records the existing
master-6/JPEG admission discrepancy; it must not be interpreted as a free port.
expands the fabric to nine native masters and seven-bit global IDs. It adds
master 8 and preserves all existing identities, target policy, and timeout
behavior. Master 8 is fed only by its dedicated PCLK-to-HP AXI64/ID3 bridge,
whose source is idle. `APB4_GA` remains reserved and inactive; the GA2D APB
shell, IRQ, payload/DMA, and pixel function remain deferred. The GA2D
specification also records the existing master-6/JPEG admission discrepancy;
it must not be interpreted as a free port.
## LP control plane
@@ -31,8 +34,8 @@ master from writing SYSCTRL/RCU, watchdog, and GPIO administration windows.
## HP data plane
The native payload fabric is AXI64 with 32-bit addresses and six-bit global
IDs. It has eight masters:
The native payload fabric is AXI64 with 32-bit addresses and seven-bit global
IDs. It has nine masters:
| Index | Master | Adaptation |
| ---: | --- | --- |
@@ -42,10 +45,12 @@ IDs. It has eight masters:
| 3 | I/O gateway A | USB2 and SDIO0, PCLK-to-HP CDC, AXI32-to-64 |
| 4 | I/O gateway B | SDIO1 and SPI-SD, PCLK-to-HP CDC, AXI32-to-64 |
| 5 | LP data gateway | Hazard3 memory traffic, LP-to-HP CDC, AXI32-to-64 |
| 6 | reserved | permanently idle and denied |
| 6 | JPEG | PCLK-to-HP AXI64 CDC; zero normal admission credit (`GA2D-GAP-01`) |
| 7 | EXT-H | PCLK-to-HP AXI64 CDC |
| 8 | GA2D bridge placeholder | dedicated PCLK-to-HP AXI64/ID3 CDC; source held idle |
Each source receives a fixed three-bit master prefix. The crossbar maintains
Each source receives a fixed four-bit master prefix over a three-bit source
ID. The crossbar maintains
independent read and write arbitration for each target, enabling read/write
overlap and cross-target concurrency. Different IDs from HP/DMA/EXT-H may be
active on the same or different targets up to master and target credits. The
@@ -54,7 +59,7 @@ reads and two writes; serial and error targets use one read and one write.
| Target | Current backend |
| --- | --- |
| on-chip SRAM | native AXI64/ID6 striped technology macros in HP |
| on-chip SRAM | native AXI64/ID7 striped technology macros in HP |
| SDRAM | HP-to-memory AXI64 CDC, local 64-to-32 SDRAM adaptation |
| QPI PSRAM | AXI64-to-32, CDC, selected QPI frontend |
| OPI/HyperBus | AXI64-to-32, CDC, selected OPI frontend |
@@ -69,7 +74,8 @@ the integration RTL:
| HP I-cache | all five memories | none | allowed | cache attributes preserved |
| HP D-cache | all five memories | SRAM, SDRAM, QPI, OPI | denied | cache attributes preserved |
| DMA, I/O A/B, LP gateway | all five memories | SRAM, SDRAM, QPI, OPI | denied | `AxCACHE=0` required |
| reserved | none | none | denied | fail-closed |
| GA2D bridge placeholder | all five memories | SRAM, SDRAM, QPI, OPI | denied | `AxCACHE=0` required; source is idle in P2 |
| JPEG | none | none | denied | zero normal admission credit (`GA2D-GAP-01`) |
| EXT-H | all five memories within slot ACL | SRAM, SDRAM, QPI, OPI within slot ACL | denied | `AxCACHE=0` required |
XPI is read-only on the data plane. A denied target, instruction access,
+8 -5
View File
@@ -15,16 +15,19 @@ ecosystem of the referenced devices. Official sources were rechecked on
| [NXP i.MX RT1180](https://www.nxp.com/products/i.MX-RT1180) and [reference manual](https://www.nxp.com/docs/en/reference-manual/IMXRT1180RM.pdf) | Heterogeneous M7/M33 resource isolation and recovery; TRDC assigns initiators to fixed domains and protects memory/peripheral regions, while SRC owns slice reset | Current product; RM Rev 10.0 and data-sheet updates were published in 2026. Depends on TrustZone/security lifecycle and NXP clock/reset IP | Reuse immutable master identity, root-owned policy, fail-closed regions, and slice lifecycle. Avoid pretending a software owner field alone is a security boundary or importing the full secure lifecycle |
| [ST STM32MP resource manager](https://wiki.st.com/stm32mpu/wiki/Resource_manager_for_coprocessing), [coprocessor management](https://wiki.st.com/stm32mpu/wiki/Coprocessor_management_overview), and [RIFSC](https://wiki.st.com/stm32mpu/wiki/RIFSC_internal_peripheral) | Prevents Linux and MCU firmware from driving the same peripheral; boot-time ETZPC/RIF hardware assignment is mirrored in device tree, RemoteProc/RPMsg/mailbox, and resource-manager software | Active STM32MP1/MP2 documentation, updated through 2025-2026. Depends on TF-A, OP-TEE, Linux device tree, mailbox, and remoteproc services | Reuse quiesce-before-owner-change, hardware exclusion, and one-owner IRQ routing. Defer the Linux resource driver; avoid split hardware/software ownership tables without parity checks |
| [TI AM62x host identities](https://software-dl.ti.com/tisci/esd/latest/5_soc_doc/am62x/hosts.html), [firewalls](https://software-dl.ti.com/tisci/esd/11_01_05/5_soc_doc/am62x/firewalls.html), and [RM board configuration](https://software-dl.ti.com/mcu-plus-sdk/esd/AM62X/09_00_00_19/exports/docs/api_guide_am62x/RESOURCE_ALLOCATION_GUIDE.html) | Prevents initiator spoofing and unauthorized memory/resource use; immutable host IDs select boot-configured firewall permissions and resource ranges through system firmware | Current TISCI/Processor SDK pages were published or crawled in 2026. Depends on TIFS/DM firmware, secure proxy, boardcfg, and interconnect privilege IDs | Reuse generated fixed identities, boot policy, explicit read/write/cache permissions, and first-fault evidence. Avoid a privileged message stack and runtime-reprogrammable policy in this MVP |
| [Arm NIC-400 optimization](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Cycle%20Models/White%20Papers/ARM%20CoreLink%20NIC-400%20Optimization.pdf) and [Arm system QoS](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Quality%20of%20Service%20QoS%20in%20Arm%20Systems.pdf) | Scales mixed AXI/AHB/APB widths and clocks while controlling latency and bandwidth; target-local buffering, register slices, outstanding limits, hierarchical gateways, and QoS regulators are topology parameters | NIC-400 is mature rather than new; Arm still published an updated QoS guide in 2026. Commercial use depends on licensed IP/configuration and performance modelling | Reuse target-aware credits, independent channel/CDC boundaries, hierarchical I/O gateways, measurable wait/high-water counters, and bounded promotion. Avoid a packetized NoC, virtual networks, and opaque generated RTL for an 8x6 fabric |
| [Arm NIC-400 optimization](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Cycle%20Models/White%20Papers/ARM%20CoreLink%20NIC-400%20Optimization.pdf) and [Arm system QoS](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Quality%20of%20Service%20QoS%20in%20Arm%20Systems.pdf) | Scales mixed AXI/AHB/APB widths and clocks while controlling latency and bandwidth; target-local buffering, register slices, outstanding limits, hierarchical gateways, and QoS regulators are topology parameters | NIC-400 is mature rather than new; Arm still published an updated QoS guide in 2026. Commercial use depends on licensed IP/configuration and performance modelling | Reuse target-aware credits, independent channel/CDC boundaries, hierarchical I/O gateways, measurable wait/high-water counters, and bounded promotion. Avoid a packetized NoC, virtual networks, and opaque generated RTL for a 9x6 fabric |
## Technical Selection
Mini remains a small, non-coherent, performance-first SoC. Hazard3 is the
only root-management master. Vexii I/D, DMA, I/O gateways, the LP data gateway,
and EXT-H use an eight-master native AXI64 data plane. APB remains a separate
control plane. Every data initiator has a generated fixed identity, target
permissions, execute/cache-attribute rules, outstanding limit, QoS class, and
fault attribution.
EXT-H, and an idle GA2D bridge placeholder use a nine-master native AXI64 data
plane with seven-bit global IDs. The placeholder is a dedicated
PCLK-to-HP AXI64/ID3 bridge only: `APB4_GA` remains reserved and inactive, and
the GA2D APB shell, IRQ, payload/DMA, and pixel function remain deferred. APB
remains a separate control plane. Every data initiator has a generated fixed
identity, target permissions, execute/cache-attribute rules, outstanding
limit, QoS class, and fault attribution.
The design combines the references at their smallest useful boundary:
+2 -2
View File
@@ -227,8 +227,8 @@ contract.
The APU provides one PCLK-domain 32-bit AXI4 master with 32-bit addresses,
one-bit ID/user, and ID zero. It occupies the unused third input of I/O Gateway
A and uses the existing PCLK-to-HP `axi4_async_bridge` and 32-to-64 upsizer.
It retains global data-master identity 3; the eight-master crossbar and global
ID width do not expand.
It retains global data-master identity 3; the nine-master crossbar and
seven-bit global ID width preserve that identity.
Gateway A MUST replace its fixed-priority selection with a burst-boundary
Common round-robin arbiter among APU, SDIO0, and USB2. Ownership is retained
+15 -11
View File
@@ -1,10 +1,11 @@
# Mini Data-Plane Fabric Monitor
The approved [GA2D Phase 2](ga2d.md#phase-2---expand-axi64-fabric-and-resource-integration)
[GA2D Phase 2](ga2d.md#phase-2---expand-axi64-fabric-and-resource-integration)
adds master bank 8, version 1.1, and master bit 3 at `FAULT[12]`, preserving
the existing packed fields. It also requires complete four-bit master identity
through SYSCTRL. These are pending implementation changes, not current monitor
capabilities; the freeze does not alter executable RTL or HAL definitions.
the existing packed fields. It also carries the complete four-bit master
identity through SYSCTRL. Bank 8 observes the dedicated PCLK-to-HP
AXI64/ID3 GA2D bridge placeholder, whose source is idle; it does not imply an
implemented GA2D APB shell, IRQ, payload/DMA, or pixel function.
## Scope
@@ -24,11 +25,11 @@ so a multi-register sample is stable while live counting continues.
| Offset | Name | Access | Contract |
| ---: | --- | --- | --- |
| `0x000` | `IP_ID` | RO | `0x44504D4E` (`DPMN`) |
| `0x004` | `IP_VERSION` | RO | `0x00010000` |
| `0x004` | `IP_VERSION` | RO | `0x00010001` |
| `0x008` | `CAPABILITY` | RO | target count `[31:24]`, master count `[23:16]`, saturating/snapshot capability `[1:0]` |
| `0x00C` | `CONTROL` | RW | enable bit 0, freeze bit 1, clear pulse bit 2, snapshot pulse bit 3 |
| `0x010` | `STATUS` | RO | write outstanding `[23:16]`, read outstanding `[15:8]`, flush busy bit 2, recovery bit 1, idle bit 0 |
| `0x014` | `FAULT` | RO | reason `[11:8]`, target `[7:5]`, master `[4:2]`, write bit 1, valid bit 0 |
| `0x014` | `FAULT` | RO | master high bit 3 `[12]`, reason `[11:8]`, target `[7:5]`, master low bits `[4:2]`, write bit 1, valid bit 0 |
| `0x018` | `FAULT_ADDRESS` | RO | address of the first retained fault |
| `0x01C` | `FLUSH_COUNT` | RO | snapshotted warm-flush rising-edge count |
| `0x020` | `FAULT_COUNT` | RO | live count of all observed fault events |
@@ -41,12 +42,14 @@ does not clear state.
The first fault after reset or clear is sticky. Later faults increment
`FAULT_COUNT` but do not overwrite its identity or address. This preserves the
root cause across the PCLK-to-HP bridge and prevents a short data-plane pulse
from being missed by software.
root cause across the PCLK-to-HP bridge. The monitor counts data-plane faults
only when their HP valid/ready report handshake succeeds, so mailbox
backpressure does not duplicate or lose an accepted event.
## Master Counter Banks
Eight master banks start at `0x100 + master * 0x20`:
Nine master banks start at `0x100 + master * 0x20`. Master bank 8 occupies
`0x200..0x21F`:
| Relative offset | Counter |
| ---: | --- |
@@ -60,8 +63,9 @@ Eight master banks start at `0x100 + master * 0x20`:
| `0x1C` | write high-water `[5:3]`, read high-water `[2:0]` |
Master indices are HP I-cache, HP D-cache, central DMA, I/O gateway A, I/O
gateway B, LP data gateway, reserved, and EXT-H. The reserved slot remains
visible so an integration defect cannot silently disappear from accounting.
gateway B, LP data gateway, JPEG, EXT-H, and the idle GA2D bridge placeholder.
JPEG remains visible with zero normal admission credit (`GA2D-GAP-01`), so an
integration defect cannot silently disappear from accounting.
## Target Counter Banks
+16 -7
View File
@@ -898,7 +898,14 @@ comparing recipes. The full product must be analyzed, including wider ID and
interrupt routing. Report unclosed timing honestly; it blocks a frequency or
verified-readiness claim rather than authorizing a new timing contract.
The existing implementation workflow's final IHP130 command is:
Only Phase 6 executes synthesis, OpenSTA, netlist simulation, warning
collection, and metric collection for GA2D. Earlier phases require their
listed directed functional, integration, firmware, and lint/formal evidence,
but defer full-product physical evidence to Phase 6. This scheduling does not
waive any GA2D-V14 requirement or permit an earlier phase to claim
verified-readiness.
The Phase 6 final IHP130 command is:
```sh
python3 scripts/regress.py --root . --suite pr --pdk IHP130 --netsim-boot-only
@@ -987,9 +994,9 @@ make CONFIG=configs/cluster/mini-mpw.mk SIMU=VERILATOR comp
```
Completion: GA2D-V01/V02 pass for this boundary; all old IRQ mappings and
debug/timer/exception paths remain usable. Report missing synthesis/timing
evidence for the expanded priority encoder; do not change priority width or
reset behavior to avoid a failure.
debug/timer/exception paths remain usable. Synthesis/timing evidence is
deferred exclusively to Phase 6; do not change priority width or reset
behavior to avoid a failure.
### Phase 2 - Expand AXI64 Fabric and Resource Integration
@@ -1021,8 +1028,9 @@ make CONFIG=configs/ci/ihp130.mk HAVE_CSR=YES APP=ci_smoke SIMU=VERILATOR firmwa
Completion: GA2D-V01/V03/V08 platform cases pass with master-8 BFM traffic,
old/new IDs cannot alias, the new source has one credit per direction, and
all target/monitor routes retain ID7. Include affected synthesis/STA and
export/netlist evidence; a parameter-only elaboration pass is insufficient.
all target/monitor routes retain ID7. Synthesis, STA, netlist, warning, and
metric evidence is deferred exclusively to Phase 6; a parameter-only
elaboration pass is insufficient for this phase's directed platform cases.
### Phase 3 - GA2D Naming Migration and APB4 Shell
@@ -1115,7 +1123,8 @@ ID: `GA2D-P6`.
Dependencies: Phase 5 and resolution/evidence of applicable baseline gaps.
Scope: complete HAL/host checks, real LP ISR and HP acceptance payloads,
cache/ownership handoff, deterministic benchmark/report artifacts, randomized
campaign, competing-master progress, full regression, and physical evidence.
campaign, competing-master progress, full regression, and the only GA2D
synthesis/timing/netlist/physical-evidence execution phase.
Changes: tests, SDK/app acceptance and benchmark integration, documentation
and evidence/readiness records justified by results. No frozen allocation,
+3 -3
View File
@@ -5,7 +5,7 @@
The Mini SoC on-chip SRAM is a synthesis-time configurable AXI4 target backed
by fixed 32-bit single-port technology wrappers. The reusable module keeps a
32-bit/ID1 compatibility mode; the Mini product instantiates native
64-bit/ID6 and stripes each beat over two wrappers. Supported capacities are
64-bit/ID7 and stripes each beat over two wrappers. Supported capacities are
4, 16, 32, 64, and 128 KiB in compatibility mode; the product selects 32 KiB.
The data aperture starts at
`0x3000_0000`; its generated end address and linker length match the selected
@@ -59,7 +59,7 @@ with `PRESENT=0`, zero memory bytes, and zero banks.
## AXI4 datapath
The product target uses 32-bit addresses, 64-bit data, six-bit ID, and one-bit
The product target uses 32-bit addresses, 64-bit data, seven-bit ID, and one-bit
USER. It accepts one active read or write transaction, gives AR priority when
AR and AW are simultaneously valid, and preserves the ID to the terminal
response. The compatibility parameterization retains 32-bit data and one-bit
@@ -142,7 +142,7 @@ malformed accesses, counters, all four PDK wrapper polarities and masks, and
the GF180 511/512 depth boundary. The setup tests independently validate the
SKY130 artifact manifest and generated-file hashes. Full Verilator regression
firmware exercises the first and last locations through the SoC interconnect.
The native AXI64 test additionally covers six-bit IDs, continuous 64-bit bursts,
The native AXI64 test additionally covers seven-bit IDs, continuous 64-bit bursts,
and upper/lower 32-bit byte strobes.
`make CONFIG=configs/ci/ihp130.mk formal-onchip-ram` runs a 20-cycle bounded
+30 -16
View File
@@ -1,10 +1,12 @@
# Mini Resource Controller
The approved [GA2D contract](ga2d.md) adds resource 8 and version 1.1 during
its Phase 2, with LP vector 32 / HP PLIC source 11 connected in Phase 3.
Its source-stop/drain-before-block sequence is specified there. These changes
are pending implementation; the existing resources and register fields below
are not renumbered or reinterpreted by the documentation freeze.
[GA2D Phase 2](ga2d.md#phase-2---expand-axi64-fabric-and-resource-integration)
adds resource 8 and version 1.1. It covers only the dedicated PCLK-to-HP
AXI64/ID3 GA2D bridge placeholder, whose source is idle. LP vector 32 / HP
PLIC source 11 and GA2D APB-shell wiring remain Phase 3 work; `APB4_GA`
therefore remains reserved and inactive. Its source-stop/drain-before-block
sequence is specified there. Existing resources and register fields are not
renumbered or reinterpreted.
## Scope
@@ -27,17 +29,20 @@ Resource indices are fixed:
| 5 | EXT-H | 3 |
| 6 | JPEG | 9 |
| 7 | APU | 10 |
| 8 | GA2D bridge placeholder (idle) | 11, not routed until Phase 3 |
Owner `0` routes the resource interrupt to the existing LP vector. Owner `1`
removes it from LP and routes it to the listed HP PLIC source. Reset masks both
routes. Hardware never delivers one resource interrupt to both owners.
For resources 0 through 7, owner `0` routes the resource interrupt to the
existing LP vector. Owner `1` removes it from LP and routes it to the listed HP
PLIC source. Resource 8 has a fixed-inactive raw IRQ and no LP or HP IRQ route
until Phase 3. Reset masks both applicable routes. Hardware never delivers one
resource interrupt to both owners.
## Register ABI
| Offset | Name | Access | Contract |
| ---: | --- | --- | --- |
| `0x000` | `IP_ID` | RO | `0x52534354` (`RSCT`) |
| `0x004` | `IP_VERSION` | RO | `0x00010000` |
| `0x004` | `IP_VERSION` | RO | `0x00010001` |
| `0x008` | `CAPABILITY` | RO | resource count and ABI capability |
| `0x00C` | `GLOBAL_STATUS` | RO | cache request/clean and resource fault summary |
| `0x010` | `CACHE_CONTROL` | RW | bit 0 clean ACK, bit 1 live request |
@@ -61,6 +66,13 @@ leaves the owner unchanged, and raises the resource-fault interrupt on LP IRQ
condition for DMA and I/O resources; this is safe but can delay an otherwise
independent handoff.
For resource 8, the PCLK source stop admits an already presented address
handshake before closing new traffic. Its HP block and acknowledgement require
a fresh synchronized source-quiesced confirmation after the source has drained
its AXI state. This prevents a stale idle indication from acknowledging a legal
`WVALID`-before-`AWVALID` write. The PCLK controller view also qualifies
resource-8 idle and ACK with the live source-safe-idle signal.
## Cache Maintenance
VexiiRiscv implements `Zicbom` with a 64-byte CBO block. On HP shutdown the AON
@@ -78,11 +90,13 @@ and a Linux platform driver remain software responsibilities.
## Delivery Boundary
Central owner/lock, quiesce-gated handoff, cache request/ACK, fault IRQ, and
LP/HP IRQ routing are implemented and directed-tested. `CONTROL.QUIESCE`
blocks the corresponding data-crossbar master and waits per-master outstanding
zero; shared I/O gateways are conservatively blocked as a pair. `CONTROL.RESET`
also blocks new data and masks IRQ but is not yet connected to every peripheral
engine's internal reset state machine. The APU-P1 shell is an exception: its
index-7 quiesce acknowledgement and reset are connected locally in PCLK. It
must not be described as independent peripheral power isolation or reset containment until
LP/HP IRQ routing are implemented and directed-tested. P2 appends resource 8
for the idle GA2D bridge placeholder only; it creates no GA2D IRQ route or
functional GA2D peripheral. `CONTROL.QUIESCE` blocks the corresponding
data-crossbar master and waits per-master outstanding zero; shared I/O gateways
are conservatively blocked as a pair. `CONTROL.RESET` also blocks new data and
masks IRQ but is not yet connected to every peripheral engine's internal reset
state machine. The APU-P1 shell is an exception: its index-7 quiesce
acknowledgement and reset are connected locally in PCLK. It must not be
described as independent peripheral power isolation or reset containment until
those downstream acknowledgements and fault-injection tests exist.
+1 -1
View File
@@ -12,7 +12,7 @@ timings expressed in SDRAM-clock cycles.
| AXI4 data window | `0x38000000` - `0x3BFFFFFF` |
| Data window size | 64 MiB |
| APB4 configuration window | `0x1000D000` - `0x1000DFFF` |
| SoC data boundary | 64-bit AXI/ID6 from HP into the stable memory domain |
| SoC data boundary | 64-bit AXI/ID7 from HP into the stable memory domain |
| Controller frontend | local 64-to-32 adaptation, then 32-bit AXI over SDRAM x16 |
| Address organization | 2-bit bank, 13-bit row, 10-bit column |
| Physical interface | `sdram_if` (`BA[1:0]`, `A[12:0]`, `DQ[15:0]`) |
+9 -2
View File
@@ -17,7 +17,14 @@ enable/clear, and sticky terminal test result. It receives user-bus idle,
fault metadata, ten wait counters (including independent SDIO0 and SDIO1
master wait counters), and asynchronous RTC wake. `sysctrl_core`
synchronizes RTC wake with the Common `cdc_sync` primitive before storing its
sticky state.
sticky state. HP data-plane faults cross into PCLK through an acknowledged
mailbox. Their HP sources use valid/ready flow control and retain the complete
44-bit `{master,target,address,write,reason}` payload until the mailbox
accepts it, so every accepted no-reset event is delivered once with coherent
metadata. A reset in either mailbox domain aborts an item already accepted by
the mailbox; a unilateral PCLK reset backpressures an unaccepted HP source
event until the link is released. A data-plane fault visible in the same PCLK
cycle as a local bus fault retains data-plane priority.
`pll_ctrl_if` carries a one-request PLL configuration handshake. SystemCtrl
asserts `req_valid_o` after a valid `PLL_CMD.APPLY`, holds `busy` until the
@@ -56,7 +63,7 @@ offset macros.
| `0x01C` | `PLL_STATUS` | RO | Active profile, valid, busy, error/error reason, safe clock, lock, and capability. |
| `0x020` | `USER_CORE_RESET` | RO/unsupported | Product reads all ones and rejects writes. MPW retains its reset mask. |
| `0x024` | `USER_CORE_STATUS` | RO/unsupported | Product reports present=0, idle=1, and sticky unsupported-write error. |
| `0x028` | `FAULT_MASTER` | RO | First fault master, a three-bit AXI master ID (0..7); HP is 7. |
| `0x028` | `FAULT_MASTER` | RO | First fault master, a four-bit AXI master ID (0..8); HP is 7 and the P2 GA2D bridge placeholder is 8. The offset is unchanged. |
| `0x02C` | `FAULT_DETAIL` | RO | First raw RIB response code. |
| `0x040` | `PERF_CTRL` | RW | Bit 0 enable, bit 1 clear pulse, bit 2 snapshot pulse. |
| `0x044`-`0x098` | `PERF_*_WAIT_{LO,HI}` | RO | Snapshot of management, user, central DMA, SDIO0, SDIO1, APB4, SDRAM, PSRAM, and flash wait counters. |
+23 -8
View File
@@ -1,10 +1,11 @@
# Mini Product LP/HP Architecture
The frozen [GA2D specification](ip/ga2d.md) approves a phased expansion to a
64-bit LP interrupt vector, nine AXI64 masters with seven-bit global IDs, and
Resource Controller entry 8. These are pending implementation requirements;
this document's current-product descriptions do not imply those phases have
already been delivered. Existing hart, memory, and source identities remain fixed.
The frozen [GA2D specification](ip/ga2d.md) defines the phased GA2D delivery.
Phase 2 expands the implemented platform to nine AXI64 masters with seven-bit
global IDs and Resource Controller entry 8. Its dedicated PCLK-to-HP
AXI64/ID3 bridge is an idle placeholder only. `APB4_GA` remains reserved and
inactive, and the GA2D APB shell, IRQ, payload/DMA, and pixel function remain
deferred. Existing hart, memory, and source identities remain fixed.
## Product contract
@@ -78,7 +79,7 @@ same memory admission, inactive-pad, ACL, and fault path as HP and DMA.
## Native AXI64 data plane
`soc_data_plane` contains an 8-master, 6-target AXI64 crossbar. Read and write
`soc_data_plane` contains a 9-master, 6-target AXI64 crossbar. Read and write
channels progress independently, and different source IDs may be active against
the same or different targets. The same source ID is blocked until completion.
SRAM and SDRAM accept four reads and two writes; serial memories and the error
@@ -94,9 +95,10 @@ and a Common FIFO preserves write-data order where AXI4 W has no ID.
| I/O gateway B | SDIO1 and SPI-SD, then PCLK-to-HP CDC and upsizer |
| LP data gateway | Hazard3 memory traffic, LP-to-HP CDC and upsizer |
| EXT-H | PCLK-to-HP AXI64 async bridge, ID prefix 7 |
| GA2D bridge placeholder | dedicated PCLK-to-HP AXI64/ID3 async bridge; source held idle |
Targets are SRAM, SDRAM, QPI PSRAM, OPI/HyperBus PSRAM, XPI/flash, and a
finite-latency error slave. SRAM is a native AXI64, six-bit-ID target in HP and
finite-latency error slave. SRAM is a native AXI64, seven-bit-ID target in HP and
stripes each beat across two existing 32-bit technology macros. SDRAM, QPI,
OPI, and XPI cross directly from HP to the stable memory domain as AXI64 and
are downsized only beside their current 32-bit controller frontends. Serial
@@ -113,6 +115,14 @@ All async AXI channels use Common coordinated warm-flush FIFOs and expose a
source-domain epoch. HP shutdown holds a flush request until every bridge sees
it, then waits for bridge recovery before resetting the core.
`data_plane_fault_cdc` carries HP fault metadata to PCLK through Common's
one-entry `async_reqack` mailbox. The crossbar and target guards hold a
valid, stable 44-bit fault payload until its ready handshake, applying
backpressure before another reportable fault can retire. Reset in either
mailbox domain aborts an item already accepted by the mailbox; a unilateral
PCLK reset keeps an unaccepted HP-source event backpressured until the link
is released.
## Memory and shared pads
Product profiles instantiate on-chip SRAM, SDRAM, QPI, OPI/HyperBus, and XPI
@@ -144,11 +154,16 @@ Its IRQ is delivered to LP IRQ 28 or HP PLIC source 3 according to owner,
never both. Software discovers it through `<retrosoc/hal/extension.h>`.
The Resource Controller at `0x2000_A000` is the central owner and IRQ authority
for DMA, USB2, SDIO0/1, SPI-SD, EXT-H, JPEG, and APU. Handoff requires idle,
for DMA, USB2, SDIO0/1, SPI-SD, EXT-H, JPEG, and APU, and the lifecycle
authority for the idle GA2D bridge placeholder. Resource 8 has no routed IRQ
until Phase 3. Handoff requires idle,
owner lock is sticky, and rejected handoffs raise LP IRQ 29. APU index 7 routes
exclusively to LP IRQ31 or HP PLIC source10. The controller also carries the
AON cache request/clean acknowledgement used before HP drain. See
[`ip/resource-controller.md`](ip/resource-controller.md).
Resource 8 qualifies its HP block acknowledgement with a fresh synchronized
source-quiesced state, so an old idle sample cannot hand off a
`WVALID`-before-`AWVALID` write.
The root-only Fabric Monitor at `0x2000_B000` records per-master and
per-target traffic, wait, promotion, credit high-water, timeout, isolation,
+1 -1
View File
@@ -16,7 +16,7 @@
| Target-aware multi-outstanding AXI64 | Data crossbar | Multi-ID, ordering, backpressure, and formal tests | implemented: SRAM/SDRAM use 4R/2W credits; serial targets use 1R/1W; full formal proof pending |
| LP access to every memory window through the data plane | LP data gateway | no-PLL boot and memory-window smoke | implemented |
| Bounded QoS and recovery priority | Data crossbar | starvation and emergency-promotion test | implemented and directed-tested at a reduced four-cycle bound; production bound is 256 cycles and full liveness proof remains pending |
| Initiator ACL and first-fault attribution | Generated data policy, crossbar, SYSCTRL, and Fabric Monitor | target/execute/cache/range denial and injection tests | implemented: fixed policy is topology-generated and the monitor retains the first pulse across APB CDC |
| Initiator ACL and first-fault attribution | Generated data policy, crossbar, SYSCTRL, and Fabric Monitor | target/execute/cache/range denial and injection tests | implemented: fixed policy is topology-generated and valid/ready fault reporting retains every accepted event across the HP/PCLK CDC |
| Stable memory functional clocks | Memory integration | HP DFS while refresh/protocol engines continue | implemented digitally: SRAM is native HP AXI64; SDRAM and all serial targets cross directly from HP to stable memory as AXI64 before local downsizing |
| Reset epoch and stale-response rejection | Async bridges | unilateral reset and clock-stop matrix | partial: coordinated warm flush and epoch implemented |
| HP normal and forced hot reset | AON lifecycle controller and Resource Controller | cache request/ACK, drain, timeout, flush, and recovery tests | implemented digitally: Zicbom and bounded ACK window exist; range policy and Linux service remain software work |
+2 -2
View File
@@ -114,7 +114,7 @@ digraph mini_soc_block_diagram {
];
data_plane [
fillcolor="#BFDBFE",
label="Native AXI64 Data Plane\n8 masters x 6 targets, global ID6\ntarget credits, QoS aging, generated ACL",
label="Native AXI64 Data Plane\n9 masters x 6 targets, global ID7\ntarget credits, QoS aging, generated ACL",
shape=hexagon
];
guards [
@@ -123,7 +123,7 @@ digraph mini_soc_block_diagram {
];
sram [
fillcolor="#FDE68A",
label="32 KiB on-chip SRAM\nnative AXI64 / ID6"
label="32 KiB on-chip SRAM\nnative AXI64 / ID7"
];
monitor [
fillcolor="#FCE7F3",
+2 -2
View File
@@ -99,7 +99,7 @@
<title>data_plane</title>
<path fill="#bfdbfe" stroke="#4b5563" stroke-width="1.1" d="M1871.04,-420.1C1871.04,-420.1 1811.22,-448.16 1811.22,-448.16 1805.79,-450.7 1794.36,-453.25 1788.36,-453.25 1788.36,-453.25 1649.26,-453.25 1649.26,-453.25 1643.26,-453.25 1631.83,-450.7 1626.39,-448.16 1626.39,-448.16 1566.57,-420.1 1566.57,-420.1 1561.14,-417.55 1561.14,-412.45 1566.57,-409.9 1566.57,-409.9 1626.39,-381.84 1626.39,-381.84 1631.83,-379.3 1643.26,-376.75 1649.26,-376.75 1649.26,-376.75 1788.36,-376.75 1788.36,-376.75 1794.36,-376.75 1805.79,-379.3 1811.22,-381.84 1811.22,-381.84 1871.04,-409.9 1871.04,-409.9 1876.47,-412.45 1876.47,-417.55 1871.04,-420.1"/>
<text text-anchor="middle" x="1718.81" y="-423.5" font-family="Arial" font-size="10.00" fill="#111827">Native AXI64 Data Plane</text>
<text text-anchor="middle" x="1718.81" y="-412.5" font-family="Arial" font-size="10.00" fill="#111827">8 masters x 6 targets, global ID6</text>
<text text-anchor="middle" x="1718.81" y="-412.5" font-family="Arial" font-size="10.00" fill="#111827">9 masters x 6 targets, global ID7</text>
<text text-anchor="middle" x="1718.81" y="-401.5" font-family="Arial" font-size="10.00" fill="#111827">target credits, QoS aging, generated ACL</text>
</g>
<!-- aon&#45;&gt;data_plane -->
@@ -297,7 +297,7 @@
<title>sram</title>
<path fill="#fde68a" stroke="#4b5563" stroke-width="1.1" d="M2498.61,-491C2498.61,-491 2405.61,-491 2405.61,-491 2399.61,-491 2393.61,-485 2393.61,-479 2393.61,-479 2393.61,-467 2393.61,-467 2393.61,-461 2399.61,-455 2405.61,-455 2405.61,-455 2498.61,-455 2498.61,-455 2504.61,-455 2510.61,-461 2510.61,-467 2510.61,-467 2510.61,-479 2510.61,-479 2510.61,-485 2504.61,-491 2498.61,-491"/>
<text text-anchor="middle" x="2452.11" y="-476" font-family="Arial" font-size="10.00" fill="#111827">32 KiB on&#45;chip SRAM</text>
<text text-anchor="middle" x="2452.11" y="-465" font-family="Arial" font-size="10.00" fill="#111827">native AXI64 / ID6</text>
<text text-anchor="middle" x="2452.11" y="-465" font-family="Arial" font-size="10.00" fill="#111827">native AXI64 / ID7</text>
</g>
<!-- guards&#45;&gt;sram -->
<g id="edge17" class="edge">

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

+6 -3
View File
@@ -141,9 +141,12 @@ capabilities:
- The canonical address map exposes configurable on-chip SRAM, a 64 MiB SDRAM
window, and an 8 MiB PSRAM window. Address-window capacity does not guarantee
that every implementation includes the corresponding physical memory.
- AXI4 uses a 32-bit LP control plane and an 8x6 native AXI64 HP data plane.
Vexii I/D ports remain independent; DMA and I/O masters cross into HP and
current memory frontends are reached through 64-to-32 target adapters.
- AXI4 uses a 32-bit LP control plane and a 9x6 native AXI64 HP data plane
with seven-bit global IDs. Vexii I/D ports remain independent; DMA and I/O
masters cross into HP and current memory frontends are reached through
64-to-32 target adapters. Master 8 is a dedicated PCLK-to-HP AXI64/ID3 GA2D
bridge whose source is idle; `APB4_GA` remains reserved and inactive, and no
GA2D APB shell, IRQ, payload/DMA, or pixel function is implemented.
- 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.
+19 -19
View File
@@ -8020,19 +8020,19 @@
{
"id": "p1",
"direction": "in",
"width": 8,
"width": 9,
"side": "west"
},
{
"id": "p2",
"direction": "out",
"width": 16,
"width": 18,
"side": "east"
},
{
"id": "p3",
"direction": "out",
"width": 8,
"width": 9,
"side": "south"
}
],
@@ -8058,7 +8058,7 @@
{
"id": "p1",
"direction": "out",
"width": 8,
"width": 9,
"side": "east"
}
],
@@ -8077,7 +8077,7 @@
{
"id": "p2",
"direction": "in",
"width": 16,
"width": 18,
"side": "west"
}
],
@@ -8096,7 +8096,7 @@
{
"id": "p3",
"direction": "in",
"width": 8,
"width": 9,
"side": "north"
}
],
@@ -8144,7 +8144,7 @@
"file": "rtl/mini/top/apb4_system.sv",
"scope": "apb4_system",
"symbol": "resource_idle_i",
"bits": 8
"bits": 9
}
],
"instance_ports": [
@@ -8172,7 +8172,7 @@
"file": "rtl/mini/top/apb4_system.sv",
"scope": "apb4_system",
"symbol": "s_resource_owner",
"bits": 16
"bits": 18
}
],
"instance_ports": [
@@ -8200,7 +8200,7 @@
"file": "rtl/mini/top/apb4_system.sv",
"scope": "apb4_system",
"symbol": "s_resource_irq_lp",
"bits": 8
"bits": 9
}
],
"instance_ports": [
@@ -8213,7 +8213,7 @@
"zigzag-dir": "horizontal"
}
],
"note": "Eight resources retain independent owner/lock/quiesce/reset state. IRQ steering and cache-clean coordination are control relationships, not a hardware cache-coherence implementation."
"note": "Nine resources retain independent owner/lock/quiesce/reset state; resource 8 is the idle GA2D bridge placeholder only. IRQ steering and cache-clean coordination are control relationships, not a hardware cache-coherence implementation."
},
"monitor": {
"nodes": [
@@ -8228,7 +8228,7 @@
{
"id": "p0",
"direction": "out",
"width": 8,
"width": 9,
"side": "east"
}
],
@@ -8247,7 +8247,7 @@
{
"id": "p0",
"direction": "in",
"width": 8,
"width": 9,
"side": "west"
},
{
@@ -8331,7 +8331,7 @@
"file": "rtl/mini/top/soc_data_plane.sv",
"scope": "soc_data_plane",
"symbol": "s_monitor_master_read_accept",
"bits": 8
"bits": 9
}
],
"instance_ports": [
@@ -8351,7 +8351,7 @@
"bindings": [
{
"file": "rtl/mini/top/soc_data_plane.sv",
"text": ".fault_valid_i(fault_valid_o)"
"text": ".fault_valid_i(fault_valid_o && fault_ready_i)"
}
],
"signals": [
@@ -8366,7 +8366,7 @@
{
"node": "core",
"port": "fault_valid_i",
"expression": "fault_valid_o"
"expression": "fault_valid_o && fault_ready_i"
}
],
"zigzag-dir": "horizontal"
@@ -8573,7 +8573,7 @@
"instance_ports": []
}
],
"note": "PRODUCT uses a native AXI64/ID6 SRAM target in the HP clock domain. The selected IHP130 profile supplies 32 KiB. Bank count and physical macro organization are distinct from the address aperture."
"note": "PRODUCT uses a native AXI64/ID7 SRAM target in the HP clock domain. The selected IHP130 profile supplies 32 KiB. Bank count and physical macro organization are distinct from the address aperture."
},
"xpi": {
"nodes": [
@@ -9676,7 +9676,7 @@
},
{
"file": "rtl/mini/top/axi4_data_crossbar.sv",
"text": "function automatic logic [CountWidth-1:0] master_read_limit(input int unsigned master); if ((master <= 2) || (master == 7)) return CountWidth'(4); if ((master == 3) || (master == 4)) return CountWidth'(2); if (master == 5) return CountWidth'(1); return '0; endfunction"
"text": "function automatic logic [CountWidth-1:0] master_read_limit(input int unsigned master); if ((master <= 2) || (master == 7)) return CountWidth'(4); if ((master == 3) || (master == 4)) return CountWidth'(2); if (master == 5) return CountWidth'(1); if (master == 8) return CountWidth'(1); return '0; endfunction"
}
],
"instance_ports": [
@@ -10903,7 +10903,7 @@
},
{
"id": "sram",
"title": "HP-domain SRAM\nnative AXI64 / ID6",
"title": "HP-domain SRAM\nnative AXI64 / ID7",
"x": 12.6,
"y": 3.5,
"w": 4.0,
@@ -11513,7 +11513,7 @@
},
{
"file": "rtl/mini/top/axi4_data_crossbar.sv",
"text": "function automatic logic [CountWidth-1:0] master_read_limit(input int unsigned master); if ((master <= 2) || (master == 7)) return CountWidth'(4); if ((master == 3) || (master == 4)) return CountWidth'(2); if (master == 5) return CountWidth'(1); return '0; endfunction"
"text": "function automatic logic [CountWidth-1:0] master_read_limit(input int unsigned master); if ((master <= 2) || (master == 7)) return CountWidth'(4); if ((master == 3) || (master == 4)) return CountWidth'(2); if (master == 5) return CountWidth'(1); if (master == 8) return CountWidth'(1); return '0; endfunction"
}
],
"instance_ports": [
+2 -2
View File
@@ -150,12 +150,12 @@
"Lifecycle-gated device identity reads."
],
"resource": [
"Eight independently managed shared resources.",
"Nine independently managed shared resources; resource 8 is the idle GA2D bridge placeholder only.",
"Owner locks, quiesce/reset and LP/HP IRQ routing.",
"Explicit cache-maintenance handoff and sticky faults."
],
"monitor": [
"Eight master and six target observation banks.",
"Nine master and six target observation banks; bank 8 observes the idle GA2D bridge placeholder.",
"Saturating counters, snapshots and outstanding high-water marks.",
"Sticky first-fault attribution and live isolation status."
],
+2 -2
View File
@@ -333,7 +333,7 @@
"sources": [
"docs/ip/resource-controller.md"
],
"summary": "LP-controlled ownership, quiesce, reset and LP/HP IRQ routing for eight resources."
"summary": "LP-controlled ownership, quiesce, reset and LP/HP IRQ routing for nine resources; resource 8 is the idle GA2D bridge placeholder only."
},
{
"id": "monitor",
@@ -344,7 +344,7 @@
"sources": [
"docs/ip/fabric-monitor.md"
],
"summary": "Snapshot counters and sticky fault attribution beside the HP data crossbar."
"summary": "Nine-master/six-target snapshot counters and sticky fault attribution beside the HP data crossbar; bank 8 observes the idle GA2D bridge placeholder."
},
{
"id": "i2s",
+2 -1
View File
@@ -11,7 +11,8 @@
#ip("resource")
#ip-reference("resource","resource",4,legacy:[
Eight resources are managed: central DMA, USB2, SDIO0, SDIO1, SPI-SD, EXT-H, JPEG and APU.
Nine resources are managed: central DMA, USB2, SDIO0, SDIO1, SPI-SD, EXT-H, JPEG,
APU, and the idle GA2D bridge placeholder. Resource 8 has no routed IRQ in Phase 2.
Ownership changes require quiesce, completion of accepted traffic and cache-maintenance
handoff. HP can inspect allowed status but cannot take over root writes. An ownership grant
does not bypass the target access policy or EXT-H address bounds.
+1 -1
View File
@@ -15,7 +15,7 @@
#ip-reference("sram","sram",5,legacy:[
The reference profile selects eight 4 KiB banks for 32 KiB total. The configuration accepts
4, 16, 32, 64 or 128 KiB; only 32 KiB is selected by the committed product profiles.
SRAM has a native AXI64/ID6 data interface in the HP domain and an APB4 configuration window.
SRAM has a native AXI64/ID7 data interface in the HP domain and an APB4 configuration window.
Technology macros and behavioral models are selected by the configuration. A larger configurable
capacity is not a statement of qualified area, timing or yield.
])
@@ -35,7 +35,7 @@ paths and APB4 register targets. The compatibility RIBP boundary for selected MP
described in @mpw. It is not the PRODUCT data fabric.
The LP control fabric uses 32-bit data. APB accesses cross LP to PCLK through asynchronous
request/response bridges. The HP data plane uses 64-bit data, 32-bit addresses and six-bit
request/response bridges. The HP data plane uses 64-bit data, 32-bit addresses and seven-bit
global transaction IDs. Adapters preserve byte lanes and response attribution across width
and clock boundaries. HP MMIO cannot write root-owned SYSCTRL/RCU, watchdog, GPIO administration
and other protected management controls.
@@ -590,7 +590,7 @@
"id": "resource",
"title": "Resource Controller",
"implementation": "Partial",
"scope": "Eight independently managed shared resources.",
"scope": "Nine independently managed shared resources; resource 8 is the idle GA2D bridge placeholder only.",
"dependencies": "No additional off-chip component implied; use the selected clock/reset and access policy.",
"hal": "Published API and syntax example; see the IP chapter.",
"linux": "Native driver support not established in this publication.",
@@ -610,7 +610,7 @@
"id": "monitor",
"title": "Fabric Monitor",
"implementation": "Integrated",
"scope": "Eight master and six target observation banks.",
"scope": "Nine master and six target observation banks; bank 8 observes the idle GA2D bridge placeholder.",
"dependencies": "No additional off-chip component implied; use the selected clock/reset and access policy.",
"hal": "Published API and syntax example; see the IP chapter.",
"linux": "Native driver support not established in this publication.",
+7 -7
View File
@@ -206,10 +206,10 @@
"parameters": {
"ADDR_WIDTH": 32,
"DATA_WIDTH": 64,
"ID_WIDTH": 6,
"ID_WIDTH": 7,
"USER_WIDTH": 1
},
"parameter_note": "Native PRODUCT data fabric is AXI64 with six-bit IDs; this example uses only the data channel."
"parameter_note": "Native PRODUCT data fabric is AXI64 with seven-bit IDs; this example uses only the data channel."
},
"axis": {
"source": {
@@ -2059,9 +2059,9 @@
],
"review_note": "Replaced resource-busy/cache-handoff prose with actual admission, idle, acknowledgement and owner ports. Reviewed owner-write guards.",
"parameters": {
"ResourceCount": 8
"ResourceCount": 9
},
"parameter_note": "The reviewed resource-controller integration tracks eight resource positions."
"parameter_note": "The reviewed resource-controller integration tracks nine resource positions."
},
"monitor": {
"source": {
@@ -2134,10 +2134,10 @@
],
"review_note": "Removed invented SNAPSHOT and snapshot-valid signals; used actual control decode and live/snapshot register arrays.",
"parameters": {
"NumMasters": 8,
"NumMasters": 9,
"NumTargets": 6
},
"parameter_note": "Reference monitor parameters are eight masters and six target positions."
"parameter_note": "Reference monitor parameters are nine masters and six target positions."
},
"sysctrl": {
"source": {
@@ -2319,7 +2319,7 @@
"parameters": {
"ADDR_WIDTH": 32,
"DATA_WIDTH": 64,
"ID_WIDTH": 6,
"ID_WIDTH": 7,
"USER_WIDTH": 1
},
"parameter_note": "The PRODUCT SRAM data port is native AXI64."
+2 -2
View File
@@ -124,7 +124,7 @@ module sysctrl_core (
logic [2:0] s_fault_detail_d, s_fault_detail_q;
logic [31:0] s_fault_addr_d, s_fault_addr_q;
logic [31:0] s_fault_count_d, s_fault_count_q;
logic [2:0] s_fault_master_d, s_fault_master_q;
logic [3:0] s_fault_master_d, s_fault_master_q;
logic s_perf_en_d, s_perf_en_q;
logic [63:0] s_perf_mgmt_wait_d, s_perf_mgmt_wait_q;
logic [63:0] s_perf_user_wait_d, s_perf_user_wait_q;
@@ -653,7 +653,7 @@ module sysctrl_core (
s_sysctrl_coresel_q
};
`endif
FaultMaster: read_data_o = {29'd0, s_fault_master_q};
FaultMaster: read_data_o = {28'd0, s_fault_master_q};
FaultDetail: read_data_o = {29'd0, s_fault_detail_q};
PerfCtrl: read_data_o = {31'd0, s_perf_en_q};
PerfMgmtWaitLo: read_data_o = s_perf_mgmt_wait_q[31:0];
+1 -1
View File
@@ -16,7 +16,7 @@ interface sysctrl_if ();
logic user_bus_enable_o;
logic user_bus_idle_i;
logic fault_access_i;
logic [ 2:0] fault_master_i;
logic [ 3:0] fault_master_i;
logic [ 2:0] fault_code_i;
logic perf_enable_o;
logic perf_clear_o;
+1
View File
@@ -17,6 +17,7 @@
/top/axi4_target_guard.sv
/top/fabric_monitor.sv
/top/soc_data_plane.sv
/top/data_plane_fault_cdc.sv
/top/axi4_error_slave.sv
/top/rib2axi4.sv
/top/ahbl2axi4.sv
+9 -8
View File
@@ -3,13 +3,14 @@
`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.
[GA2D](../../../docs/ip/ga2d.md) defines approved, not yet implemented changes:
Phase 1 expands the root LP IRQ vector to 64 bits while retaining the legacy
32-bit user-core interface; Phase 2 adds data master/resource 8 and ID7;
Phase 3 appends APB slot 28 and GA2D's LP32/HP PLIC11 interrupt. Existing
allocations remain stable. Until those phases land, the manifest and generated
outputs retain the baseline capacities described below. The Xh3irq SDK path
also requires the Phase 1 implementation; a wiring-only expansion is insufficient.
[GA2D](../../../docs/ip/ga2d.md) Phase 2 expands the topology to data
master/resource 8 and seven-bit global IDs while retaining all existing
allocations. It adds only a dedicated PCLK-to-HP AXI64/ID3 GA2D bridge whose
source is held idle. `APB4_GA` remains reserved and inactive; the GA2D APB
shell, IRQ wiring, payload/DMA, and pixel function remain deferred to later
phases. Phase 3 appends APB slot 28 and GA2D's LP32/HP PLIC11 interrupt. The
Xh3irq SDK path also requires the Phase 1 implementation; a wiring-only
expansion is insufficient.
The topology generator validates APB4 island ownership against
`../address_map/memory_map.json` and emits generated SystemVerilog include
@@ -46,7 +47,7 @@ the canonical memory map. Slot 10 is the Resource Controller; slot 11 is the
external HP-domain Fabric Monitor reached through its explicit PCLK-to-HP APB
bridge.
`data_master_policies` defines all eight native data-plane master identities,
`data_master_policies` defines all nine native data-plane master identities,
read/write target sets, instruction permission, and non-cacheable attribute
requirements. The generator rejects missing, reordered, or unknown entries
and emits packed `soc_data_policy.svh` constants consumed by the crossbar.
@@ -108,9 +108,28 @@
{"name": "sdram_config", "source": "pclk", "destination": "memory", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_sdram_cfg_cdc"},
{"name": "sram_config", "source": "pclk", "destination": "hp", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_sram_cfg_cdc"},
{"name": "fabric_monitor", "source": "pclk", "destination": "hp", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_fabric_monitor_cdc"},
{
"name": "data_plane_fault",
"source": "hp",
"destination": "pclk",
"primitive": "async_reqack",
"path": "rtl/mini/top/data_plane_fault_cdc.sv",
"instance": "u_fault_mailbox",
"unilateral_reset": {
"source_reset": "abort_accepted_mailbox_item",
"destination_reset": "abort_accepted_item_backpressure_unaccepted_source"
}
},
{"name": "io_dma_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_io_cdc"},
{"name": "apu_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_io_cdc"},
{"name": "jpeg_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_jpeg_cdc"},
{"name": "ga2d_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_cdc"},
{"name": "ga2d_source_idle", "source": "pclk", "destination": "hp", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_source_idle_sync"},
{"name": "ga2d_source_quiesced", "source": "pclk", "destination": "hp", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_source_quiesced_sync"},
{"name": "ga2d_hp_reset", "source": "hp", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_hp_reset_sync"},
{"name": "ga2d_flush", "source": "hp", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_flush_sync"},
{"name": "ga2d_master_idle", "source": "hp", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_master_idle_sync"},
{"name": "ga2d_block_ack", "source": "hp", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ga2d_block_ack_sync"},
{"name": "extension_h_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ext_h_cdc"},
{"name": "sdram_data", "source": "hp", "destination": "memory", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_target_cdc"},
{"name": "serial_memory_data", "source": "hp", "destination": "memory", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_target_cdc"},
@@ -29,6 +29,7 @@ DATA_MASTER_NAMES = (
"lp_gateway",
"jpeg",
"ext_h",
"ga2d",
)
DATA_TARGET_NAMES = ("sram", "sdram", "qpi", "opi", "xpi")
COMPATIBILITY_IRQ_BINDINGS = (
@@ -327,7 +328,9 @@ def parse_fabric_links(value: Any) -> list[FabricLink]:
def parse_data_master_policies(value: Any) -> list[DataMasterPolicy]:
if not isinstance(value, list) or len(value) != len(DATA_MASTER_NAMES):
raise ValueError("data_master_policies must define all eight data masters")
raise ValueError(
f"data_master_policies must define all {len(DATA_MASTER_NAMES)} data masters"
)
policies: list[DataMasterPolicy] = []
for position, entry in enumerate(value):
policy = require_object(entry, f"data_master_policies[{position}]")
@@ -575,7 +578,7 @@ def render_data_policy(policies: list[DataMasterPolicy]) -> str:
)
for policy in reversed(policies)
)
return f"40'b{bits}"
return f"{len(policies) * len(DATA_TARGET_NAMES)}'b{bits}"
instruction_bits = "".join(
"1" if policy.allow_instruction else "0" for policy in reversed(policies)
@@ -588,8 +591,8 @@ def render_data_policy(policies: list[DataMasterPolicy]) -> str:
"// Generated by rtl/mini/integration/generate_soc_topology.py; do not edit.",
f"`define {'SOC_DATA_POLICY_READ_TARGET_MASK':<44} {packed_target_mask('read_targets')}",
f"`define {'SOC_DATA_POLICY_WRITE_TARGET_MASK':<44} {packed_target_mask('write_targets')}",
f"`define {'SOC_DATA_POLICY_ALLOW_INSTRUCTION':<44} 8'b{instruction_bits}",
f"`define {'SOC_DATA_POLICY_REQUIRE_NONCACHEABLE':<44} 8'b{noncacheable_bits}",
f"`define {'SOC_DATA_POLICY_ALLOW_INSTRUCTION':<44} {len(policies)}'b{instruction_bits}",
f"`define {'SOC_DATA_POLICY_REQUIRE_NONCACHEABLE':<44} {len(policies)}'b{noncacheable_bits}",
"",
]
)
+8
View File
@@ -409,6 +409,14 @@
"write_targets": ["sram", "sdram", "qpi", "opi"],
"allow_instruction": false,
"require_noncacheable": true
},
{
"index": 8,
"name": "ga2d",
"read_targets": ["sram", "sdram", "qpi", "opi", "xpi"],
"write_targets": ["sram", "sdram", "qpi", "opi"],
"allow_instruction": false,
"require_noncacheable": true
}
],
"apb4_periph_targets": [
+15 -15
View File
@@ -23,8 +23,8 @@ module apb4_system (
input logic rst_aud_n_i,
input logic debug_halted_i,
input logic ext_h_data_idle_i,
input logic [7:0] resource_idle_i,
input logic [7:0] resource_block_ack_i,
input logic [8:0] resource_idle_i,
input logic [8:0] resource_block_ack_i,
input logic [6:0] resource_irq_i,
input logic cache_request_i,
axi4_if.slave axi4,
@@ -45,10 +45,10 @@ module apb4_system (
output logic ext_h_irq_raw_o,
output logic [1:0] ext_h_owner_o,
output logic cache_clean_o,
output logic [7:0][1:0] resource_owner_o,
output logic [7:0] resource_owner_lock_o,
output logic [7:0] resource_quiesce_o,
output logic [7:0] resource_reset_o,
output logic [8:0][1:0] resource_owner_o,
output logic [8:0] resource_owner_lock_o,
output logic [8:0] resource_quiesce_o,
output logic [8:0] resource_reset_o,
output logic [6:0] resource_irq_lp_o,
output logic [6:0] resource_irq_hp_o,
output logic [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] irq_o
@@ -98,13 +98,13 @@ module apb4_system (
logic s_ext_h_irq;
logic s_ext_h_irq_raw;
logic [ 1:0] unused_ext_h_owner;
logic [ 7:0] s_resource_irq;
logic [ 7:0] s_resource_irq_lp;
logic [ 7:0] s_resource_irq_hp;
logic [ 7:0][1:0] s_resource_owner;
logic [ 7:0] s_resource_owner_lock;
logic [ 7:0] s_resource_quiesce;
logic [ 7:0] s_resource_reset;
logic [ 8:0] s_resource_irq;
logic [ 8:0] s_resource_irq_lp;
logic [ 8:0] s_resource_irq_hp;
logic [ 8:0][1:0] s_resource_owner;
logic [ 8:0] s_resource_owner_lock;
logic [ 8:0] s_resource_quiesce;
logic [ 8:0] s_resource_reset;
logic s_resource_fault_irq;
logic s_cache_clean;
logic s_unused_resource;
@@ -112,7 +112,7 @@ module apb4_system (
logic s_unused_product_input;
`endif
assign s_resource_irq = {resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]};
assign s_resource_irq = {1'b0, resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]};
assign s_ext_h_irq = s_resource_irq_lp[5];
assign ext_h_irq_raw_o = s_ext_h_irq_raw;
assign ext_h_owner_o = s_resource_owner[5];
@@ -234,7 +234,7 @@ module apb4_system (
apb4_crc u_apb4_crc (.apb4(u_crc_apb4_if));
resource_controller #(
.ResourceCount(8)
.ResourceCount(9)
) u_resource_controller (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
+16 -8
View File
@@ -5,9 +5,11 @@ module axi4_address_gate (
input logic clk_i,
input logic rst_n_i,
input logic block_new_i,
input logic clear_i,
axi4_if.slave source,
axi4_if.master sink,
output logic idle_o
output logic idle_o,
output logic write_pending_o
);
logic s_write_pending_d;
logic s_write_pending_q;
@@ -29,15 +31,15 @@ module axi4_address_gate (
assign sink.awqos = source.awqos;
assign sink.awregion = source.awregion;
assign sink.awuser = source.awuser;
assign sink.awvalid = source.awvalid && !block_new_i && !s_write_pending_q;
assign source.awready = sink.awready && !block_new_i && !s_write_pending_q;
assign sink.awvalid = source.awvalid && !block_new_i && !clear_i && !s_write_pending_q;
assign source.awready = sink.awready && !block_new_i && !clear_i && !s_write_pending_q;
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 && (s_write_pending_q || s_aw_accept);
assign source.wready = sink.wready && (s_write_pending_q || s_aw_accept);
assign sink.wvalid = source.wvalid && !clear_i && (s_write_pending_q || s_aw_accept);
assign source.wready = sink.wready && !clear_i && (s_write_pending_q || s_aw_accept);
assign source.bid = sink.bid;
assign source.bresp = sink.bresp;
@@ -56,8 +58,8 @@ module axi4_address_gate (
assign sink.arqos = source.arqos;
assign sink.arregion = source.arregion;
assign sink.aruser = source.aruser;
assign sink.arvalid = source.arvalid && !block_new_i && !s_read_pending_q;
assign source.arready = sink.arready && !block_new_i && !s_read_pending_q;
assign sink.arvalid = source.arvalid && !block_new_i && !clear_i && !s_read_pending_q;
assign source.arready = sink.arready && !block_new_i && !clear_i && !s_read_pending_q;
assign source.rid = sink.rid;
assign source.rdata = sink.rdata;
@@ -71,7 +73,9 @@ module axi4_address_gate (
assign s_b_accept = source.bvalid && source.bready;
assign s_ar_accept = source.arvalid && source.arready;
assign s_r_accept = source.rvalid && source.rready && source.rlast;
assign idle_o = !s_write_pending_q && !s_read_pending_q && !source.awvalid && !source.arvalid;
assign write_pending_o = s_write_pending_q || s_aw_accept;
assign idle_o = !s_write_pending_q && !s_read_pending_q && !source.awvalid && !source.wvalid &&
!source.arvalid;
always_comb begin
s_write_pending_d = s_write_pending_q;
@@ -80,6 +84,10 @@ module axi4_address_gate (
if (s_aw_accept) s_write_pending_d = 1'b1;
if (s_r_accept) s_read_pending_d = 1'b0;
if (s_ar_accept) s_read_pending_d = 1'b1;
if (clear_i) begin
s_write_pending_d = 1'b0;
s_read_pending_d = 1'b0;
end
end
dffr #(
+192 -82
View File
@@ -4,7 +4,7 @@
`include "mmap_define.svh"
module axi4_data_crossbar #(
parameter int unsigned NumMasters = 8,
parameter int unsigned NumMasters = 9,
parameter int unsigned NumTargets = 6,
parameter int unsigned StarvationCycles = 256,
parameter logic [NumMasters-1:0][NumTargets-2:0] ReadTargetMask = '1,
@@ -18,6 +18,8 @@ module axi4_data_crossbar #(
input logic block_new_i,
input logic [NumMasters-1:0] master_block_i,
input logic recovery_i,
input logic flush_i,
input logic fault_ready_i,
input logic [1:0] mem_pad_mode_i,
input logic [31:0] ext_h_read_base_i,
input logic [31:0] ext_h_read_limit_i,
@@ -30,7 +32,7 @@ module axi4_data_crossbar #(
output logic [7:0] outstanding_read_o,
output logic [7:0] outstanding_write_o,
output logic fault_valid_o,
output logic [2:0] fault_master_o,
output logic [3:0] fault_master_o,
output logic [2:0] fault_target_o,
output logic [31:0] fault_addr_o,
output logic fault_write_o,
@@ -72,7 +74,7 @@ module axi4_data_crossbar #(
localparam logic [3:0] FaultProtocol = 4'd4;
typedef struct packed {
logic [5:0] id;
logic [6:0] id;
logic [31:0] addr;
logic [7:0] len;
logic [2:0] size;
@@ -93,13 +95,13 @@ module axi4_data_crossbar #(
} write_channel_t;
typedef struct packed {
logic [5:0] id;
logic [6:0] id;
logic [1:0] resp;
logic user;
} write_resp_t;
typedef struct packed {
logic [5:0] id;
logic [6:0] id;
logic [63:0] data;
logic [1:0] resp;
logic last;
@@ -161,6 +163,13 @@ module axi4_data_crossbar #(
logic [NumMasters-1:0] s_write_resp_valid;
logic [NumMasters-1:0] s_read_terminal;
logic [NumMasters-1:0] s_write_terminal;
logic [NumTargets-1:0] s_invalid_read_response;
logic [NumTargets-1:0] s_invalid_write_response;
logic [NumTargets-1:0] s_invalid_read_fault_accept;
logic [NumTargets-1:0] s_invalid_write_fault_accept;
logic s_protocol_fault_pending;
logic s_protocol_fault_event;
logic s_protocol_recovery_q;
logic [NumTargets-1:0] s_target_write_owner_full;
logic [NumTargets-1:0] s_target_write_owner_empty;
@@ -194,6 +203,10 @@ module axi4_data_crossbar #(
logic [NumMasters-1:0] s_read_accept;
logic [NumMasters-1:0] s_write_accept;
logic [NumMasters-1:0] s_read_accept_pre;
logic [NumMasters-1:0] s_write_accept_pre;
logic [NumMasters-1:0] s_read_fault_accept;
logic [NumMasters-1:0] s_write_fault_accept;
logic [NumMasters-1:0][TargetWidth-1:0] s_read_accept_target;
logic [NumMasters-1:0][TargetWidth-1:0] s_write_accept_target;
logic [NumMasters-1:0][ 2:0] s_read_accept_id;
@@ -203,11 +216,12 @@ module axi4_data_crossbar #(
logic [NumTargets-1:0][ 4:0] s_read_max_priority;
logic [NumTargets-1:0][ 4:0] s_write_max_priority;
logic s_fault_valid_d;
logic [ 2:0] s_fault_master_d;
logic [ 3:0] s_fault_master_d;
logic [ 2:0] s_fault_target_d;
logic [ 31:0] s_fault_addr_d;
logic s_fault_write_d;
logic [ 3:0] s_fault_reason_d;
logic s_fault_slot_ready;
function automatic logic [TargetWidth-1:0] decode_target(input logic [31:0] addr,
input logic [1:0] pad_mode);
@@ -282,12 +296,14 @@ module axi4_data_crossbar #(
if ((master <= 2) || (master == 7)) return CountWidth'(4);
if ((master == 3) || (master == 4)) return CountWidth'(2);
if (master == 5) return CountWidth'(1);
if (master == 8) return CountWidth'(1);
return '0;
endfunction
function automatic logic [CountWidth-1:0] master_write_limit(input int unsigned master);
if ((master == 1) || (master == 2) || (master == 7)) return CountWidth'(2);
if ((master >= 3) && (master <= 5)) return CountWidth'(1);
if (master == 8) return CountWidth'(1);
return '0;
endfunction
@@ -311,10 +327,12 @@ module axi4_data_crossbar #(
3, 4: base_priority = 4'd10;
2, 7: base_priority = 4'd8;
5: base_priority = recovery ? 4'd15 : 4'd2;
8: base_priority = 4'd8;
default: base_priority = 4'd0;
endcase
if (recovery && (master == 5)) return 5'd31;
if (aged) return 5'd16;
if (master == 8) return {1'b0, base_priority};
return {1'b0, (request_qos > base_priority) ? request_qos : base_priority};
endfunction
@@ -466,7 +484,7 @@ module axi4_data_crossbar #(
) u_write_owner_fifo (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.flush_i(1'b0),
.flush_i(flush_i),
.push_i (s_target_write_owner_push[target]),
.full_o (s_target_write_owner_full[target]),
.dat_i (s_write_selected[target]),
@@ -540,7 +558,8 @@ module axi4_data_crossbar #(
s_read_decoded_target[master] : TargetError;
s_write_routed_target[master] = (s_write_fault_reason[master] == 4'd0) ?
s_write_decoded_target[master] : TargetError;
if (!block_new_i && !master_block_i[master] && m_arvalid[master] &&
if (!block_new_i && !s_protocol_recovery_q && !s_protocol_fault_pending &&
!master_block_i[master] && m_arvalid[master] &&
(s_target_read_count_q[s_read_routed_target[master]] <
target_read_limit(
s_read_routed_target[master]
@@ -550,7 +569,8 @@ module axi4_data_crossbar #(
))) && !s_read_id_busy_q[master][m_ar[master].id[2:0]]) begin
s_read_req[s_read_routed_target[master]][master] = 1'b1;
end
if (!block_new_i && !master_block_i[master] && m_awvalid[master] &&
if (!block_new_i && !s_protocol_recovery_q && !s_protocol_fault_pending &&
!master_block_i[master] && m_awvalid[master] &&
!s_target_write_owner_full[s_write_routed_target[master]] &&
(s_target_write_count_q[s_write_routed_target[master]] <
target_write_limit(
@@ -616,6 +636,21 @@ module axi4_data_crossbar #(
end
end
always_comb begin
s_read_accept_pre = '0;
s_write_accept_pre = '0;
for (int target = 0; target < NumTargets; target++) begin
if (s_read_grant_valid[target]) begin
automatic logic [MasterWidth-1:0] owner = s_read_selected[target];
s_read_accept_pre[owner] = m_arvalid[owner] && t_arready[target];
end
if (s_write_grant_valid[target]) begin
automatic logic [MasterWidth-1:0] owner = s_write_selected[target];
s_write_accept_pre[owner] = m_awvalid[owner] && t_awready[target];
end
end
end
always_comb begin
m_arready = '0;
t_ar = '{default: '0};
@@ -627,14 +662,17 @@ module axi4_data_crossbar #(
for (int target = 0; target < NumTargets; target++) begin
if (s_read_grant_valid[target]) begin
automatic logic [MasterWidth-1:0] owner = s_read_selected[target];
t_ar[target] = m_ar[owner];
t_arvalid[target] = m_arvalid[owner];
m_arready[owner] = t_arready[target];
s_read_capture[target] = t_arvalid[target] && t_arready[target];
if (s_read_capture[target]) begin
s_read_accept[owner] = 1'b1;
s_read_accept_target[owner] = TargetWidth'(target);
s_read_accept_id[owner] = m_ar[owner].id[2:0];
t_ar[target] = m_ar[owner];
if (owner == MasterWidth'(8)) t_ar[target].qos = 4'd0;
if ((s_read_fault_reason[owner] == 4'd0) || s_read_fault_accept[owner]) begin
t_arvalid[target] = m_arvalid[owner];
m_arready[owner] = t_arready[target];
s_read_capture[target] = t_arvalid[target] && t_arready[target];
if (s_read_capture[target]) begin
s_read_accept[owner] = 1'b1;
s_read_accept_target[owner] = TargetWidth'(target);
s_read_accept_id[owner] = m_ar[owner].id[2:0];
end
end
end
end
@@ -652,15 +690,18 @@ module axi4_data_crossbar #(
for (int target = 0; target < NumTargets; target++) begin
if (s_write_grant_valid[target]) begin
automatic logic [MasterWidth-1:0] owner = s_write_selected[target];
t_aw[target] = m_aw[owner];
t_awvalid[target] = m_awvalid[owner];
m_awready[owner] = t_awready[target];
s_write_capture[target] = t_awvalid[target] && t_awready[target];
s_target_write_owner_push[target] = s_write_capture[target];
if (s_write_capture[target]) begin
s_write_accept[owner] = 1'b1;
s_write_accept_target[owner] = TargetWidth'(target);
s_write_accept_id[owner] = m_aw[owner].id[2:0];
t_aw[target] = m_aw[owner];
if (owner == MasterWidth'(8)) t_aw[target].qos = 4'd0;
if ((s_write_fault_reason[owner] == 4'd0) || s_write_fault_accept[owner]) begin
t_awvalid[target] = m_awvalid[owner];
m_awready[owner] = t_awready[target];
s_write_capture[target] = t_awvalid[target] && t_awready[target];
s_target_write_owner_push[target] = s_write_capture[target];
if (s_write_capture[target]) begin
s_write_accept[owner] = 1'b1;
s_write_accept_target[owner] = TargetWidth'(target);
s_write_accept_id[owner] = m_aw[owner].id[2:0];
end
end
end
end
@@ -688,29 +729,105 @@ module axi4_data_crossbar #(
end
always_comb begin
s_read_resp_req = '0;
s_write_resp_req = '0;
s_read_resp_req = '0;
s_write_resp_req = '0;
s_invalid_read_response = '0;
s_invalid_write_response = '0;
for (int target = 0; target < NumTargets; target++) begin
if (t_rvalid[target]) begin
s_read_resp_req[t_r[target].id[5:3]][target] = 1'b1;
if (t_rvalid[target] && !flush_i) begin
if (t_r[target].id[6:3] < 4'(NumMasters)) begin
s_read_resp_req[t_r[target].id[6:3]][target] = 1'b1;
end else begin
s_invalid_read_response[target] = 1'b1;
end
end
if (t_bvalid[target]) begin
s_write_resp_req[t_b[target].id[5:3]][target] = 1'b1;
if (t_bvalid[target] && !flush_i) begin
if (t_b[target].id[6:3] < 4'(NumMasters)) begin
s_write_resp_req[t_b[target].id[6:3]][target] = 1'b1;
end else begin
s_invalid_write_response[target] = 1'b1;
end
end
end
end
assign s_protocol_fault_pending = (|s_invalid_read_response) || (|s_invalid_write_response);
assign s_fault_slot_ready = !fault_valid_o || fault_ready_i;
always_comb begin
s_fault_valid_d = 1'b0;
s_fault_master_d = '0;
s_fault_target_d = '0;
s_fault_addr_d = '0;
s_fault_write_d = 1'b0;
s_fault_reason_d = '0;
s_invalid_read_fault_accept = '0;
s_invalid_write_fault_accept = '0;
s_read_fault_accept = '0;
s_write_fault_accept = '0;
if (s_fault_slot_ready) begin
for (int target = 0; target < NumTargets; target++) begin
if (!s_fault_valid_d && !s_protocol_recovery_q && s_invalid_read_response[target]) begin
s_fault_valid_d = 1'b1;
s_fault_master_d = t_r[target].id[6:3];
s_fault_target_d = 3'(target);
s_fault_addr_d = '0;
s_fault_write_d = 1'b0;
s_fault_reason_d = FaultProtocol;
s_invalid_read_fault_accept[target] = 1'b1;
end
if (!s_fault_valid_d && !s_protocol_recovery_q && s_invalid_write_response[target]) begin
s_fault_valid_d = 1'b1;
s_fault_master_d = t_b[target].id[6:3];
s_fault_target_d = 3'(target);
s_fault_addr_d = '0;
s_fault_write_d = 1'b1;
s_fault_reason_d = FaultProtocol;
s_invalid_write_fault_accept[target] = 1'b1;
end
end
for (int master = 0; master < NumMasters; master++) begin
if (!s_fault_valid_d && s_read_accept_pre[master] &&
(s_read_fault_reason[master] != 4'd0)) begin
s_fault_valid_d = 1'b1;
s_fault_master_d = 4'(master);
s_fault_target_d = 3'(s_read_decoded_target[master]);
s_fault_addr_d = m_ar[master].addr;
s_fault_write_d = 1'b0;
s_fault_reason_d = s_read_fault_reason[master];
s_read_fault_accept[master] = 1'b1;
end
if (!s_fault_valid_d && s_write_accept_pre[master] &&
(s_write_fault_reason[master] != 4'd0)) begin
s_fault_valid_d = 1'b1;
s_fault_master_d = 4'(master);
s_fault_target_d = 3'(s_write_decoded_target[master]);
s_fault_addr_d = m_aw[master].addr;
s_fault_write_d = 1'b1;
s_fault_reason_d = s_write_fault_reason[master];
s_write_fault_accept[master] = 1'b1;
end
end
end
end
assign s_protocol_fault_event = (|s_invalid_read_fault_accept) || (|s_invalid_write_fault_accept);
always_comb begin
m_r = '{default: '0};
m_rvalid = '0;
t_rready = '0;
t_rready = flush_i ? '1 : '0;
s_read_terminal = '0;
s_read_complete_id = '0;
m_b = '{default: '0};
m_bvalid = '0;
t_bready = '0;
t_bready = flush_i ? '1 : '0;
s_write_terminal = '0;
s_write_complete_id = '0;
for (int target = 0; target < NumTargets; target++) begin
if (s_invalid_read_fault_accept[target]) t_rready[target] = 1'b1;
if (s_invalid_write_fault_accept[target]) t_bready[target] = 1'b1;
end
for (int master = 0; master < NumMasters; master++) begin
if (s_read_resp_valid[master]) begin
automatic logic [TargetWidth-1:0] target = s_read_resp_selected[master];
@@ -810,33 +927,6 @@ module axi4_data_crossbar #(
end
end
always_comb begin
s_fault_valid_d = 1'b0;
s_fault_master_d = '0;
s_fault_target_d = '0;
s_fault_addr_d = '0;
s_fault_write_d = 1'b0;
s_fault_reason_d = '0;
for (int master = 0; master < NumMasters; master++) begin
if (!s_fault_valid_d && s_read_accept[master] && (s_read_fault_reason[master] != 4'd0)) begin
s_fault_valid_d = 1'b1;
s_fault_master_d = 3'(master);
s_fault_target_d = 3'(s_read_decoded_target[master]);
s_fault_addr_d = m_ar[master].addr;
s_fault_reason_d = s_read_fault_reason[master];
end
if (!s_fault_valid_d && s_write_accept[master] &&
(s_write_fault_reason[master] != 4'd0)) begin
s_fault_valid_d = 1'b1;
s_fault_master_d = 3'(master);
s_fault_target_d = 3'(s_write_decoded_target[master]);
s_fault_addr_d = m_aw[master].addr;
s_fault_write_d = 1'b1;
s_fault_reason_d = s_write_fault_reason[master];
end
end
end
always_comb begin
outstanding_read_o = '0;
outstanding_write_o = '0;
@@ -846,8 +936,8 @@ module axi4_data_crossbar #(
end
end
assign idle_o = (outstanding_read_o == 8'd0) && (outstanding_write_o == 8'd0) &&
!(|s_route_count_q);
assign idle_o = !s_protocol_recovery_q && (outstanding_read_o == 8'd0) &&
(outstanding_write_o == 8'd0) && !(|s_route_count_q);
for (genvar master = 0; master < NumMasters; master++) begin : gen_master_idle
assign master_idle_o[master] = (s_master_read_count_q[master] == '0) &&
(s_master_write_count_q[master] == '0) && (s_route_count_q[master] == '0) &&
@@ -897,6 +987,7 @@ module axi4_data_crossbar #(
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
fault_valid_o <= 1'b0;
fault_master_o <= '0;
fault_target_o <= '0;
@@ -904,24 +995,43 @@ module axi4_data_crossbar #(
fault_write_o <= 1'b0;
fault_reason_o <= '0;
end else begin
s_master_read_count_q <= s_master_read_count_d;
s_master_write_count_q <= s_master_write_count_d;
s_target_read_count_q <= s_target_read_count_d;
s_target_write_count_q <= s_target_write_count_d;
s_read_id_busy_q <= s_read_id_busy_d;
s_write_id_busy_q <= s_write_id_busy_d;
s_write_route_q <= s_write_route_d;
s_route_read_ptr_q <= s_route_read_ptr_d;
s_route_write_ptr_q <= s_route_write_ptr_d;
s_route_count_q <= s_route_count_d;
s_read_age_q <= s_read_age_d;
s_write_age_q <= s_write_age_d;
fault_valid_o <= s_fault_valid_d;
fault_master_o <= s_fault_master_d;
fault_target_o <= s_fault_target_d;
fault_addr_o <= s_fault_addr_d;
fault_write_o <= s_fault_write_d;
fault_reason_o <= s_fault_reason_d;
if (flush_i) begin
s_master_read_count_q <= '0;
s_master_write_count_q <= '0;
s_target_read_count_q <= '0;
s_target_write_count_q <= '0;
s_read_id_busy_q <= '0;
s_write_id_busy_q <= '0;
s_write_route_q <= '0;
s_route_read_ptr_q <= '0;
s_route_write_ptr_q <= '0;
s_route_count_q <= '0;
s_read_age_q <= '0;
s_write_age_q <= '0;
s_protocol_recovery_q <= 1'b0;
end else begin
s_master_read_count_q <= s_master_read_count_d;
s_master_write_count_q <= s_master_write_count_d;
s_target_read_count_q <= s_target_read_count_d;
s_target_write_count_q <= s_target_write_count_d;
s_read_id_busy_q <= s_read_id_busy_d;
s_write_id_busy_q <= s_write_id_busy_d;
s_write_route_q <= s_write_route_d;
s_route_read_ptr_q <= s_route_read_ptr_d;
s_route_write_ptr_q <= s_route_write_ptr_d;
s_route_count_q <= s_route_count_d;
s_read_age_q <= s_read_age_d;
s_write_age_q <= s_write_age_d;
if (s_protocol_fault_event) s_protocol_recovery_q <= 1'b1;
end
if (!fault_valid_o || fault_ready_i) begin
fault_valid_o <= s_fault_valid_d;
fault_master_o <= s_fault_master_d;
fault_target_o <= s_fault_target_d;
fault_addr_o <= s_fault_addr_d;
fault_write_o <= s_fault_write_d;
fault_reason_o <= s_fault_reason_d;
end
end
end
@@ -938,7 +1048,7 @@ module axi4_data_crossbar #(
end
initial begin
if ((NumMasters != 8) || (NumTargets != 6) || (StarvationCycles < 2) ||
if ((NumMasters != 9) || (NumTargets != 6) || (StarvationCycles < 2) ||
((StarvationCycles & (StarvationCycles - 1)) != 0)) begin
$fatal(1, "axi4_data_crossbar: invalid product topology or aging interval");
end
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: MulanPSL-2.0
module axi4_id_prefix #(
parameter logic [2:0] MasterIndex = 3'd0
parameter logic [3:0] MasterIndex = 4'd0
) (
axi4_if.slave source,
axi4_if.master sink
+117 -45
View File
@@ -20,6 +20,7 @@ module axi4_target_guard #(
output logic abort_o,
input logic abort_done_i,
output logic timeout_valid_o,
input logic timeout_ready_i,
output logic isolated_o,
output logic timeout_write_o,
output logic [IdWidth-1:0] timeout_id_o,
@@ -100,13 +101,24 @@ module axi4_target_guard #(
logic [31:0] s_write_timeout_d, s_write_timeout_q;
logic s_write_last_seen_d, s_write_last_seen_q;
logic s_isolated_d, s_isolated_q;
logic s_timeout_read;
logic s_timeout_write;
logic s_read_progress;
logic s_write_progress;
logic s_read_timeout_enable;
logic s_write_timeout_enable;
logic s_read_missing_last;
logic s_read_timeout_raw;
logic s_write_timeout_raw;
logic s_read_timeout_latched_d, s_read_timeout_latched_q;
logic s_write_timeout_latched_d, s_write_timeout_latched_q;
logic s_read_timeout_pending;
logic s_write_timeout_pending;
logic s_timeout_hold_d, s_timeout_hold_q;
logic s_timeout_sel_write_d, s_timeout_sel_write_q;
logic s_timeout_sel_write;
logic s_timeout_accept;
logic s_read_timeout_accept;
logic s_write_timeout_accept;
logic s_timeout_block;
assign s_ar_push_data = {
source.arid,
@@ -208,9 +220,9 @@ module axi4_target_guard #(
assign sink.arqos = s_ar_qos;
assign sink.arregion = s_ar_region;
assign sink.aruser = s_ar_user;
assign sink.arvalid = (s_read_state_q == ReadSend) && !s_isolated_q;
assign sink.arvalid = (s_read_state_q == ReadSend) && !s_isolated_q && !s_read_timeout_pending;
assign s_ar_pop = ((s_read_state_q == ReadSend) &&
(sink.arready || s_timeout_read || s_isolated_q)) ||
((sink.arvalid && sink.arready) || s_read_timeout_accept || s_isolated_q)) ||
((s_read_state_q == ReadIdle) && s_isolated_q && !s_ar_empty);
assign s_read_missing_last = (s_read_state_q == ReadForward) && sink.rvalid &&
@@ -224,7 +236,8 @@ module axi4_target_guard #(
assign source.ruser = (s_read_state_q == ReadSynthetic) ? '0 : sink.ruser;
assign source.rvalid = (s_read_state_q == ReadSynthetic) ||
((s_read_state_q == ReadForward) && sink.rvalid);
assign sink.rready = (s_read_state_q == ReadForward) ? source.rready :
assign sink.rready = (s_read_state_q == ReadForward) && !s_read_timeout_pending ?
source.rready :
((s_read_state_q == ReadAbort) ||
(s_read_state_q == ReadSynthetic));
@@ -234,7 +247,8 @@ module axi4_target_guard #(
(((s_read_state_q == ReadSend) && !sink.arready) ||
((s_read_state_q == ReadForward) && source.rready &&
!sink.rvalid));
assign s_timeout_read = s_read_timeout_enable && (s_read_timeout_q == timeout_i - 1'b1);
assign s_read_timeout_raw = s_read_timeout_enable && (s_read_timeout_q == timeout_i - 1'b1);
assign s_read_timeout_pending = s_read_timeout_latched_q || s_read_timeout_raw;
always_comb begin
s_read_state_d = s_read_state_q;
@@ -242,7 +256,9 @@ module axi4_target_guard #(
s_read_addr_d = s_read_addr_q;
s_read_remaining_d = s_read_remaining_q;
s_read_timeout_d = s_read_timeout_q;
if (s_read_state_q == ReadIdle) begin
if (s_timeout_block) begin
s_read_timeout_d = s_read_timeout_q;
end else if (s_read_state_q == ReadIdle) begin
s_read_timeout_d = '0;
if (!s_ar_empty && s_isolated_q) begin
s_read_id_d = s_ar_id;
@@ -259,7 +275,7 @@ module axi4_target_guard #(
s_read_state_d = ReadSynthetic;
end else if (s_isolated_q && (s_read_state_q == ReadForward)) begin
s_read_state_d = ReadAbort;
end else if (s_timeout_read) begin
end else if (s_read_timeout_accept) begin
s_read_timeout_d = '0;
if (s_read_state_q == ReadSend) begin
s_read_id_d = s_ar_id;
@@ -271,6 +287,8 @@ module axi4_target_guard #(
s_read_addr_d = s_read_addr_q;
s_read_state_d = ReadAbort;
end
end else if (s_read_timeout_pending) begin
s_read_timeout_d = s_read_timeout_q;
end else begin
s_read_timeout_d = s_read_progress ? 32'd0 :
s_read_timeout_enable ? s_read_timeout_q + 1'b1 : s_read_timeout_q;
@@ -317,17 +335,19 @@ module axi4_target_guard #(
assign sink.awqos = s_aw_qos;
assign sink.awregion = s_aw_region;
assign sink.awuser = s_aw_user;
assign sink.awvalid = (s_write_state_q == WriteSend) && !s_isolated_q;
assign sink.awvalid = (s_write_state_q == WriteSend) && !s_isolated_q && !s_write_timeout_pending;
assign s_aw_pop = ((s_write_state_q == WriteSend) &&
(sink.awready || s_timeout_write || s_isolated_q)) ||
((sink.awvalid && sink.awready) || s_write_timeout_accept || s_isolated_q)) ||
((s_write_state_q == WriteIdle) && s_isolated_q && !s_aw_empty);
assign sink.wdata = source.wdata;
assign sink.wstrb = source.wstrb;
assign sink.wlast = source.wlast;
assign sink.wuser = source.wuser;
assign sink.wvalid = (s_write_state_q == WriteStream) && source.wvalid;
assign source.wready = (s_write_state_q == WriteStream) ? sink.wready :
assign sink.wvalid = (s_write_state_q == WriteStream) && source.wvalid &&
!s_write_timeout_pending;
assign source.wready = (s_write_state_q == WriteStream) && !s_write_timeout_pending ?
sink.wready :
(s_write_state_q == WriteDrop);
assign source.bid = (s_write_state_q == WriteSynthetic) ? s_write_id_q : sink.bid;
@@ -335,7 +355,8 @@ module axi4_target_guard #(
assign source.buser = (s_write_state_q == WriteSynthetic) ? '0 : sink.buser;
assign source.bvalid = (s_write_state_q == WriteSynthetic) ||
((s_write_state_q == WriteResponse) && sink.bvalid);
assign sink.bready = (s_write_state_q == WriteResponse) ? source.bready :
assign sink.bready = (s_write_state_q == WriteResponse) && !s_write_timeout_pending ?
source.bready :
((s_write_state_q == WriteAbort) ||
(s_write_state_q == WriteSynthetic));
@@ -346,7 +367,8 @@ module axi4_target_guard #(
(((s_write_state_q == WriteSend) && !sink.awready) ||
((s_write_state_q == WriteStream) && source.wvalid && !sink.wready) ||
((s_write_state_q == WriteResponse) && source.bready && !sink.bvalid));
assign s_timeout_write = s_write_timeout_enable && (s_write_timeout_q == timeout_i - 1'b1);
assign s_write_timeout_raw = s_write_timeout_enable && (s_write_timeout_q == timeout_i - 1'b1);
assign s_write_timeout_pending = s_write_timeout_latched_q || s_write_timeout_raw;
always_comb begin
s_write_state_d = s_write_state_q;
@@ -354,7 +376,9 @@ module axi4_target_guard #(
s_write_addr_d = s_write_addr_q;
s_write_timeout_d = s_write_timeout_q;
s_write_last_seen_d = s_write_last_seen_q;
if (s_write_state_q == WriteIdle) begin
if (s_timeout_block) begin
s_write_timeout_d = s_write_timeout_q;
end else if (s_write_state_q == WriteIdle) begin
s_write_timeout_d = '0;
s_write_last_seen_d = 1'b0;
if (!s_aw_empty && s_isolated_q) begin
@@ -371,7 +395,7 @@ module axi4_target_guard #(
end else if (s_isolated_q && ((s_write_state_q == WriteStream) ||
(s_write_state_q == WriteResponse))) begin
s_write_state_d = WriteAbort;
end else if (s_timeout_write) begin
end else if (s_write_timeout_accept) begin
s_write_timeout_d = '0;
if (s_write_state_q == WriteSend) begin
s_write_id_d = s_aw_id;
@@ -380,6 +404,8 @@ module axi4_target_guard #(
end else begin
s_write_state_d = WriteAbort;
end
end else if (s_write_timeout_pending) begin
s_write_timeout_d = s_write_timeout_q;
end else begin
s_write_timeout_d = s_write_progress ? 32'd0 :
s_write_timeout_enable ? s_write_timeout_q + 1'b1 : s_write_timeout_q;
@@ -422,50 +448,96 @@ module axi4_target_guard #(
always_comb begin
s_isolated_d = s_isolated_q;
if ((s_timeout_read && (s_read_state_q == ReadForward)) ||
(s_timeout_write && ((s_write_state_q == WriteStream) ||
(s_write_state_q == WriteResponse)))) begin
if ((s_read_timeout_accept && (s_read_state_q == ReadForward)) ||
(s_write_timeout_accept && ((s_write_state_q == WriteStream) ||
(s_write_state_q == WriteResponse)))) begin
s_isolated_d = 1'b1;
end
end
assign s_timeout_sel_write = s_timeout_hold_q ? s_timeout_sel_write_q :
!s_read_timeout_pending && s_write_timeout_pending;
assign timeout_valid_o = !clear_i &&
(s_timeout_hold_q || s_read_timeout_pending ||
s_write_timeout_pending);
assign s_timeout_accept = timeout_valid_o && timeout_ready_i;
assign s_read_timeout_accept = s_timeout_accept && !s_timeout_sel_write;
assign s_write_timeout_accept = s_timeout_accept && s_timeout_sel_write;
assign s_timeout_block = timeout_valid_o && !timeout_ready_i;
always_comb begin
s_read_timeout_latched_d = s_read_timeout_latched_q;
s_write_timeout_latched_d = s_write_timeout_latched_q;
s_timeout_hold_d = s_timeout_hold_q;
s_timeout_sel_write_d = s_timeout_sel_write_q;
if (clear_i) begin
s_read_timeout_latched_d = 1'b0;
s_write_timeout_latched_d = 1'b0;
s_timeout_hold_d = 1'b0;
end else begin
if (s_read_timeout_accept) begin
s_read_timeout_latched_d = 1'b0;
end else if (s_read_timeout_raw) begin
s_read_timeout_latched_d = 1'b1;
end
if (s_write_timeout_accept) begin
s_write_timeout_latched_d = 1'b0;
end else if (s_write_timeout_raw) begin
s_write_timeout_latched_d = 1'b1;
end
if (s_timeout_hold_q) begin
if (s_timeout_accept) s_timeout_hold_d = 1'b0;
end else if (timeout_valid_o && !timeout_ready_i) begin
s_timeout_hold_d = 1'b1;
s_timeout_sel_write_d = s_timeout_sel_write;
end
end
end
assign abort_o = (s_read_state_q == ReadAbort) || (s_write_state_q == WriteAbort);
assign clear_busy_o = clear_i || abort_o;
assign timeout_valid_o = s_timeout_read || s_timeout_write;
assign isolated_o = s_isolated_q;
assign timeout_write_o = s_timeout_write;
assign timeout_id_o = s_timeout_write ?
assign timeout_write_o = s_timeout_sel_write;
assign timeout_id_o = s_timeout_sel_write ?
((s_write_state_q == WriteSend) ? s_aw_id : s_write_id_q) :
((s_read_state_q == ReadSend) ? s_ar_id : s_read_id_q);
assign timeout_addr_o = s_timeout_write ?
assign timeout_addr_o = s_timeout_sel_write ?
((s_write_state_q == WriteSend) ? s_aw_addr : s_write_addr_q) :
((s_read_state_q == ReadSend) ? s_ar_addr : s_read_addr_q);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_read_state_q <= ReadIdle;
s_read_id_q <= '0;
s_read_addr_q <= '0;
s_read_remaining_q <= '0;
s_read_timeout_q <= '0;
s_write_state_q <= WriteIdle;
s_write_id_q <= '0;
s_write_addr_q <= '0;
s_write_timeout_q <= '0;
s_write_last_seen_q <= 1'b0;
s_isolated_q <= 1'b0;
s_read_state_q <= ReadIdle;
s_read_id_q <= '0;
s_read_addr_q <= '0;
s_read_remaining_q <= '0;
s_read_timeout_q <= '0;
s_write_state_q <= WriteIdle;
s_write_id_q <= '0;
s_write_addr_q <= '0;
s_write_timeout_q <= '0;
s_write_last_seen_q <= 1'b0;
s_isolated_q <= 1'b0;
s_read_timeout_latched_q <= 1'b0;
s_write_timeout_latched_q <= 1'b0;
s_timeout_hold_q <= 1'b0;
s_timeout_sel_write_q <= 1'b0;
end else begin
s_read_state_q <= s_read_state_d;
s_read_id_q <= s_read_id_d;
s_read_addr_q <= s_read_addr_d;
s_read_remaining_q <= s_read_remaining_d;
s_read_timeout_q <= s_read_timeout_d;
s_write_state_q <= s_write_state_d;
s_write_id_q <= s_write_id_d;
s_write_addr_q <= s_write_addr_d;
s_write_timeout_q <= s_write_timeout_d;
s_write_last_seen_q <= s_write_last_seen_d;
s_isolated_q <= s_isolated_d;
s_read_state_q <= s_read_state_d;
s_read_id_q <= s_read_id_d;
s_read_addr_q <= s_read_addr_d;
s_read_remaining_q <= s_read_remaining_d;
s_read_timeout_q <= s_read_timeout_d;
s_write_state_q <= s_write_state_d;
s_write_id_q <= s_write_id_d;
s_write_addr_q <= s_write_addr_d;
s_write_timeout_q <= s_write_timeout_d;
s_write_last_seen_q <= s_write_last_seen_d;
s_isolated_q <= s_isolated_d;
s_read_timeout_latched_q <= s_read_timeout_latched_d;
s_write_timeout_latched_q <= s_write_timeout_latched_d;
s_timeout_hold_q <= s_timeout_hold_d;
s_timeout_sel_write_q <= s_timeout_sel_write_d;
end
end
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: MulanPSL-2.0
module axi4_upsizer_32to64 #(
parameter logic [2:0] MasterIndex = 3'd0
parameter logic [3:0] MasterIndex = 4'd0
) (
input logic clk_i,
input logic rst_n_i,
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
module data_plane_fault_cdc (
// verilog_format: off -- preserve the HP/PCLK fault-mailbox boundary columns
input logic clk_hp_i,
input logic rst_hp_n_i,
input logic fault_valid_i,
input logic [ 3:0] fault_master_i,
input logic [ 2:0] fault_target_i,
input logic [31:0] fault_addr_i,
input logic fault_write_i,
input logic [ 3:0] fault_reason_i,
output logic fault_ready_o,
input logic clk_pclk_i,
input logic rst_pclk_n_i,
output logic fault_valid_o,
output logic [ 3:0] fault_master_o,
output logic [ 2:0] fault_target_o,
output logic [31:0] fault_addr_o,
output logic fault_write_o,
output logic [ 3:0] fault_reason_o
// verilog_format: on
);
localparam int unsigned FaultPayloadWidth = 44;
logic s_fault_mailbox_ready;
logic s_fault_mailbox_valid;
logic [FaultPayloadWidth-1:0] s_fault_mailbox_data;
logic [FaultPayloadWidth-1:0] s_fault_payload;
assign fault_valid_o = s_fault_mailbox_valid;
assign fault_ready_o = s_fault_mailbox_ready;
assign s_fault_payload = {
fault_master_i, fault_target_i, fault_addr_i, fault_write_i, fault_reason_i
};
assign {fault_master_o, fault_target_o, fault_addr_o, fault_write_o, fault_reason_o} =
s_fault_mailbox_data;
// The HP producer holds valid and this payload until fault_ready_o accepts it.
async_reqack #(
.DATA_WIDTH(FaultPayloadWidth)
) u_fault_mailbox (
.src_clk_i (clk_hp_i),
.src_rst_n_i(rst_hp_n_i),
.src_valid_i(fault_valid_i),
.src_ready_o(s_fault_mailbox_ready),
.src_data_i (s_fault_payload),
.dst_clk_i (clk_pclk_i),
.dst_rst_n_i(rst_pclk_n_i),
.dst_valid_o(s_fault_mailbox_valid),
.dst_ready_i(1'b1),
.dst_data_o (s_fault_mailbox_data)
);
endmodule
+9 -8
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: MulanPSL-2.0
module fabric_monitor #(
parameter int unsigned NumMasters = 8,
parameter int unsigned NumMasters = 9,
parameter int unsigned NumTargets = 6
) (
// verilog_format: off -- preserve the monitor event boundary columns
@@ -15,7 +15,7 @@ module fabric_monitor #(
input logic [7:0] outstanding_read_i,
input logic [7:0] outstanding_write_i,
input logic fault_valid_i,
input logic [2:0] fault_master_i,
input logic [3:0] fault_master_i,
input logic [2:0] fault_target_i,
input logic [31:0] fault_addr_i,
input logic fault_write_i,
@@ -41,7 +41,7 @@ module fabric_monitor #(
// verilog_format: on
);
localparam logic [31:0] IpId = 32'h4450_4D4E;
localparam logic [31:0] IpVersion = 32'h0001_0000;
localparam logic [31:0] IpVersion = 32'h0001_0001;
localparam logic [11:0] IpIdOffset = 12'h000;
localparam logic [11:0] IpVersionOffset = 12'h004;
localparam logic [11:0] CapabilityOffset = 12'h008;
@@ -60,7 +60,7 @@ module fabric_monitor #(
logic s_flush_q;
logic s_fault_valid_q;
logic s_fault_write_q;
logic [ 2:0] s_fault_master_q;
logic [ 3:0] s_fault_master_q;
logic [ 2:0] s_fault_target_q;
logic [ 3:0] s_fault_reason_q;
logic [31:0] s_fault_addr_q;
@@ -126,10 +126,11 @@ module fabric_monitor #(
};
FaultOffset:
s_read_data = {
20'd0,
19'd0,
s_fault_master_q[3],
s_fault_reason_q,
s_fault_target_q,
s_fault_master_q,
s_fault_master_q[2:0],
s_fault_write_q,
s_fault_valid_q
};
@@ -417,8 +418,8 @@ module fabric_monitor #(
`ifndef SYNTHESIS
initial begin
if ((NumMasters != 8) || (NumTargets != 6)) begin
$fatal(1, "fabric_monitor: product topology must remain 8x6");
if ((NumMasters != 9) || (NumTargets != 6)) begin
$fatal(1, "fabric_monitor: product topology must remain 9x6");
end
end
`endif
+2 -2
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: MulanPSL-2.0
module resource_controller #(
parameter int unsigned ResourceCount = 8
parameter int unsigned ResourceCount = 9
) (
// verilog_format: off -- preserve the resource ownership boundary columns
input logic clk_i,
@@ -23,7 +23,7 @@ module resource_controller #(
// verilog_format: on
);
localparam logic [31:0] IpId = 32'h5253_4354;
localparam logic [31:0] IpVersion = 32'h0001_0000;
localparam logic [31:0] IpVersion = 32'h0001_0001;
localparam logic [11:0] IpIdOffset = 12'h000;
localparam logic [11:0] IpVersionOffset = 12'h004;
localparam logic [11:0] CapabilityOffset = 12'h008;
+144 -90
View File
@@ -87,6 +87,8 @@ module retrosoc (
u_ext_h_wide_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
u_jpeg_wide_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
u_ga2d_wide_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_apu_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
@@ -101,7 +103,7 @@ module retrosoc (
u_hp_mmio_gated_axi4_if (.aclk(clk_hp_i), .aresetn(rst_hp_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_hp_mmio_lp_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(6), .USER_WIDTH(1))
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(7), .USER_WIDTH(1))
u_data_sram_axi4_if (.aclk(clk_hp_i), .aresetn(rst_hp_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_retired_data_sram_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
@@ -194,12 +196,19 @@ module retrosoc (
logic [ 7:0] s_data_plane_outstanding_read;
logic [ 7:0] s_data_plane_outstanding_write;
logic [ 7:0] s_apu_bridge_epoch;
logic s_data_plane_fault_valid;
logic [ 2:0] s_data_plane_fault_master;
logic [ 2:0] s_data_plane_fault_target;
logic [31:0] s_data_plane_fault_addr;
logic s_data_plane_fault_write;
logic [ 3:0] s_data_plane_fault_reason;
logic s_data_plane_fault_valid_hp;
logic s_data_plane_fault_ready_hp;
logic [ 3:0] s_data_plane_fault_master_hp;
logic [ 2:0] s_data_plane_fault_target_hp;
logic [31:0] s_data_plane_fault_addr_hp;
logic s_data_plane_fault_write_hp;
logic [ 3:0] s_data_plane_fault_reason_hp;
logic s_data_plane_fault_valid_pclk;
logic [ 3:0] s_data_plane_fault_master_pclk;
logic [ 2:0] s_data_plane_fault_target_pclk;
logic [31:0] s_data_plane_fault_addr_pclk;
logic s_data_plane_fault_write_pclk;
logic [ 3:0] s_data_plane_fault_reason_pclk;
logic s_hp_mmio_idle;
logic [ 3:0] s_pclk_pending_d;
logic [ 3:0] s_pclk_pending_q;
@@ -235,21 +244,26 @@ module retrosoc (
logic [31:0] s_ext_h_timeout;
logic s_ext_h_irq_raw;
logic [ 1:0] s_ext_h_owner;
logic [ 7:0][1:0] s_resource_owner;
logic [ 7:0] s_resource_owner_lock;
logic [ 7:0] s_resource_quiesce;
logic [ 7:0] s_resource_reset;
logic [ 7:0] s_resource_idle_hp;
logic [ 7:0] s_resource_idle_pclk;
logic [ 7:0] s_resource_block_ack_hp;
logic [ 7:0] s_resource_block_ack_pclk;
logic [ 8:0][1:0] s_resource_owner;
logic [ 8:0] s_resource_owner_lock;
logic [ 8:0] s_resource_quiesce;
logic [ 8:0] s_resource_reset;
logic [ 8:0] s_resource_idle_hp;
logic [ 8:0] s_resource_idle_pclk;
logic [ 8:0] s_resource_block_ack_hp;
logic [ 8:0] s_resource_block_ack_pclk;
logic [ 6:0] s_resource_irq_raw;
logic [ 6:0] s_resource_irq_lp;
logic [ 6:0] s_resource_irq_hp;
logic s_apu_idle;
logic s_jpeg_idle;
logic [ 7:0] s_resource_idle_combined;
logic [ 7:0] s_resource_block_ack_combined;
logic [ 8:0] s_resource_idle_combined;
logic [ 8:0] s_resource_block_ack_combined;
logic s_ga2d_source_stop;
logic s_ga2d_source_safe_idle;
logic s_ga2d_bridge_clear_busy;
logic [ 7:0] s_ga2d_bridge_epoch;
logic s_ga2d_data_ready;
logic [31:0] s_fault_addr_mux;
logic [ 3:0] s_fault_wstrb_mux;
logic s_fault_reserved_mux;
@@ -262,12 +276,13 @@ module retrosoc (
localparam bit SramPresent = 1'b0;
`endif
assign u_sysctrl_if.fault_access_i = s_data_plane_fault_valid ?
s_data_plane_fault_write : s_bus_fault_access;
assign u_sysctrl_if.fault_master_i = s_data_plane_fault_valid ?
s_data_plane_fault_master : s_bus_fault_master;
assign u_sysctrl_if.fault_code_i = s_data_plane_fault_valid ?
s_data_plane_fault_reason[2:0] : s_bus_fault_code;
// PCLK-visible data-plane faults retain their legacy priority over local bus faults.
assign u_sysctrl_if.fault_access_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_write_pclk : s_bus_fault_access;
assign u_sysctrl_if.fault_master_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_master_pclk : {1'b0, s_bus_fault_master};
assign u_sysctrl_if.fault_code_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_reason_pclk[2:0] : s_bus_fault_code;
assign s_perf_en = u_sysctrl_if.perf_enable_o;
assign s_perf_clear = u_sysctrl_if.perf_clear_o;
assign test_done_o = u_sysctrl_if.test_done_o;
@@ -294,10 +309,11 @@ module retrosoc (
assign u_sysctrl_if.hp_actual_released_i = s_hp_lifecycle_stat_pclk[2];
assign u_sysctrl_if.hp_draining_i = s_hp_lifecycle_stat_pclk[1];
assign u_sysctrl_if.hp_forced_fault_i = s_hp_lifecycle_stat_pclk[0];
assign s_fault_addr_mux = s_data_plane_fault_valid ? s_data_plane_fault_addr : s_bus_fault_addr;
assign s_fault_wstrb_mux = s_data_plane_fault_valid && s_data_plane_fault_write ?
assign s_fault_addr_mux = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_addr_pclk : s_bus_fault_addr;
assign s_fault_wstrb_mux = s_data_plane_fault_valid_pclk && s_data_plane_fault_write_pclk ?
4'hF : s_bus_fault_wstrb;
assign s_fault_reserved_mux = s_data_plane_fault_valid ? 1'b0 : s_bus_fault_reserved;
assign s_fault_reserved_mux = s_data_plane_fault_valid_pclk ? 1'b0 : s_bus_fault_reserved;
assign u_uart0_if.rx_i = uart_rx_i;
assign uart_tx_o = u_uart0_if.tx_o;
assign u_uart1_if.rx_i = uart1_rx_i;
@@ -467,12 +483,14 @@ module retrosoc (
);
axi4_address_gate u_hp_mmio_gate (
.clk_i (clk_hp_i),
.rst_n_i (rst_hp_n_i),
.block_new_i(s_hp_block_hp),
.source (u_hp_mmio_hp_axi4_if),
.sink (u_hp_mmio_gated_axi4_if),
.idle_o (s_hp_mmio_idle)
.clk_i (clk_hp_i),
.rst_n_i (rst_hp_n_i),
.block_new_i (s_hp_block_hp),
.clear_i (s_hp_flush_hp),
.source (u_hp_mmio_hp_axi4_if),
.sink (u_hp_mmio_gated_axi4_if),
.idle_o (s_hp_mmio_idle),
.write_pending_o()
);
cdc_sync #(
@@ -561,60 +579,87 @@ module retrosoc (
);
soc_data_plane u_data_plane (
.clk_lp_i (clk_lp_i),
.rst_lp_n_i (rst_lp_n_i),
.clk_io_i (clk_pclk_i),
.rst_io_n_i (rst_pclk_n_i),
.clk_hp_i (clk_hp_i),
.rst_hp_n_i (rst_hp_n_i),
.clk_mem_i (clk_mem_i),
.rst_mem_n_i (rst_mem_n_i),
.block_new_i (s_hp_block_hp),
.recovery_i (s_hp_recovery_hp),
.flush_i (s_hp_flush_hp),
.resource_block_i (s_resource_quiesce | s_resource_reset),
.mem_pad_mode_i (s_mem_pad_mode_lp),
.ext_h_block_i (s_ext_h_block),
.ext_h_read_base_i (s_ext_h_read_base),
.ext_h_read_limit_i (s_ext_h_read_limit),
.ext_h_write_base_i (s_ext_h_write_base),
.ext_h_write_limit_i (s_ext_h_write_limit),
.hp_icache_axi4 (u_hp_icache_axi4_if),
.hp_dcache_axi4 (u_hp_dcache_axi4_if),
.dma_axi4 (u_dma_axi4_if),
.sdio0_axi4 (u_sdio0_axi4_if),
.sdio1_axi4 (u_sdio1_axi4_if),
.spisd_axi4 (u_spisd_axi4_if),
.usb2_axi4 (u_usb2_axi4_if),
.apu_axi4 (u_apu_axi4_if),
.jpeg_axi4 (u_jpeg_wide_axi4_if),
.lp_data_axi4 (u_mgmt_data_axi4_if),
.ext_h_axi4 (u_ext_h_wide_axi4_if),
.sram_gateway_axi4 (u_data_sram_axi4_if),
.sdram_gateway_axi4 (u_data_sdram_axi4_if),
.qpi_gateway_axi4 (u_data_qpi_axi4_if),
.opi_gateway_axi4 (u_data_opi_axi4_if),
.xpi_gateway_axi4 (u_data_xpi_axi4_if),
.fabric_monitor_apb4 (u_fabric_monitor_hp_if),
.idle_o (s_data_plane_idle),
.flush_busy_o (s_data_plane_flush_busy),
.ext_h_idle_o (s_ext_h_data_idle),
.apu_bridge_epoch_o (s_apu_bridge_epoch),
.resource_idle_o (s_resource_idle_hp),
.resource_block_ack_o(s_resource_block_ack_hp),
.outstanding_read_o (s_data_plane_outstanding_read),
.outstanding_write_o (s_data_plane_outstanding_write),
.fault_valid_o (s_data_plane_fault_valid),
.fault_master_o (s_data_plane_fault_master),
.fault_target_o (s_data_plane_fault_target),
.fault_addr_o (s_data_plane_fault_addr),
.fault_write_o (s_data_plane_fault_write),
.fault_reason_o (s_data_plane_fault_reason)
.clk_lp_i (clk_lp_i),
.rst_lp_n_i (rst_lp_n_i),
.clk_io_i (clk_pclk_i),
.rst_io_n_i (rst_pclk_n_i),
.clk_hp_i (clk_hp_i),
.rst_hp_n_i (rst_hp_n_i),
.clk_mem_i (clk_mem_i),
.rst_mem_n_i (rst_mem_n_i),
.block_new_i (s_hp_block_hp),
.recovery_i (s_hp_recovery_hp),
.flush_i (s_hp_flush_hp),
.resource_block_i (s_resource_quiesce | s_resource_reset),
.mem_pad_mode_i (s_mem_pad_mode_lp),
.ext_h_block_i (s_ext_h_block),
.ext_h_read_base_i (s_ext_h_read_base),
.ext_h_read_limit_i (s_ext_h_read_limit),
.ext_h_write_base_i (s_ext_h_write_base),
.ext_h_write_limit_i (s_ext_h_write_limit),
.hp_icache_axi4 (u_hp_icache_axi4_if),
.hp_dcache_axi4 (u_hp_dcache_axi4_if),
.dma_axi4 (u_dma_axi4_if),
.sdio0_axi4 (u_sdio0_axi4_if),
.sdio1_axi4 (u_sdio1_axi4_if),
.spisd_axi4 (u_spisd_axi4_if),
.usb2_axi4 (u_usb2_axi4_if),
.apu_axi4 (u_apu_axi4_if),
.jpeg_axi4 (u_jpeg_wide_axi4_if),
.ga2d_axi4 (u_ga2d_wide_axi4_if),
.lp_data_axi4 (u_mgmt_data_axi4_if),
.ext_h_axi4 (u_ext_h_wide_axi4_if),
.sram_gateway_axi4 (u_data_sram_axi4_if),
.sdram_gateway_axi4 (u_data_sdram_axi4_if),
.qpi_gateway_axi4 (u_data_qpi_axi4_if),
.opi_gateway_axi4 (u_data_opi_axi4_if),
.xpi_gateway_axi4 (u_data_xpi_axi4_if),
.fabric_monitor_apb4 (u_fabric_monitor_hp_if),
.idle_o (s_data_plane_idle),
.flush_busy_o (s_data_plane_flush_busy),
.ext_h_idle_o (s_ext_h_data_idle),
.apu_bridge_epoch_o (s_apu_bridge_epoch),
.ga2d_source_stop_o (s_ga2d_source_stop),
.ga2d_source_safe_idle_o (s_ga2d_source_safe_idle),
.ga2d_bridge_clear_busy_o(s_ga2d_bridge_clear_busy),
.ga2d_bridge_epoch_o (s_ga2d_bridge_epoch),
.ga2d_data_ready_o (s_ga2d_data_ready),
.resource_idle_o (s_resource_idle_hp),
.resource_block_ack_o (s_resource_block_ack_hp),
.outstanding_read_o (s_data_plane_outstanding_read),
.outstanding_write_o (s_data_plane_outstanding_write),
.fault_valid_o (s_data_plane_fault_valid_hp),
.fault_ready_i (s_data_plane_fault_ready_hp),
.fault_master_o (s_data_plane_fault_master_hp),
.fault_target_o (s_data_plane_fault_target_hp),
.fault_addr_o (s_data_plane_fault_addr_hp),
.fault_write_o (s_data_plane_fault_write_hp),
.fault_reason_o (s_data_plane_fault_reason_hp)
);
data_plane_fault_cdc u_data_plane_fault_cdc (
.clk_hp_i (clk_hp_i),
.rst_hp_n_i (rst_hp_n_i),
.fault_valid_i (s_data_plane_fault_valid_hp),
.fault_master_i(s_data_plane_fault_master_hp),
.fault_target_i(s_data_plane_fault_target_hp),
.fault_addr_i (s_data_plane_fault_addr_hp),
.fault_write_i (s_data_plane_fault_write_hp),
.fault_reason_i(s_data_plane_fault_reason_hp),
.fault_ready_o (s_data_plane_fault_ready_hp),
.clk_pclk_i (clk_pclk_i),
.rst_pclk_n_i (rst_pclk_n_i),
.fault_valid_o (s_data_plane_fault_valid_pclk),
.fault_master_o(s_data_plane_fault_master_pclk),
.fault_target_o(s_data_plane_fault_target_pclk),
.fault_addr_o (s_data_plane_fault_addr_pclk),
.fault_write_o (s_data_plane_fault_write_pclk),
.fault_reason_o(s_data_plane_fault_reason_pclk)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(8)
.DATA_WIDTH(9)
) u_resource_idle_sync (
.clk_i (clk_pclk_i),
.rst_n_i(rst_pclk_n_i),
@@ -623,7 +668,7 @@ module retrosoc (
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(8)
.DATA_WIDTH(9)
) u_resource_block_ack_sync (
.clk_i (clk_pclk_i),
.rst_n_i(rst_pclk_n_i),
@@ -632,6 +677,7 @@ module retrosoc (
);
axi4_master_idle u_idle_master (.axi4(u_idle_axi4_if));
axi4_master_idle u_ga2d_master_idle (.axi4(u_ga2d_wide_axi4_if));
axi4_master_idle u_retired_sram_master (.axi4(u_retired_data_sram_axi4_if));
axi4_master_idle u_retired_sdram_master (.axi4(u_retired_data_sdram_axi4_if));
axi4_master_idle u_retired_qpi_master (.axi4(u_retired_data_qpi_axi4_if));
@@ -723,7 +769,7 @@ module retrosoc (
.Present (SramPresent),
.CapacityKiB(`SOC_ADDR_SRAM_SIZE >> 10),
.DataWidth (64),
.IdWidth (6)
.IdWidth (7)
) u_onchip_ram (
.clk_i (clk_hp_i),
.rst_n_i (rst_hp_n_i),
@@ -855,7 +901,7 @@ module retrosoc (
.usb2 (usb2),
.opipsram (u_opipsram_raw_if),
.i2c1 (u_i2c1_if),
.fault_valid_i (s_data_plane_fault_valid || s_bus_fault_valid),
.fault_valid_i (s_data_plane_fault_valid_pclk || s_bus_fault_valid),
.fault_addr_i (s_fault_addr_mux),
.fault_wstrb_i (s_fault_wstrb_mux),
.fault_reserved_i (s_fault_reserved_mux),
@@ -917,16 +963,19 @@ module retrosoc (
);
assign s_resource_idle_combined = {
s_ga2d_source_safe_idle && s_resource_idle_pclk[8],
s_apu_idle && s_resource_idle_pclk[7],
s_jpeg_idle && s_resource_idle_pclk[6],
s_ext_h_data_idle && s_resource_idle_pclk[5],
s_resource_idle_pclk[4:0]
};
assign s_resource_block_ack_combined = {
s_apu_idle && s_resource_block_ack_pclk[7], s_resource_block_ack_pclk[6:0]
s_ga2d_source_safe_idle && s_resource_block_ack_pclk[8],
s_apu_idle && s_resource_block_ack_pclk[7],
s_resource_block_ack_pclk[6:0]
};
logic [36:0] s_unused_domain_inputs;
logic [41:0] s_unused_domain_inputs;
assign s_unused_domain_inputs = {
clk_pclk_i,
rst_pclk_n_i,
@@ -934,9 +983,9 @@ module retrosoc (
rst_mem_n_i ^ s_mem_pad_lock_lp,
s_data_plane_outstanding_read,
s_data_plane_outstanding_write,
s_data_plane_fault_target,
s_data_plane_fault_addr[1:0],
s_data_plane_fault_reason[3],
s_data_plane_fault_target_pclk,
s_data_plane_fault_addr_pclk[1:0],
s_data_plane_fault_reason_pclk[3],
s_mgmt_router_idle,
s_hp_lifecycle_draining,
s_hp_lifecycle_fault,
@@ -944,6 +993,11 @@ module retrosoc (
^s_resource_owner_lock,
^s_resource_quiesce,
^s_resource_reset,
s_ga2d_source_stop,
s_ga2d_source_safe_idle,
s_ga2d_bridge_clear_busy,
^s_ga2d_bridge_epoch,
s_ga2d_data_ready,
^unused_cdc_clear_busy,
^unused_cdc_epoch,
^{s_hp_mmio_epoch, s_hp_mmio_clear_busy},
+386 -80
View File
@@ -16,7 +16,7 @@ module soc_data_plane (
input logic block_new_i,
input logic recovery_i,
input logic flush_i,
input logic [7:0] resource_block_i,
input logic [8:0] resource_block_i,
input logic [1:0] mem_pad_mode_i,
input logic ext_h_block_i,
input logic [31:0] ext_h_read_base_i,
@@ -32,6 +32,7 @@ module soc_data_plane (
axi4_if.slave usb2_axi4,
axi4_if.slave apu_axi4,
axi4_if.slave jpeg_axi4,
axi4_if.slave ga2d_axi4,
axi4_if.slave lp_data_axi4,
axi4_if.slave ext_h_axi4,
axi4_if.master sram_gateway_axi4,
@@ -40,16 +41,22 @@ module soc_data_plane (
axi4_if.master opi_gateway_axi4,
axi4_if.master xpi_gateway_axi4,
apb4_if.slave fabric_monitor_apb4,
input logic fault_ready_i,
output logic idle_o,
output logic flush_busy_o,
output logic ext_h_idle_o,
output logic [7:0] apu_bridge_epoch_o,
output logic [7:0] resource_idle_o,
output logic [7:0] resource_block_ack_o,
output logic ga2d_source_stop_o,
output logic ga2d_source_safe_idle_o,
output logic ga2d_bridge_clear_busy_o,
output logic [7:0] ga2d_bridge_epoch_o,
output logic ga2d_data_ready_o,
output logic [8:0] resource_idle_o,
output logic [8:0] resource_block_ack_o,
output logic [7:0] outstanding_read_o,
output logic [7:0] outstanding_write_o,
output logic fault_valid_o,
output logic [2:0] fault_master_o,
output logic [3:0] fault_master_o,
output logic [2:0] fault_target_o,
output logic [31:0] fault_addr_o,
output logic fault_write_o,
@@ -58,6 +65,9 @@ module soc_data_plane (
);
localparam int unsigned NumIoMasters = 3;
localparam int unsigned NumMemoryTargets = 5;
localparam int unsigned NumDataMasters = 9;
localparam int unsigned NumFaultSources = NumMemoryTargets + 1;
localparam int unsigned FaultSourceWidth = $clog2(NumFaultSources);
localparam logic [3:0] FaultTimeout = 4'd5;
logic [ 1:0] s_mem_pad_mode_hp;
@@ -70,58 +80,85 @@ module soc_data_plane (
logic [NumMemoryTargets-1:0] s_guard_timeout_valid;
logic [NumMemoryTargets-1:0] s_guard_isolated;
logic [NumMemoryTargets-1:0] s_guard_timeout_write;
logic [NumMemoryTargets-1:0][ 5:0] s_guard_timeout_id;
logic [NumMemoryTargets-1:0][ 6:0] s_guard_timeout_id;
logic [NumMemoryTargets-1:0][31:0] s_guard_timeout_addr;
logic [NumMemoryTargets-1:0] s_target_abort_mem;
logic s_crossbar_fault_valid;
logic [ 2:0] s_crossbar_fault_master;
logic [ 3:0] s_crossbar_fault_master;
logic [ 2:0] s_crossbar_fault_target;
logic [ 31:0] s_crossbar_fault_addr;
logic s_crossbar_fault_write;
logic [ 3:0] s_crossbar_fault_reason;
logic s_lp_clear_busy;
logic s_ext_clear_busy;
logic s_jpeg_clear_busy;
logic [ NumIoMasters-1:0][ 7:0] unused_io_epoch;
logic [NumMemoryTargets-1:0][ 7:0] unused_target_epoch;
logic [ 7:0] unused_lp_epoch;
logic [ 7:0] unused_ext_epoch;
logic [ 7:0] unused_jpeg_epoch;
logic [ 2:0] s_unused_epoch;
logic [ 7:0] s_resource_block_hp;
logic [ 7:0] s_master_idle;
logic [ 7:0] s_master_block;
logic [ 7:0] s_monitor_master_read_accept;
logic [ 7:0] s_monitor_master_write_accept;
logic [ 7:0] s_monitor_master_read_beat;
logic [ 7:0] s_monitor_master_write_beat;
logic [ 7:0] s_monitor_master_wait;
logic [ 7:0] s_monitor_master_promotion;
logic [ 7:0][ 2:0] s_monitor_master_read_outstanding;
logic [ 7:0][ 2:0] s_monitor_master_write_outstanding;
logic [ 5:0] s_monitor_target_read_accept;
logic [ 5:0] s_monitor_target_write_accept;
logic [ 5:0] s_monitor_target_read_beat;
logic [ 5:0] s_monitor_target_write_beat;
logic [ 5:0] s_monitor_target_wait;
logic [ 5:0][ 2:0] s_monitor_target_read_outstanding;
logic [ 5:0][ 2:0] s_monitor_target_write_outstanding;
logic [ 5:0] s_monitor_target_timeout;
logic [ 5:0] s_monitor_target_isolated;
logic s_crossbar_fault_ready;
logic [NumMemoryTargets-1:0] s_guard_timeout_ready;
logic [ NumFaultSources-1:0] s_fault_src_req;
logic s_fault_src_candidate_valid;
logic [FaultSourceWidth-1:0] s_fault_src_candidate;
logic s_fault_src_hold_d, s_fault_src_hold_q;
logic [FaultSourceWidth-1:0] s_fault_src_sel_d, s_fault_src_sel_q;
logic [FaultSourceWidth-1:0] s_fault_src_last_d, s_fault_src_last_q;
logic s_fault_src_valid;
logic [FaultSourceWidth-1:0] s_fault_src_sel;
logic s_lp_clear_busy;
logic s_ext_clear_busy;
logic s_jpeg_clear_busy;
logic s_ga2d_clear_busy;
logic [ NumIoMasters-1:0][7:0] unused_io_epoch;
logic [NumMemoryTargets-1:0][7:0] unused_target_epoch;
logic [ 7:0] unused_lp_epoch;
logic [ 7:0] unused_ext_epoch;
logic [ 7:0] unused_jpeg_epoch;
logic [ 7:0] s_ga2d_epoch;
logic [ 2:0] s_unused_epoch;
logic s_ga2d_recovery_condition;
logic s_ga2d_source_stop_q;
logic s_ga2d_source_stop_ready;
logic s_ga2d_source_safe_idle;
logic s_ga2d_write_pending;
logic s_ga2d_source_safe_idle_hp;
logic s_ga2d_source_quiesced_q;
logic s_ga2d_source_quiesced_hp;
logic s_ga2d_hp_reset_n_pclk;
logic s_ga2d_flush_pclk;
logic [ 7:0] s_ga2d_epoch_seen_q;
logic s_ga2d_data_ready_q;
logic s_ga2d_rearm_q;
logic s_ga2d_master_idle_pclk;
logic s_ga2d_block_ack_pclk;
logic [ 8:0] s_resource_block_hp;
logic [ 8:0] s_master_idle;
logic [ 8:0] s_master_block;
logic [ 8:0] s_monitor_master_read_accept;
logic [ 8:0] s_monitor_master_write_accept;
logic [ 8:0] s_monitor_master_read_beat;
logic [ 8:0] s_monitor_master_write_beat;
logic [ 8:0] s_monitor_master_wait;
logic [ 8:0] s_monitor_master_promotion;
logic [ 8:0][2:0] s_monitor_master_read_outstanding;
logic [ 8:0][2:0] s_monitor_master_write_outstanding;
logic [ 5:0] s_monitor_target_read_accept;
logic [ 5:0] s_monitor_target_write_accept;
logic [ 5:0] s_monitor_target_read_beat;
logic [ 5:0] s_monitor_target_write_beat;
logic [ 5:0] s_monitor_target_wait;
logic [ 5:0][2:0] s_monitor_target_read_outstanding;
logic [ 5:0][2:0] s_monitor_target_write_outstanding;
logic [ 5:0] s_monitor_target_timeout;
logic [ 5:0] s_monitor_target_isolated;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_master_axi4[8] (
) u_master_axi4[NumDataMasters] (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_crossbar_target_axi4[6] (
.aclk (clk_hp_i),
@@ -130,7 +167,7 @@ module soc_data_plane (
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_target_axi4[NumMemoryTargets] (
.aclk (clk_hp_i),
@@ -139,7 +176,7 @@ module soc_data_plane (
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_target_mem_axi4[NumMemoryTargets-1] (
.aclk (clk_mem_i),
@@ -157,7 +194,7 @@ module soc_data_plane (
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_hp_icache_prefixed_axi4 (
.aclk (clk_hp_i),
@@ -166,7 +203,7 @@ module soc_data_plane (
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_hp_dcache_prefixed_axi4 (
.aclk (clk_hp_i),
@@ -229,7 +266,7 @@ module soc_data_plane (
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_ext_h_prefixed_axi4 (
.aclk (clk_hp_i),
@@ -247,12 +284,39 @@ module soc_data_plane (
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_jpeg_prefixed_axi4 (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) u_ga2d_gated_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) u_ga2d_hp_axi4 (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (7),
.USER_WIDTH(1)
) u_ga2d_prefixed_axi4 (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(2)
@@ -264,15 +328,112 @@ module soc_data_plane (
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(8)
.DATA_WIDTH(9)
) u_resource_block_sync (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
.dat_i (resource_block_i),
.dat_o (s_resource_block_hp)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_ga2d_source_idle_sync (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
.dat_i (s_ga2d_source_safe_idle),
.dat_o (s_ga2d_source_safe_idle_hp)
);
// A fresh source quiesce prevents stale idle from blocking W-before-AW traffic.
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_ga2d_source_quiesced_sync (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
.dat_i (s_ga2d_source_quiesced_q),
.dat_o (s_ga2d_source_quiesced_hp)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_ga2d_hp_reset_sync (
.clk_i (clk_io_i),
.rst_n_i(rst_io_n_i),
.dat_i (rst_hp_n_i),
.dat_o (s_ga2d_hp_reset_n_pclk)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_ga2d_flush_sync (
.clk_i (clk_io_i),
.rst_n_i(rst_io_n_i),
.dat_i (flush_i),
.dat_o (s_ga2d_flush_pclk)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_ga2d_master_idle_sync (
.clk_i (clk_io_i),
.rst_n_i(rst_io_n_i),
.dat_i (s_master_idle[8]),
.dat_o (s_ga2d_master_idle_pclk)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_ga2d_block_ack_sync (
.clk_i (clk_io_i),
.rst_n_i(rst_io_n_i),
.dat_i (resource_block_ack_o[8]),
.dat_o (s_ga2d_block_ack_pclk)
);
assign s_ga2d_recovery_condition = resource_block_i[8] || !s_ga2d_hp_reset_n_pclk ||
s_ga2d_flush_pclk || s_ga2d_clear_busy ||
(s_ga2d_epoch != s_ga2d_epoch_seen_q);
assign s_ga2d_source_stop_ready = (!ga2d_axi4.awvalid || ga2d_axi4.awready) &&
(!ga2d_axi4.arvalid || ga2d_axi4.arready) &&
(!ga2d_axi4.wvalid || s_ga2d_write_pending);
assign ga2d_source_stop_o = s_ga2d_source_stop_q;
assign ga2d_source_safe_idle_o = s_ga2d_source_safe_idle;
assign ga2d_bridge_clear_busy_o = s_ga2d_clear_busy;
assign ga2d_bridge_epoch_o = s_ga2d_epoch;
assign ga2d_data_ready_o = s_ga2d_data_ready_q;
always_ff @(posedge clk_io_i or negedge rst_io_n_i) begin
if (!rst_io_n_i) begin
s_ga2d_source_stop_q <= 1'b1;
s_ga2d_epoch_seen_q <= '0;
s_ga2d_data_ready_q <= 1'b0;
s_ga2d_rearm_q <= 1'b1;
s_ga2d_source_quiesced_q <= 1'b0;
end else begin
s_ga2d_epoch_seen_q <= s_ga2d_epoch;
s_ga2d_source_quiesced_q <= resource_block_i[8] && s_ga2d_source_stop_q &&
s_ga2d_source_safe_idle;
if (s_ga2d_recovery_condition) begin
s_ga2d_rearm_q <= 1'b1;
s_ga2d_data_ready_q <= 1'b0;
if (s_ga2d_source_stop_ready) begin
s_ga2d_source_stop_q <= 1'b1;
end
end else if (s_ga2d_rearm_q) begin
s_ga2d_data_ready_q <= 1'b0;
if (s_ga2d_source_safe_idle && s_ga2d_master_idle_pclk && !s_ga2d_block_ack_pclk) begin
s_ga2d_source_stop_q <= 1'b0;
s_ga2d_rearm_q <= 1'b0;
end
end else begin
s_ga2d_data_ready_q <= 1'b1;
end
end
end
assign s_master_block = {
s_resource_block_hp[8] && s_ga2d_source_quiesced_hp,
s_resource_block_hp[5],
s_resource_block_hp[6],
1'b0,
@@ -282,6 +443,8 @@ module soc_data_plane (
2'b00
};
assign resource_idle_o = {
(s_resource_block_hp[8] ? s_ga2d_source_quiesced_hp : s_ga2d_source_safe_idle_hp) &&
s_master_idle[8],
s_master_idle[3],
s_master_idle[6],
s_master_idle[7],
@@ -291,10 +454,13 @@ module soc_data_plane (
s_master_idle[3],
s_master_idle[2]
};
assign resource_block_ack_o = s_resource_block_hp;
assign resource_block_ack_o = {
s_resource_block_hp[8] && s_ga2d_source_quiesced_hp && s_master_idle[8],
s_resource_block_hp[7:0]
};
axi4_id_prefix #(
.MasterIndex(3'd0)
.MasterIndex(4'd0)
) u_hp_icache_prefix (
.source(hp_icache_axi4),
.sink (u_hp_icache_prefixed_axi4)
@@ -304,7 +470,7 @@ module soc_data_plane (
.sink (u_master_axi4[0])
);
axi4_id_prefix #(
.MasterIndex(3'd1)
.MasterIndex(4'd1)
) u_hp_dcache_prefix (
.source(hp_dcache_axi4),
.sink (u_hp_dcache_prefixed_axi4)
@@ -357,7 +523,7 @@ module soc_data_plane (
.dst_axi4 (u_io_hp_axi4[master])
);
axi4_upsizer_32to64 #(
.MasterIndex(3'(master + 2))
.MasterIndex(4'(master + 2))
) u_io_upsizer (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
@@ -381,7 +547,7 @@ module soc_data_plane (
.dst_axi4 (u_lp_data_hp_axi4)
);
axi4_upsizer_32to64 #(
.MasterIndex(3'd5)
.MasterIndex(4'd5)
) u_lp_data_upsizer (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
@@ -403,7 +569,7 @@ module soc_data_plane (
.dst_axi4 (u_jpeg_hp_axi4)
);
axi4_id_prefix #(
.MasterIndex(3'd6)
.MasterIndex(4'd6)
) u_jpeg_prefix (
.source(u_jpeg_hp_axi4),
.sink (u_jpeg_prefixed_axi4)
@@ -413,6 +579,41 @@ module soc_data_plane (
.sink (u_master_axi4[6])
);
axi4_address_gate u_ga2d_source_gate (
.clk_i (clk_io_i),
.rst_n_i (rst_io_n_i),
.block_new_i (s_ga2d_source_stop_q),
.clear_i (s_ga2d_flush_pclk),
.source (ga2d_axi4),
.sink (u_ga2d_gated_axi4),
.idle_o (s_ga2d_source_safe_idle),
.write_pending_o(s_ga2d_write_pending)
);
axi4_async_bridge #(
.DataWidth(64),
.IdWidth (3)
) u_ga2d_cdc (
.src_clk_i (clk_io_i),
.src_rst_n_i (rst_io_n_i),
.dst_clk_i (clk_hp_i),
.dst_rst_n_i (rst_hp_n_i),
.clear_i (flush_i),
.clear_busy_o(s_ga2d_clear_busy),
.epoch_o (s_ga2d_epoch),
.src_axi4 (u_ga2d_gated_axi4),
.dst_axi4 (u_ga2d_hp_axi4)
);
axi4_id_prefix #(
.MasterIndex(4'd8)
) u_ga2d_prefix (
.source(u_ga2d_hp_axi4),
.sink (u_ga2d_prefixed_axi4)
);
axi4_connector u_ga2d_connector (
.source(u_ga2d_prefixed_axi4),
.sink (u_master_axi4[8])
);
axi4_async_bridge #(
.DataWidth(64),
.IdWidth (3)
@@ -428,15 +629,17 @@ module soc_data_plane (
.dst_axi4 (u_ext_h_hp_axi4)
);
axi4_address_gate u_ext_h_address_gate (
.clk_i (clk_io_i),
.rst_n_i (rst_io_n_i),
.block_new_i(ext_h_block_i),
.source (ext_h_axi4),
.sink (u_ext_h_gated_axi4),
.idle_o (ext_h_idle_o)
.clk_i (clk_io_i),
.rst_n_i (rst_io_n_i),
.block_new_i (ext_h_block_i),
.clear_i (1'b0),
.source (ext_h_axi4),
.sink (u_ext_h_gated_axi4),
.idle_o (ext_h_idle_o),
.write_pending_o()
);
axi4_id_prefix #(
.MasterIndex(3'd7)
.MasterIndex(4'd7)
) u_ext_h_prefix (
.source(u_ext_h_hp_axi4),
.sink (u_ext_h_prefixed_axi4)
@@ -447,6 +650,8 @@ module soc_data_plane (
);
axi4_data_crossbar #(
.NumMasters (NumDataMasters),
.NumTargets (6),
.ReadTargetMask (`SOC_DATA_POLICY_READ_TARGET_MASK),
.WriteTargetMask (`SOC_DATA_POLICY_WRITE_TARGET_MASK),
.AllowInstruction (`SOC_DATA_POLICY_ALLOW_INSTRUCTION),
@@ -457,6 +662,8 @@ module soc_data_plane (
.block_new_i (block_new_i),
.master_block_i (s_master_block),
.recovery_i (recovery_i),
.flush_i (flush_i),
.fault_ready_i (s_crossbar_fault_ready),
.mem_pad_mode_i (s_mem_pad_mode_hp),
.ext_h_read_base_i (ext_h_read_base_i),
.ext_h_read_limit_i (ext_h_read_limit_i),
@@ -496,6 +703,7 @@ module soc_data_plane (
(target == 1) ? 32'd8192 : 32'd65535;
axi4_target_guard #(
.IdWidth (7),
.ReadDepth (target < 2 ? 4 : 2),
.WriteDepth(2)
) u_target_guard (
@@ -507,6 +715,7 @@ module soc_data_plane (
.abort_o (s_guard_abort[target]),
.abort_done_i (s_guard_abort_done[target]),
.timeout_valid_o(s_guard_timeout_valid[target]),
.timeout_ready_i(s_guard_timeout_ready[target]),
.isolated_o (s_guard_isolated[target]),
.timeout_write_o(s_guard_timeout_write[target]),
.timeout_id_o (s_guard_timeout_id[target]),
@@ -524,7 +733,7 @@ module soc_data_plane (
end else begin : gen_stable_memory
axi4_async_bridge #(
.DataWidth(64),
.IdWidth (6)
.IdWidth (7)
) u_target_cdc (
.src_clk_i (clk_hp_i),
.src_rst_n_i (rst_hp_n_i),
@@ -546,7 +755,7 @@ module soc_data_plane (
.dat_o (s_target_abort_mem[target])
);
axi4_downsizer_64to32 #(
.WideIdWidth(6)
.WideIdWidth(7)
) u_target_downsizer (
.clk_i (clk_mem_i),
.rst_n_i(rst_mem_n_i),
@@ -560,17 +769,20 @@ module soc_data_plane (
axi4_error_slave #(
.Response(2'b11),
.IdWidth (6)
.IdWidth (7)
) u_data_error_slave (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
.axi4 (u_crossbar_target_axi4[5])
);
assign s_monitor_target_timeout = {1'b0, s_guard_timeout_valid};
assign s_monitor_target_timeout = {1'b0, s_guard_timeout_valid & s_guard_timeout_ready};
assign s_monitor_target_isolated = {1'b0, s_guard_isolated};
fabric_monitor u_fabric_monitor (
fabric_monitor #(
.NumMasters(NumDataMasters),
.NumTargets(6)
) u_fabric_monitor (
.clk_i (clk_hp_i),
.rst_n_i (rst_hp_n_i),
.idle_i (idle_o),
@@ -579,7 +791,7 @@ module soc_data_plane (
.flush_i (flush_i),
.outstanding_read_i (outstanding_read_o),
.outstanding_write_i (outstanding_write_o),
.fault_valid_i (fault_valid_o),
.fault_valid_i (fault_valid_o && fault_ready_i),
.fault_master_i (fault_master_o),
.fault_target_i (fault_target_o),
.fault_addr_i (fault_addr_o),
@@ -622,29 +834,123 @@ module soc_data_plane (
end
always_comb begin
fault_valid_o = s_crossbar_fault_valid;
fault_master_o = s_crossbar_fault_master;
fault_target_o = s_crossbar_fault_target;
fault_addr_o = s_crossbar_fault_addr;
fault_write_o = s_crossbar_fault_write;
fault_reason_o = s_crossbar_fault_reason;
if (!s_crossbar_fault_valid) begin
for (int target = NumMemoryTargets - 1; target >= 0; target--) begin
if (s_guard_timeout_valid[target]) begin
fault_valid_o = 1'b1;
fault_master_o = s_guard_timeout_id[target][5:3];
fault_target_o = 3'(target);
fault_addr_o = s_guard_timeout_addr[target];
fault_write_o = s_guard_timeout_write[target];
fault_reason_o = FaultTimeout;
s_fault_src_req = '0;
s_fault_src_req[0] = s_crossbar_fault_valid;
for (int target = 0; target < NumMemoryTargets; target++) begin
s_fault_src_req[target+1] = s_guard_timeout_valid[target];
end
end
always_comb begin
s_fault_src_candidate_valid = 1'b0;
s_fault_src_candidate = '0;
for (int offset = 1; offset <= NumFaultSources; offset++) begin
int src;
src = int'(s_fault_src_last_q) + offset;
if (src >= NumFaultSources) src = src - NumFaultSources;
if (!s_fault_src_candidate_valid && s_fault_src_req[src]) begin
s_fault_src_candidate_valid = 1'b1;
s_fault_src_candidate = FaultSourceWidth'(src);
end
end
end
always_comb begin
s_fault_src_valid = 1'b0;
s_fault_src_sel = '0;
if (s_fault_src_hold_q) begin
s_fault_src_sel = s_fault_src_sel_q;
s_fault_src_valid = s_fault_src_req[s_fault_src_sel_q];
end else if (s_fault_src_candidate_valid) begin
s_fault_src_sel = s_fault_src_candidate;
s_fault_src_valid = 1'b1;
end
end
always_comb begin
fault_valid_o = s_fault_src_valid;
fault_master_o = '0;
fault_target_o = '0;
fault_addr_o = '0;
fault_write_o = 1'b0;
fault_reason_o = '0;
if (s_fault_src_valid) begin
if (s_fault_src_sel == FaultSourceWidth'(0)) begin
fault_master_o = s_crossbar_fault_master;
fault_target_o = s_crossbar_fault_target;
fault_addr_o = s_crossbar_fault_addr;
fault_write_o = s_crossbar_fault_write;
fault_reason_o = s_crossbar_fault_reason;
end else begin
for (int target = 0; target < NumMemoryTargets; target++) begin
if (s_fault_src_sel == FaultSourceWidth'(target + 1)) begin
fault_master_o = s_guard_timeout_id[target][6:3];
fault_target_o = 3'(target);
fault_addr_o = s_guard_timeout_addr[target];
fault_write_o = s_guard_timeout_write[target];
fault_reason_o = FaultTimeout;
end
end
end
end
end
always_comb begin
s_crossbar_fault_ready = 1'b0;
s_guard_timeout_ready = '0;
if (s_fault_src_valid && fault_ready_i) begin
if (s_fault_src_sel == FaultSourceWidth'(0)) begin
s_crossbar_fault_ready = 1'b1;
end else begin
for (int target = 0; target < NumMemoryTargets; target++) begin
if (s_fault_src_sel == FaultSourceWidth'(target + 1)) begin
s_guard_timeout_ready[target] = 1'b1;
end
end
end
end
end
always_comb begin
s_fault_src_hold_d = s_fault_src_hold_q;
s_fault_src_sel_d = s_fault_src_sel_q;
s_fault_src_last_d = s_fault_src_last_q;
if (flush_i) begin
s_fault_src_hold_d = 1'b0;
end else if (s_fault_src_hold_q) begin
if (!s_fault_src_valid) begin
s_fault_src_hold_d = 1'b0;
end else if (fault_ready_i) begin
s_fault_src_hold_d = 1'b0;
s_fault_src_last_d = s_fault_src_sel_q;
end
end else if (s_fault_src_candidate_valid) begin
if (fault_ready_i) begin
s_fault_src_last_d = s_fault_src_candidate;
end else begin
s_fault_src_hold_d = 1'b1;
s_fault_src_sel_d = s_fault_src_candidate;
end
end
end
// Each source holds its payload until accepted; the selector locks it while
// the mailbox backpressures and rotates grants after every accepted event.
always_ff @(posedge clk_hp_i or negedge rst_hp_n_i) begin
if (!rst_hp_n_i) begin
s_fault_src_hold_q <= 1'b0;
s_fault_src_sel_q <= '0;
s_fault_src_last_q <= FaultSourceWidth'(NumFaultSources - 1);
end else begin
s_fault_src_hold_q <= s_fault_src_hold_d;
s_fault_src_sel_q <= s_fault_src_sel_d;
s_fault_src_last_q <= s_fault_src_last_d;
end
end
assign flush_busy_o = (|s_io_clear_busy) || (|s_target_clear_busy) ||
(|s_guard_clear_busy) || s_lp_clear_busy || s_ext_clear_busy ||
s_jpeg_clear_busy;
s_jpeg_clear_busy || s_ga2d_clear_busy;
assign apu_bridge_epoch_o = unused_io_epoch[1];
assign s_unused_epoch = {
^unused_io_epoch, ^unused_target_epoch, ^{unused_lp_epoch, unused_ext_epoch, unused_jpeg_epoch}
+1
View File
@@ -342,6 +342,7 @@
"core_wrapper.sv",
"clock_config_controller.sv",
"clock_frequency_monitor.sv",
"data_plane_fault_cdc.sv",
"extension_compat.sv",
"extension_dma_master.sv",
"extension_slot.sv",
+15
View File
@@ -23,6 +23,10 @@ CDC_PRIMITIVES = {
"edge_det",
"hazard3_apb_async_bridge",
}
DATA_PLANE_FAULT_RESET_CONTRACT = {
"source_reset": "abort_accepted_mailbox_item",
"destination_reset": "abort_accepted_item_backpressure_unaccepted_source",
}
IDENTIFIER_RE = re.compile(r"[A-Za-z_][A-Za-z0-9_]*$")
HIERARCHICAL_PIN_RE = re.compile(
r"[A-Za-z_][A-Za-z0-9_.]*(?:/[A-Za-z_][A-Za-z0-9_.]*)+$"
@@ -144,6 +148,17 @@ def validate(document_path: Path, root: Path) -> None:
raise ValueError(f"{field}.primitive is not an approved CDC primitive")
path = root / require_string(crossing.get("path"), f"{field}.path")
instance = require_identifier(crossing.get("instance"), f"{field}.instance")
if name == "data_plane_fault":
if primitive != "async_reqack" or instance != "u_fault_mailbox":
raise ValueError(
f"{field} must use async_reqack instance u_fault_mailbox"
)
reset_contract = crossing.get("unilateral_reset")
if (not isinstance(reset_contract, dict) or
reset_contract != DATA_PLANE_FAULT_RESET_CONTRACT):
raise ValueError(
f"{field}.unilateral_reset must declare the data-plane fault reset contract"
)
require_instance(path, primitive, instance, field)
+2
View File
@@ -34,6 +34,7 @@ TEST_SOURCES = (
"crt/src/hal/dma_math.c",
"crt/src/hal/jpeg_math.c",
"crt/src/hal/apu.c",
"crt/src/hal/fabric_monitor.c",
"crt/src/hal/sysctrl.c",
"crt/src/hal/clock.c",
"crt/src/hal/resource.c",
@@ -95,6 +96,7 @@ def main() -> int:
"-Werror",
"-fno-builtin",
"-DRS_APU_TEST_MMIO",
"-DRS_FABRIC_MONITOR_TEST_MMIO",
"-I",
str(memory_map_root / "include"),
"-I",
+56
View File
@@ -11,6 +11,7 @@
#include <retrosoc/hal/clock.h>
#include <retrosoc/hal/extension.h>
#include <retrosoc/hal/dma.h>
#include <retrosoc/hal/fabric_monitor.h>
#include <retrosoc/hal/i2c.h>
#include <retrosoc/hal/lcd.h>
#include <retrosoc/hal/i2s.h>
@@ -44,8 +45,10 @@ unsigned long long __umoddi3(unsigned long long dividend, unsigned long long div
static uint8_t storage[32];
static uint32_t image_call_count;
volatile uint32_t rs_apu_test_mmio[1024];
volatile uint32_t rs_fabric_monitor_test_mmio[1024];
#define APU_TEST_REG(offset) rs_apu_test_mmio[(offset) / 4U]
#define FABRIC_MONITOR_TEST_REG(offset) rs_fabric_monitor_test_mmio[(offset) / 4U]
void putch(char ch) {
(void)ch;
@@ -855,6 +858,12 @@ static int test_extension_validation(void) {
static int test_resource_validation(void) {
rs_resource_status_t status;
if ((RS_RESOURCE_DMA != 0) || (RS_RESOURCE_USB2 != 1) || (RS_RESOURCE_SDIO0 != 2) ||
(RS_RESOURCE_SDIO1 != 3) || (RS_RESOURCE_SPISD != 4) || (RS_RESOURCE_EXT_H != 5) ||
(RS_RESOURCE_JPEG != 6) || (RS_RESOURCE_APU != 7) || (RS_RESOURCE_GA2D != 8) ||
(RS_RESOURCE_COUNT != 9)) {
return 1;
}
if ((rs_resource_get_status((rs_resource_t)RS_RESOURCE_COUNT, &status) != RS_EINVAL) ||
(rs_resource_get_status(RS_RESOURCE_DMA, NULL) != RS_EINVAL) ||
(rs_resource_set_owner((rs_resource_t)RS_RESOURCE_COUNT, RS_RESOURCE_OWNER_LP, false) !=
@@ -863,8 +872,54 @@ static int test_resource_validation(void) {
(rs_resource_set_lifecycle((rs_resource_t)RS_RESOURCE_COUNT, false, false) != RS_EINVAL) ||
(rs_resource_clear_fault((rs_resource_t)RS_RESOURCE_COUNT) != RS_EINVAL) ||
(rs_resource_get_cache_status(NULL) != RS_EINVAL)) {
return 2;
}
return 0;
}
static void test_fabric_monitor_mmio_reset(void) {
for (size_t index = 0U;
index < (sizeof(rs_fabric_monitor_test_mmio) / sizeof(rs_fabric_monitor_test_mmio[0]));
++index) {
rs_fabric_monitor_test_mmio[index] = 0U;
}
}
static int test_fabric_monitor_hal_contract(void) {
rs_fabric_fault_t fault;
if ((RS_FABRIC_MASTER_HP_ICACHE != 0) || (RS_FABRIC_MASTER_HP_DCACHE != 1) ||
(RS_FABRIC_MASTER_DMA != 2) || (RS_FABRIC_MASTER_IO_A != 3) ||
(RS_FABRIC_MASTER_IO_B != 4) || (RS_FABRIC_MASTER_LP != 5) ||
(RS_FABRIC_MASTER_JPEG != 6) || (RS_FABRIC_MASTER_RESERVED != 6) ||
(RS_FABRIC_MASTER_EXT_H != 7) || (RS_FABRIC_MASTER_GA2D != 8) ||
(RS_FABRIC_MASTER_COUNT != 9)) {
return 1;
}
test_fabric_monitor_mmio_reset();
FABRIC_MONITOR_TEST_REG(UINT32_C(0x004)) = UINT32_C(0x00010000);
FABRIC_MONITOR_TEST_REG(UINT32_C(0x014)) =
UINT32_C(0x00001000) | UINT32_C(0x0A00) | UINT32_C(0x0080) | UINT32_C(0x000C) |
UINT32_C(0x0003);
FABRIC_MONITOR_TEST_REG(UINT32_C(0x018)) = UINT32_C(0x12345678);
FABRIC_MONITOR_TEST_REG(UINT32_C(0x020)) = UINT32_C(0x0000002A);
if ((rs_fabric_monitor_read_fault(&fault) != RS_OK) || (fault.master != 3U) ||
(fault.target != 4U) || (fault.reason != 10U) || !fault.valid || !fault.write ||
(fault.address != UINT32_C(0x12345678)) || (fault.count != UINT32_C(0x0000002A))) {
return 2;
}
FABRIC_MONITOR_TEST_REG(UINT32_C(0x004)) = UINT32_C(0x00010001);
FABRIC_MONITOR_TEST_REG(UINT32_C(0x014)) =
UINT32_C(0x00001000) | UINT32_C(0x0A00) | UINT32_C(0x0080) | UINT32_C(0x0003);
if ((rs_fabric_monitor_read_fault(&fault) != RS_OK) ||
(fault.master != RS_FABRIC_MASTER_GA2D)) {
return 3;
}
if (rs_fabric_monitor_read_fault(NULL) != RS_EINVAL) {
return 4;
}
return 0;
}
@@ -1205,6 +1260,7 @@ int main(void) {
test_user_ip_validation(),
test_extension_validation(),
test_resource_validation(),
test_fabric_monitor_hal_contract(),
test_apu_validation(),
test_apu_hal_contract(),
test_jpeg_validation(),
+1
View File
@@ -374,6 +374,7 @@ module apu_p2_integration_tb;
.abort_o (target_guard_abort),
.abort_done_i (target_guard_abort),
.timeout_valid_o(),
.timeout_ready_i(1'b1),
.isolated_o (),
.timeout_write_o(),
.timeout_id_o (),
+38 -6
View File
@@ -4,7 +4,9 @@ module axi4_address_gate_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic block_new_i = 1'b0;
logic clear_i = 1'b0;
logic idle_o;
logic write_pending_o;
axi4_if #(
.ADDR_WIDTH(32),
@@ -28,12 +30,14 @@ module axi4_address_gate_tb;
always #5 clk_i = ~clk_i;
axi4_address_gate u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.block_new_i(block_new_i),
.source (source),
.sink (sink),
.idle_o (idle_o)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.block_new_i (block_new_i),
.clear_i (clear_i),
.source (source),
.sink (sink),
.idle_o (idle_o),
.write_pending_o(write_pending_o)
);
initial begin
@@ -111,6 +115,15 @@ module axi4_address_gate_tb;
sink.bvalid = 1'b0;
if (!idle_o) $fatal(1, "write completion did not restore idle");
source.wvalid = 1'b1;
#1;
if (idle_o || source.wready || sink.wvalid || write_pending_o) begin
$fatal(1, "write data before its address was accepted or reported idle");
end
source.wvalid = 1'b0;
#1;
if (!idle_o) $fatal(1, "unaccepted write data did not restore idle after withdrawal");
block_new_i = 1'b0;
source.arvalid = 1'b1;
@(posedge clk_i);
@@ -128,6 +141,25 @@ module axi4_address_gate_tb;
sink.rvalid = 1'b0;
if (!idle_o) $fatal(1, "read completion did not restore idle");
block_new_i = 1'b0;
clear_i = 1'b1;
source.awvalid = 1'b1;
source.wvalid = 1'b1;
source.arvalid = 1'b1;
#1;
if (source.awready || source.wready || source.arready || sink.awvalid || sink.wvalid ||
sink.arvalid) begin
$fatal(1, "clear boundary accepted a source transaction");
end
@(posedge clk_i);
@(negedge clk_i);
source.awvalid = 1'b0;
source.wvalid = 1'b0;
source.arvalid = 1'b0;
clear_i = 1'b0;
#1;
if (!idle_o) $fatal(1, "clear boundary did not restore the gate to idle");
$display("AXI4 address gate quiesce test passed");
$finish;
end
+260 -34
View File
@@ -1,29 +1,31 @@
`timescale 1ns / 1ps
module axi4_data_crossbar_tb;
localparam int NumMasters = 8;
localparam int NumMasters = 9;
localparam int NumTargets = 6;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic idle_o;
logic [ 7:0] master_block_i = '0;
logic [ 7:0] master_idle_o;
logic [ 8:0] master_block_i = '0;
logic [ 8:0] master_idle_o;
logic [ 7:0] outstanding_read_o;
logic [ 7:0] outstanding_write_o;
logic fault_valid_o;
logic [ 2:0] fault_master_o;
logic fault_ready_i = 1'b1;
logic [ 3:0] fault_master_o;
logic [ 2:0] fault_target_o;
logic [31:0] fault_addr_o;
logic fault_write_o;
logic [ 3:0] fault_reason_o;
logic recovery_i = 1'b0;
logic [ 7:0] monitor_master_promotion_o;
logic flush_i = 1'b0;
logic [ 8:0] monitor_master_promotion_o;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) masters[NumMasters] (
.aclk (clk_i),
@@ -32,7 +34,7 @@ module axi4_data_crossbar_tb;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) targets[NumTargets] (
.aclk (clk_i),
@@ -47,17 +49,23 @@ module axi4_data_crossbar_tb;
end
axi4_data_crossbar #(
.StarvationCycles (4),
.ReadTargetMask (40'b1111100000111111111111111111111111111111),
.WriteTargetMask (40'b0111100000011110111101111011110111100000),
.AllowInstruction (8'b00000001),
.RequireNoncacheable(8'b11111100)
.StarvationCycles(4),
.ReadTargetMask(
'{5'b11111, 5'b11111, 5'b11111, 5'b11111, 5'b11111, 5'b11111, 5'b11111, 5'b11111, 5'b11111}
),
.WriteTargetMask(
'{5'b01111, 5'b01111, 5'b01111, 5'b01111, 5'b01111, 5'b01111, 5'b01111, 5'b01111, 5'b00000}
),
.AllowInstruction(9'b000000001),
.RequireNoncacheable(9'b111111100)
) u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.block_new_i (1'b0),
.master_block_i (master_block_i),
.recovery_i (recovery_i),
.flush_i (flush_i),
.fault_ready_i (fault_ready_i),
.mem_pad_mode_i (2'd1),
.ext_h_read_base_i (32'h3000_0000),
.ext_h_read_limit_i (32'h4FFF_FFFF),
@@ -78,7 +86,7 @@ module axi4_data_crossbar_tb;
.monitor_master_promotion_o(monitor_master_promotion_o)
);
task automatic issue_master1_read(input logic [5:0] id, input logic [31:0] addr);
task automatic issue_master1_read(input logic [6:0] id, input logic [31:0] addr);
begin
@(negedge clk_i);
masters[1].arid = id;
@@ -90,7 +98,7 @@ module axi4_data_crossbar_tb;
end
endtask
task automatic return_target0_read(input logic [5:0] id, input logic [63:0] data);
task automatic return_target0_read(input logic [6:0] id, input logic [63:0] data);
begin
@(negedge clk_i);
targets[0].rid = id;
@@ -104,7 +112,7 @@ module axi4_data_crossbar_tb;
end
endtask
task automatic return_target1_read(input logic [5:0] id, input logic [63:0] data);
task automatic return_target1_read(input logic [6:0] id, input logic [63:0] data);
begin
@(negedge clk_i);
targets[1].rid = id;
@@ -118,7 +126,7 @@ module axi4_data_crossbar_tb;
end
endtask
task automatic return_target5_read(input logic [5:0] id);
task automatic return_target5_read(input logic [6:0] id);
begin
@(negedge clk_i);
targets[5].rid = id;
@@ -131,6 +139,57 @@ module axi4_data_crossbar_tb;
end
endtask
task automatic return_target0_write(input logic [6:0] id);
begin
@(negedge clk_i);
targets[0].bid = id;
targets[0].bresp = 2'b00;
targets[0].bvalid = 1'b1;
do @(posedge clk_i); while (!targets[0].bready);
@(negedge clk_i);
targets[0].bvalid = 1'b0;
end
endtask
task automatic return_invalid_target0_response(input logic [3:0] prefix,
input logic write_access);
logic [6:0] id;
begin
id = {prefix, 3'd0};
@(negedge clk_i);
if (write_access) begin
targets[0].bid = id;
targets[0].bresp = 2'b00;
targets[0].bvalid = 1'b1;
end else begin
targets[0].rid = id;
targets[0].rdata = 64'hDEAD_BEEF_0000_0000 | id;
targets[0].rresp = 2'b00;
targets[0].rlast = 1'b1;
targets[0].rvalid = 1'b1;
end
#1;
if (!(write_access ? targets[0].bready : targets[0].rready)) begin
$fatal(1, "invalid returned master prefix was not accepted for containment");
end
@(posedge clk_i);
#1;
if (!fault_valid_o || (fault_master_o != prefix) || (fault_target_o != 3'd0) ||
(fault_reason_o != 4'd4) || (fault_write_o != write_access)) begin
$fatal(1, "invalid returned master prefix was not contained");
end
if (masters[0].rvalid || masters[0].bvalid) begin
$fatal(1, "invalid response prefix fell back to master 0");
end
@(negedge clk_i);
if (write_access) begin
targets[0].bvalid = 1'b0;
end else begin
targets[0].rvalid = 1'b0;
end
end
endtask
`define INIT_MASTER(index) \
masters[index].awid = '0; \
masters[index].awaddr = '0; \
@@ -188,6 +247,7 @@ module axi4_data_crossbar_tb;
`INIT_MASTER(5)
`INIT_MASTER(6)
`INIT_MASTER(7)
`INIT_MASTER(8)
`INIT_TARGET(0)
`INIT_TARGET(1)
`INIT_TARGET(2)
@@ -239,6 +299,83 @@ module axi4_data_crossbar_tb;
$fatal(1, "read completion did not drain the crossbar");
end
ga2d_master_id_credit_and_qos : begin
@(negedge clk_i);
targets[0].arready = 1'b0;
masters[8].arid = 7'h40;
masters[8].araddr = 32'h3000_0040;
masters[8].arqos = 4'hF;
masters[8].arvalid = 1'b1;
#1;
if (!targets[0].arvalid || (targets[0].arid != 7'h40) || (targets[0].arqos != 4'd0)) begin
$fatal(1, "GA2D read ID prefix or AxQOS was not preserved");
end
targets[0].arready = 1'b1;
do @(posedge clk_i); while (!masters[8].arready);
@(negedge clk_i);
masters[8].arvalid = 1'b0;
masters[8].arqos = '0;
@(negedge clk_i);
targets[0].awready = 1'b0;
masters[8].awid = 7'h41;
masters[8].awaddr = 32'h3000_0080;
masters[8].awqos = 4'hF;
masters[8].awvalid = 1'b1;
#1;
if (!targets[0].awvalid || (targets[0].awid != 7'h41) || (targets[0].awqos != 4'd0)) begin
$fatal(1, "GA2D write ID prefix or AxQOS was not preserved");
end
targets[0].awready = 1'b1;
do @(posedge clk_i); while (!masters[8].awready);
@(negedge clk_i);
masters[8].awvalid = 1'b0;
masters[8].awqos = '0;
masters[8].wdata = 64'hA5A5_5A5A_1122_3344;
masters[8].wstrb = 8'hFF;
masters[8].wvalid = 1'b1;
do @(posedge clk_i); while (!masters[8].wready);
@(negedge clk_i);
masters[8].wvalid = 1'b0;
@(negedge clk_i);
masters[8].arid = 7'h42;
masters[8].araddr = 32'h3000_00C0;
masters[8].arvalid = 1'b1;
masters[8].awid = 7'h43;
masters[8].awaddr = 32'h3000_0100;
masters[8].awvalid = 1'b1;
#1;
if (masters[8].arready || masters[8].awready) begin
$fatal(1, "GA2D exceeded its one-read plus one-write credit");
end
masters[8].arvalid = 1'b0;
masters[8].awvalid = 1'b0;
fork
return_target0_read(7'h40, 64'h8888_8888_8888_0040);
begin
wait (masters[8].rvalid);
if ((masters[8].rid != 7'h40) || (masters[8].rdata != 64'h8888_8888_8888_0040)) begin
$fatal(1, "GA2D read response did not return to master 8");
end
end
join
fork
return_target0_write(7'h41);
begin
wait (masters[8].bvalid);
if (masters[8].bid != 7'h41) begin
$fatal(1, "GA2D write response did not return to master 8");
end
end
join
@(negedge clk_i);
if (!idle_o || (outstanding_read_o != 8'd0) || (outstanding_write_o != 8'd0)) begin
$fatal(1, "GA2D master credits did not drain independently");
end
end
issue_master1_read(6'b001_010, 32'h3000_0040);
issue_master1_read(6'b001_011, 32'h3000_0080);
if (outstanding_read_o != 8'd2) begin
@@ -268,25 +405,76 @@ module axi4_data_crossbar_tb;
$fatal(1, "same-target reads did not drain the crossbar");
end
@(negedge clk_i);
masters[6].arid = 6'b110_000;
masters[6].araddr = 32'h3000_0000;
masters[6].arvalid = 1'b1;
do @(posedge clk_i); while (!masters[6].arready);
#1;
if (!fault_valid_o || (fault_master_o != 3'd6) ||
(fault_reason_o != 4'd3) || fault_write_o) begin
$fatal(1, "reserved-master ACL fault attribution mismatch");
jpeg_zero_credit : begin
@(negedge clk_i);
masters[6].arid = 7'h30;
masters[6].araddr = 32'h3000_0000;
masters[6].arvalid = 1'b1;
#1;
if (masters[6].arready || targets[0].arvalid) begin
$fatal(1, "JPEG read received normal admission credit");
end
masters[6].arvalid = 1'b0;
@(negedge clk_i);
masters[6].awid = 7'h31;
masters[6].awaddr = 32'h3000_0040;
masters[6].awvalid = 1'b1;
#1;
if (masters[6].awready || targets[0].awvalid) begin
$fatal(1, "JPEG write received normal admission credit");
end
masters[6].awvalid = 1'b0;
end
fault_backpressure : begin
@(negedge clk_i);
fault_ready_i = 1'b0;
masters[2].arid = 6'b010_110;
masters[2].araddr = 32'h3000_0060;
masters[2].arcache = 4'b0011;
masters[2].arvalid = 1'b1;
do @(posedge clk_i); while (!masters[2].arready);
#1;
if (!fault_valid_o || (fault_master_o != 4'd2) ||
(fault_addr_o != 32'h3000_0060) || (fault_reason_o != 4'd3)) begin
$fatal(1, "first backpressured fault was not retained");
end
@(negedge clk_i);
masters[2].arvalid = 1'b0;
masters[2].arcache = '0;
masters[1].arid = 6'b001_110;
masters[1].araddr = 32'h3000_00A0;
masters[1].arprot = 3'b100;
masters[1].arvalid = 1'b1;
#1;
if (masters[1].arready) begin
$fatal(1, "second faulting request bypassed a full fault slot");
end
repeat (2) begin
@(posedge clk_i);
#1;
if (!fault_valid_o || (fault_master_o != 4'd2) ||
(fault_addr_o != 32'h3000_0060) || (fault_reason_o != 4'd3) ||
masters[1].arready) begin
$fatal(1, "backpressured fault payload or admission was not held");
end
end
return_target5_read(6'b010_110);
@(negedge clk_i);
fault_ready_i = 1'b1;
do @(posedge clk_i); while (!masters[1].arready);
#1;
if (!fault_valid_o || (fault_master_o != 4'd1) ||
(fault_addr_o != 32'h3000_00A0) || (fault_reason_o != 4'd3)) begin
$fatal(1, "second backpressured fault was not delivered after release");
end
@(negedge clk_i);
masters[1].arvalid = 1'b0;
masters[1].arprot = '0;
return_target5_read(6'b001_110);
@(posedge clk_i);
end
@(negedge clk_i);
masters[6].arvalid = 1'b0;
targets[5].rid = 6'b110_000;
targets[5].rresp = 2'b10;
targets[5].rlast = 1'b1;
targets[5].rvalid = 1'b1;
do @(posedge clk_i); while (!targets[5].rready);
@(negedge clk_i);
targets[5].rvalid = 1'b0;
@(negedge clk_i);
masters[2].arid = 6'b010_001;
@@ -399,6 +587,44 @@ module axi4_data_crossbar_tb;
return_target0_read(6'b000_101, 64'h0000_0000_0000_0280);
end
invalid_return_prefix_recovery : begin
for (int prefix = 9; prefix < 16; prefix++) begin
return_invalid_target0_response(4'(prefix), prefix[0]);
if (prefix == 9) begin
masters[8].arid = 7'h42;
masters[8].araddr = 32'h3000_0140;
masters[8].arvalid = 1'b1;
#1;
if (masters[8].arready || idle_o) begin
$fatal(1, "protocol recovery accepted a new request before flush");
end
masters[8].arvalid = 1'b0;
end
flush_i = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
flush_i = 1'b0;
end
masters[8].arid = 7'h42;
masters[8].araddr = 32'h3000_0140;
masters[8].arvalid = 1'b1;
do @(posedge clk_i); while (!masters[8].arready);
@(negedge clk_i);
masters[8].arvalid = 1'b0;
fork
return_target0_read(7'h42, 64'h8888_8888_8888_0042);
begin
wait (masters[8].rvalid);
if ((masters[8].rid != 7'h42) || (masters[8].rdata != 64'h8888_8888_8888_0042)) begin
$fatal(1, "crossbar did not recover after protocol flush");
end
end
join
end
@(negedge clk_i);
if (!idle_o || (outstanding_read_o != 8'd0) || (outstanding_write_o != 8'd0)) begin
$fatal(1, "ACL and QoS transactions did not drain the crossbar");
+15 -13
View File
@@ -9,7 +9,7 @@ module axi4_downsizer_64to32_tb;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.ID_WIDTH (7),
.USER_WIDTH(1)
) wide (
.aclk (clk_i),
@@ -27,7 +27,9 @@ module axi4_downsizer_64to32_tb;
always #5 clk_i = ~clk_i;
axi4_downsizer_64to32 u_dut (
axi4_downsizer_64to32 #(
.WideIdWidth(7)
) u_dut (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.clear_i(1'b0),
@@ -85,7 +87,7 @@ module axi4_downsizer_64to32_tb;
endtask
task automatic accept_read(input logic [31:0] address, input logic [7:0] length,
input logic [2:0] size, input logic [2:0] id,
input logic [2:0] size, input logic [6:0] id,
input logic [7:0] expected_length);
begin
@(negedge clk_i);
@@ -110,7 +112,7 @@ module axi4_downsizer_64to32_tb;
endtask
task automatic accept_write(input logic [31:0] address, input logic [7:0] length,
input logic [2:0] size, input logic [2:0] id,
input logic [2:0] size, input logic [6:0] id,
input logic [7:0] expected_length);
begin
@(negedge clk_i);
@@ -134,7 +136,7 @@ module axi4_downsizer_64to32_tb;
end
endtask
task automatic return_write_response(input logic [2:0] expected_id, input logic [1:0] response);
task automatic return_write_response(input logic [6:0] expected_id, input logic [1:0] response);
begin
@(negedge clk_i);
narrow.bresp = response;
@@ -166,7 +168,7 @@ module axi4_downsizer_64to32_tb;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
accept_read(32'h0000_0040, 8'd0, 3'd3, 3'd5, 8'd1);
accept_read(32'h0000_0040, 8'd0, 3'd3, 7'h40, 8'd1);
@(negedge clk_i);
narrow.rdata = 32'h1122_3344;
narrow.rresp = `AXI4_RESP_SLAVE_ERROR;
@@ -181,7 +183,7 @@ module axi4_downsizer_64to32_tb;
narrow.rresp = `AXI4_RESP_OKAY;
narrow.rlast = 1'b1;
#1;
if (!wide.rvalid || narrow.rready || wide.rid != 3'd5 ||
if (!wide.rvalid || narrow.rready || wide.rid != 7'h40 ||
wide.rdata != 64'h5566_7788_1122_3344 || wide.rresp != `AXI4_RESP_SLAVE_ERROR ||
!wide.rlast) begin
$fatal(1, "64-bit read assembly or backpressure mismatch");
@@ -194,7 +196,7 @@ module axi4_downsizer_64to32_tb;
wide.rready = 1'b0;
narrow.rvalid = 1'b0;
accept_read(32'h0000_0000, 8'd1, 3'd2, 3'd3, 8'd1);
accept_read(32'h0000_0000, 8'd1, 3'd2, 7'h41, 8'd1);
@(negedge clk_i);
narrow.rdata = 32'hA5A5_0000;
narrow.rresp = `AXI4_RESP_OKAY;
@@ -202,7 +204,7 @@ module axi4_downsizer_64to32_tb;
narrow.rvalid = 1'b1;
wide.rready = 1'b1;
#1;
if (wide.rdata != 64'h0000_0000_A5A5_0000 || wide.rid != 3'd3) begin
if (wide.rdata != 64'h0000_0000_A5A5_0000 || wide.rid != 7'h41) begin
$fatal(1, "lower 32-bit read lane mismatch");
end
@(posedge clk_i);
@@ -218,7 +220,7 @@ module axi4_downsizer_64to32_tb;
wide.rready = 1'b0;
narrow.rvalid = 1'b0;
accept_write(32'h0000_0080, 8'd0, 3'd3, 3'd6, 8'd1);
accept_write(32'h0000_0080, 8'd0, 3'd3, 7'h42, 8'd1);
@(negedge clk_i);
wide.wdata = 64'h1122_3344_5566_7788;
wide.wstrb = 8'hF3;
@@ -240,9 +242,9 @@ module axi4_downsizer_64to32_tb;
@(negedge clk_i);
wide.wvalid = 1'b0;
narrow.wready = 1'b0;
return_write_response(3'd6, `AXI4_RESP_DECODE_ERROR);
return_write_response(7'h42, `AXI4_RESP_DECODE_ERROR);
accept_write(32'h0000_0004, 8'd1, 3'd2, 3'd2, 8'd1);
accept_write(32'h0000_0004, 8'd1, 3'd2, 7'h43, 8'd1);
@(negedge clk_i);
wide.wdata = 64'hCAFE_0000_DEAD_0000;
wide.wstrb = 8'hF0;
@@ -266,7 +268,7 @@ module axi4_downsizer_64to32_tb;
@(negedge clk_i);
wide.wvalid = 1'b0;
narrow.wready = 1'b0;
return_write_response(3'd2, `AXI4_RESP_OKAY);
return_write_response(7'h43, `AXI4_RESP_OKAY);
$display("AXI4 64-to-32 downsizer test passed");
$finish;
+100 -16
View File
@@ -5,14 +5,16 @@ module axi4_target_guard_tb;
logic rst_n_i = 1'b0;
logic abort_o;
logic timeout_valid_o;
logic timeout_ready_i = 1'b1;
logic isolated_o;
logic timeout_write_o;
logic [ 5:0] timeout_id_o;
logic [ 6:0] timeout_id_o;
logic [31:0] timeout_addr_o;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) source (
.aclk (clk_i),
@@ -21,7 +23,7 @@ module axi4_target_guard_tb;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) sink (
.aclk (clk_i),
@@ -31,6 +33,7 @@ module axi4_target_guard_tb;
always #5 clk_i = ~clk_i;
axi4_target_guard #(
.IdWidth (7),
.ReadDepth (4),
.WriteDepth(2)
) u_dut (
@@ -42,6 +45,8 @@ module axi4_target_guard_tb;
.abort_o (abort_o),
.abort_done_i (abort_o),
.timeout_valid_o(timeout_valid_o),
.timeout_ready_i(timeout_ready_i),
.isolated_o (isolated_o),
.timeout_write_o(timeout_write_o),
.timeout_id_o (timeout_id_o),
.timeout_addr_o (timeout_addr_o),
@@ -49,7 +54,7 @@ module axi4_target_guard_tb;
.sink (sink)
);
task automatic issue_read(input logic [5:0] id, input logic [7:0] len, input logic [31:0] addr);
task automatic issue_read(input logic [6:0] id, input logic [7:0] len, input logic [31:0] addr);
begin
@(negedge clk_i);
source.arid = id;
@@ -62,7 +67,19 @@ module axi4_target_guard_tb;
end
endtask
task automatic expect_error_read(input logic [5:0] id, input int unsigned beats);
task automatic issue_write_address(input logic [6:0] id, input logic [31:0] addr);
begin
@(negedge clk_i);
source.awid = id;
source.awaddr = addr;
source.awvalid = 1'b1;
do @(posedge clk_i); while (!source.awready);
@(negedge clk_i);
source.awvalid = 1'b0;
end
endtask
task automatic expect_error_read(input logic [6:0] id, input int unsigned beats);
begin
for (int beat = 0; beat < beats; beat++) begin
do @(posedge clk_i); while (!source.rvalid);
@@ -74,7 +91,7 @@ module axi4_target_guard_tb;
end
endtask
task automatic return_read_beat(input logic [5:0] id, input logic last, input logic expected_last,
task automatic return_read_beat(input logic [6:0] id, input logic last, input logic expected_last,
input logic [1:0] expected_resp);
begin
@(negedge clk_i);
@@ -146,26 +163,93 @@ module axi4_target_guard_tb;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
issue_read(6'h07, 8'd1, 32'h3800_0020);
issue_read(7'h40, 8'd1, 32'h3800_0020);
do @(posedge clk_i); while (!sink.arvalid);
return_read_beat(6'h07, 1'b0, 1'b0, 2'b00);
return_read_beat(6'h07, 1'b0, 1'b1, 2'b10);
return_read_beat(7'h40, 1'b0, 1'b0, 2'b00);
return_read_beat(7'h40, 1'b0, 1'b1, 2'b10);
issue_read(6'h08, 8'd0, 32'h3800_0030);
do @(posedge clk_i); while (!sink.arvalid);
return_read_beat(6'h08, 1'b1, 1'b1, 2'b00);
issue_read(6'h09, 8'd1, 32'h3800_0040);
timeout_ready_i = 1'b0;
sink.arready = 1'b0;
issue_read(7'h09, 8'd1, 32'h3800_0040);
wait (timeout_valid_o);
if (timeout_write_o || (timeout_id_o != 6'h09) || (timeout_addr_o != 32'h3800_0040)) begin
if (timeout_write_o || (timeout_id_o != 7'h09) || (timeout_addr_o != 32'h3800_0040)) begin
$fatal(1, "backpressured target-guard timeout attribution mismatch");
end
@(posedge clk_i);
#1;
if (!timeout_valid_o) begin
$fatal(1, "target-guard timeout was not latched before sink recovery");
end
@(negedge clk_i);
sink.arready = 1'b1;
repeat (3) begin
@(posedge clk_i);
#1;
if (!timeout_valid_o || timeout_write_o || (timeout_id_o != 7'h09) ||
(timeout_addr_o != 32'h3800_0040) || sink.arvalid || source.rvalid) begin
$fatal(1, "backpressured target-guard timeout was not held safely");
end
end
@(negedge clk_i);
timeout_ready_i = 1'b1;
expect_error_read(7'h09, 2);
if (isolated_o) begin
$fatal(1, "pre-accept timeout incorrectly isolated the target");
end
timeout_ready_i = 1'b0;
sink.awready = 1'b0;
issue_write_address(7'h4C, 32'h3800_0060);
wait (timeout_valid_o);
if (!timeout_write_o || (timeout_id_o != 7'h4C) || (timeout_addr_o != 32'h3800_0060)) begin
$fatal(1, "backpressured target-guard write timeout attribution mismatch");
end
@(posedge clk_i);
#1;
if (!timeout_valid_o) begin
$fatal(1, "target-guard write timeout was not latched before sink recovery");
end
@(negedge clk_i);
sink.awready = 1'b1;
repeat (3) begin
@(posedge clk_i);
#1;
if (!timeout_valid_o || !timeout_write_o || (timeout_id_o != 7'h4C) ||
(timeout_addr_o != 32'h3800_0060) || sink.awvalid || source.bvalid) begin
$fatal(1, "backpressured target-guard write timeout was not held safely");
end
end
@(negedge clk_i);
timeout_ready_i = 1'b1;
source.wdata = 64'h0123_4567_89AB_CDEF;
source.wstrb = 8'hFF;
source.wvalid = 1'b1;
do @(posedge clk_i); while (!source.wready);
@(negedge clk_i);
source.wvalid = 1'b0;
do @(posedge clk_i); while (!source.bvalid);
if ((source.bid != 7'h4C) || (source.bresp != 2'b10) || sink.awvalid || sink.wvalid) begin
$fatal(1, "backpressured target-guard write termination mismatch");
end
if (isolated_o) begin
$fatal(1, "pre-accept write timeout incorrectly isolated the target");
end
issue_read(7'h0A, 8'd1, 32'h3800_0080);
wait (timeout_valid_o);
if (timeout_write_o || (timeout_id_o != 7'h0A) || (timeout_addr_o != 32'h3800_0080)) begin
$fatal(1, "target guard read timeout attribution mismatch");
end
expect_error_read(6'h09, 2);
expect_error_read(7'h0A, 2);
fork
begin
issue_read(6'h0A, 8'd0, 32'h3800_0080);
expect_error_read(6'h0A, 1);
issue_read(7'h0B, 8'd0, 32'h3800_00C0);
expect_error_read(7'h0B, 1);
end
begin
repeat (12) begin
@@ -176,7 +260,7 @@ module axi4_target_guard_tb;
join
@(negedge clk_i);
source.awid = 6'h0B;
source.awid = 7'h4B;
source.awaddr = 32'h3800_0100;
source.awvalid = 1'b1;
do @(posedge clk_i); while (!source.awready);
@@ -189,7 +273,7 @@ module axi4_target_guard_tb;
@(negedge clk_i);
source.wvalid = 1'b0;
do @(posedge clk_i); while (!source.bvalid);
if ((source.bid != 6'h0B) || (source.bresp != 2'b10) || sink.awvalid || sink.wvalid) begin
if ((source.bid != 7'h4B) || (source.bresp != 2'b10) || sink.awvalid || sink.wvalid) begin
$fatal(1, "isolated target write termination mismatch");
end
+17 -10
View File
@@ -3,14 +3,14 @@
module fabric_monitor_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [ 7:0] master_read_accept_i = '0;
logic [ 7:0] master_write_accept_i = '0;
logic [ 7:0] master_read_beat_i = '0;
logic [ 7:0] master_write_beat_i = '0;
logic [ 7:0] master_wait_i = '0;
logic [ 7:0] master_promotion_i = '0;
logic [ 7:0][2:0] master_read_outstanding_i = '0;
logic [ 7:0][2:0] master_write_outstanding_i = '0;
logic [ 8:0] master_read_accept_i = '0;
logic [ 8:0] master_write_accept_i = '0;
logic [ 8:0] master_read_beat_i = '0;
logic [ 8:0] master_write_beat_i = '0;
logic [ 8:0] master_wait_i = '0;
logic [ 8:0] master_promotion_i = '0;
logic [ 8:0][2:0] master_read_outstanding_i = '0;
logic [ 8:0][2:0] master_write_outstanding_i = '0;
logic [ 5:0] target_read_accept_i = '0;
logic [ 5:0] target_write_accept_i = '0;
logic [ 5:0] target_read_beat_i = '0;
@@ -40,7 +40,7 @@ module fabric_monitor_tb;
.outstanding_read_i (8'd2),
.outstanding_write_i (8'd1),
.fault_valid_i (fault_valid_i),
.fault_master_i (3'd5),
.fault_master_i (4'd8),
.fault_target_i (3'd2),
.fault_addr_i (32'h4000_0040),
.fault_write_i (1'b1),
@@ -112,9 +112,14 @@ module fabric_monitor_tb;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
apb_read(12'h004, read_data);
if (read_data != 32'h0001_0001) $fatal(1, "fabric monitor version mismatch");
apb_read(12'h008, read_data);
if (read_data != 32'h0609_0003) $fatal(1, "fabric monitor capability mismatch");
apb_write(12'h00C, 32'h0000_0001);
@(negedge clk_i);
master_read_accept_i[0] = 1'b1;
master_read_accept_i[8] = 1'b1;
master_read_beat_i[0] = 1'b1;
master_promotion_i[0] = 1'b1;
master_read_outstanding_i[0] = 3'd3;
@@ -147,6 +152,8 @@ module fabric_monitor_tb;
apb_write(12'h00C, 32'h0000_0009);
apb_read(12'h100, read_data);
if (read_data != 32'd1) $fatal(1, "master read request count mismatch");
apb_read(12'h200, read_data);
if (read_data != 32'd1) $fatal(1, "GA2D master bank request count mismatch");
apb_read(12'h110, read_data);
if (read_data != 32'd3) $fatal(1, "master wait count mismatch");
apb_read(12'h114, read_data);
@@ -168,7 +175,7 @@ module fabric_monitor_tb;
apb_read(12'h018, read_data);
if (read_data != 32'h4000_0040) $fatal(1, "fault address mismatch");
apb_read(12'h014, read_data);
if (read_data != 32'h0000_0557) $fatal(1, "sticky fault attribution mismatch");
if (read_data != 32'h0000_1543) $fatal(1, "sticky fault attribution mismatch");
apb_read(12'h020, read_data);
if (read_data != 32'd1) $fatal(1, "fault count mismatch");
+737
View File
@@ -0,0 +1,737 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
`timescale 1ns / 1ps
module ga2d_platform_idle_target (
axi4_if.slave axi4
);
assign axi4.awready = 1'b1;
assign axi4.wready = 1'b1;
assign axi4.bid = '0;
assign axi4.bresp = 2'b00;
assign axi4.buser = '0;
assign axi4.bvalid = 1'b0;
assign axi4.arready = 1'b1;
assign axi4.rid = '0;
assign axi4.rdata = '0;
assign axi4.rresp = 2'b00;
assign axi4.rlast = 1'b1;
assign axi4.ruser = '0;
assign axi4.rvalid = 1'b0;
endmodule
module ga2d_platform_sram_target (
input logic clk_i,
input logic rst_n_i,
input logic hold_ar_i,
input logic hold_response_i,
output logic [6:0] last_arid_o,
output logic saw_ga2d_o,
output logic saw_legacy_o,
output logic saw_ga2d_write_o,
axi4_if.slave axi4
);
logic read_pending_q;
logic [6:0] read_id_q;
logic read_valid_q;
logic write_address_pending_q;
logic write_data_pending_q;
logic [6:0] write_id_q;
logic write_valid_q;
assign axi4.awready = !write_address_pending_q && !write_valid_q;
assign axi4.wready = write_address_pending_q && !write_data_pending_q && !write_valid_q;
assign axi4.bid = write_id_q;
assign axi4.bresp = 2'b00;
assign axi4.buser = '0;
assign axi4.bvalid = write_valid_q;
assign axi4.arready = !hold_ar_i && !read_pending_q;
assign axi4.rid = read_id_q;
assign axi4.rdata = 64'hA5A5_0000_0000_0000 | read_id_q;
assign axi4.rresp = 2'b00;
assign axi4.rlast = 1'b1;
assign axi4.ruser = '0;
assign axi4.rvalid = read_valid_q;
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
read_pending_q <= 1'b0;
read_id_q <= '0;
read_valid_q <= 1'b0;
write_address_pending_q <= 1'b0;
write_data_pending_q <= 1'b0;
write_id_q <= '0;
write_valid_q <= 1'b0;
last_arid_o <= '0;
saw_ga2d_o <= 1'b0;
saw_legacy_o <= 1'b0;
saw_ga2d_write_o <= 1'b0;
end else begin
if (axi4.awvalid && axi4.awready) begin
write_address_pending_q <= 1'b1;
write_id_q <= axi4.awid;
if (axi4.awid == 7'h40) saw_ga2d_write_o <= 1'b1;
end
if (axi4.wvalid && axi4.wready) begin
write_data_pending_q <= 1'b1;
end
if (write_address_pending_q && (write_data_pending_q || (axi4.wvalid && axi4.wready))) begin
write_valid_q <= 1'b1;
end
if (write_valid_q && axi4.bready) begin
write_address_pending_q <= 1'b0;
write_data_pending_q <= 1'b0;
write_valid_q <= 1'b0;
end
if (axi4.arvalid && axi4.arready) begin
read_pending_q <= 1'b1;
read_id_q <= axi4.arid;
last_arid_o <= axi4.arid;
if (axi4.arid == 7'h40) saw_ga2d_o <= 1'b1;
if (axi4.arid == 7'h08) saw_legacy_o <= 1'b1;
end
if (read_pending_q && !hold_response_i) begin
read_valid_q <= 1'b1;
if (read_valid_q && axi4.rready) begin
read_pending_q <= 1'b0;
read_valid_q <= 1'b0;
end
end
end
end
endmodule
module ga2d_platform_tb;
logic clk_lp_i = 1'b0;
logic clk_io_i = 1'b0;
logic clk_hp_i = 1'b0;
logic clk_mem_i = 1'b0;
logic rst_lp_n_i = 1'b0;
logic rst_io_n_i = 1'b0;
logic rst_hp_n_i = 1'b0;
logic rst_mem_n_i = 1'b0;
logic block_new_i = 1'b0;
logic recovery_i = 1'b0;
logic flush_i = 1'b0;
logic [ 8:0] resource_block_i = '0;
logic [ 1:0] mem_pad_mode_i = 2'd1;
logic ext_h_block_i = 1'b0;
logic sram_hold_ar_i = 1'b0;
logic sram_hold_response_i = 1'b0;
logic [ 6:0] sram_last_arid;
logic sram_saw_ga2d;
logic sram_saw_legacy;
logic sram_saw_ga2d_write;
logic idle_o;
logic flush_busy_o;
logic ext_h_idle_o;
logic [ 7:0] apu_bridge_epoch_o;
logic ga2d_source_stop_o;
logic ga2d_source_safe_idle_o;
logic ga2d_bridge_clear_busy_o;
logic [ 7:0] ga2d_bridge_epoch_o;
logic ga2d_data_ready_o;
logic [ 8:0] resource_idle_o;
logic [ 8:0] resource_block_ack_o;
logic [ 7:0] outstanding_read_o;
logic [ 7:0] outstanding_write_o;
logic fault_valid_o;
logic [ 3:0] fault_master_o;
logic [ 2:0] fault_target_o;
logic [31:0] fault_addr_o;
logic fault_write_o;
logic [ 3:0] fault_reason_o;
logic [ 7:0] epoch_before;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) hp_icache_axi4 (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) hp_dcache_axi4 (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) dma_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) sdio0_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) sdio1_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) spisd_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) usb2_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) apu_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) jpeg_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) ga2d_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) lp_data_axi4 (
.aclk (clk_lp_i),
.aresetn(rst_lp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (3),
.USER_WIDTH(1)
) ext_h_axi4 (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (7),
.USER_WIDTH(1)
) sram_gateway_axi4 (
.aclk (clk_hp_i),
.aresetn(rst_hp_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) sdram_gateway_axi4 (
.aclk (clk_mem_i),
.aresetn(rst_mem_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) qpi_gateway_axi4 (
.aclk (clk_mem_i),
.aresetn(rst_mem_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) opi_gateway_axi4 (
.aclk (clk_mem_i),
.aresetn(rst_mem_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) xpi_gateway_axi4 (
.aclk (clk_mem_i),
.aresetn(rst_mem_n_i)
);
apb4_if fabric_monitor_apb4 (
.pclk (clk_hp_i),
.presetn(rst_hp_n_i)
);
always #5 clk_lp_i = ~clk_lp_i;
always #7 clk_io_i = ~clk_io_i;
always #11 clk_hp_i = ~clk_hp_i;
always #13 clk_mem_i = ~clk_mem_i;
axi4_master_idle u_hp_icache_idle (.axi4(hp_icache_axi4));
axi4_master_idle u_dma_idle (.axi4(dma_axi4));
axi4_master_idle u_sdio0_idle (.axi4(sdio0_axi4));
axi4_master_idle u_sdio1_idle (.axi4(sdio1_axi4));
axi4_master_idle u_spisd_idle (.axi4(spisd_axi4));
axi4_master_idle u_usb2_idle (.axi4(usb2_axi4));
axi4_master_idle u_apu_idle (.axi4(apu_axi4));
axi4_master_idle u_jpeg_idle (.axi4(jpeg_axi4));
axi4_master_idle u_lp_data_idle (.axi4(lp_data_axi4));
axi4_master_idle u_ext_h_idle (.axi4(ext_h_axi4));
ga2d_platform_sram_target u_sram_target (
.clk_i (clk_hp_i),
.rst_n_i (rst_hp_n_i),
.hold_ar_i (sram_hold_ar_i),
.hold_response_i (sram_hold_response_i),
.last_arid_o (sram_last_arid),
.saw_ga2d_o (sram_saw_ga2d),
.saw_legacy_o (sram_saw_legacy),
.saw_ga2d_write_o(sram_saw_ga2d_write),
.axi4 (sram_gateway_axi4)
);
ga2d_platform_idle_target u_sdram_target (.axi4(sdram_gateway_axi4));
ga2d_platform_idle_target u_qpi_target (.axi4(qpi_gateway_axi4));
ga2d_platform_idle_target u_opi_target (.axi4(opi_gateway_axi4));
ga2d_platform_idle_target u_xpi_target (.axi4(xpi_gateway_axi4));
soc_data_plane u_dut (
.clk_lp_i (clk_lp_i),
.rst_lp_n_i (rst_lp_n_i),
.clk_io_i (clk_io_i),
.rst_io_n_i (rst_io_n_i),
.clk_hp_i (clk_hp_i),
.rst_hp_n_i (rst_hp_n_i),
.clk_mem_i (clk_mem_i),
.rst_mem_n_i (rst_mem_n_i),
.block_new_i (block_new_i),
.recovery_i (recovery_i),
.flush_i (flush_i),
.resource_block_i (resource_block_i),
.mem_pad_mode_i (mem_pad_mode_i),
.ext_h_block_i (ext_h_block_i),
.ext_h_read_base_i (32'h3000_0000),
.ext_h_read_limit_i (32'h4FFF_FFFF),
.ext_h_write_base_i (32'h3000_0000),
.ext_h_write_limit_i (32'h4FFF_FFFF),
.hp_icache_axi4 (hp_icache_axi4),
.hp_dcache_axi4 (hp_dcache_axi4),
.dma_axi4 (dma_axi4),
.sdio0_axi4 (sdio0_axi4),
.sdio1_axi4 (sdio1_axi4),
.spisd_axi4 (spisd_axi4),
.usb2_axi4 (usb2_axi4),
.apu_axi4 (apu_axi4),
.jpeg_axi4 (jpeg_axi4),
.ga2d_axi4 (ga2d_axi4),
.lp_data_axi4 (lp_data_axi4),
.ext_h_axi4 (ext_h_axi4),
.sram_gateway_axi4 (sram_gateway_axi4),
.sdram_gateway_axi4 (sdram_gateway_axi4),
.qpi_gateway_axi4 (qpi_gateway_axi4),
.opi_gateway_axi4 (opi_gateway_axi4),
.xpi_gateway_axi4 (xpi_gateway_axi4),
.fabric_monitor_apb4 (fabric_monitor_apb4),
.idle_o (idle_o),
.flush_busy_o (flush_busy_o),
.ext_h_idle_o (ext_h_idle_o),
.apu_bridge_epoch_o (apu_bridge_epoch_o),
.ga2d_source_stop_o (ga2d_source_stop_o),
.ga2d_source_safe_idle_o (ga2d_source_safe_idle_o),
.ga2d_bridge_clear_busy_o(ga2d_bridge_clear_busy_o),
.ga2d_bridge_epoch_o (ga2d_bridge_epoch_o),
.ga2d_data_ready_o (ga2d_data_ready_o),
.resource_idle_o (resource_idle_o),
.resource_block_ack_o (resource_block_ack_o),
.outstanding_read_o (outstanding_read_o),
.outstanding_write_o (outstanding_write_o),
.fault_valid_o (fault_valid_o),
.fault_ready_i (1'b1),
.fault_master_o (fault_master_o),
.fault_target_o (fault_target_o),
.fault_addr_o (fault_addr_o),
.fault_write_o (fault_write_o),
.fault_reason_o (fault_reason_o)
);
task automatic issue_ga2d_read(input logic [2:0] id, input logic [31:0] address);
begin
@(negedge clk_io_i);
ga2d_axi4.arid = id;
ga2d_axi4.araddr = address;
ga2d_axi4.arlen = '0;
ga2d_axi4.arsize = 3'd3;
ga2d_axi4.arburst = 2'b01;
ga2d_axi4.arlock = 1'b0;
ga2d_axi4.arcache = '0;
ga2d_axi4.arprot = '0;
ga2d_axi4.arqos = 4'hF;
ga2d_axi4.arregion = '0;
ga2d_axi4.aruser = '0;
ga2d_axi4.arvalid = 1'b1;
do @(posedge clk_io_i); while (!ga2d_axi4.arready);
@(negedge clk_io_i);
ga2d_axi4.arvalid = 1'b0;
end
endtask
task automatic expect_ga2d_read(input logic [2:0] id);
begin
wait (ga2d_axi4.rvalid);
if ((ga2d_axi4.rid != id) || (ga2d_axi4.rresp != 2'b00)) begin
$fatal(1, "GA2D response did not preserve the local source ID");
end
end
endtask
task automatic issue_ga2d_write(input logic [2:0] id, input logic [31:0] address,
input logic [63:0] data);
begin
@(negedge clk_io_i);
ga2d_axi4.awid = id;
ga2d_axi4.awaddr = address;
ga2d_axi4.awlen = '0;
ga2d_axi4.awsize = 3'd3;
ga2d_axi4.awburst = 2'b01;
ga2d_axi4.awlock = 1'b0;
ga2d_axi4.awcache = '0;
ga2d_axi4.awprot = '0;
ga2d_axi4.awqos = 4'hF;
ga2d_axi4.awregion = '0;
ga2d_axi4.awuser = '0;
ga2d_axi4.awvalid = 1'b1;
do @(posedge clk_io_i); while (!ga2d_axi4.awready);
@(negedge clk_io_i);
ga2d_axi4.awvalid = 1'b0;
ga2d_axi4.wdata = data;
ga2d_axi4.wstrb = '1;
ga2d_axi4.wlast = 1'b1;
ga2d_axi4.wuser = '0;
ga2d_axi4.wvalid = 1'b1;
do @(posedge clk_io_i); while (!ga2d_axi4.wready);
@(negedge clk_io_i);
ga2d_axi4.wvalid = 1'b0;
end
endtask
task automatic expect_ga2d_write(input logic [2:0] id);
begin
wait (ga2d_axi4.bvalid);
if ((ga2d_axi4.bid != id) || (ga2d_axi4.bresp != 2'b00)) begin
$fatal(1, "GA2D write response did not preserve the local source ID");
end
end
endtask
task automatic issue_legacy_read(input logic [2:0] id, input logic [31:0] address);
begin
@(negedge clk_hp_i);
hp_dcache_axi4.arid = id;
hp_dcache_axi4.araddr = address;
hp_dcache_axi4.arlen = '0;
hp_dcache_axi4.arsize = 3'd3;
hp_dcache_axi4.arburst = 2'b01;
hp_dcache_axi4.arlock = 1'b0;
hp_dcache_axi4.arcache = '0;
hp_dcache_axi4.arprot = '0;
hp_dcache_axi4.arqos = '0;
hp_dcache_axi4.arregion = '0;
hp_dcache_axi4.aruser = '0;
hp_dcache_axi4.arvalid = 1'b1;
do @(posedge clk_hp_i); while (!hp_dcache_axi4.arready);
@(negedge clk_hp_i);
hp_dcache_axi4.arvalid = 1'b0;
end
endtask
task automatic expect_legacy_read(input logic [2:0] id);
begin
wait (hp_dcache_axi4.rvalid);
if ((hp_dcache_axi4.rid != id) || (hp_dcache_axi4.rresp != 2'b00)) begin
$fatal(1, "legacy response did not preserve its source ID");
end
end
endtask
task automatic wait_for_data_ready;
begin
wait (ga2d_data_ready_o && !ga2d_source_stop_o);
end
endtask
initial begin
ga2d_axi4.awid = '0;
ga2d_axi4.awaddr = '0;
ga2d_axi4.awlen = '0;
ga2d_axi4.awsize = 3'd3;
ga2d_axi4.awburst = 2'b01;
ga2d_axi4.awlock = 1'b0;
ga2d_axi4.awcache = '0;
ga2d_axi4.awprot = '0;
ga2d_axi4.awqos = '0;
ga2d_axi4.awregion = '0;
ga2d_axi4.awuser = '0;
ga2d_axi4.awvalid = 1'b0;
ga2d_axi4.wdata = '0;
ga2d_axi4.wstrb = '0;
ga2d_axi4.wlast = 1'b1;
ga2d_axi4.wuser = '0;
ga2d_axi4.wvalid = 1'b0;
ga2d_axi4.bready = 1'b1;
ga2d_axi4.arid = '0;
ga2d_axi4.araddr = '0;
ga2d_axi4.arlen = '0;
ga2d_axi4.arsize = 3'd3;
ga2d_axi4.arburst = 2'b01;
ga2d_axi4.arlock = 1'b0;
ga2d_axi4.arcache = '0;
ga2d_axi4.arprot = '0;
ga2d_axi4.arqos = '0;
ga2d_axi4.arregion = '0;
ga2d_axi4.aruser = '0;
ga2d_axi4.arvalid = 1'b0;
ga2d_axi4.rready = 1'b1;
hp_dcache_axi4.awid = '0;
hp_dcache_axi4.awaddr = '0;
hp_dcache_axi4.awlen = '0;
hp_dcache_axi4.awsize = 3'd3;
hp_dcache_axi4.awburst = 2'b01;
hp_dcache_axi4.awlock = 1'b0;
hp_dcache_axi4.awcache = '0;
hp_dcache_axi4.awprot = '0;
hp_dcache_axi4.awqos = '0;
hp_dcache_axi4.awregion = '0;
hp_dcache_axi4.awuser = '0;
hp_dcache_axi4.awvalid = 1'b0;
hp_dcache_axi4.wdata = '0;
hp_dcache_axi4.wstrb = '0;
hp_dcache_axi4.wlast = 1'b1;
hp_dcache_axi4.wuser = '0;
hp_dcache_axi4.wvalid = 1'b0;
hp_dcache_axi4.bready = 1'b1;
hp_dcache_axi4.arid = '0;
hp_dcache_axi4.araddr = '0;
hp_dcache_axi4.arlen = '0;
hp_dcache_axi4.arsize = 3'd3;
hp_dcache_axi4.arburst = 2'b01;
hp_dcache_axi4.arlock = 1'b0;
hp_dcache_axi4.arcache = '0;
hp_dcache_axi4.arprot = '0;
hp_dcache_axi4.arqos = '0;
hp_dcache_axi4.arregion = '0;
hp_dcache_axi4.aruser = '0;
hp_dcache_axi4.arvalid = 1'b0;
hp_dcache_axi4.rready = 1'b1;
fabric_monitor_apb4.paddr = '0;
fabric_monitor_apb4.pprot = '0;
fabric_monitor_apb4.psel = 1'b0;
fabric_monitor_apb4.penable = 1'b0;
fabric_monitor_apb4.pwrite = 1'b0;
fabric_monitor_apb4.pwdata = '0;
fabric_monitor_apb4.pstrb = '0;
repeat (3) @(posedge clk_io_i);
rst_lp_n_i = 1'b1;
rst_io_n_i = 1'b1;
rst_hp_n_i = 1'b1;
rst_mem_n_i = 1'b1;
wait_for_data_ready();
fork
issue_ga2d_read(3'd0, 32'h3000_0040);
expect_ga2d_read(3'd0);
issue_legacy_read(3'd0, 32'h3000_0080);
expect_legacy_read(3'd0);
join
if (!sram_saw_ga2d || !sram_saw_legacy) begin
$fatal(1, "mixed legacy and GA2D IDs did not reach distinct global IDs");
end
fork
issue_ga2d_write(3'd0, 32'h3000_00C0, 64'h0123_4567_89AB_CDEF);
expect_ga2d_write(3'd0);
join
if (!sram_saw_ga2d_write) begin
$fatal(1, "GA2D write did not preserve global ID 7'h40");
end
wait (ga2d_source_safe_idle_o);
@(negedge clk_io_i);
resource_block_i[8] = 1'b1;
ga2d_axi4.wdata = 64'hCAFE_BABE_0123_4567;
ga2d_axi4.wstrb = '1;
ga2d_axi4.wlast = 1'b1;
ga2d_axi4.wuser = '0;
ga2d_axi4.wvalid = 1'b1;
repeat (2) @(posedge clk_io_i);
#1;
if (ga2d_source_stop_o || ga2d_source_safe_idle_o || resource_block_ack_o[8] ||
ga2d_axi4.wready) begin
$fatal(1, "resource block accepted or acknowledged W-before-AW traffic");
end
@(negedge clk_io_i);
ga2d_axi4.awid = 3'd3;
ga2d_axi4.awaddr = 32'h3000_0120;
ga2d_axi4.awlen = '0;
ga2d_axi4.awsize = 3'd3;
ga2d_axi4.awburst = 2'b01;
ga2d_axi4.awlock = 1'b0;
ga2d_axi4.awcache = '0;
ga2d_axi4.awprot = '0;
ga2d_axi4.awqos = '0;
ga2d_axi4.awregion = '0;
ga2d_axi4.awuser = '0;
ga2d_axi4.awvalid = 1'b1;
do @(posedge clk_io_i); while (!ga2d_axi4.awready);
#1;
if (!ga2d_source_stop_o) begin
$fatal(1, "resource block did not close after the W-before-AW address handshake");
end
if (!ga2d_axi4.wready) begin
$fatal(1, "W-before-AW write data was not accepted with its address");
end
@(negedge clk_io_i);
ga2d_axi4.awvalid = 1'b0;
ga2d_axi4.wvalid = 1'b0;
if (resource_block_ack_o[8]) begin
$fatal(1, "resource block acknowledged before the W-before-AW response drained");
end
expect_ga2d_write(3'd3);
wait (resource_block_ack_o[8]);
if (!ga2d_source_safe_idle_o || !resource_idle_o[8] || ga2d_data_ready_o) begin
$fatal(1, "W-before-AW resource stop did not reach qualified idle");
end
@(negedge clk_io_i);
resource_block_i[8] = 1'b0;
wait_for_data_ready();
sram_hold_ar_i = 1'b1;
@(negedge clk_io_i);
resource_block_i[8] = 1'b1;
ga2d_axi4.arid = 3'd1;
ga2d_axi4.araddr = 32'h3000_0100;
ga2d_axi4.arlen = '0;
ga2d_axi4.arsize = 3'd3;
ga2d_axi4.arburst = 2'b01;
ga2d_axi4.arlock = 1'b0;
ga2d_axi4.arcache = '0;
ga2d_axi4.arprot = '0;
ga2d_axi4.arqos = '0;
ga2d_axi4.arregion = '0;
ga2d_axi4.aruser = '0;
ga2d_axi4.arvalid = 1'b1;
do @(posedge clk_io_i); while (!ga2d_axi4.arready);
#1;
if (!ga2d_source_stop_o) begin
$fatal(1, "resource stop did not close after the presented address entered transport");
end
@(negedge clk_io_i);
ga2d_axi4.arvalid = 1'b0;
wait (ga2d_source_stop_o);
if (ga2d_source_safe_idle_o || resource_block_ack_o[8]) begin
$fatal(1, "resource block acknowledged before the accepted read drained");
end
sram_hold_ar_i = 1'b0;
fork
expect_ga2d_read(3'd1);
wait (resource_block_ack_o[8]);
join
if (!ga2d_source_safe_idle_o || !resource_idle_o[8] || ga2d_data_ready_o) begin
$fatal(1, "GA2D resource stop did not reach qualified idle");
end
@(negedge clk_io_i);
resource_block_i[8] = 1'b0;
wait_for_data_ready();
sram_hold_response_i = 1'b1;
issue_ga2d_read(3'd2, 32'h3000_0140);
wait (sram_last_arid == 7'h42);
epoch_before = ga2d_bridge_epoch_o;
@(negedge clk_hp_i);
flush_i = 1'b1;
repeat (4) @(posedge clk_io_i);
if (ga2d_data_ready_o) begin
$fatal(1, "GA2D data-ready remained asserted during a warm flush");
end
repeat (4) @(posedge clk_hp_i);
@(negedge clk_hp_i);
flush_i = 1'b0;
wait (ga2d_bridge_epoch_o != epoch_before);
repeat (4) @(posedge clk_io_i);
if (ga2d_axi4.rvalid) begin
$fatal(1, "late pre-flush response reached the GA2D source");
end
sram_hold_response_i = 1'b0;
wait_for_data_ready();
epoch_before = ga2d_bridge_epoch_o;
@(negedge clk_hp_i);
rst_hp_n_i = 1'b0;
repeat (3) @(posedge clk_hp_i);
if (ga2d_data_ready_o) begin
$fatal(1, "GA2D data-ready remained asserted while HP reset was active");
end
@(negedge clk_hp_i);
rst_hp_n_i = 1'b1;
wait (ga2d_bridge_epoch_o != epoch_before);
wait_for_data_ready();
@(negedge clk_io_i);
rst_io_n_i = 1'b0;
repeat (3) @(posedge clk_io_i);
if (ga2d_data_ready_o || !ga2d_source_stop_o) begin
$fatal(1, "PCLK reset did not close the GA2D source path");
end
@(negedge clk_io_i);
rst_io_n_i = 1'b1;
wait_for_data_ready();
$display("GA2D P2 bridge, ID7, lifecycle, flush, and reset test passed");
$finish;
end
initial begin
#50000;
$fatal(1, "GA2D platform test timed out");
end
endmodule
+8 -8
View File
@@ -14,7 +14,7 @@ module onchip_ram64_tb #(
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(64),
.ID_WIDTH (6),
.ID_WIDTH (7),
.USER_WIDTH(1)
) mem_axi4 (
.aclk (clk_i),
@@ -31,7 +31,7 @@ module onchip_ram64_tb #(
.Present (1'b1),
.CapacityKiB(CapacityKiB),
.DataWidth (64),
.IdWidth (6)
.IdWidth (7)
) u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
@@ -41,7 +41,7 @@ module onchip_ram64_tb #(
.cfg_apb4 (cfg_apb4)
);
task automatic issue_write(input logic [5:0] id, input logic [31:0] address,
task automatic issue_write(input logic [6:0] id, input logic [31:0] address,
input logic [7:0] length, input logic [2:0] size,
input logic [63:0] seed, input logic [7:0] strobe);
begin
@@ -74,7 +74,7 @@ module onchip_ram64_tb #(
end
endtask
task automatic expect_read(input logic [5:0] id, input logic [31:0] address,
task automatic expect_read(input logic [6:0] id, input logic [31:0] address,
input logic [7:0] length, input logic [63:0] seed);
integer previous_cycle;
integer cycle_count;
@@ -154,10 +154,10 @@ module onchip_ram64_tb #(
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
issue_write(6'h2A, SramBase + 32'h100, 8'd3, 3'd3, 64'h1000_2000_3000_4000, 8'hFF);
expect_read(6'h2B, SramBase + 32'h100, 8'd3, 64'h1000_2000_3000_4000);
issue_write(6'h2C, SramBase + 32'h10C, 8'd0, 3'd2, 64'hDEAD_BEEF_0000_0000, 8'hF0);
expect_read(6'h2D, SramBase + 32'h108, 8'd0, 64'hDEAD_BEEF_3000_4001);
issue_write(7'h40, SramBase + 32'h100, 8'd3, 3'd3, 64'h1000_2000_3000_4000, 8'hFF);
expect_read(7'h41, SramBase + 32'h100, 8'd3, 64'h1000_2000_3000_4000);
issue_write(7'h42, SramBase + 32'h10C, 8'd0, 3'd2, 64'hDEAD_BEEF_0000_0000, 8'hF0);
expect_read(7'h43, SramBase + 32'h108, 8'd0, 64'hDEAD_BEEF_3000_4001);
$display("native AXI64 on-chip SRAM test passed");
$finish;
+25 -10
View File
@@ -3,17 +3,17 @@
module resource_controller_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [ 7:0] idle_i = '0;
logic [ 7:0] block_ack_i = '0;
logic [ 7:0] irq_i = '0;
logic [ 8:0] idle_i = '0;
logic [ 8:0] block_ack_i = '0;
logic [ 8:0] irq_i = '0;
logic cache_request_i = 1'b0;
logic cache_clean_o;
logic [ 7:0][1:0] owner_o;
logic [ 7:0] owner_lock_o;
logic [ 7:0] quiesce_o;
logic [ 7:0] reset_o;
logic [ 7:0] irq_lp_o;
logic [ 7:0] irq_hp_o;
logic [ 8:0][1:0] owner_o;
logic [ 8:0] owner_lock_o;
logic [ 8:0] quiesce_o;
logic [ 8:0] reset_o;
logic [ 8:0] irq_lp_o;
logic [ 8:0] irq_hp_o;
logic fault_irq_o;
logic [31:0] read_data;
@@ -92,10 +92,14 @@ module resource_controller_tb;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
idle_i = 8'hFF;
idle_i = 9'h1FF;
apb_read(12'h000, read_data);
if (read_data != 32'h5253_4354) $fatal(1, "resource controller ID mismatch");
apb_read(12'h004, read_data);
if (read_data != 32'h0001_0001) $fatal(1, "resource controller version mismatch");
apb_read(12'h008, read_data);
if (read_data != 32'h0000_0901) $fatal(1, "resource controller capability mismatch");
irq_i[1] = 1'b1;
#1;
@@ -147,6 +151,17 @@ module resource_controller_tb;
$fatal(1, "APU resource index 7 ownership or IRQ routing mismatch");
end
apb_read(12'h200, read_data);
if (read_data != 32'd0 || owner_o[8] != 2'd0 || owner_lock_o[8]) begin
$fatal(1, "GA2D resource 8 did not reset to unlocked LP ownership");
end
apb_write(12'h204, 32'h0000_0001, 1'b0);
block_ack_i[8] = 1'b1;
apb_write(12'h200, 32'h0000_0001, 1'b0);
if ((owner_o[8] != 2'd1) || irq_lp_o[8] || irq_hp_o[8]) begin
$fatal(1, "GA2D resource 8 lifecycle or inactive IRQ mismatch");
end
$display("Resource Controller ownership, IRQ, and cache handshake test passed");
$finish;
end
+185 -27
View File
@@ -3,10 +3,38 @@
module sysctrl_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic fault_valid_i = 1'b0;
logic [31:0] fault_addr_i = '0;
logic [ 3:0] fault_wstrb_i = '0;
logic fault_reserved_i = 1'b0;
logic clk_hp_i = 1'b0;
logic rst_hp_n_i = 1'b0;
logic s_bus_fault_valid;
logic [31:0] s_bus_fault_addr;
logic [ 3:0] s_bus_fault_wstrb;
logic s_bus_fault_reserved;
logic s_bus_fault_access;
logic [ 3:0] s_bus_fault_master;
logic [ 2:0] s_bus_fault_code;
logic s_data_plane_fault_valid_hp;
logic [ 3:0] s_data_plane_fault_master_hp;
logic [ 2:0] s_data_plane_fault_target_hp;
logic [31:0] s_data_plane_fault_addr_hp;
logic s_data_plane_fault_write_hp;
logic [ 3:0] s_data_plane_fault_reason_hp;
logic s_data_plane_fault_ready_hp;
logic s_data_plane_fault_valid_pclk;
logic [ 3:0] s_data_plane_fault_master_pclk;
logic [ 2:0] s_data_plane_fault_target_pclk;
logic [31:0] s_data_plane_fault_addr_pclk;
logic s_data_plane_fault_write_pclk;
logic [ 3:0] s_data_plane_fault_reason_pclk;
logic [ 3:0] s_data_plane_fault_delivery_count;
logic [ 3:0] s_data_plane_fault_delivery_master[0:2];
logic [ 2:0] s_data_plane_fault_delivery_target[0:2];
logic [31:0] s_data_plane_fault_delivery_addr [0:2];
logic s_data_plane_fault_delivery_write [0:2];
logic [ 3:0] s_data_plane_fault_delivery_reason[0:2];
logic fault_valid_i;
logic [31:0] fault_addr_i;
logic [ 3:0] fault_wstrb_i;
logic fault_reserved_i;
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
@@ -15,7 +43,60 @@ module sysctrl_tb;
pll_ctrl_if pll_ctrl ();
clock_ctrl_if clock_ctrl ();
always #5 clk_i = ~clk_i;
always #17 clk_i = ~clk_i;
always #3 clk_hp_i = ~clk_hp_i;
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_data_plane_fault_delivery_count <= '0;
end else if (s_data_plane_fault_valid_pclk) begin
if (s_data_plane_fault_delivery_count < 4'd3) begin
s_data_plane_fault_delivery_master[s_data_plane_fault_delivery_count] <=
s_data_plane_fault_master_pclk;
s_data_plane_fault_delivery_target[s_data_plane_fault_delivery_count] <=
s_data_plane_fault_target_pclk;
s_data_plane_fault_delivery_addr[s_data_plane_fault_delivery_count] <=
s_data_plane_fault_addr_pclk;
s_data_plane_fault_delivery_write[s_data_plane_fault_delivery_count] <=
s_data_plane_fault_write_pclk;
s_data_plane_fault_delivery_reason[s_data_plane_fault_delivery_count] <=
s_data_plane_fault_reason_pclk;
end
s_data_plane_fault_delivery_count <= s_data_plane_fault_delivery_count + 1'b1;
end
end
data_plane_fault_cdc u_data_plane_fault_cdc (
.clk_hp_i (clk_hp_i),
.rst_hp_n_i (rst_hp_n_i),
.fault_valid_i (s_data_plane_fault_valid_hp),
.fault_master_i(s_data_plane_fault_master_hp),
.fault_target_i(s_data_plane_fault_target_hp),
.fault_addr_i (s_data_plane_fault_addr_hp),
.fault_write_i (s_data_plane_fault_write_hp),
.fault_reason_i(s_data_plane_fault_reason_hp),
.fault_ready_o (s_data_plane_fault_ready_hp),
.clk_pclk_i (clk_i),
.rst_pclk_n_i (rst_n_i),
.fault_valid_o (s_data_plane_fault_valid_pclk),
.fault_master_o(s_data_plane_fault_master_pclk),
.fault_target_o(s_data_plane_fault_target_pclk),
.fault_addr_o (s_data_plane_fault_addr_pclk),
.fault_write_o (s_data_plane_fault_write_pclk),
.fault_reason_o(s_data_plane_fault_reason_pclk)
);
assign fault_valid_i = s_data_plane_fault_valid_pclk || s_bus_fault_valid;
assign sysctrl.fault_access_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_write_pclk : s_bus_fault_access;
assign sysctrl.fault_master_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_master_pclk : s_bus_fault_master;
assign sysctrl.fault_code_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_reason_pclk[2:0] : s_bus_fault_code;
assign fault_addr_i = s_data_plane_fault_valid_pclk ?
s_data_plane_fault_addr_pclk : s_bus_fault_addr;
assign fault_wstrb_i = s_data_plane_fault_valid_pclk && s_data_plane_fault_write_pclk ?
4'hF : s_bus_fault_wstrb;
assign fault_reserved_i = s_data_plane_fault_valid_pclk ? 1'b0 : s_bus_fault_reserved;
apb4_sysctrl u_sysctrl (
.clk_i (clk_i),
@@ -30,6 +111,31 @@ module sysctrl_tb;
.clock_ctrl (clock_ctrl)
);
task automatic send_data_plane_fault(input logic [3:0] master, input logic [2:0] target,
input logic [31:0] address, input logic write_access,
input logic [3:0] reason, input logic require_backpressure);
logic saw_backpressure;
begin
saw_backpressure = 1'b0;
@(negedge clk_hp_i);
s_data_plane_fault_master_hp = master;
s_data_plane_fault_target_hp = target;
s_data_plane_fault_addr_hp = address;
s_data_plane_fault_write_hp = write_access;
s_data_plane_fault_reason_hp = reason;
s_data_plane_fault_valid_hp = 1'b1;
do begin
@(posedge clk_hp_i);
if (!s_data_plane_fault_ready_hp) saw_backpressure = 1'b1;
end while (!s_data_plane_fault_ready_hp);
if (require_backpressure && !saw_backpressure) begin
$fatal(1, "slow PCLK did not backpressure the successive HP fault");
end
@(negedge clk_hp_i);
s_data_plane_fault_valid_hp = 1'b0;
end
endtask
task automatic read_register(input logic [31:0] address, output logic [31:0] data);
begin
@(negedge clk_i);
@@ -102,9 +208,19 @@ module sysctrl_tb;
apb4.pwdata = '0;
apb4.pstrb = '0;
sysctrl.user_bus_idle_i = 1'b1;
sysctrl.fault_access_i = 1'b0;
sysctrl.fault_master_i = '0;
sysctrl.fault_code_i = `RIB_RESP_RESERVED;
s_bus_fault_valid = 1'b0;
s_bus_fault_addr = '0;
s_bus_fault_wstrb = '0;
s_bus_fault_reserved = 1'b0;
s_bus_fault_access = 1'b0;
s_bus_fault_master = '0;
s_bus_fault_code = `RIB_RESP_RESERVED;
s_data_plane_fault_valid_hp = 1'b0;
s_data_plane_fault_master_hp = '0;
s_data_plane_fault_target_hp = '0;
s_data_plane_fault_addr_hp = '0;
s_data_plane_fault_write_hp = 1'b0;
s_data_plane_fault_reason_hp = '0;
sysctrl.perf_mgmt_wait_i = 64'd11;
sysctrl.perf_user_wait_i = 64'd12;
sysctrl.perf_dma_wait_i = 64'd13;
@@ -136,41 +252,58 @@ module sysctrl_tb;
clock_ctrl.fault_i = '0;
clock_ctrl.memory_i = 32'h0000_0005;
repeat (2) @(posedge clk_i);
rst_n_i = 1'b1;
rst_n_i = 1'b1;
rst_hp_n_i = 1'b1;
repeat (3) @(posedge clk_hp_i);
@(negedge clk_i);
sysctrl.fault_master_i = 3'd3;
fault_valid_i = 1'b1;
fault_addr_i = 32'h1001_2000;
fault_wstrb_i = 4'hF;
fault_reserved_i = 1'b1;
@(negedge clk_i);
fault_valid_i = 1'b0;
send_data_plane_fault(4'd8, 3'd5, 32'h1001_2000, 1'b1, {1'b0, `RIB_RESP_RESERVED}, 1'b0);
send_data_plane_fault(4'd4, 3'd2, 32'h1001_2800, 1'b0, {1'b0, `RIB_RESP_DECERR}, 1'b1);
send_data_plane_fault(4'd1, 3'd4, 32'h1001_2C00, 1'b1, {1'b0, `RIB_RESP_SLVERR}, 1'b1);
wait (s_data_plane_fault_delivery_count == 4'd3);
@(posedge clk_i);
#1;
if ((s_data_plane_fault_delivery_master[0] != 4'd8) ||
(s_data_plane_fault_delivery_target[0] != 3'd5) ||
(s_data_plane_fault_delivery_addr[0] != 32'h1001_2000) ||
!s_data_plane_fault_delivery_write[0] ||
(s_data_plane_fault_delivery_reason[0] != {1'b0, `RIB_RESP_RESERVED}) ||
(s_data_plane_fault_delivery_master[1] != 4'd4) ||
(s_data_plane_fault_delivery_target[1] != 3'd2) ||
(s_data_plane_fault_delivery_addr[1] != 32'h1001_2800) ||
s_data_plane_fault_delivery_write[1] ||
(s_data_plane_fault_delivery_reason[1] != {1'b0, `RIB_RESP_DECERR}) ||
(s_data_plane_fault_delivery_master[2] != 4'd1) ||
(s_data_plane_fault_delivery_target[2] != 3'd4) ||
(s_data_plane_fault_delivery_addr[2] != 32'h1001_2C00) ||
!s_data_plane_fault_delivery_write[2] ||
(s_data_plane_fault_delivery_reason[2] != {1'b0, `RIB_RESP_SLVERR})) begin
$fatal(1, "successive HP faults were not delivered exactly once and coherently");
end
read_register(32'h1000_B010, read_data);
if (read_data !== 32'h0000_000B) $fatal(1, "fault status was not recorded");
read_register(32'h1000_B014, read_data);
if (read_data !== 32'h1001_2000) $fatal(1, "fault address was not recorded");
read_register(32'h1000_B018, read_data);
if (read_data !== 32'h0000_0001) $fatal(1, "fault count was not incremented");
if (read_data !== 32'h0000_0003) $fatal(1, "consecutive data-plane faults were lost");
read_register(32'h1000_B028, read_data);
if (read_data !== 32'h0000_0003) $fatal(1, "three-bit fault master was not recorded");
if (read_data !== 32'h0000_0008) $fatal(1, "four-bit fault master was not recorded");
read_register(32'h1000_B02C, read_data);
if (read_data !== `RIB_RESP_RESERVED) $fatal(1, "fault detail was not recorded");
@(negedge clk_i);
sysctrl.fault_master_i = 3'd4;
sysctrl.fault_code_i = `RIB_RESP_DECERR;
fault_valid_i = 1'b1;
fault_addr_i = 32'hA000_0000;
fault_wstrb_i = 4'h0;
fault_reserved_i = 1'b0;
s_bus_fault_master = 4'd4;
s_bus_fault_code = `RIB_RESP_DECERR;
s_bus_fault_valid = 1'b1;
s_bus_fault_addr = 32'hA000_0000;
s_bus_fault_wstrb = 4'h0;
s_bus_fault_reserved = 1'b0;
@(negedge clk_i);
fault_valid_i = 1'b0;
s_bus_fault_valid = 1'b0;
read_register(32'h1000_B014, read_data);
if (read_data !== 32'h1001_2000) $fatal(1, "later fault overwrote first fault address");
read_register(32'h1000_B018, read_data);
if (read_data !== 32'h0000_0002) $fatal(1, "later fault did not increment count");
if (read_data !== 32'h0000_0004) $fatal(1, "later fault did not increment count");
read_register(32'h1000_B02C, read_data);
if (read_data !== `RIB_RESP_RESERVED) $fatal(1, "later fault overwrote first fault detail");
@@ -178,6 +311,31 @@ module sysctrl_tb;
read_register(32'h1000_B010, read_data);
if (read_data !== 32'h0000_000A) $fatal(1, "fault W1C did not clear pending");
send_data_plane_fault(4'd8, 3'd2, 32'h1001_3000, 1'b0, {1'b0, `RIB_RESP_RESERVED}, 1'b0);
wait (s_data_plane_fault_valid_pclk);
@(negedge clk_i);
s_bus_fault_master = 4'd4;
s_bus_fault_code = `RIB_RESP_DECERR;
s_bus_fault_valid = 1'b1;
s_bus_fault_addr = 32'hA000_1000;
s_bus_fault_wstrb = 4'h0;
s_bus_fault_reserved = 1'b0;
@(negedge clk_i);
s_bus_fault_valid = 1'b0;
read_register(32'h1000_B014, read_data);
if (read_data !== 32'h1001_3000) begin
$fatal(1, "simultaneous local fault overrode the PCLK-visible data-plane fault");
end
read_register(32'h1000_B028, read_data);
if (read_data !== 32'h0000_0008) begin
$fatal(1, "fault arbitration lost the data-plane master high bit");
end
wait (s_data_plane_fault_delivery_count == 4'd4);
read_register(32'h1000_B018, read_data);
if (read_data !== 32'h0000_0005) begin
$fatal(1, "simultaneous local fault was not deterministically suppressed");
end
write_register(32'h1000_B040, 32'h0000_0005);
read_register(32'h1000_B044, read_data);
if (read_data !== 32'd11) $fatal(1, "performance snapshot was not recorded");
+39
View File
@@ -51,13 +51,30 @@ def test_clock_reset_domain_inventory_matches_the_rcu() -> None:
("clint_timebase", "aon", "lp"),
("jtag_dmi", "jtag", "lp"),
("hp_mmio", "hp", "lp"),
("data_plane_fault", "hp", "pclk"),
("io_dma_data", "pclk", "hp"),
("apu_data", "pclk", "hp"),
("ga2d_data", "pclk", "hp"),
("ga2d_source_idle", "pclk", "hp"),
("ga2d_source_quiesced", "pclk", "hp"),
("ga2d_hp_reset", "hp", "pclk"),
("ga2d_flush", "hp", "pclk"),
("ga2d_master_idle", "hp", "pclk"),
("ga2d_block_ack", "hp", "pclk"),
}
clint = next(
crossing for crossing in document["crossings"] if crossing["name"] == "clint_timebase"
)
assert clint["primitive"] == "edge_det"
data_plane_fault = next(
crossing for crossing in document["crossings"] if crossing["name"] == "data_plane_fault"
)
assert data_plane_fault["primitive"] == "async_reqack"
assert data_plane_fault["instance"] == "u_fault_mailbox"
assert data_plane_fault["unilateral_reset"] == {
"source_reset": "abort_accepted_mailbox_item",
"destination_reset": "abort_accepted_item_backpressure_unaccepted_source",
}
assert {
"usb2_work",
"usb2_result",
@@ -125,3 +142,25 @@ def test_clock_reset_domain_inventory_rejects_invalid_sta_net_driver(tmp_path: P
result = check(write_invalid_map(tmp_path, document))
assert result.returncode != 0
assert "sta.net must be a SystemVerilog identifier" in result.stderr
def test_clock_reset_domain_inventory_requires_data_plane_fault_reset_contract(
tmp_path: Path,
) -> None:
document = json.loads(DOMAIN_MAP.read_text(encoding="utf-8"))
data_plane_fault = next(
crossing for crossing in document["crossings"] if crossing["name"] == "data_plane_fault"
)
data_plane_fault.pop("unilateral_reset")
result = check(write_invalid_map(tmp_path, document))
assert result.returncode != 0
assert "unilateral_reset must declare the data-plane fault reset contract" in result.stderr
document = json.loads(DOMAIN_MAP.read_text(encoding="utf-8"))
data_plane_fault = next(
crossing for crossing in document["crossings"] if crossing["name"] == "data_plane_fault"
)
data_plane_fault["instance"] = "u_other_mailbox"
result = check(write_invalid_map(tmp_path, document))
assert result.returncode != 0
assert "must use async_reqack instance u_fault_mailbox" in result.stderr
+143
View File
@@ -0,0 +1,143 @@
"""Directed GA2D Phase 2 fabric and lifecycle verification."""
from __future__ import annotations
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_ga2d_p2_preserves_deferred_apb_irq_and_payload_boundaries() -> None:
memory_map = json.loads(
(ROOT / "rtl/mini/address_map/memory_map.json").read_text(encoding="utf-8")
)
regions = {region["symbol"]: region for region in memory_map["regions"]}
topology = json.loads(
(ROOT / "rtl/mini/integration/soc_topology.json").read_text(encoding="utf-8")
)
apb4_system = (ROOT / "rtl/mini/top/apb4_system.sv").read_text(encoding="utf-8")
top = (ROOT / "rtl/mini/top/retrosoc.sv").read_text(encoding="utf-8")
assert regions["APB4_GA"] == {
"symbol": "APB4_GA",
"base": "0x10012000",
"size": "0x00001000",
"route": "reserved",
"kind": "reserved",
"public": False,
"user_access": "none",
}
assert all("ga2d" not in interrupt["name"].lower() for interrupt in topology["interrupts"])
assert not list((ROOT / "rtl/ip/multimedia").glob("ga2d_*.sv"))
assert ".ResourceCount(9)" in apb4_system
assert "1'b0, resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]" in apb4_system
assert "resource_irq_lp_o = {s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]}" in apb4_system
assert "s_ga2d_source_safe_idle && s_resource_idle_pclk[8]" in top
assert "s_ga2d_source_safe_idle && s_resource_block_ack_pclk[8]" in top
def test_ga2d_p2_bridge_prefix_lifecycle_and_recovery(tmp_path: Path) -> None:
verilator = shutil.which("verilator")
if verilator is None:
return
topology = tmp_path / "topology"
memory_map = tmp_path / "memory_map"
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/integration/generate_soc_topology.py"),
"--map",
str(ROOT / "rtl/mini/integration/soc_topology.json"),
"--memory-map",
str(ROOT / "rtl/mini/address_map/memory_map.json"),
"--output-dir",
str(topology),
],
check=True,
)
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",
"YES",
"--sram-size-kib",
"32",
],
check=True,
)
common = ROOT / "rtl/managed/clusterip/common/rtl"
top = ROOT / "rtl/mini/top"
output = tmp_path / "ga2d_platform_tb"
ccache_tmp = tmp_path / "ccache"
ccache_tmp.mkdir()
subprocess.run(
[
verilator,
"--binary",
"--timing",
"-Wno-fatal",
"--top-module",
"ga2d_platform_tb",
"-I" + str(topology / "rtl"),
"-I" + str(memory_map / "rtl"),
"-I" + str(common),
"-I" + str(common / "cdc"),
"-I" + str(common / "interface"),
str(common / "interface/apb4_if.sv"),
str(common / "interface/axi4_if.sv"),
str(common / "interface/axi4_addr_gen.sv"),
str(common / "utils/register.sv"),
str(common / "utils/fifo.sv"),
str(common / "utils/xchecker.sv"),
str(common / "utils/spill_register.sv"),
str(common / "utils/bin2gray.sv"),
str(common / "utils/gray2bin.sv"),
str(common / "stream/round_robin_arbiter.sv"),
str(common / "cdc/cdc_sync.sv"),
str(common / "cdc/cdc_rst_ctrlr.sv"),
str(common / "cdc/cdc_2phase.sv"),
str(common / "clkrst/rst_sync.sv"),
str(top / "soc_common_cdc.sv"),
str(top / "axi4_connector.sv"),
str(top / "axi4_master_idle.sv"),
str(top / "axi4_async_bridge.sv"),
str(top / "axi4_address_gate.sv"),
str(top / "axi4_upsizer_32to64.sv"),
str(top / "axi4_id_prefix.sv"),
str(top / "axi4_data_crossbar.sv"),
str(top / "axi4_target_guard.sv"),
str(top / "fabric_monitor.sv"),
str(top / "axi4_error_slave.sv"),
str(top / "axi4_downsizer_64to32.sv"),
str(top / "hp_axi4_mux3.sv"),
str(top / "soc_data_plane.sv"),
str(ROOT / "tests/rtl/ga2d_platform_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 "GA2D P2 bridge, ID7, lifecycle, flush, and reset test passed" in result.stdout
+45 -2
View File
@@ -194,6 +194,10 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "SOC_DATA_POLICY_WRITE_TARGET_MASK" in data_policy
assert "SOC_DATA_POLICY_ALLOW_INSTRUCTION" in data_policy
assert "SOC_DATA_POLICY_REQUIRE_NONCACHEABLE" in data_policy
assert "`define SOC_DATA_POLICY_READ_TARGET_MASK 45'b111111111111111111111111111111111111111111111" in data_policy
assert "`define SOC_DATA_POLICY_WRITE_TARGET_MASK 45'b011110111101111011110111101111011110111100000" in data_policy
assert "`define SOC_DATA_POLICY_ALLOW_INSTRUCTION 9'b000000001" in data_policy
assert "`define SOC_DATA_POLICY_REQUIRE_NONCACHEABLE 9'b111111100" in data_policy
assert "RS_SOC_IRQ_VECTOR_WIDTH UINT32_C(64)" in irq_metadata
assert "RS_SOC_EXTERNAL_IRQ_COUNT UINT32_C(62)" in irq_metadata
assert "RS_SOC_IRQ_UART0 UINT32_C(2)" in irq_metadata
@@ -252,6 +256,37 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
]
def test_ga2d_p2_topology_is_data_master_only() -> None:
document = json.loads(TOPOLOGY.read_text(encoding="utf-8"))
policies = document["data_master_policies"]
assert [policy["name"] for policy in policies] == [
"hp_icache",
"hp_dcache",
"dma",
"io_gateway_a",
"io_gateway_b",
"lp_gateway",
"jpeg",
"ext_h",
"ga2d",
]
assert [policy["index"] for policy in policies] == list(range(9))
assert policies[8] == {
"index": 8,
"name": "ga2d",
"read_targets": ["sram", "sdram", "qpi", "opi", "xpi"],
"write_targets": ["sram", "sdram", "qpi", "opi"],
"allow_instruction": False,
"require_noncacheable": True,
}
assert all(
target["name"] != "ga2d"
for target in document["apb4_periph_targets"] + document["apb4_system_targets"]
)
assert all("ga2d" not in interrupt["name"] for interrupt in document["interrupts"])
def test_apu_p1_fixed_resource_and_hp_irq_allocations() -> None:
periph = (ROOT / "rtl/mini/top/apb4_periph.sv").read_text(encoding="utf-8")
system = (ROOT / "rtl/mini/top/apb4_system.sv").read_text(encoding="utf-8")
@@ -262,12 +297,12 @@ def test_apu_p1_fixed_resource_and_hp_irq_allocations() -> None:
assert "s_hp_plic_source[10] = resource_irq_hp_i[6];" in periph
assert "s_apu_irq_raw, s_jpeg_irq_raw" in periph
assert ".ResourceCount(8)" in system
assert ".ResourceCount(9)" in system
assert ".apu_owner_i (s_resource_owner[7])" in top
assert ".apu_quiesce_i (s_resource_quiesce[7])" in top
assert ".apu_reset_i (s_resource_reset[7])" in top
assert "RS_RESOURCE_APU = 7" in resource_header
assert "RS_RESOURCE_COUNT = 8" in resource_header
assert "RS_RESOURCE_COUNT = 9" in resource_header
def test_topology_always_adds_the_user_apb_target(tmp_path: Path) -> None:
@@ -419,6 +454,14 @@ def test_topology_rejects_invalid_irq_groups_and_bindings(tmp_path: Path) -> Non
assert "core interrupt bit 0 must retain its compatibility binding" in result.stderr
def test_topology_rejects_missing_ga2d_data_policy(tmp_path: Path) -> None:
document = json.loads(TOPOLOGY.read_text(encoding="utf-8"))
document["data_master_policies"].pop()
result = validate(write_invalid_topology(tmp_path, document))
assert result.returncode != 0
assert "all 9 data masters" in result.stderr
def test_generated_irq_wiring_preserves_the_expected_core_vector(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
+21
View File
@@ -10,6 +10,23 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PERIPHERAL = ROOT / "rtl/ip/peripheral"
TOP = ROOT / "rtl/mini/top"
def test_sysctrl_fault_master_keeps_the_data_plane_high_bit() -> None:
interface = (PERIPHERAL / "sysctrl_if.sv").read_text(encoding="utf-8")
core = (PERIPHERAL / "sysctrl_core.sv").read_text(encoding="utf-8")
top = (TOP / "retrosoc.sv").read_text(encoding="utf-8")
fault_cdc = (TOP / "data_plane_fault_cdc.sv").read_text(encoding="utf-8")
assert "logic [ 3:0] fault_master_i;" in interface
assert "28'd0, s_fault_master_q" in core
assert "{1'b0, s_bus_fault_master}" in top
assert "data_plane_fault_cdc u_data_plane_fault_cdc" in top
assert ".fault_ready_i (s_data_plane_fault_ready_hp)" in top
assert "s_data_plane_fault_valid_pclk || s_bus_fault_valid" in top
assert "async_reqack" in fault_cdc
assert "fault_ready_o" in fault_cdc
def test_sysctrl_registers_lifecycle_faults_and_wake(tmp_path: Path) -> None:
@@ -59,6 +76,10 @@ def test_sysctrl_registers_lifecycle_faults_and_wake(tmp_path: Path) -> None:
str(common / "interface/apb4_if.sv"),
str(common / "utils/register.sv"),
str(common / "cdc/cdc_sync.sv"),
str(common / "clkrst/rst_sync.sv"),
str(common / "cdc/cdc_rst_ctrlr.sv"),
str(TOP / "soc_common_cdc.sv"),
str(TOP / "data_plane_fault_cdc.sv"),
str(PERIPHERAL / "pll_ctrl_if.sv"),
str(PERIPHERAL / "clock_ctrl_if.sv"),
str(PERIPHERAL / "sysctrl_if.sv"),