mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add testbenches for on-chip RAM and resource controller, enhance AXI4 and APB4 support
- Introduced to validate AXI4 interface for 64-bit on-chip SRAM. - Added to test resource controller functionality including ownership, IRQ handling, and cache handshake. - Updated to include resource controller interface. - Enhanced to cover additional IRQ scenarios. - Added new tests in for AXI4 target guard timeout and isolation. - Updated to reflect changes in the high-performance profile. - Modified to verify on-chip SRAM bank configurations. - Added for directed verification of resource controller. - Updated to check SDRAM mapped window coverage. - Enhanced to ensure correct IRQ mappings and APB target generation.
This commit is contained in:
77 files changed
+2821
-513
No files matched your search
@@ -44,7 +44,7 @@ SRAM_SIZE_KIB ?= $(if $(filter ICS55,$(PDK)),128,32)
|
||||
PDK_BEHAV ?= NO
|
||||
HAVE_SVA ?= NO
|
||||
HAVE_HP ?= YES
|
||||
HP_CONFIG ?= rv32imafdc_max
|
||||
HP_CONFIG ?= rv32imafdc_zicbom_max
|
||||
BUILD_RELEASE ?= NO
|
||||
JTAG_IDCODE ?= DEADBEEF
|
||||
EXT_CLK_HZ ?= 72000000
|
||||
@@ -159,7 +159,7 @@ VALID_SYNTH_RECIPE := balanced area speed
|
||||
VALID_STA := NONE OPENSTA
|
||||
VALID_PDK := ICS55 IHP130 SKY130 GF180
|
||||
VALID_BOOL := YES NO
|
||||
VALID_HP_CONFIG := rv32imafdc_max
|
||||
VALID_HP_CONFIG := rv32imafdc_zicbom_max
|
||||
VALID_ISA := RV32E RV32I RV32IM
|
||||
VALID_APP := benchmark bringup ci_smoke coremark debug hp_boot shell xpi_flash_loader
|
||||
VALID_LINK_TYPE := xip jtag_sram ld2_all_sram ld2_sram ld2_psram ld2_sdram
|
||||
|
||||
@@ -91,8 +91,8 @@ used with commercial 32 KiB SRAM and PLL simulation models.
|
||||
| [`configs/ci/ihp130-shell.mk`](configs/ci/ihp130-shell.mk) | RV32IM | `shell` | Pull-request firmware build with CSR support enabled. |
|
||||
| [`configs/ci/ihp130-debug.mk`](configs/ci/ihp130-debug.mk) | RV32IM | `debug` | Verilator remote-bitbang acceptance of the Hazard3 JTAG DTM, Debug Module, OpenOCD, and GDB. |
|
||||
| [`configs/ci/ihp130-hp.mk`](configs/ci/ihp130-hp.mk) | LP RV32IM / HP RV32IMAFDC | `hp_boot` | Linux image/bundle flow and HP RTL validation on the fixed product topology. |
|
||||
| [`configs/benchmark/ihp130-hazard3-coremark.mk`](configs/benchmark/ihp130-hazard3-coremark.mk) | LP RV32IM / HP RV32IMAFDC | `coremark` | Fixed four-iteration LP SRAM CoreMark measurement with the product HP core present. |
|
||||
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | LP RV32IM / HP RV32IMAFDC | `bringup` | Site profile with PLL/SRAM intentionally disabled for regression compatibility. |
|
||||
| [`configs/benchmark/ihp130-hazard3-coremark.mk`](configs/benchmark/ihp130-hazard3-coremark.mk) | LP RV32IM / HP RV32IMAFDC+Zicbom | `coremark` | Fixed four-iteration LP SRAM CoreMark measurement with the product HP core present. |
|
||||
| [`configs/cluster/ics55.mk`](configs/cluster/ics55.mk) | LP RV32IM / HP RV32IMAFDC+Zicbom | `bringup` | Site profile with PLL/SRAM intentionally disabled for regression compatibility. |
|
||||
| [`configs/cluster/mini-mpw.mk`](configs/cluster/mini-mpw.mk) | RV32IM | `bringup` | Legacy MPW C0-C3/user-IP selection profile; not part of the Mini product ABI. |
|
||||
|
||||
CI Verilator firmware simulations explicitly select the `ci_smoke`
|
||||
|
||||
@@ -262,9 +262,10 @@ static bool rs_ci_smoke_sdram_wait_ready(void) {
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_sdram_access(void) {
|
||||
volatile uint8_t *const bytes = (volatile uint8_t *)(uintptr_t)RS_SOC_SDRAM_BASE;
|
||||
volatile uint16_t *const halfs = (volatile uint16_t *)(uintptr_t)RS_SOC_SDRAM_BASE;
|
||||
volatile uint32_t *const words = (volatile uint32_t *)(uintptr_t)RS_SOC_SDRAM_BASE;
|
||||
const uintptr_t scratch = (uintptr_t)(RS_SOC_SDRAM_END - RS_CI_SMOKE_SDRAM_SPAN + UINT32_C(1));
|
||||
volatile uint8_t *const bytes = (volatile uint8_t *)scratch;
|
||||
volatile uint16_t *const halfs = (volatile uint16_t *)scratch;
|
||||
volatile uint32_t *const words = (volatile uint32_t *)scratch;
|
||||
uint32_t index;
|
||||
|
||||
if (!rs_ci_smoke_sdram_wait_ready()) {
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
clock-frequency = <72000000>;
|
||||
mmu-type = "riscv,sv32";
|
||||
riscv,isa-base = "rv32i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicsr",
|
||||
"zifencei";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicbom",
|
||||
"zicsr", "zifencei";
|
||||
riscv,cbom-block-size = <64>;
|
||||
|
||||
hp_cpu_intc: interrupt-controller {
|
||||
compatible = "riscv,cpu-intc";
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ CoreMark quick measurement; its `-standard` counterpart is reserved for a
|
||||
runs the quick CoreMark profile.
|
||||
`ci/ihp130-hp.mk` is the asymmetric Linux application profile. It starts HP
|
||||
from the external 72 MHz safe clock and LP from REF24, runs `hp_boot` entirely
|
||||
from 32 KiB on-chip SRAM, and
|
||||
from 32 KiB on-chip SRAM, enables VexiiRiscv `Zicbom` with 64-byte blocks, and
|
||||
generates VexiiRiscv RTL only below the selected build variant. It is not part
|
||||
of the supported PR matrix until Linux boot, HP performance, synthesis, and
|
||||
timing evidence are qualified.
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
@@ -3,7 +3,7 @@ MINI_MODE := PRODUCT
|
||||
PDK := IHP130
|
||||
HAVE_PLL := NO
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
PDK_BEHAV := YES
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -6,7 +6,7 @@ HAVE_SRAM_IF := NO
|
||||
HAVE_SRAM_MACRO := NO
|
||||
SRAM_SIZE_KIB := 32
|
||||
HAVE_HP := YES
|
||||
HP_CONFIG := rv32imafdc_max
|
||||
HP_CONFIG := rv32imafdc_zicbom_max
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 72000000
|
||||
AUD_CLK_HZ := 18432000
|
||||
|
||||
@@ -52,6 +52,10 @@ MPW compatibility API; selector mutators return `RS_ENOTSUP` in product builds.
|
||||
See the [extension contract](../docs/ip/extensions.md) and
|
||||
[legacy user-IP contract](../docs/ip/user-ip.md).
|
||||
|
||||
`<retrosoc/hal/resource.h>` owns the central DMA, USB2, SDIO0/1, SPI-SD, and
|
||||
EXT-H owner/lock, lifecycle-request, fault, and HP cache-maintenance handshake.
|
||||
See the [Resource Controller contract](../docs/ip/resource-controller.md).
|
||||
|
||||
`<retrosoc/hal/memory.h>` provides the uniform Mini memory inventory for
|
||||
SRAM, SDRAM, QPI PSRAM, OPI/HyperBus PSRAM, and XPI. It reports the fixed
|
||||
window, device/initialization/ready/active state, shared-pad mode, DMA and
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef RETROSOC_HAL_RESOURCE_H
|
||||
#define RETROSOC_HAL_RESOURCE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
typedef enum {
|
||||
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_COUNT = 6,
|
||||
} rs_resource_t;
|
||||
|
||||
typedef enum {
|
||||
RS_RESOURCE_OWNER_LP = 0,
|
||||
RS_RESOURCE_OWNER_HP = 1,
|
||||
} rs_resource_owner_t;
|
||||
|
||||
typedef struct {
|
||||
rs_resource_owner_t owner;
|
||||
uint16_t handoff_count;
|
||||
bool owner_locked;
|
||||
bool blocked;
|
||||
bool idle;
|
||||
bool quiesced;
|
||||
bool in_reset;
|
||||
bool irq_pending;
|
||||
bool fault;
|
||||
} rs_resource_status_t;
|
||||
|
||||
typedef struct {
|
||||
bool request;
|
||||
bool clean;
|
||||
} rs_resource_cache_status_t;
|
||||
|
||||
rs_status_t rs_resource_get_status(rs_resource_t resource, rs_resource_status_t *status);
|
||||
rs_status_t rs_resource_set_owner(rs_resource_t resource, rs_resource_owner_t owner, bool lock);
|
||||
rs_status_t rs_resource_set_lifecycle(rs_resource_t resource, bool quiesce, bool reset);
|
||||
rs_status_t rs_resource_clear_fault(rs_resource_t resource);
|
||||
rs_status_t rs_resource_get_cache_status(rs_resource_cache_status_t *status);
|
||||
rs_status_t rs_resource_acknowledge_cache_clean(void);
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/extension.h>
|
||||
#include <retrosoc/hal/resource.h>
|
||||
|
||||
#define RS_EXTENSION_IDENTIFICATION_OFFSET UINT32_C(0x000)
|
||||
#define RS_EXTENSION_VERSION_OFFSET UINT32_C(0x004)
|
||||
@@ -110,6 +111,7 @@ rs_status_t rs_extension_get_status(rs_extension_slot_t slot, rs_extension_statu
|
||||
rs_status_t rs_extension_set_owner(rs_extension_slot_t slot, rs_extension_owner_t owner,
|
||||
bool lock) {
|
||||
uint32_t value;
|
||||
rs_status_t status;
|
||||
|
||||
if ((owner != RS_EXTENSION_OWNER_LP) && (owner != RS_EXTENSION_OWNER_HP)) {
|
||||
return RS_EINVAL;
|
||||
@@ -118,12 +120,19 @@ rs_status_t rs_extension_set_owner(rs_extension_slot_t slot, rs_extension_owner_
|
||||
if (lock) {
|
||||
value |= RS_EXTENSION_OWNER_LOCK;
|
||||
}
|
||||
if (slot == RS_EXTENSION_SLOT_H) {
|
||||
status = rs_resource_set_owner(RS_RESOURCE_EXT_H, (rs_resource_owner_t)owner, lock);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return rs_extension_write(slot, RS_EXTENSION_OWNER_OFFSET, value);
|
||||
}
|
||||
|
||||
rs_status_t rs_extension_set_lifecycle(rs_extension_slot_t slot, bool quiesce, bool reset,
|
||||
bool clear_fault) {
|
||||
uint32_t command = 0U;
|
||||
rs_status_t status;
|
||||
|
||||
if (quiesce) {
|
||||
command |= RS_EXTENSION_COMMAND_QUIESCE;
|
||||
@@ -134,6 +143,15 @@ rs_status_t rs_extension_set_lifecycle(rs_extension_slot_t slot, bool quiesce, b
|
||||
if (clear_fault) {
|
||||
command |= RS_EXTENSION_COMMAND_CLEAR_FAULT;
|
||||
}
|
||||
if (slot == RS_EXTENSION_SLOT_H) {
|
||||
status = rs_resource_set_lifecycle(RS_RESOURCE_EXT_H, quiesce, reset);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
if (clear_fault && (rs_resource_clear_fault(RS_RESOURCE_EXT_H) != RS_OK)) {
|
||||
return RS_EIO;
|
||||
}
|
||||
}
|
||||
return rs_extension_write(slot, RS_EXTENSION_COMMAND_OFFSET, command);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ rs_status_t rs_onchip_sram_probe(rs_onchip_sram_info_t *info) {
|
||||
info->present = (capability & RS_ONCHIP_SRAM_CAP_PRESENT) != 0U;
|
||||
|
||||
if ((bank_bytes != RS_ONCHIP_SRAM_BANK_BYTES_VALUE) || (info->max_burst_beats != 16U) ||
|
||||
(info->data_bytes != 4U) ||
|
||||
((info->data_bytes != 4U) && (info->data_bytes != 8U)) ||
|
||||
((capability & (RS_ONCHIP_SRAM_CAP_NATIVE_AXI4 | RS_ONCHIP_SRAM_CAP_BYTE_WRITE |
|
||||
RS_ONCHIP_SRAM_CAP_FIXED | RS_ONCHIP_SRAM_CAP_INCR |
|
||||
RS_ONCHIP_SRAM_CAP_WRAP | RS_ONCHIP_SRAM_CAP_PERFORMANCE)) !=
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/resource.h>
|
||||
|
||||
#define RS_RESOURCE_CACHE_CONTROL_OFFSET UINT32_C(0x010)
|
||||
#define RS_RESOURCE_BASE_OFFSET UINT32_C(0x100)
|
||||
#define RS_RESOURCE_STRIDE UINT32_C(0x020)
|
||||
#define RS_RESOURCE_OWNER_OFFSET UINT32_C(0x000)
|
||||
#define RS_RESOURCE_CONTROL_OFFSET UINT32_C(0x004)
|
||||
#define RS_RESOURCE_STATUS_OFFSET UINT32_C(0x008)
|
||||
#define RS_RESOURCE_FAULT_OFFSET UINT32_C(0x00C)
|
||||
#define RS_RESOURCE_HANDOFF_COUNT_OFFSET UINT32_C(0x010)
|
||||
|
||||
#define RS_RESOURCE_OWNER_MASK UINT32_C(0x00000003)
|
||||
#define RS_RESOURCE_OWNER_LOCK UINT32_C(0x00000100)
|
||||
#define RS_RESOURCE_CONTROL_QUIESCE UINT32_C(0x00000001)
|
||||
#define RS_RESOURCE_CONTROL_RESET UINT32_C(0x00000002)
|
||||
#define RS_RESOURCE_STATUS_IDLE UINT32_C(0x00000010)
|
||||
#define RS_RESOURCE_STATUS_FAULT UINT32_C(0x00000020)
|
||||
#define RS_RESOURCE_STATUS_IRQ UINT32_C(0x00000040)
|
||||
#define RS_RESOURCE_STATUS_BLOCKED UINT32_C(0x00000080)
|
||||
#define RS_RESOURCE_CACHE_CLEAN UINT32_C(0x00000001)
|
||||
#define RS_RESOURCE_CACHE_REQUEST UINT32_C(0x00000002)
|
||||
|
||||
static bool rs_resource_valid(rs_resource_t resource) {
|
||||
return (uint32_t)resource < (uint32_t)RS_RESOURCE_COUNT;
|
||||
}
|
||||
|
||||
static volatile uint32_t *rs_resource_register(uint32_t offset) {
|
||||
return (volatile uint32_t *)(RS_SOC_APB4_RESOURCE_CTRL_BASE + (uintptr_t)offset);
|
||||
}
|
||||
|
||||
static uint32_t rs_resource_offset(rs_resource_t resource, uint32_t offset) {
|
||||
return RS_RESOURCE_BASE_OFFSET + ((uint32_t)resource * RS_RESOURCE_STRIDE) + offset;
|
||||
}
|
||||
|
||||
rs_status_t rs_resource_get_status(rs_resource_t resource, rs_resource_status_t *status) {
|
||||
uint32_t owner;
|
||||
uint32_t state;
|
||||
|
||||
if ((status == NULL) || !rs_resource_valid(resource)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
owner = *rs_resource_register(rs_resource_offset(resource, RS_RESOURCE_OWNER_OFFSET));
|
||||
state = *rs_resource_register(rs_resource_offset(resource, RS_RESOURCE_STATUS_OFFSET));
|
||||
status->handoff_count = (uint16_t)*rs_resource_register(
|
||||
rs_resource_offset(resource, RS_RESOURCE_HANDOFF_COUNT_OFFSET));
|
||||
status->owner = (rs_resource_owner_t)(owner & RS_RESOURCE_OWNER_MASK);
|
||||
status->owner_locked = (owner & RS_RESOURCE_OWNER_LOCK) != 0U;
|
||||
status->blocked = (state & RS_RESOURCE_STATUS_BLOCKED) != 0U;
|
||||
status->idle = (state & RS_RESOURCE_STATUS_IDLE) != 0U;
|
||||
status->quiesced = (state & RS_RESOURCE_CONTROL_QUIESCE) != 0U;
|
||||
status->in_reset = (state & RS_RESOURCE_CONTROL_RESET) != 0U;
|
||||
status->fault = (state & RS_RESOURCE_STATUS_FAULT) != 0U;
|
||||
status->irq_pending = (state & RS_RESOURCE_STATUS_IRQ) != 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_resource_set_owner(rs_resource_t resource, rs_resource_owner_t owner, bool lock) {
|
||||
rs_resource_status_t status;
|
||||
uint32_t value;
|
||||
uint32_t timeout;
|
||||
|
||||
if (!rs_resource_valid(resource) ||
|
||||
((owner != RS_RESOURCE_OWNER_LP) && (owner != RS_RESOURCE_OWNER_HP))) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((rs_resource_get_status(resource, &status) != RS_OK) || status.owner_locked) {
|
||||
return RS_EIO;
|
||||
}
|
||||
if (rs_resource_set_lifecycle(resource, true, false) != RS_OK) {
|
||||
return RS_EIO;
|
||||
}
|
||||
for (timeout = 0U; timeout < RS_TIMEOUT_DEFAULT; ++timeout) {
|
||||
if ((rs_resource_get_status(resource, &status) == RS_OK) && status.blocked && status.idle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!status.blocked || !status.idle) {
|
||||
(void)rs_resource_set_lifecycle(resource, false, false);
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
value = (uint32_t)owner;
|
||||
if (lock) {
|
||||
value |= RS_RESOURCE_OWNER_LOCK;
|
||||
}
|
||||
*rs_resource_register(rs_resource_offset(resource, RS_RESOURCE_OWNER_OFFSET)) = value;
|
||||
if (rs_resource_get_status(resource, &status) != RS_OK) {
|
||||
(void)rs_resource_set_lifecycle(resource, false, false);
|
||||
return RS_EIO;
|
||||
}
|
||||
(void)rs_resource_set_lifecycle(resource, false, false);
|
||||
return ((status.owner == owner) && (status.owner_locked == lock)) ? RS_OK : RS_EIO;
|
||||
}
|
||||
|
||||
rs_status_t rs_resource_set_lifecycle(rs_resource_t resource, bool quiesce, bool reset) {
|
||||
uint32_t value = 0U;
|
||||
|
||||
if (!rs_resource_valid(resource)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if (quiesce) {
|
||||
value |= RS_RESOURCE_CONTROL_QUIESCE;
|
||||
}
|
||||
if (reset) {
|
||||
value |= RS_RESOURCE_CONTROL_RESET;
|
||||
}
|
||||
*rs_resource_register(rs_resource_offset(resource, RS_RESOURCE_CONTROL_OFFSET)) = value;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_resource_clear_fault(rs_resource_t resource) {
|
||||
if (!rs_resource_valid(resource)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*rs_resource_register(rs_resource_offset(resource, RS_RESOURCE_FAULT_OFFSET)) = UINT32_C(1);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_resource_get_cache_status(rs_resource_cache_status_t *status) {
|
||||
uint32_t value;
|
||||
|
||||
if (status == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
value = *rs_resource_register(RS_RESOURCE_CACHE_CONTROL_OFFSET);
|
||||
status->request = (value & RS_RESOURCE_CACHE_REQUEST) != 0U;
|
||||
status->clean = (value & RS_RESOURCE_CACHE_CLEAN) != 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_resource_acknowledge_cache_clean(void) {
|
||||
rs_resource_cache_status_t status;
|
||||
|
||||
if ((rs_resource_get_cache_status(&status) != RS_OK) || !status.request) {
|
||||
return RS_EIO;
|
||||
}
|
||||
*rs_resource_register(RS_RESOURCE_CACHE_CONTROL_OFFSET) = RS_RESOURCE_CACHE_CLEAN;
|
||||
return RS_OK;
|
||||
}
|
||||
@@ -61,6 +61,8 @@ the root README and subsystem guides.
|
||||
behavior of the legacy 4 KiB user-IP window.
|
||||
- [ip/extensions.md](ip/extensions.md) defines product EXT-L/EXT-H fixed
|
||||
windows, lifecycle, capability, ACL, fault, and HAL contracts.
|
||||
- [ip/resource-controller.md](ip/resource-controller.md) defines centralized
|
||||
DMA/I/O/EXT-H ownership, IRQ routing, cache handoff, and fault contracts.
|
||||
- [ip/clint.md](ip/clint.md) defines the standard CLINT register map, fixed
|
||||
timebase, RV32 access rules, interrupt behavior, and verification contract.
|
||||
- [ip/gpio.md](ip/gpio.md) defines the GPIO dual-window ABI, pad ownership,
|
||||
|
||||
+13
-12
@@ -40,15 +40,16 @@ IDs. It has eight masters:
|
||||
| 7 | EXT-H | PCLK-to-HP AXI64 CDC |
|
||||
|
||||
Each source receives a fixed three-bit master prefix. The crossbar maintains
|
||||
independent read and write owners for each target, enabling read/write overlap
|
||||
and cross-target concurrency. Different IDs from HP/DMA/EXT-H may be active on
|
||||
different targets up to the master credit. The same ID is blocked until
|
||||
completion, and each target remains single-outstanding per direction.
|
||||
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
|
||||
same source ID is blocked until completion. SRAM/SDRAM target credits are four
|
||||
reads and two writes; serial and error targets use one read and one write.
|
||||
|
||||
| Target | Current backend |
|
||||
| --- | --- |
|
||||
| on-chip SRAM | AXI64-to-32, HP-to-LP CDC, native AXI32 SRAM |
|
||||
| SDRAM | AXI64-to-32, HP-to-LP CDC, AXI32 controller |
|
||||
| on-chip SRAM | native AXI64/ID6 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 |
|
||||
| XPI/flash | AXI64-to-32, CDC, XPI frontend |
|
||||
@@ -68,15 +69,15 @@ fail-closed according to the synchronized AON pad mode.
|
||||
- `apb4_async_bridge` converts one APB request into a request/response CDC
|
||||
transaction and guarantees a finite APB completion when the destination runs.
|
||||
|
||||
Normal HP shutdown blocks new addresses, drains accepted traffic, and performs
|
||||
a coordinated warm flush. Forced timeout records a lifecycle fault. Synthetic
|
||||
completion for every accepted transaction behind a permanently stopped target
|
||||
is not yet claimed.
|
||||
Normal HP shutdown requests software cache maintenance, blocks new addresses,
|
||||
drains accepted traffic, and performs a coordinated warm flush. Target guards
|
||||
provide bounded synthetic `SLVERR` completion and fail-closed isolation for a
|
||||
stopped target.
|
||||
|
||||
## Verification boundary
|
||||
|
||||
`tests/test_axi4.py` retains LP fabric, downsizer, burst, response, and
|
||||
backpressure coverage. Full-product Verilator/Icarus simulation exercises LP
|
||||
boot, HP elaboration, the memory gateways, and product APB paths. The current
|
||||
implementation does not claim same-target multi-outstanding reordering, cache
|
||||
coherency, formal crossbar proof, CDC signoff, or physical bandwidth closure.
|
||||
implementation does not claim cache coherency, full AXI formal proof, CDC
|
||||
signoff, or physical bandwidth closure.
|
||||
@@ -30,10 +30,18 @@ gateway, and EXT-H use a 64-bit memory plane. APB remains a separate control
|
||||
plane. Every data-plane initiator has a fixed identity, an outstanding-credit
|
||||
limit, a QoS class, an access policy, and fault attribution.
|
||||
|
||||
The first delivery contract is target-aware rather than uniform: high
|
||||
bandwidth initiators can issue up to four reads and two writes, while serial
|
||||
memory targets advertise lower credits. Stable target-specific functional
|
||||
clocks keep SDRAM refresh and serial-memory timing independent of HP DFS.
|
||||
The independent Resource Controller applies the RT1180/TRDC-style resource
|
||||
domain idea without claiming a security lifecycle: six fixed resources have
|
||||
idle-gated owner changes, sticky owner lock, fault attribution, and mutually
|
||||
exclusive LP/HP IRQ delivery. The AON shutdown sequence uses a 64-byte Zicbom
|
||||
cache-maintenance request/ACK before blocking HP traffic. This is explicit
|
||||
software-managed coherency, not a coherent interconnect.
|
||||
|
||||
The first delivery contract is target-aware rather than uniform: SRAM/SDRAM
|
||||
admit four reads and two writes, while serial memory targets advertise lower
|
||||
credits. A queued target guard bounds stalls and fail-closes after accepted
|
||||
timeouts. Stable target-specific functional clocks keep SDRAM refresh and
|
||||
serial-memory timing independent of HP DFS.
|
||||
|
||||
No release may describe the implementation as timing closed, CDC signed off,
|
||||
silicon qualified, functionally safe, or cache coherent until the separate
|
||||
|
||||
+7
-5
@@ -16,12 +16,14 @@
|
||||
Regression Verilator firmware simulations override the profiles' manual
|
||||
`bringup` default with `APP=ci_smoke`. The IHP130 PR simulation also uses the
|
||||
32 KiB `ld2_all_sram` layout, the explicit Verilator `--fast-flash` backend,
|
||||
and a 360-second wall-clock budget. The full serial XPI path remains covered
|
||||
by the Icarus assembly self-test and directed XPI model tests; the accelerated
|
||||
run is the broad software-visible integration test. This application verifies UART output,
|
||||
and a 360-second wall-clock budget. GF180, ICS55, and SKY130 use the common
|
||||
`ld2_sdram` execution layout, the same fast-flash backend, and a 600-second
|
||||
budget so the broad smoke does not execute from the serial PSRAM model. The
|
||||
full serial XPI and PSRAM path remains covered by the Icarus assembly self-test
|
||||
and directed memory-model tests. This application verifies UART output,
|
||||
archinfo APB readback, on-chip SRAM first/last-word and 8/16/32-bit access,
|
||||
RNG integration, SDRAM 8/16/32-bit mapped-window access,
|
||||
and test-status completion within the CI time budget;
|
||||
RNG integration, SDRAM 8/16/32-bit access in a reserved tail scratch area, and
|
||||
test-status completion within the CI time budget;
|
||||
`bringup` retains the full automatic application-information report for
|
||||
manual runs.
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ extension interfaces.
|
||||
|
||||
- [timer.md](timer.md) defines the dual APB4 general timer.
|
||||
- [sysctrl.md](sysctrl.md) defines the APB4 SystemCtrl register ABI, control-plane contracts, HAL, and verification.
|
||||
- [resource-controller.md](resource-controller.md) defines root-managed resource ownership, IRQ routing, and cache-maintenance handoff.
|
||||
- [user-ip.md](user-ip.md) defines the selectable user-IP window and software ownership boundary.
|
||||
- [ws2812.md](ws2812.md) defines the WS2812 transmitter.
|
||||
- [clint.md](clint.md) defines the management-hart software and timer interrupt block.
|
||||
|
||||
@@ -38,9 +38,11 @@ supports a byte-masked final beat and reports AXI response errors and
|
||||
no-progress timeouts. Programmed ranges are enforced by the data-plane M7
|
||||
firewall; M6 and control-plane addresses remain denied in hardware.
|
||||
|
||||
OWNER also controls interrupt routing. LP ownership delivers the slot event on
|
||||
LP IRQ 28; HP ownership delivers it on HP PLIC source 3. The two routes are
|
||||
mutually exclusive. Quiesce or reset blocks new EXT-H AXI addresses and STATUS
|
||||
For EXT-H, the central Resource Controller owner is the interrupt-routing
|
||||
authority. LP ownership delivers the slot event on LP IRQ 28; HP ownership
|
||||
delivers it on HP PLIC source 3, never both. The local `OWNER` register remains
|
||||
an ABI-compatible mirror, and `rs_extension_set_owner()` updates both through
|
||||
the Resource HAL. Quiesce or reset blocks new EXT-H AXI addresses and STATUS
|
||||
does not report idle until the DMA and address gate have drained.
|
||||
|
||||
`<retrosoc/hal/extension.h>` provides discovery, status, ownership, lifecycle,
|
||||
|
||||
+26
-19
@@ -2,9 +2,12 @@
|
||||
|
||||
## Scope and maturity
|
||||
|
||||
The Mini SoC on-chip SRAM is a synthesis-time configurable, 32-bit native-AXI4
|
||||
target backed by fixed `1024 x 32` single-port technology wrappers. Supported
|
||||
capacities are 4, 16, 32, 64, and 128 KiB. The data aperture starts at
|
||||
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
|
||||
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
|
||||
physical capacity. A management-only APB4 window at `0x1001_7000` reports the
|
||||
configuration and saturating performance counters.
|
||||
@@ -29,10 +32,10 @@ dependencies and do not transfer a vendor's qualification to retroSoC.
|
||||
| [CAST SRAM-CTRL and ECC-SRAM](https://www.cast-inc.com/peripherals/memory-controllers/sram-ctrl) | Commercial IP emphasizes native AXI/AHB/APB, byte accesses, low latency, lint/scan readiness, SECDED, testbenches, scripts, and integration documentation. | The products remain offered. Use the features and deliverables as an IP-readiness checklist, not as evidence for this implementation. |
|
||||
| [Synopsys STAR Memory System](https://www.synopsys.com/articles/embedded-memory-test.html) | Hierarchical test, diagnosis, redundancy repair, tester patterns, and physical failed-bit mapping address manufacturing yield and field diagnosis. | The product family remains published. Keep DFT/repair as a physical-delivery phase instead of embedding an unqualified March engine in the AXI datapath. |
|
||||
|
||||
The selected architecture is static capacity configuration plus a native AXI
|
||||
datapath. Dynamic bank reassignment, caches, multiple outstanding IDs, and
|
||||
multi-master bank scheduling require changes above this target and are not
|
||||
cost-effective in the current one-owner-per-target fabric.
|
||||
The selected architecture is static capacity configuration plus a native AXI64
|
||||
datapath. The data crossbar queues up to four SRAM reads and two writes while
|
||||
this SRAM engine completes one transaction at a time; IDs are preserved to the
|
||||
terminal response.
|
||||
|
||||
## Configuration and address contract
|
||||
|
||||
@@ -56,19 +59,20 @@ with `PRESENT=0`, zero memory bytes, and zero banks.
|
||||
|
||||
## AXI4 datapath
|
||||
|
||||
The target uses the project-wide 32-bit address/data and 1-bit ID/USER
|
||||
geometry. 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 product target uses 32-bit addresses, 64-bit data, six-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
|
||||
ID for standalone/formal reuse.
|
||||
|
||||
Supported requests are naturally aligned 1-, 2-, or 4-byte transfers using
|
||||
Supported product requests are naturally aligned 1-, 2-, 4-, or 8-byte transfers using
|
||||
`FIXED`, `INCR`, or legal 2/4/8/16-beat `WRAP` bursts. Bursts are limited to 16
|
||||
beats and one 4 KiB page. Because a bank is exactly one 4 KiB page, a legal
|
||||
transaction selects one bank for its lifetime.
|
||||
transaction selects one striped bank pair for its lifetime.
|
||||
|
||||
The macro is issued directly on AR acceptance. The first response is available
|
||||
one cycle later. With `RREADY` asserted, following beats issue on preceding
|
||||
response cycles, giving one word per cycle without bubbles. Backpressure stops
|
||||
response cycles, giving one 64-bit beat per cycle without bubbles. Backpressure stops
|
||||
new reads and holds data, ID, response, and `RLAST` stable.
|
||||
|
||||
After AW acceptance the target consumes one W beat per cycle. Strobes outside
|
||||
@@ -110,7 +114,8 @@ the register parity test prevents drift without adding a generator.
|
||||
|
||||
## Technology mapping
|
||||
|
||||
`tc_sram_1024x32` is the stable technology boundary. Behavioral simulation
|
||||
`tc_sram_1024x32` and `tc_sram_4096x32` remain the stable technology
|
||||
boundaries. Behavioral simulation
|
||||
uses the Common byte-mask RAM model. IHP130 maps to
|
||||
`RM_IHPSG13_1P_1024x32_c2_bm_bist`. GF180 composes four byte lanes across two
|
||||
`gf180mcu_fd_ip_sram__sram512x8m8wm1` depth halves and registers the address
|
||||
@@ -120,9 +125,9 @@ exports 32 data bits and hides OpenRAM's required physical spare column; a
|
||||
future physical adapter must tie the spare enable and spare input low. The
|
||||
required spare row expands the macro address port to 11 bits, so the wrapper
|
||||
ties its high bit low and exposes exactly logical addresses 0 through 1023.
|
||||
ICS55 retains its existing mapping but its supported profiles keep the macro
|
||||
disabled. Bank count, rather than technology depth or width, implements every
|
||||
product size.
|
||||
ICS55 pairs two 4096x32 macros for the 32 KiB AXI64 product target, but its
|
||||
committed profiles keep the macro disabled. Bank count, rather than technology
|
||||
depth or width, implements every product size.
|
||||
|
||||
The wrapper preserves byte masks and one-cycle synchronous reads. PDK timing,
|
||||
LEF/GDS placement, power hookup, BIST pins, and foundry signoff remain
|
||||
@@ -130,13 +135,15 @@ physical-flow responsibilities.
|
||||
|
||||
## Verification and performance evidence
|
||||
|
||||
`tests/test_onchip_ram.py` elaborates all five capacities and covers bank
|
||||
`tests/test_onchip_ram.py` elaborates all five 32-bit compatibility capacities and covers bank
|
||||
boundaries, first/last words, byte/half/word masks, `FIXED`, `INCR`, `WRAP`,
|
||||
16-beat continuous traffic, backpressure, AR/AW priority, absent-memory and
|
||||
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,
|
||||
and upper/lower 32-bit byte strobes.
|
||||
|
||||
`make CONFIG=configs/ci/ihp130.mk formal-onchip-ram` runs a 20-cycle bounded
|
||||
proof and cover set for AXI stability, channel exclusion, response bounds,
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# Mini Resource Controller
|
||||
|
||||
## Scope
|
||||
|
||||
The Resource Controller at `0x2000_A000` is the root-management ownership and
|
||||
interrupt-routing authority for central DMA, USB2, SDIO0, SDIO1, SPI-SD, and
|
||||
EXT-H. Hazard3 has read/write access; HP MMIO may inspect status but writes are
|
||||
rejected by the root-control firewall.
|
||||
It is handwritten RTL and has a matching handwritten
|
||||
`<retrosoc/hal/resource.h>` API; no register generator is used.
|
||||
|
||||
Resource indices are fixed:
|
||||
|
||||
| Index | Resource | HP PLIC source |
|
||||
| ---: | --- | ---: |
|
||||
| 0 | central DMA | 4 |
|
||||
| 1 | USB2 | 5 |
|
||||
| 2 | SDIO0 | 6 |
|
||||
| 3 | SDIO1 | 7 |
|
||||
| 4 | SPI-SD | 8 |
|
||||
| 5 | EXT-H | 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.
|
||||
|
||||
## Register ABI
|
||||
|
||||
| Offset | Name | Access | Contract |
|
||||
| ---: | --- | --- | --- |
|
||||
| `0x000` | `IP_ID` | RO | `0x52534354` (`RSCT`) |
|
||||
| `0x004` | `IP_VERSION` | RO | `0x00010000` |
|
||||
| `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 |
|
||||
|
||||
Each resource has a `0x20` stride starting at `0x100`:
|
||||
|
||||
| Relative offset | Name | Access | Contract |
|
||||
| ---: | --- | --- | --- |
|
||||
| `0x00` | `OWNER` | RW | bits 1:0 owner, bit 8 sticky owner lock |
|
||||
| `0x04` | `CONTROL` | RW | bit 0 quiesce request, bit 1 reset request |
|
||||
| `0x08` | `STATUS` | RO | owner, lifecycle request, idle, fault, raw IRQ, and HP block ACK |
|
||||
| `0x0C` | `FAULT` | RW1C | rejected handoff fault |
|
||||
| `0x10` | `HANDOFF_COUNT` | RO | saturating successful-owner-change count |
|
||||
|
||||
An owner change is accepted only after software requests quiesce and the
|
||||
resource reports both HP block ACK and idle. The HAL performs block-new,
|
||||
round-trip CDC acknowledgement, bounded drain, owner write,
|
||||
and release in that order. An illegal owner, busy handoff, or write after owner lock returns APB `PSLVERR`,
|
||||
leaves the owner unchanged, and raises the resource-fault interrupt on LP IRQ
|
||||
29. The implementation currently uses the conservative whole-data-plane idle
|
||||
condition for DMA and I/O resources; this is safe but can delay an otherwise
|
||||
independent handoff.
|
||||
|
||||
## Cache Maintenance
|
||||
|
||||
VexiiRiscv implements `Zicbom` with a 64-byte CBO block. On HP shutdown the AON
|
||||
lifecycle controller first asserts the Resource Controller cache request while
|
||||
HP remains released and its MMIO path remains open. Software cleans and
|
||||
invalidates shared ranges with CBO operations, reports completion to LP, and LP
|
||||
writes `CACHE_CONTROL.CLEAN`. AON then blocks new addresses and drains the data
|
||||
plane. Missing acknowledgement is bounded by the lifecycle timeout and records
|
||||
a forced fault before reset proceeds.
|
||||
|
||||
This handshake provides an execution window and explicit evidence point; it
|
||||
does not create hardware coherency. Buffer ownership, fences, CBO range policy,
|
||||
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. It must not be
|
||||
described as independent peripheral power isolation or reset containment until
|
||||
those downstream acknowledgements and fault-injection tests exist.
|
||||
+6
-3
@@ -12,13 +12,16 @@ timings expressed in SDRAM-clock cycles.
|
||||
| AXI4 data window | `0x38000000` - `0x3BFFFFFF` |
|
||||
| Data window size | 64 MiB |
|
||||
| APB4 configuration window | `0x1000D000` - `0x1000DFFF` |
|
||||
| Data width | 32-bit AXI over SDRAM x16 |
|
||||
| SoC data boundary | 64-bit AXI/ID6 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]`) |
|
||||
| Clocking | One edge updates control/data; the opposite edge samples |
|
||||
|
||||
Configuration requests enter through the timed `sdram_cfg` APB4 port exported
|
||||
by `apb4_periph`. AXI data requests enter `axi4` and are queued by `sdram_axi4`
|
||||
Configuration requests cross PCLK into the stable memory domain through the
|
||||
timed `sdram_cfg` APB4 port exported by `apb4_periph`. AXI64 data requests cross
|
||||
directly from HP to memory and are adapted locally; AXI32 requests then enter
|
||||
`axi4` and are queued by `sdram_axi4`
|
||||
into native multi-beat commands for `sdram_core`. Register accesses stay on the
|
||||
APB4 window and do not share the data-path arbiter. The physical SDRAM instance
|
||||
remains in the SoC top.
|
||||
|
||||
+28
-14
@@ -8,7 +8,7 @@ Every committed `MINI_MODE=PRODUCT` profile instantiates two fixed harts:
|
||||
| --- | --- | --- |
|
||||
| Core | Hazard3 | generated VexiiRiscv |
|
||||
| Hart ID | 0 | 1 |
|
||||
| ISA | profile RV32I/RV32IM | RV32IMAFDC, S/U mode, Sv32 |
|
||||
| ISA | profile RV32I/RV32IM | RV32IMAFDC + Zicbom, S/U mode, Sv32 |
|
||||
| Reset clock | REF24 at 24 MHz | external 72 MHz safe clock |
|
||||
| Role | boot, control, diagnostics, recovery | high-throughput application/Linux |
|
||||
| JTAG | reset owner | selectable while HP is held in reset |
|
||||
@@ -73,12 +73,11 @@ 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
|
||||
ownership are independent, so one target may read and write concurrently and
|
||||
different targets progress concurrently. Different source IDs from a
|
||||
high-bandwidth master may be active against different targets. The same source
|
||||
ID is blocked until completion, and each target currently remains
|
||||
single-outstanding per direction. Global IDs contain a fixed master prefix
|
||||
plus the source ID.
|
||||
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
|
||||
target accept one per direction. Responses route by the global-ID master prefix,
|
||||
and a Common FIFO preserves write-data order where AXI4 W has no ID.
|
||||
|
||||
| Master | Entry path |
|
||||
| --- | --- |
|
||||
@@ -91,11 +90,18 @@ plus the source ID.
|
||||
| EXT-H | PCLK-to-HP AXI64 async bridge, ID prefix 7 |
|
||||
|
||||
Targets are SRAM, SDRAM, QPI PSRAM, OPI/HyperBus PSRAM, XPI/flash, and a
|
||||
finite-latency error slave. Current 32-bit memory frontends use AXI64-to-32
|
||||
downsizers. QPI, OPI, and XPI controllers run from the stable 36 MHz memory
|
||||
root; their APB windows use PCLK-to-memory proxies. SRAM and SDRAM still use
|
||||
LP-domain frontends and remain explicit native-64-bit follow-up work. Inactive
|
||||
QPI/OPI windows route to `SLVERR`.
|
||||
finite-latency error slave. SRAM is a native AXI64, six-bit-ID target in HP and
|
||||
stripes each beat across two existing 32-bit technology macros. SDRAM crosses
|
||||
HP to the stable memory domain as AXI64 and is downsized only beside the current
|
||||
32-bit SDRAM frontend. QPI, OPI, and XPI retain transitional 32-bit LP staging
|
||||
before their stable memory-domain engines. Inactive QPI/OPI windows return
|
||||
`SLVERR`.
|
||||
|
||||
Every memory target has a queued guard. SRAM/SDRAM queue depth matches their
|
||||
credits. Target stalls are bounded by target-specific timeouts; a pre-accept
|
||||
stall receives synthetic `SLVERR`, while an accepted timeout flushes the CDC
|
||||
boundary, completes the original burst with `SLVERR`, and permanently isolates
|
||||
that target until hard reset so a late response cannot contaminate new traffic.
|
||||
|
||||
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
|
||||
@@ -131,6 +137,12 @@ EXT-H DMA performs aligned 64-bit memory copies with a partial final strobe.
|
||||
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, and EXT-H. Handoff requires idle, owner lock is
|
||||
sticky, and rejected handoffs raise LP IRQ 29. It also carries the AON cache
|
||||
request/clean acknowledgement used before HP drain. See
|
||||
[`ip/resource-controller.md`](ip/resource-controller.md).
|
||||
|
||||
The old `APB4_USER_IP` window is a read-only compatibility/capability window.
|
||||
Product writes to `CORESEL`, `IPSEL`, `USER_CORE_RESET`, or
|
||||
`USER_CORE_STATUS` return APB `PSLVERR`; legacy HAL mutators return
|
||||
@@ -149,8 +161,10 @@ so absolute commercial paths are never tracked.
|
||||
|
||||
Behavioral RTL, firmware, directed data-plane/lifecycle/clock tests, manifest
|
||||
parity, and quality checks are the evidence for this implementation. HP stop
|
||||
implements drain, coordinated flush, actual-release status, and bounded forced
|
||||
reset, but a forced reset cannot preserve dirty cache data. It must not be
|
||||
implements a pre-drain cache request/ACK window, drain, coordinated flush,
|
||||
actual-release status, and bounded forced reset. Vexii implements 64-byte
|
||||
`Zicbom`; software still owns shared-range selection, and a forced reset cannot
|
||||
preserve dirty cache data when the ACK times out. It must not be
|
||||
called cache coherent, power isolated, timing closed, CDC/RDC signed off, or
|
||||
silicon-qualified. Synthesis, netlist simulation, STA, MMMC, clock-tree, DFT,
|
||||
and analogue PLL qualification are separate gates.
|
||||
@@ -13,16 +13,17 @@
|
||||
| Requirement | Implementation owner | Required evidence | Status |
|
||||
| --- | --- | --- | --- |
|
||||
| Independent HP I-cache and D-cache paths | HP subsystem and data plane | Concurrent different-target AXI test | implemented |
|
||||
| Target-aware multi-outstanding AXI64 | Data crossbar | Multi-ID, ordering, backpressure, and formal tests | partial: concurrent across targets; one per target |
|
||||
| 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 | partial: priority and aging implemented; full bound proof pending |
|
||||
| Initiator ACL and first-fault attribution | Data firewall and SYSCTRL fault manager | legal/illegal access and injection tests | implemented |
|
||||
| Stable memory functional clocks | Memory integration | HP DFS while refresh/protocol engines continue | partial: QPI/OPI/XPI migrated; SRAM/SDRAM remain LP |
|
||||
| Stable memory functional clocks | Memory integration | HP DFS while refresh/protocol engines continue | implemented digitally: SRAM is native HP AXI64; SDRAM AXI64 crosses to stable memory; serial targets retain transitional LP staging |
|
||||
| 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 | drain, timeout, flush, and recovery tests | partial: cache-clean ACK remains software policy |
|
||||
| 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 |
|
||||
| Clock monitor and programmable timeout | AON clock/reset subsystem | 8x8 DFS and clock-loss tests | implemented |
|
||||
| Operational EXT-H ACL, timeout, and data path | Extension subsystem | transfer, denial, hang, and quiesce tests | implemented |
|
||||
| Ownership-aware IRQ handoff | Lifecycle and IRQ router | pending edge/level migration tests | partial: EXT-H LP/HP route implemented |
|
||||
| Ownership-aware IRQ handoff | Resource Controller and HP PLIC | idle handoff, owner lock, LP/HP exclusion, and fault tests | implemented for DMA, USB2, SDIO0/1, SPI-SD, and EXT-H; downstream per-engine reset ACK remains pending |
|
||||
| Bounded target timeout and isolation | Target guards | pre-/post-accept timeout, burst completion, and late-response isolation | implemented: synthetic SLVERR and fail-closed isolation; physical fault injection pending |
|
||||
| QPI/OPI pad exclusion and inactive-window error | Memory pad manager | simulation and formal mutual-exclusion proof | implemented |
|
||||
| Technology clock cells and physical closure | Technology/physical flow | synthesis, MMMC, SDF, CDC/RDC, and PVT | physical-pending |
|
||||
|
||||
@@ -32,17 +33,30 @@ sources of truth.
|
||||
|
||||
## Current verification evidence
|
||||
|
||||
- IHP130 `ci_smoke`, Verilator with SVA, the 32 KiB all-SRAM layout, and the
|
||||
explicit fast-flash backend: `SIM_TEST_PASS code=0` at 5,770,694 cycles.
|
||||
- IHP130 no-PLL Icarus assembly regression with the serial flash, QPI PSRAM,
|
||||
and SDRAM models: `SIM_TEST_PASS` at 4.014 ms.
|
||||
- Committed ICS55 compatibility profile with PLL/SRAM disabled: Icarus
|
||||
`SIM_TEST_PASS` at 4.014 ms.
|
||||
- Git-ignored local ICS55 profile with PLL, SRAM interface, SRAM macro, and
|
||||
32 KiB enabled: Icarus `SIM_TEST_PASS` at 4.014 ms.
|
||||
- Directed AXI64 crossbar, async warm-flush bridge, clock-monitor, HP lifecycle,
|
||||
and EXT-H DMA tests pass. Repository RTL style/readiness, clock/reset-domain,
|
||||
embedded-C policy/host, Ruff, and Pytest gates pass.
|
||||
- The complete Python suite passes: 306 tests, including directed AXI64
|
||||
crossbar, same-target IDs, target isolation, native AXI64 SRAM, async
|
||||
warm-flush, clock monitor, HP lifecycle, Resource Controller, EXT-H DMA,
|
||||
topology, clock/reset inventory, and physical macro mapping.
|
||||
- Generated PRODUCT Vexii manifests select `rv32imafdc_zicbom_max`. IHP130
|
||||
PRODUCT Icarus assembly passes at 3.998665187 ms; the matching Verilator
|
||||
assembly run passes in 221,756 cycles. Its PR `ci_smoke` Verilator run with
|
||||
SVA, fast flash, and the 32 KiB all-SRAM layout passes every peripheral test
|
||||
and reports `SIM_TEST_PASS code=0` after 5,679,566 cycles.
|
||||
- The committed ICS55 no-PLL/no-SRAM PRODUCT profile passes Icarus assembly at
|
||||
3.998665187 ms. Both ignored local ICS55 variants, with 32 KiB SRAM and PLL
|
||||
respectively off and on, pass the same PRODUCT Icarus test at 3.998665187 ms.
|
||||
The local commercial SRAM and PLL sources remain outside Git.
|
||||
- The committed ICS55 PRODUCT `ci_smoke` Verilator run with SVA, fast flash,
|
||||
and the SDRAM execution layout passes every peripheral check and reports
|
||||
`SIM_TEST_PASS code=0` after 6,984,536 cycles. GF180, ICS55, and SKY130 use
|
||||
this bounded 600-second path in PR regression; serial PSRAM boot remains in
|
||||
their Icarus assembly coverage.
|
||||
- The Yosys/Slang frontend elaborates the corrected downsizer and HP AXI mux
|
||||
with zero errors or warnings. The generated IRQ SVA now binds to the LP clock
|
||||
and reset, and the top-level unused-domain vector has exact width.
|
||||
- Repository format, full RTL style audit/readiness, clock/reset-domain,
|
||||
embedded-C policy/host, Ruff, and Pytest gates pass. Focused post-CI-fix
|
||||
Python/RTL coverage passes 91 tests.
|
||||
- Product-mode SYSCTRL and the current 11-state PLL/RCU controller pass their
|
||||
bounded proof and cover targets. The PLL/RCU proof covers successful switch,
|
||||
unsupported-PLL failure, and timeout failure paths.
|
||||
|
||||
@@ -49,9 +49,10 @@ SRAM_INSTANCES = {
|
||||
def onchip_sram_instances(capacity_kib: int) -> dict[str, tuple[list[int], str]]:
|
||||
if capacity_kib <= 0 or capacity_kib % 4 != 0:
|
||||
raise ValueError("SRAM_SIZE_KIB must be a positive multiple of 4")
|
||||
count = capacity_kib // 4
|
||||
count = 2 * ((capacity_kib + 7) // 8)
|
||||
return {
|
||||
f"u_retrosoc.u_onchip_ram.gen_memory.gen_bank[{index}].u_ram.u_mem": (
|
||||
"u_retrosoc.u_onchip_ram.gen_memory64."
|
||||
f"gen_bank[{index // 2}].u_ram_{'lo' if index % 2 == 0 else 'hi'}.u_mem": (
|
||||
[2000 + (index % 4) * 500, 500 + (index // 4) * 750],
|
||||
"N",
|
||||
)
|
||||
|
||||
@@ -570,6 +570,15 @@
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_RESOURCE_CTRL",
|
||||
"base": "0x2000A000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_system",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "SRAM",
|
||||
"base": "0x30000000",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
/top/axi4_id_prefix.sv
|
||||
/top/axi4_interconnect.sv
|
||||
/top/axi4_data_crossbar.sv
|
||||
/top/axi4_target_guard.sv
|
||||
/top/soc_data_plane.sv
|
||||
/top/axi4_error_slave.sv
|
||||
/top/rib2axi4.sv
|
||||
@@ -32,6 +33,7 @@
|
||||
/top/retrosoc_core.sv
|
||||
/top/onchip_ram_reg.sv
|
||||
/top/onchip_ram.sv
|
||||
/top/resource_controller.sv
|
||||
/top/apb4_periph.sv
|
||||
/top/apb4_system.sv
|
||||
/top/rib_bus.sv
|
||||
|
||||
@@ -108,11 +108,18 @@
|
||||
{"name": "qpi_target", "source": "lp", "destination": "pclk", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_psram_target_cdc"},
|
||||
{"name": "xpi_target", "source": "lp", "destination": "pclk", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_xpi_target_cdc"},
|
||||
{"name": "opi_target", "source": "lp", "destination": "pclk", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_opi_target_cdc"},
|
||||
{"name": "sdram_config", "source": "pclk", "destination": "lp", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_sdram_cfg_cdc"},
|
||||
{"name": "sram_config", "source": "pclk", "destination": "lp", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_sram_cfg_cdc"},
|
||||
{"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": "io_dma_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_io_cdc"},
|
||||
{"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": "memory_data", "source": "hp", "destination": "lp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_target_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": "lp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_target_cdc"},
|
||||
{"name": "sdram_abort", "source": "hp", "destination": "memory", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_abort_sync"},
|
||||
{"name": "hp_cache_request", "source": "aon", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_hp_cache_req_sync"},
|
||||
{"name": "hp_cache_clean", "source": "pclk", "destination": "aon", "primitive": "cdc_sync", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_hp_cache_clean_sync"},
|
||||
{"name": "resource_block", "source": "pclk", "destination": "hp", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_resource_block_sync"},
|
||||
{"name": "resource_idle", "source": "hp", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_resource_idle_sync"},
|
||||
{"name": "resource_block_ack", "source": "hp", "destination": "pclk", "primitive": "cdc_sync", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_resource_block_ack_sync"},
|
||||
{"name": "memory_pad_mode_hp", "source": "aon", "destination": "hp", "primitive": "cdc_sync", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_mem_pad_mode_sync"},
|
||||
{"name": "memory_pad_mode_lp", "source": "aon", "destination": "lp", "primitive": "cdc_sync", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_mem_pad_mode_sync"},
|
||||
{"name": "dvp_enable", "source": "pclk", "destination": "dvp", "primitive": "cdc_2phase", "path": "rtl/ip/multimedia/axi4s_dvp.sv", "instance": "u_dvp_config_cdc"},
|
||||
@@ -159,7 +166,7 @@
|
||||
"same_domain_contracts": [
|
||||
{
|
||||
"name": "lp_pclk_generated_clock",
|
||||
"source_domain": "lp",
|
||||
"source_domain": "hp",
|
||||
"destination_domain": "pclk",
|
||||
"clock": "clk_pclk_i",
|
||||
"reset": "rst_pclk_n_i",
|
||||
@@ -173,7 +180,7 @@
|
||||
"clock": "clk_mem_i",
|
||||
"reset": "rst_mem_n_i",
|
||||
"relationship": "declared_transition_boundary",
|
||||
"description": "The stable 36 MHz memory root is exported; controller engine migration remains explicit in RTL and documentation."
|
||||
"description": "SDRAM AXI64 commands cross from HP into the stable 36 MHz memory domain; refresh and protocol timing do not follow HP DFS."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -27,7 +27,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
|
||||
("timer0", "apb4_periph", 3, 3, "s_tim0_irq"),
|
||||
("timer1", "apb4_periph", 4, 4, "s_tim1_irq"),
|
||||
("psram", "apb4_periph", 5, 5, "psram.irq_o"),
|
||||
("spisd", "apb4_periph", 6, 6, "spisd.irq_o"),
|
||||
("spisd", "apb4_periph", 6, 6, "resource_irq_lp_i[4]"),
|
||||
("i2c0", "apb4_periph", 7, 7, "i2c0.irq_o"),
|
||||
("i2s", "apb4_periph", 8, 8, "i2s.irq_o"),
|
||||
("xpi", "apb4_periph", 9, 9, "s_xpi_irq"),
|
||||
@@ -36,6 +36,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
|
||||
("rtc", "apb4_system", 2, 13, "u_rtc_if.irq_o"),
|
||||
("watchdog_early_warning", "apb4_system", 3, 14, "u_wdg_if.irq_o"),
|
||||
("rng", "apb4_system", 4, 16, "s_rng_irq"),
|
||||
("resource_fault", "apb4_system", 7, 29, "s_resource_fault_irq"),
|
||||
("ws2812", "apb4_periph", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "apb4_periph", 11, 18, "gpio.irq_o"),
|
||||
("i2c1", "apb4_periph", 12, 19, "i2c1.irq_o"),
|
||||
@@ -767,8 +768,8 @@ def render_irq_sva(vector_width: int, groups: list[IrqGroup], interrupts: list[I
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
" .clk_i(clk_i),",
|
||||
" .rst_n_i(rst_n_i),",
|
||||
" .clk_i(clk_lp_i),",
|
||||
" .rst_n_i(rst_lp_n_i),",
|
||||
" .irq_i(s_irq),",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
{
|
||||
"name": "apb4_system",
|
||||
"width": 7,
|
||||
"width": 8,
|
||||
"top_signal": "s_apb4_system_irq"
|
||||
}
|
||||
],
|
||||
@@ -71,7 +71,7 @@
|
||||
"group": "apb4_periph",
|
||||
"group_bit": 6,
|
||||
"core_bit": 6,
|
||||
"signal": "spisd.irq_o"
|
||||
"signal": "resource_irq_lp_i[4]"
|
||||
},
|
||||
{
|
||||
"name": "i2c0",
|
||||
@@ -103,7 +103,7 @@
|
||||
"group": "apb4_periph",
|
||||
"group_bit": 16,
|
||||
"core_bit": 10,
|
||||
"signal": "sdio0.irq_o",
|
||||
"signal": "resource_irq_lp_i[2]",
|
||||
"user_visible": false
|
||||
},
|
||||
{
|
||||
@@ -185,7 +185,7 @@
|
||||
"group": "apb4_periph",
|
||||
"group_bit": 14,
|
||||
"core_bit": 20,
|
||||
"signal": "s_dma_irq",
|
||||
"signal": "resource_irq_lp_i[0]",
|
||||
"user_visible": false
|
||||
},
|
||||
{
|
||||
@@ -202,7 +202,7 @@
|
||||
"group": "apb4_periph",
|
||||
"group_bit": 17,
|
||||
"core_bit": 21,
|
||||
"signal": "sdio1.irq_o",
|
||||
"signal": "resource_irq_lp_i[3]",
|
||||
"user_visible": false
|
||||
},
|
||||
{
|
||||
@@ -220,7 +220,7 @@
|
||||
"group": "apb4_periph",
|
||||
"group_bit": 19,
|
||||
"core_bit": 24,
|
||||
"signal": "s_usb2_irq",
|
||||
"signal": "resource_irq_lp_i[1]",
|
||||
"user_visible": false
|
||||
},
|
||||
{
|
||||
@@ -258,6 +258,15 @@
|
||||
"core_bit": 28,
|
||||
"signal": "s_ext_h_irq",
|
||||
"user_visible": false
|
||||
},
|
||||
{
|
||||
"name": "resource_fault",
|
||||
"description": "Resource ownership and handoff fault interrupt",
|
||||
"group": "apb4_system",
|
||||
"group_bit": 7,
|
||||
"core_bit": 29,
|
||||
"signal": "s_resource_fault_irq",
|
||||
"user_visible": false
|
||||
}
|
||||
],
|
||||
"wake_sources": [
|
||||
@@ -581,6 +590,13 @@
|
||||
"timed_interface": "u_ext_h_apb4_if",
|
||||
"pure_interface": "u_ext_h_apb4_pure_if",
|
||||
"region": "APB4_EXT_H"
|
||||
},
|
||||
{
|
||||
"slot": 10,
|
||||
"name": "resource_ctrl",
|
||||
"timed_interface": "u_resource_ctrl_apb4_if",
|
||||
"pure_interface": "u_resource_ctrl_apb4_pure_if",
|
||||
"region": "APB4_RESOURCE_CTRL"
|
||||
}
|
||||
],
|
||||
"gpio_alt_functions": [
|
||||
|
||||
@@ -119,6 +119,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/spisd_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/spisd.c \
|
||||
$(ROOT_PATH)/crt/src/hal/xpi.c \
|
||||
$(ROOT_PATH)/crt/src/hal/resource.c \
|
||||
$(ROOT_PATH)/crt/src/hal/extension.c \
|
||||
$(ROOT_PATH)/crt/src/hal/user_ip.c \
|
||||
$(ROOT_PATH)/crt/src/hal/user_core.c
|
||||
|
||||
+24
-15
@@ -23,6 +23,8 @@ module apb4_periph (
|
||||
input logic debug_halted_i,
|
||||
input logic timebase_tick_i,
|
||||
input logic ext_h_hp_irq_i,
|
||||
input logic [4:0] resource_irq_lp_i,
|
||||
input logic [4:0] resource_irq_hp_i,
|
||||
axi4_if.slave cfg_axi4,
|
||||
axi4_if.slave psram_axi4,
|
||||
axi4_if.slave xpi_axi4,
|
||||
@@ -62,6 +64,7 @@ module apb4_periph (
|
||||
output logic hp_software_irq_o,
|
||||
output logic hp_machine_external_irq_o,
|
||||
output logic hp_supervisor_external_irq_o,
|
||||
output logic [4:0] resource_irq_raw_o,
|
||||
output logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
@@ -184,23 +187,24 @@ axi4_stream_if #(
|
||||
`include "apb4_periph_connections.svh"
|
||||
);
|
||||
|
||||
assign u_dma_req_if.i2s_tx_proc = ~s_dma_i2s_tx_stall;
|
||||
assign u_dma_req_if.i2s_rx_proc = ~s_dma_i2s_rx_stall;
|
||||
assign u_dma_req_if.qspi_tx_proc = ~s_dma_xpi_tx_stall;
|
||||
assign u_dma_req_if.qspi_rx_proc = ~s_dma_xpi_rx_stall;
|
||||
assign u_dma_req_if.uart_tx_proc = ~s_dma_uart_tx_stall;
|
||||
assign u_dma_req_if.uart_rx_proc = ~s_dma_uart_rx_stall;
|
||||
assign u_dma_req_if.i2c0_tx_proc = ~s_dma_i2c0_tx_stall;
|
||||
assign u_dma_req_if.i2c0_rx_proc = ~s_dma_i2c0_rx_stall;
|
||||
assign u_dma_req_if.i2c1_tx_proc = ~s_dma_i2c1_tx_stall;
|
||||
assign u_dma_req_if.i2c1_rx_proc = ~s_dma_i2c1_rx_stall;
|
||||
assign u_dma_req_if.crypto_in_proc = s_dma_crypto_in_proc;
|
||||
assign u_dma_req_if.i2s_tx_proc = ~s_dma_i2s_tx_stall;
|
||||
assign u_dma_req_if.i2s_rx_proc = ~s_dma_i2s_rx_stall;
|
||||
assign u_dma_req_if.qspi_tx_proc = ~s_dma_xpi_tx_stall;
|
||||
assign u_dma_req_if.qspi_rx_proc = ~s_dma_xpi_rx_stall;
|
||||
assign u_dma_req_if.uart_tx_proc = ~s_dma_uart_tx_stall;
|
||||
assign u_dma_req_if.uart_rx_proc = ~s_dma_uart_rx_stall;
|
||||
assign u_dma_req_if.i2c0_tx_proc = ~s_dma_i2c0_tx_stall;
|
||||
assign u_dma_req_if.i2c0_rx_proc = ~s_dma_i2c0_rx_stall;
|
||||
assign u_dma_req_if.i2c1_tx_proc = ~s_dma_i2c1_tx_stall;
|
||||
assign u_dma_req_if.i2c1_rx_proc = ~s_dma_i2c1_rx_stall;
|
||||
assign u_dma_req_if.crypto_in_proc = s_dma_crypto_in_proc;
|
||||
assign u_dma_req_if.crypto_out_proc = s_dma_crypto_out_proc;
|
||||
assign hp_time_o = u_hp_clint_if.mtime_o;
|
||||
assign hp_timer_irq_o = u_hp_clint_if.timer_irq_o[1];
|
||||
assign hp_software_irq_o = u_hp_clint_if.software_irq_o[1];
|
||||
assign hp_machine_external_irq_o = s_hp_plic_context_irq[0];
|
||||
assign hp_time_o = u_hp_clint_if.mtime_o;
|
||||
assign hp_timer_irq_o = u_hp_clint_if.timer_irq_o[1];
|
||||
assign hp_software_irq_o = u_hp_clint_if.software_irq_o[1];
|
||||
assign hp_machine_external_irq_o = s_hp_plic_context_irq[0];
|
||||
assign hp_supervisor_external_irq_o = s_hp_plic_context_irq[1];
|
||||
assign resource_irq_raw_o = {spisd.irq_o, sdio1.irq_o, sdio0.irq_o, s_usb2_irq, s_dma_irq};
|
||||
|
||||
apb4_async_bridge u_psram_cfg_mem_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
@@ -274,6 +278,11 @@ axi4_stream_if #(
|
||||
s_hp_plic_source[1] = uart1.irq_o;
|
||||
s_hp_plic_source[2] = s_mailbox_hp_irq;
|
||||
s_hp_plic_source[3] = ext_h_hp_irq_i;
|
||||
s_hp_plic_source[4] = resource_irq_hp_i[0];
|
||||
s_hp_plic_source[5] = resource_irq_hp_i[1];
|
||||
s_hp_plic_source[6] = resource_irq_hp_i[2];
|
||||
s_hp_plic_source[7] = resource_irq_hp_i[3];
|
||||
s_hp_plic_source[8] = resource_irq_hp_i[4];
|
||||
end
|
||||
|
||||
`include "apb4_periph_irq_bindings.svh"
|
||||
|
||||
+60
-15
@@ -23,6 +23,10 @@ module apb4_system (
|
||||
input logic rst_aud_n_i,
|
||||
input logic debug_halted_i,
|
||||
input logic ext_h_data_idle_i,
|
||||
input logic [5:0] resource_idle_i,
|
||||
input logic [5:0] resource_block_ack_i,
|
||||
input logic [4:0] resource_irq_i,
|
||||
input logic cache_request_i,
|
||||
axi4_if.slave axi4,
|
||||
axi4_if.master ext_h_axi4,
|
||||
pwm_if.dut pwm,
|
||||
@@ -39,6 +43,12 @@ module apb4_system (
|
||||
output logic [31:0] ext_h_timeout_o,
|
||||
output logic ext_h_irq_raw_o,
|
||||
output logic [1:0] ext_h_owner_o,
|
||||
output logic cache_clean_o,
|
||||
output logic [5:0][1:0] resource_owner_o,
|
||||
output logic [5:0] resource_quiesce_o,
|
||||
output logic [5:0] resource_reset_o,
|
||||
output logic [4:0] resource_irq_lp_o,
|
||||
output logic [4:0] resource_irq_hp_o,
|
||||
output logic [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
@@ -75,24 +85,40 @@ module apb4_system (
|
||||
{31'd0, ARCHINFO_HAVE_PLL} |
|
||||
({31'd0, ARCHINFO_HAVE_SRAM_IF} << 1) | ({31'd0, ARCHINFO_HAVE_SRAM_MACRO} << 2);
|
||||
|
||||
logic s_rng_entropy_en;
|
||||
logic s_rng_entropy_ready;
|
||||
logic s_rng_entropy_valid;
|
||||
logic [31:0] s_rng_entropy_data;
|
||||
logic s_rng_entropy_qualified;
|
||||
logic s_rng_entropy_fault;
|
||||
logic s_rng_irq;
|
||||
logic s_ext_l_irq;
|
||||
logic s_ext_h_irq;
|
||||
logic s_ext_h_irq_raw;
|
||||
logic [ 1:0] s_ext_h_owner;
|
||||
logic s_rng_entropy_en;
|
||||
logic s_rng_entropy_ready;
|
||||
logic s_rng_entropy_valid;
|
||||
logic [31:0] s_rng_entropy_data;
|
||||
logic s_rng_entropy_qualified;
|
||||
logic s_rng_entropy_fault;
|
||||
logic s_rng_irq;
|
||||
logic s_ext_l_irq;
|
||||
logic s_ext_h_irq;
|
||||
logic s_ext_h_irq_raw;
|
||||
logic [ 1:0] unused_ext_h_owner;
|
||||
logic [ 5:0] s_resource_irq;
|
||||
logic [ 5:0] s_resource_irq_lp;
|
||||
logic [ 5:0] s_resource_irq_hp;
|
||||
logic [ 5:0][1:0] s_resource_owner;
|
||||
logic [ 5:0] s_resource_quiesce;
|
||||
logic [ 5:0] s_resource_reset;
|
||||
logic s_resource_fault_irq;
|
||||
logic s_cache_clean;
|
||||
logic s_unused_resource;
|
||||
`ifdef MINI_PRODUCT
|
||||
logic s_unused_product_input;
|
||||
`endif
|
||||
|
||||
assign s_ext_h_irq = (s_ext_h_owner == 2'd0) ? s_ext_h_irq_raw : 1'b0;
|
||||
assign ext_h_irq_raw_o = s_ext_h_irq_raw;
|
||||
assign ext_h_owner_o = s_ext_h_owner;
|
||||
assign s_resource_irq = {s_ext_h_irq_raw, resource_irq_i};
|
||||
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];
|
||||
assign cache_clean_o = s_cache_clean;
|
||||
assign resource_owner_o = s_resource_owner;
|
||||
assign resource_quiesce_o = s_resource_quiesce;
|
||||
assign resource_reset_o = s_resource_reset;
|
||||
assign resource_irq_lp_o = s_resource_irq_lp[4:0];
|
||||
assign resource_irq_hp_o = s_resource_irq_hp[4:0];
|
||||
|
||||
`ifdef PDK_IHP130
|
||||
localparam logic [31:0] ARCHINFO_TECHNOLOGY = 32'h0201_0082;
|
||||
@@ -203,6 +229,23 @@ module apb4_system (
|
||||
|
||||
apb4_crc u_apb4_crc (.apb4(u_crc_apb4_if));
|
||||
|
||||
resource_controller u_resource_controller (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.idle_i (resource_idle_i),
|
||||
.block_ack_i (resource_block_ack_i),
|
||||
.irq_i (s_resource_irq),
|
||||
.cache_request_i(cache_request_i),
|
||||
.cache_clean_o (s_cache_clean),
|
||||
.owner_o (s_resource_owner),
|
||||
.quiesce_o (s_resource_quiesce),
|
||||
.reset_o (s_resource_reset),
|
||||
.irq_lp_o (s_resource_irq_lp),
|
||||
.irq_hp_o (s_resource_irq_hp),
|
||||
.fault_irq_o (s_resource_fault_irq),
|
||||
.apb4 (u_resource_ctrl_apb4_if)
|
||||
);
|
||||
|
||||
// Generated IRQ ownership and core-vector bit assignments are topology checked.
|
||||
`include "apb4_system_irq_bindings.svh"
|
||||
|
||||
@@ -243,7 +286,7 @@ axi42apb4_system u_axi42apb4_system (
|
||||
.ext_l_irq_o (s_ext_l_irq),
|
||||
.ext_h_irq_o (s_ext_h_irq_raw),
|
||||
.ext_h_block_o (ext_h_block_o),
|
||||
.ext_h_owner_o (s_ext_h_owner),
|
||||
.ext_h_owner_o (unused_ext_h_owner),
|
||||
.ext_h_read_base_o (ext_h_read_base_o),
|
||||
.ext_h_read_limit_o (ext_h_read_limit_o),
|
||||
.ext_h_write_base_o (ext_h_write_base_o),
|
||||
@@ -251,4 +294,6 @@ axi42apb4_system u_axi42apb4_system (
|
||||
.ext_h_timeout_o (ext_h_timeout_o)
|
||||
);
|
||||
|
||||
assign s_unused_resource = ^unused_ext_h_owner;
|
||||
|
||||
endmodule
|
||||
@@ -12,6 +12,7 @@ module axi4_data_crossbar #(
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic block_new_i,
|
||||
input logic [NumMasters-1:0] master_block_i,
|
||||
input logic recovery_i,
|
||||
input logic [1:0] mem_pad_mode_i,
|
||||
input logic [31:0] ext_h_read_base_i,
|
||||
@@ -21,6 +22,7 @@ module axi4_data_crossbar #(
|
||||
axi4_if.slave masters [NumMasters],
|
||||
axi4_if.master targets [NumTargets],
|
||||
output logic idle_o,
|
||||
output logic [NumMasters-1:0] master_idle_o,
|
||||
output logic [7:0] outstanding_read_o,
|
||||
output logic [7:0] outstanding_write_o,
|
||||
output logic fault_valid_o,
|
||||
@@ -85,11 +87,11 @@ module axi4_data_crossbar #(
|
||||
logic user;
|
||||
} read_resp_t;
|
||||
|
||||
addr_channel_t m_aw [NumMasters];
|
||||
addr_channel_t m_ar [NumMasters];
|
||||
write_channel_t m_w [NumMasters];
|
||||
write_resp_t m_b [NumMasters];
|
||||
read_resp_t m_r [NumMasters];
|
||||
addr_channel_t m_aw [NumMasters];
|
||||
addr_channel_t m_ar [NumMasters];
|
||||
write_channel_t m_w [NumMasters];
|
||||
write_resp_t m_b [NumMasters];
|
||||
read_resp_t m_r [NumMasters];
|
||||
logic [NumMasters-1:0] m_awvalid;
|
||||
logic [NumMasters-1:0] m_awready;
|
||||
logic [NumMasters-1:0] m_wvalid;
|
||||
@@ -101,11 +103,11 @@ module axi4_data_crossbar #(
|
||||
logic [NumMasters-1:0] m_rvalid;
|
||||
logic [NumMasters-1:0] m_rready;
|
||||
|
||||
addr_channel_t t_aw [NumTargets];
|
||||
addr_channel_t t_ar [NumTargets];
|
||||
write_channel_t t_w [NumTargets];
|
||||
write_resp_t t_b [NumTargets];
|
||||
read_resp_t t_r [NumTargets];
|
||||
addr_channel_t t_aw [NumTargets];
|
||||
addr_channel_t t_ar [NumTargets];
|
||||
write_channel_t t_w [NumTargets];
|
||||
write_resp_t t_b [NumTargets];
|
||||
read_resp_t t_r [NumTargets];
|
||||
logic [NumTargets-1:0] t_awvalid;
|
||||
logic [NumTargets-1:0] t_awready;
|
||||
logic [NumTargets-1:0] t_wvalid;
|
||||
@@ -141,20 +143,24 @@ module axi4_data_crossbar #(
|
||||
logic [NumMasters-1:0] s_read_terminal;
|
||||
logic [NumMasters-1:0] s_write_terminal;
|
||||
|
||||
logic [NumTargets-1:0] s_read_owner_valid_d, s_read_owner_valid_q;
|
||||
logic [NumTargets-1:0] s_write_owner_valid_d, s_write_owner_valid_q;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_read_owner_d, s_read_owner_q;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_write_owner_d, s_write_owner_q;
|
||||
logic [NumTargets-1:0] s_target_write_owner_full;
|
||||
logic [NumTargets-1:0] s_target_write_owner_empty;
|
||||
logic [NumTargets-1:0] s_target_write_owner_push;
|
||||
logic [NumTargets-1:0] s_target_write_owner_pop;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data;
|
||||
logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count;
|
||||
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
|
||||
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
|
||||
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
|
||||
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
|
||||
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
|
||||
|
||||
logic [NumMasters-1:0][CountWidth-1:0] s_master_read_count_d, s_master_read_count_q;
|
||||
logic [NumMasters-1:0][CountWidth-1:0] s_master_write_count_d, s_master_write_count_q;
|
||||
logic [NumTargets-1:0][CountWidth-1:0] s_target_read_count_d, s_target_read_count_q;
|
||||
logic [NumTargets-1:0][CountWidth-1:0] s_target_write_count_d, s_target_write_count_q;
|
||||
logic [NumMasters-1:0][SourceIds-1:0] s_read_id_busy_d, s_read_id_busy_q;
|
||||
logic [NumMasters-1:0][SourceIds-1:0] s_write_id_busy_d, s_write_id_busy_q;
|
||||
logic [NumTargets-1:0][NumMasters-1:0][AgeWidth-1:0] s_read_age_d, s_read_age_q;
|
||||
@@ -262,6 +268,17 @@ module axi4_data_crossbar #(
|
||||
return '0;
|
||||
endfunction
|
||||
|
||||
function automatic logic [CountWidth-1:0] target_read_limit(input logic [TargetWidth-1:0] target);
|
||||
if ((target == TargetSram) || (target == TargetSdram)) return CountWidth'(4);
|
||||
return CountWidth'(1);
|
||||
endfunction
|
||||
|
||||
function automatic logic [CountWidth-1:0] target_write_limit(
|
||||
input logic [TargetWidth-1:0] target);
|
||||
if ((target == TargetSram) || (target == TargetSdram)) return CountWidth'(2);
|
||||
return CountWidth'(1);
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] master_priority(input int unsigned master,
|
||||
input logic [3:0] request_qos, input logic aged,
|
||||
input logic recovery);
|
||||
@@ -418,6 +435,22 @@ module axi4_data_crossbar #(
|
||||
.selected_o(s_write_selected[target]),
|
||||
.valid_o (s_write_grant_valid[target])
|
||||
);
|
||||
|
||||
fifo #(
|
||||
.DATA_WIDTH (MasterWidth),
|
||||
.BUFFER_DEPTH(RouteDepth)
|
||||
) u_write_owner_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(1'b0),
|
||||
.push_i (s_target_write_owner_push[target]),
|
||||
.full_o (s_target_write_owner_full[target]),
|
||||
.dat_i (s_write_selected[target]),
|
||||
.pop_i (s_target_write_owner_pop[target]),
|
||||
.empty_o(s_target_write_owner_empty[target]),
|
||||
.dat_o (s_target_write_owner_data[target]),
|
||||
.cnt_o (unused_target_write_owner_count[target])
|
||||
);
|
||||
end
|
||||
|
||||
|
||||
@@ -477,20 +510,23 @@ 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 && m_arvalid[master] &&
|
||||
!s_read_owner_valid_q[s_read_routed_target[master]] &&
|
||||
(s_master_read_count_q[master] <
|
||||
((s_read_fault_reason[master] != 4'd0) ? CountWidth'(1) :
|
||||
master_read_limit(
|
||||
if (!block_new_i && !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]
|
||||
)) && (s_master_read_count_q[master] <
|
||||
((s_read_fault_reason[master] != 4'd0) ? CountWidth'(1) : master_read_limit(
|
||||
master
|
||||
))) && !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 && m_awvalid[master] &&
|
||||
!s_write_owner_valid_q[s_write_routed_target[master]] &&
|
||||
(s_master_write_count_q[master] <
|
||||
((s_write_fault_reason[master] != 4'd0) ? CountWidth'(1) :
|
||||
master_write_limit(
|
||||
if (!block_new_i && !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(
|
||||
s_write_routed_target[master]
|
||||
)) && (s_master_write_count_q[master] <
|
||||
((s_write_fault_reason[master] != 4'd0) ? CountWidth'(1) : master_write_limit(
|
||||
master
|
||||
))) && (s_route_count_q[master] < 2'(RouteDepth)) &&
|
||||
!s_write_id_busy_q[master][m_aw[master].id[2:0]]) begin
|
||||
@@ -575,20 +611,22 @@ module axi4_data_crossbar #(
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
m_awready = '0;
|
||||
t_aw = '{default: '0};
|
||||
t_awvalid = '0;
|
||||
s_write_capture = '0;
|
||||
s_write_accept = '0;
|
||||
s_write_accept_target = '0;
|
||||
s_write_accept_id = '0;
|
||||
m_awready = '0;
|
||||
t_aw = '{default: '0};
|
||||
t_awvalid = '0;
|
||||
s_write_capture = '0;
|
||||
s_target_write_owner_push = '0;
|
||||
s_write_accept = '0;
|
||||
s_write_accept_target = '0;
|
||||
s_write_accept_id = '0;
|
||||
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];
|
||||
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);
|
||||
@@ -599,21 +637,21 @@ module axi4_data_crossbar #(
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
m_wready = '0;
|
||||
t_w = '{default: '0};
|
||||
t_wvalid = '0;
|
||||
s_write_data_terminal = '0;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
if (s_route_count_q[master] != 2'd0) begin
|
||||
automatic
|
||||
logic [TargetWidth-1:0]
|
||||
target = s_write_route_q[master][s_route_read_ptr_q[master]];
|
||||
if (s_write_owner_valid_q[target] &&
|
||||
(s_write_owner_q[target] == MasterWidth'(master))) begin
|
||||
t_w[target] = m_w[master];
|
||||
t_wvalid[target] = m_wvalid[master];
|
||||
m_wready[master] = t_wready[target];
|
||||
m_wready = '0;
|
||||
t_w = '{default: '0};
|
||||
t_wvalid = '0;
|
||||
s_write_data_terminal = '0;
|
||||
s_target_write_owner_pop = '0;
|
||||
for (int target = 0; target < NumTargets; target++) begin
|
||||
if (!s_target_write_owner_empty[target]) begin
|
||||
automatic logic [MasterWidth-1:0] master = s_target_write_owner_data[target];
|
||||
if ((s_route_count_q[master] != 2'd0) &&
|
||||
(s_write_route_q[master][s_route_read_ptr_q[master]] == TargetWidth'(target))) begin
|
||||
t_w[target] = m_w[master];
|
||||
t_wvalid[target] = m_wvalid[master];
|
||||
m_wready[master] = t_wready[target];
|
||||
s_write_data_terminal[master] = t_wvalid[target] && t_wready[target] && t_w[target].last;
|
||||
s_target_write_owner_pop[target] = s_write_data_terminal[master];
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -623,11 +661,11 @@ module axi4_data_crossbar #(
|
||||
s_read_resp_req = '0;
|
||||
s_write_resp_req = '0;
|
||||
for (int target = 0; target < NumTargets; target++) begin
|
||||
if (s_read_owner_valid_q[target] && t_rvalid[target]) begin
|
||||
s_read_resp_req[s_read_owner_q[target]][target] = 1'b1;
|
||||
if (t_rvalid[target]) begin
|
||||
s_read_resp_req[t_r[target].id[5:3]][target] = 1'b1;
|
||||
end
|
||||
if (s_write_owner_valid_q[target] && t_bvalid[target]) begin
|
||||
s_write_resp_req[s_write_owner_q[target]][target] = 1'b1;
|
||||
if (t_bvalid[target]) begin
|
||||
s_write_resp_req[t_b[target].id[5:3]][target] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -664,35 +702,35 @@ module axi4_data_crossbar #(
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_read_owner_valid_d = s_read_owner_valid_q;
|
||||
s_write_owner_valid_d = s_write_owner_valid_q;
|
||||
s_read_owner_d = s_read_owner_q;
|
||||
s_write_owner_d = s_write_owner_q;
|
||||
s_master_read_count_d = s_master_read_count_q;
|
||||
s_master_write_count_d = s_master_write_count_q;
|
||||
s_target_read_count_d = s_target_read_count_q;
|
||||
s_target_write_count_d = s_target_write_count_q;
|
||||
s_read_id_busy_d = s_read_id_busy_q;
|
||||
s_write_id_busy_d = s_write_id_busy_q;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
if (s_read_terminal[master]) begin
|
||||
s_read_owner_valid_d[s_read_resp_selected[master]] = 1'b0;
|
||||
s_master_read_count_d[master] = s_master_read_count_d[master] - 1'b1;
|
||||
s_master_read_count_d[master] = s_master_read_count_d[master] - 1'b1;
|
||||
s_target_read_count_d[s_read_resp_selected[master]] =
|
||||
s_target_read_count_d[s_read_resp_selected[master]] - 1'b1;
|
||||
s_read_id_busy_d[master][s_read_complete_id[master]] = 1'b0;
|
||||
end
|
||||
if (s_write_terminal[master]) begin
|
||||
s_write_owner_valid_d[s_write_resp_selected[master]] = 1'b0;
|
||||
s_master_write_count_d[master] = s_master_write_count_d[master] - 1'b1;
|
||||
s_target_write_count_d[s_write_resp_selected[master]] =
|
||||
s_target_write_count_d[s_write_resp_selected[master]] - 1'b1;
|
||||
s_write_id_busy_d[master][s_write_complete_id[master]] = 1'b0;
|
||||
end
|
||||
if (s_read_accept[master]) begin
|
||||
s_read_owner_valid_d[s_read_accept_target[master]] = 1'b1;
|
||||
s_read_owner_d[s_read_accept_target[master]] = MasterWidth'(master);
|
||||
s_master_read_count_d[master] = s_master_read_count_d[master] + 1'b1;
|
||||
s_master_read_count_d[master] = s_master_read_count_d[master] + 1'b1;
|
||||
s_target_read_count_d[s_read_accept_target[master]] =
|
||||
s_target_read_count_d[s_read_accept_target[master]] + 1'b1;
|
||||
s_read_id_busy_d[master][s_read_accept_id[master]] = 1'b1;
|
||||
end
|
||||
if (s_write_accept[master]) begin
|
||||
s_write_owner_valid_d[s_write_accept_target[master]] = 1'b1;
|
||||
s_write_owner_d[s_write_accept_target[master]] = MasterWidth'(master);
|
||||
s_master_write_count_d[master] = s_master_write_count_d[master] + 1'b1;
|
||||
s_target_write_count_d[s_write_accept_target[master]] =
|
||||
s_target_write_count_d[s_write_accept_target[master]] + 1'b1;
|
||||
s_write_id_busy_d[master][s_write_accept_id[master]] = 1'b1;
|
||||
end
|
||||
end
|
||||
@@ -780,15 +818,18 @@ module axi4_data_crossbar #(
|
||||
|
||||
assign idle_o = (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) &&
|
||||
!m_arvalid[master] && !m_awvalid[master] && !m_wvalid[master];
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_read_owner_valid_q <= '0;
|
||||
s_write_owner_valid_q <= '0;
|
||||
s_read_owner_q <= '0;
|
||||
s_write_owner_q <= '0;
|
||||
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;
|
||||
@@ -804,12 +845,10 @@ module axi4_data_crossbar #(
|
||||
fault_write_o <= 1'b0;
|
||||
fault_reason_o <= '0;
|
||||
end else begin
|
||||
s_read_owner_valid_q <= s_read_owner_valid_d;
|
||||
s_write_owner_valid_q <= s_write_owner_valid_d;
|
||||
s_read_owner_q <= s_read_owner_d;
|
||||
s_write_owner_q <= s_write_owner_d;
|
||||
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;
|
||||
|
||||
@@ -9,6 +9,7 @@ module axi4_downsizer_64to32 #(
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic clear_i,
|
||||
axi4_if.slave wide,
|
||||
axi4_if.master narrow
|
||||
);
|
||||
@@ -19,6 +20,8 @@ module axi4_downsizer_64to32 #(
|
||||
|
||||
channel_state_e s_read_state_d, s_read_state_q;
|
||||
channel_state_e s_write_state_d, s_write_state_q;
|
||||
logic s_read_state_bits_q;
|
||||
logic s_write_state_bits_q;
|
||||
logic [WideIdWidth-1:0] s_read_id_d, s_read_id_q;
|
||||
logic [WideIdWidth-1:0] s_write_id_d, s_write_id_q;
|
||||
logic [2:0] s_read_size_d, s_read_size_q;
|
||||
@@ -46,6 +49,8 @@ module axi4_downsizer_64to32 #(
|
||||
logic [8:0] s_read_beats;
|
||||
logic [8:0] s_write_beats;
|
||||
|
||||
assign s_read_state_q = channel_state_e'(s_read_state_bits_q);
|
||||
assign s_write_state_q = channel_state_e'(s_write_state_bits_q);
|
||||
assign s_read_beats = {1'b0, wide.arlen} + 9'd1;
|
||||
assign s_write_beats = {1'b0, wide.awlen} + 9'd1;
|
||||
|
||||
@@ -115,6 +120,12 @@ module axi4_downsizer_64to32 #(
|
||||
s_read_addr_d = s_read_next_addr;
|
||||
if (narrow.rlast) s_read_state_d = Idle;
|
||||
end
|
||||
|
||||
if (clear_i) begin
|
||||
s_read_state_d = Idle;
|
||||
s_read_upper_d = 1'b0;
|
||||
s_read_resp_d = `AXI4_RESP_OKAY;
|
||||
end
|
||||
end
|
||||
|
||||
assign wide.awready = (s_write_state_q == Idle) && narrow.awready;
|
||||
@@ -188,6 +199,13 @@ module axi4_downsizer_64to32 #(
|
||||
s_b_pending_d = 1'b0;
|
||||
s_write_state_d = Idle;
|
||||
end
|
||||
|
||||
if (clear_i) begin
|
||||
s_write_state_d = Idle;
|
||||
s_write_upper_d = 1'b0;
|
||||
s_b_pending_d = 1'b0;
|
||||
s_b_resp_d = `AXI4_RESP_OKAY;
|
||||
end
|
||||
end
|
||||
|
||||
axi4_addr_gen #(
|
||||
@@ -215,7 +233,7 @@ module axi4_downsizer_64to32 #(
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_read_state_d),
|
||||
.dat_o (s_read_state_q)
|
||||
.dat_o (s_read_state_bits_q)
|
||||
);
|
||||
|
||||
dffr #(
|
||||
@@ -224,7 +242,7 @@ module axi4_downsizer_64to32 #(
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_write_state_d),
|
||||
.dat_o (s_write_state_q)
|
||||
.dat_o (s_write_state_bits_q)
|
||||
);
|
||||
|
||||
dffr #(
|
||||
|
||||
@@ -463,6 +463,8 @@ module axi4_interconnect #(
|
||||
`SOC_ADDR_IS_APB4_EXT_L(addr)
|
||||
&& !
|
||||
`SOC_ADDR_IS_APB4_EXT_H(addr)
|
||||
&& !
|
||||
`SOC_ADDR_IS_APB4_RESOURCE_CTRL(addr)
|
||||
);
|
||||
`else
|
||||
s_access_allowed[master] = (master != 1) || ((read_req &&
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
`include "axi4_define.svh"
|
||||
|
||||
module axi4_target_guard #(
|
||||
parameter int unsigned AddrWidth = 32,
|
||||
parameter int unsigned DataWidth = 64,
|
||||
parameter int unsigned IdWidth = 6,
|
||||
parameter int unsigned UserWidth = 1,
|
||||
parameter int unsigned ReadDepth = 4,
|
||||
parameter int unsigned WriteDepth = 2
|
||||
) (
|
||||
// verilog_format: off -- preserve the timeout/isolation boundary columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic clear_i,
|
||||
input logic [31:0] timeout_i,
|
||||
output logic clear_busy_o,
|
||||
output logic abort_o,
|
||||
input logic abort_done_i,
|
||||
output logic timeout_valid_o,
|
||||
output logic timeout_write_o,
|
||||
output logic [IdWidth-1:0] timeout_id_o,
|
||||
output logic [AddrWidth-1:0] timeout_addr_o,
|
||||
axi4_if.slave source,
|
||||
axi4_if.master sink
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam int unsigned StrbWidth = DataWidth / 8;
|
||||
localparam int unsigned AddrChannelWidth =
|
||||
IdWidth + AddrWidth + 8 + 3 + 2 + 1 + 4 + 3 + 4 + 4 + UserWidth;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
ReadIdle,
|
||||
ReadSend,
|
||||
ReadForward,
|
||||
ReadAbort,
|
||||
ReadSynthetic
|
||||
} read_state_e;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
WriteIdle,
|
||||
WriteSend,
|
||||
WriteStream,
|
||||
WriteResponse,
|
||||
WriteAbort,
|
||||
WriteDrop,
|
||||
WriteSynthetic
|
||||
} write_state_e;
|
||||
|
||||
logic [AddrChannelWidth-1:0] s_ar_push_data;
|
||||
logic [AddrChannelWidth-1:0] s_ar_head_data;
|
||||
logic [AddrChannelWidth-1:0] s_aw_push_data;
|
||||
logic [AddrChannelWidth-1:0] s_aw_head_data;
|
||||
logic s_ar_full;
|
||||
logic s_ar_empty;
|
||||
logic s_ar_push;
|
||||
logic s_ar_pop;
|
||||
logic s_aw_full;
|
||||
logic s_aw_empty;
|
||||
logic s_aw_push;
|
||||
logic s_aw_pop;
|
||||
logic [ $clog2(ReadDepth):0] unused_ar_count;
|
||||
logic [$clog2(WriteDepth):0] unused_aw_count;
|
||||
|
||||
logic [ IdWidth-1:0] s_ar_id;
|
||||
logic [ AddrWidth-1:0] s_ar_addr;
|
||||
logic [ 7:0] s_ar_len;
|
||||
logic [ 2:0] s_ar_size;
|
||||
logic [ 1:0] s_ar_burst;
|
||||
logic s_ar_lock;
|
||||
logic [ 3:0] s_ar_cache;
|
||||
logic [ 2:0] s_ar_prot;
|
||||
logic [ 3:0] s_ar_qos;
|
||||
logic [ 3:0] s_ar_region;
|
||||
logic [ UserWidth-1:0] s_ar_user;
|
||||
|
||||
logic [ IdWidth-1:0] s_aw_id;
|
||||
logic [ AddrWidth-1:0] s_aw_addr;
|
||||
logic [ 7:0] s_aw_len;
|
||||
logic [ 2:0] s_aw_size;
|
||||
logic [ 1:0] s_aw_burst;
|
||||
logic s_aw_lock;
|
||||
logic [ 3:0] s_aw_cache;
|
||||
logic [ 2:0] s_aw_prot;
|
||||
logic [ 3:0] s_aw_qos;
|
||||
logic [ 3:0] s_aw_region;
|
||||
logic [ UserWidth-1:0] s_aw_user;
|
||||
|
||||
read_state_e s_read_state_d, s_read_state_q;
|
||||
write_state_e s_write_state_d, s_write_state_q;
|
||||
logic [IdWidth-1:0] s_read_id_d, s_read_id_q;
|
||||
logic [AddrWidth-1:0] s_read_addr_d, s_read_addr_q;
|
||||
logic [8:0] s_read_remaining_d, s_read_remaining_q;
|
||||
logic [31:0] s_read_timeout_d, s_read_timeout_q;
|
||||
logic [IdWidth-1:0] s_write_id_d, s_write_id_q;
|
||||
logic [AddrWidth-1:0] s_write_addr_d, s_write_addr_q;
|
||||
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;
|
||||
|
||||
assign s_ar_push_data = {
|
||||
source.arid,
|
||||
source.araddr,
|
||||
source.arlen,
|
||||
source.arsize,
|
||||
source.arburst,
|
||||
source.arlock,
|
||||
source.arcache,
|
||||
source.arprot,
|
||||
source.arqos,
|
||||
source.arregion,
|
||||
source.aruser
|
||||
};
|
||||
assign {
|
||||
s_ar_id,
|
||||
s_ar_addr,
|
||||
s_ar_len,
|
||||
s_ar_size,
|
||||
s_ar_burst,
|
||||
s_ar_lock,
|
||||
s_ar_cache,
|
||||
s_ar_prot,
|
||||
s_ar_qos,
|
||||
s_ar_region,
|
||||
s_ar_user
|
||||
} = s_ar_head_data;
|
||||
assign s_aw_push_data = {
|
||||
source.awid,
|
||||
source.awaddr,
|
||||
source.awlen,
|
||||
source.awsize,
|
||||
source.awburst,
|
||||
source.awlock,
|
||||
source.awcache,
|
||||
source.awprot,
|
||||
source.awqos,
|
||||
source.awregion,
|
||||
source.awuser
|
||||
};
|
||||
assign {
|
||||
s_aw_id,
|
||||
s_aw_addr,
|
||||
s_aw_len,
|
||||
s_aw_size,
|
||||
s_aw_burst,
|
||||
s_aw_lock,
|
||||
s_aw_cache,
|
||||
s_aw_prot,
|
||||
s_aw_qos,
|
||||
s_aw_region,
|
||||
s_aw_user
|
||||
} = s_aw_head_data;
|
||||
|
||||
assign source.arready = !s_ar_full && !clear_i;
|
||||
assign source.awready = !s_aw_full && !clear_i;
|
||||
assign s_ar_push = source.arvalid && source.arready;
|
||||
assign s_aw_push = source.awvalid && source.awready;
|
||||
|
||||
fifo #(
|
||||
.DATA_WIDTH (AddrChannelWidth),
|
||||
.BUFFER_DEPTH(ReadDepth)
|
||||
) u_ar_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(clear_i),
|
||||
.push_i (s_ar_push),
|
||||
.full_o (s_ar_full),
|
||||
.dat_i (s_ar_push_data),
|
||||
.pop_i (s_ar_pop),
|
||||
.empty_o(s_ar_empty),
|
||||
.dat_o (s_ar_head_data),
|
||||
.cnt_o (unused_ar_count)
|
||||
);
|
||||
fifo #(
|
||||
.DATA_WIDTH (AddrChannelWidth),
|
||||
.BUFFER_DEPTH(WriteDepth)
|
||||
) u_aw_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(clear_i),
|
||||
.push_i (s_aw_push),
|
||||
.full_o (s_aw_full),
|
||||
.dat_i (s_aw_push_data),
|
||||
.pop_i (s_aw_pop),
|
||||
.empty_o(s_aw_empty),
|
||||
.dat_o (s_aw_head_data),
|
||||
.cnt_o (unused_aw_count)
|
||||
);
|
||||
|
||||
assign sink.arid = s_ar_id;
|
||||
assign sink.araddr = s_ar_addr;
|
||||
assign sink.arlen = s_ar_len;
|
||||
assign sink.arsize = s_ar_size;
|
||||
assign sink.arburst = s_ar_burst;
|
||||
assign sink.arlock = s_ar_lock;
|
||||
assign sink.arcache = s_ar_cache;
|
||||
assign sink.arprot = s_ar_prot;
|
||||
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 s_ar_pop = ((s_read_state_q == ReadSend) &&
|
||||
(sink.arready || s_timeout_read || s_isolated_q)) ||
|
||||
((s_read_state_q == ReadIdle) && s_isolated_q && !s_ar_empty);
|
||||
|
||||
assign source.rid = (s_read_state_q == ReadSynthetic) ? s_read_id_q : sink.rid;
|
||||
assign source.rdata = (s_read_state_q == ReadSynthetic) ? '0 : sink.rdata;
|
||||
assign source.rresp = (s_read_state_q == ReadSynthetic) ? `AXI4_RESP_SLAVE_ERROR : sink.rresp;
|
||||
assign source.rlast = (s_read_state_q == ReadSynthetic) ?
|
||||
(s_read_remaining_q == 9'd1) : sink.rlast;
|
||||
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 :
|
||||
((s_read_state_q == ReadAbort) ||
|
||||
(s_read_state_q == ReadSynthetic));
|
||||
|
||||
assign s_read_progress = (sink.arvalid && sink.arready) ||
|
||||
((s_read_state_q == ReadForward) && sink.rvalid && sink.rready);
|
||||
assign s_read_timeout_enable = (timeout_i != 32'd0) &&
|
||||
(((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);
|
||||
|
||||
always_comb begin
|
||||
s_read_state_d = s_read_state_q;
|
||||
s_read_id_d = s_read_id_q;
|
||||
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
|
||||
s_read_timeout_d = '0;
|
||||
if (!s_ar_empty && s_isolated_q) begin
|
||||
s_read_id_d = s_ar_id;
|
||||
s_read_addr_d = s_ar_addr;
|
||||
s_read_remaining_d = {1'b0, s_ar_len} + 1'b1;
|
||||
s_read_state_d = ReadSynthetic;
|
||||
end else if (!s_ar_empty) begin
|
||||
s_read_state_d = ReadSend;
|
||||
end
|
||||
end else if (s_isolated_q && (s_read_state_q == ReadSend)) begin
|
||||
s_read_id_d = s_ar_id;
|
||||
s_read_addr_d = s_ar_addr;
|
||||
s_read_remaining_d = {1'b0, s_ar_len} + 1'b1;
|
||||
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
|
||||
s_read_timeout_d = '0;
|
||||
if (s_read_state_q == ReadSend) begin
|
||||
s_read_id_d = s_ar_id;
|
||||
s_read_addr_d = s_ar_addr;
|
||||
s_read_remaining_d = {1'b0, s_ar_len} + 1'b1;
|
||||
s_read_state_d = ReadSynthetic;
|
||||
end else begin
|
||||
s_read_id_d = s_read_id_q;
|
||||
s_read_addr_d = s_read_addr_q;
|
||||
s_read_state_d = ReadAbort;
|
||||
end
|
||||
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;
|
||||
unique case (s_read_state_q)
|
||||
ReadSend: begin
|
||||
if (sink.arvalid && sink.arready) begin
|
||||
s_read_id_d = s_ar_id;
|
||||
s_read_addr_d = s_ar_addr;
|
||||
s_read_remaining_d = {1'b0, s_ar_len} + 1'b1;
|
||||
s_read_state_d = ReadForward;
|
||||
end
|
||||
end
|
||||
ReadForward: begin
|
||||
if (sink.rvalid && sink.rready) begin
|
||||
if (s_read_remaining_q != 9'd0) s_read_remaining_d = s_read_remaining_q - 1'b1;
|
||||
if (sink.rlast || (s_read_remaining_q == 9'd1)) s_read_state_d = ReadIdle;
|
||||
end
|
||||
end
|
||||
ReadAbort: if (abort_done_i) s_read_state_d = ReadSynthetic;
|
||||
ReadSynthetic: begin
|
||||
if (source.rvalid && source.rready) begin
|
||||
if (s_read_remaining_q == 9'd1) begin
|
||||
s_read_remaining_d = '0;
|
||||
s_read_state_d = ReadIdle;
|
||||
end else begin
|
||||
s_read_remaining_d = s_read_remaining_q - 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
default: s_read_state_d = ReadIdle;
|
||||
endcase
|
||||
end
|
||||
if (clear_i) s_read_state_d = ReadIdle;
|
||||
end
|
||||
|
||||
assign sink.awid = s_aw_id;
|
||||
assign sink.awaddr = s_aw_addr;
|
||||
assign sink.awlen = s_aw_len;
|
||||
assign sink.awsize = s_aw_size;
|
||||
assign sink.awburst = s_aw_burst;
|
||||
assign sink.awlock = s_aw_lock;
|
||||
assign sink.awcache = s_aw_cache;
|
||||
assign sink.awprot = s_aw_prot;
|
||||
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 s_aw_pop = ((s_write_state_q == WriteSend) &&
|
||||
(sink.awready || s_timeout_write || 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 :
|
||||
(s_write_state_q == WriteDrop);
|
||||
|
||||
assign source.bid = (s_write_state_q == WriteSynthetic) ? s_write_id_q : sink.bid;
|
||||
assign source.bresp = (s_write_state_q == WriteSynthetic) ? `AXI4_RESP_SLAVE_ERROR : sink.bresp;
|
||||
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 :
|
||||
((s_write_state_q == WriteAbort) ||
|
||||
(s_write_state_q == WriteSynthetic));
|
||||
|
||||
assign s_write_progress = (sink.awvalid && sink.awready) ||
|
||||
(sink.wvalid && sink.wready) ||
|
||||
((s_write_state_q == WriteResponse) && sink.bvalid && sink.bready);
|
||||
assign s_write_timeout_enable = (timeout_i != 32'd0) &&
|
||||
(((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);
|
||||
|
||||
always_comb begin
|
||||
s_write_state_d = s_write_state_q;
|
||||
s_write_id_d = s_write_id_q;
|
||||
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
|
||||
s_write_timeout_d = '0;
|
||||
s_write_last_seen_d = 1'b0;
|
||||
if (!s_aw_empty && s_isolated_q) begin
|
||||
s_write_id_d = s_aw_id;
|
||||
s_write_addr_d = s_aw_addr;
|
||||
s_write_state_d = WriteDrop;
|
||||
end else if (!s_aw_empty) begin
|
||||
s_write_state_d = WriteSend;
|
||||
end
|
||||
end else if (s_isolated_q && (s_write_state_q == WriteSend)) begin
|
||||
s_write_id_d = s_aw_id;
|
||||
s_write_addr_d = s_aw_addr;
|
||||
s_write_state_d = WriteDrop;
|
||||
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
|
||||
s_write_timeout_d = '0;
|
||||
if (s_write_state_q == WriteSend) begin
|
||||
s_write_id_d = s_aw_id;
|
||||
s_write_addr_d = s_aw_addr;
|
||||
s_write_state_d = WriteDrop;
|
||||
end else begin
|
||||
s_write_state_d = WriteAbort;
|
||||
end
|
||||
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;
|
||||
unique case (s_write_state_q)
|
||||
WriteSend: begin
|
||||
if (sink.awvalid && sink.awready) begin
|
||||
s_write_id_d = s_aw_id;
|
||||
s_write_addr_d = s_aw_addr;
|
||||
s_write_state_d = WriteStream;
|
||||
end
|
||||
end
|
||||
WriteStream: begin
|
||||
if (sink.wvalid && sink.wready && sink.wlast) begin
|
||||
s_write_last_seen_d = 1'b1;
|
||||
s_write_state_d = WriteResponse;
|
||||
end
|
||||
end
|
||||
WriteResponse: begin
|
||||
if (sink.bvalid && sink.bready) s_write_state_d = WriteIdle;
|
||||
end
|
||||
WriteAbort: begin
|
||||
if (abort_done_i) begin
|
||||
s_write_state_d = s_write_last_seen_q ? WriteSynthetic : WriteDrop;
|
||||
end
|
||||
end
|
||||
WriteDrop: begin
|
||||
if (source.wvalid && source.wready && source.wlast) begin
|
||||
s_write_last_seen_d = 1'b1;
|
||||
s_write_state_d = WriteSynthetic;
|
||||
end
|
||||
end
|
||||
WriteSynthetic: begin
|
||||
if (source.bvalid && source.bready) s_write_state_d = WriteIdle;
|
||||
end
|
||||
default: s_write_state_d = WriteIdle;
|
||||
endcase
|
||||
end
|
||||
if (clear_i) s_write_state_d = WriteIdle;
|
||||
end
|
||||
|
||||
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
|
||||
s_isolated_d = 1'b1;
|
||||
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 timeout_write_o = s_timeout_write;
|
||||
assign timeout_id_o = s_timeout_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 ?
|
||||
((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;
|
||||
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;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
if ((AddrWidth < 1) || (DataWidth < 8) || ((DataWidth % 8) != 0) ||
|
||||
(IdWidth < 1) || (UserWidth < 1) || (ReadDepth < 2) || (WriteDepth < 2) ||
|
||||
((ReadDepth & (ReadDepth - 1)) != 0) ||
|
||||
((WriteDepth & (WriteDepth - 1)) != 0) || (StrbWidth < 1)) begin
|
||||
$fatal(1, "axi4_target_guard: invalid interface or queue geometry");
|
||||
end
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
@@ -16,6 +16,7 @@ module hp_axi4_mux3 (
|
||||
} state_e;
|
||||
|
||||
state_e s_state_d, s_state_q;
|
||||
logic s_state_bits_q;
|
||||
logic [1:0] s_owner_d, s_owner_q;
|
||||
logic s_write_d, s_write_q;
|
||||
logic [1:0] s_selected;
|
||||
@@ -23,6 +24,8 @@ module hp_axi4_mux3 (
|
||||
logic s_addr_accept;
|
||||
logic s_terminal;
|
||||
|
||||
assign s_state_q = state_e'(s_state_bits_q);
|
||||
|
||||
always_comb begin
|
||||
s_selected = 2'd0;
|
||||
s_selected_write = 1'b0;
|
||||
@@ -177,7 +180,7 @@ module hp_axi4_mux3 (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_state_d),
|
||||
.dat_o (s_state_q)
|
||||
.dat_o (s_state_bits_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(2)
|
||||
|
||||
@@ -8,10 +8,12 @@ module hp_lifecycle_controller (
|
||||
input logic release_req_i,
|
||||
input logic hp_idle_i,
|
||||
input logic flush_busy_i,
|
||||
input logic cache_clean_i,
|
||||
input logic [15:0] timeout_i,
|
||||
output logic hp_release_o,
|
||||
output logic block_new_o,
|
||||
output logic flush_o,
|
||||
output logic cache_request_o,
|
||||
output logic draining_o,
|
||||
output logic forced_fault_o
|
||||
// verilog_format: on
|
||||
@@ -19,6 +21,7 @@ module hp_lifecycle_controller (
|
||||
typedef enum logic [2:0] {
|
||||
Held,
|
||||
Running,
|
||||
CacheRequest,
|
||||
Quiesce,
|
||||
FlushRequest,
|
||||
FlushWait
|
||||
@@ -36,8 +39,9 @@ module hp_lifecycle_controller (
|
||||
assign hp_release_o = s_hp_release_q;
|
||||
assign block_new_o = s_block_new_q;
|
||||
assign flush_o = s_flush_q;
|
||||
assign draining_o = (s_state_q == Quiesce) || (s_state_q == FlushRequest) ||
|
||||
(s_state_q == FlushWait);
|
||||
assign cache_request_o = s_state_q == CacheRequest;
|
||||
assign draining_o = (s_state_q == CacheRequest) || (s_state_q == Quiesce) ||
|
||||
(s_state_q == FlushRequest) || (s_state_q == FlushWait);
|
||||
assign forced_fault_o = s_forced_fault_q;
|
||||
|
||||
always_comb begin
|
||||
@@ -65,8 +69,24 @@ module hp_lifecycle_controller (
|
||||
s_flush_d = 1'b0;
|
||||
s_timeout_cnt_d = '0;
|
||||
if (!release_req_i) begin
|
||||
s_block_new_d = 1'b1;
|
||||
s_state_d = Quiesce;
|
||||
s_state_d = CacheRequest;
|
||||
end
|
||||
end
|
||||
CacheRequest: begin
|
||||
s_hp_release_d = 1'b1;
|
||||
s_block_new_d = 1'b0;
|
||||
s_flush_d = 1'b0;
|
||||
if (cache_clean_i) begin
|
||||
s_block_new_d = 1'b1;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = Quiesce;
|
||||
end else if (s_timeout_cnt_q == s_timeout_limit - 1'b1) begin
|
||||
s_forced_fault_d = 1'b1;
|
||||
s_block_new_d = 1'b1;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = Quiesce;
|
||||
end else begin
|
||||
s_timeout_cnt_d = s_timeout_cnt_q + 1'b1;
|
||||
end
|
||||
end
|
||||
Quiesce: begin
|
||||
|
||||
+134
-57
@@ -13,7 +13,9 @@
|
||||
|
||||
module onchip_ram #(
|
||||
parameter bit Present = 1'b1,
|
||||
parameter int unsigned CapacityKiB = 128
|
||||
parameter int unsigned CapacityKiB = 128,
|
||||
parameter int unsigned DataWidth = 32,
|
||||
parameter int unsigned IdWidth = 1
|
||||
) (
|
||||
// verilog_format: off -- preserve the AXI, APB, and performance grouping
|
||||
input logic clk_i,
|
||||
@@ -31,8 +33,10 @@ module onchip_ram #(
|
||||
localparam int unsigned TechnologyBankKiB = 4;
|
||||
localparam int unsigned TechnologyAddrWidth = 10;
|
||||
`endif
|
||||
localparam int unsigned NumBanks = CapacityKiB / TechnologyBankKiB;
|
||||
localparam int unsigned NumBanks = (CapacityKiB + TechnologyBankKiB - 1) / TechnologyBankKiB;
|
||||
localparam int unsigned BankIndexWidth = (NumBanks > 1) ? $clog2(NumBanks) : 1;
|
||||
localparam int unsigned DataBytes = DataWidth / 8;
|
||||
localparam int unsigned BeatSize = $clog2(DataBytes);
|
||||
localparam logic [31:0] MemoryEnd = `SOC_ADDR_SRAM_BASE + 32'(CapacityKiB * 1024) - 1'b1;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
@@ -47,7 +51,7 @@ module onchip_ram #(
|
||||
state_e s_state_d;
|
||||
state_e s_state_q;
|
||||
logic [2:0] s_state_bits_q;
|
||||
logic s_id_d, s_id_q;
|
||||
logic [IdWidth-1:0] s_id_d, s_id_q;
|
||||
logic [7:0] s_len_d, s_len_q;
|
||||
logic [7:0] s_beat_d, s_beat_q;
|
||||
logic [2:0] s_size_d, s_size_q;
|
||||
@@ -69,38 +73,38 @@ module onchip_ram #(
|
||||
logic [31:0] s_perf_stall_cycles_d, s_perf_stall_cycles_q;
|
||||
logic [31:0] s_perf_err_resps_d, s_perf_err_resps_q;
|
||||
|
||||
logic [32:0] s_ar_last_addr;
|
||||
logic [32:0] s_aw_last_addr;
|
||||
logic [31:0] s_ar_next_addr;
|
||||
logic [31:0] s_read_next_addr;
|
||||
logic [31:0] s_write_next_addr;
|
||||
logic s_ar_protocol_legal;
|
||||
logic s_aw_protocol_legal;
|
||||
logic s_ar_bounds_legal;
|
||||
logic s_aw_bounds_legal;
|
||||
logic [ 1:0] s_ar_response;
|
||||
logic [ 1:0] s_aw_response;
|
||||
logic s_ar_accept;
|
||||
logic s_aw_accept;
|
||||
logic s_w_accept;
|
||||
logic s_read_accept;
|
||||
logic s_b_accept;
|
||||
logic s_read_issue;
|
||||
logic s_read_can_issue;
|
||||
logic s_expected_wlast;
|
||||
logic [ 3:0] s_write_lane_mask;
|
||||
logic s_write_strobe_legal;
|
||||
logic s_write_beat_legal;
|
||||
logic s_write_terminal;
|
||||
logic s_err_resp_event;
|
||||
logic s_stall_event;
|
||||
logic [ 32:0] s_ar_last_addr;
|
||||
logic [ 32:0] s_aw_last_addr;
|
||||
logic [ 31:0] s_ar_next_addr;
|
||||
logic [ 31:0] s_read_next_addr;
|
||||
logic [ 31:0] s_write_next_addr;
|
||||
logic s_ar_protocol_legal;
|
||||
logic s_aw_protocol_legal;
|
||||
logic s_ar_bounds_legal;
|
||||
logic s_aw_bounds_legal;
|
||||
logic [ 1:0] s_ar_response;
|
||||
logic [ 1:0] s_aw_response;
|
||||
logic s_ar_accept;
|
||||
logic s_aw_accept;
|
||||
logic s_w_accept;
|
||||
logic s_read_accept;
|
||||
logic s_b_accept;
|
||||
logic s_read_issue;
|
||||
logic s_read_can_issue;
|
||||
logic s_expected_wlast;
|
||||
logic [DataBytes-1:0] s_write_lane_mask;
|
||||
logic s_write_strobe_legal;
|
||||
logic s_write_beat_legal;
|
||||
logic s_write_terminal;
|
||||
logic s_err_resp_event;
|
||||
logic s_stall_event;
|
||||
|
||||
logic s_mem_read;
|
||||
logic s_mem_write;
|
||||
logic [14:0] s_mem_word_addr;
|
||||
logic [31:0] s_mem_wdata;
|
||||
logic [ 3:0] s_mem_wstrb;
|
||||
logic [31:0] s_mem_rdata;
|
||||
logic s_mem_read;
|
||||
logic s_mem_write;
|
||||
logic [ 14:0] s_mem_word_addr;
|
||||
logic [DataWidth-1:0] s_mem_wdata;
|
||||
logic [DataBytes-1:0] s_mem_wstrb;
|
||||
logic [DataWidth-1:0] s_mem_rdata;
|
||||
|
||||
function automatic logic wrap_length_legal(input logic [7:0] length_i);
|
||||
return (length_i == 8'd1) || (length_i == 8'd3) || (length_i == 8'd7) || (length_i == 8'd15);
|
||||
@@ -124,13 +128,14 @@ module onchip_ram #(
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] transfer_lane_mask(input logic [2:0] size_i,
|
||||
input logic [1:0] address_i);
|
||||
unique case (size_i)
|
||||
3'd0: return 4'b0001 << address_i;
|
||||
3'd1: return 4'b0011 << address_i;
|
||||
default: return 4'b1111;
|
||||
endcase
|
||||
function automatic logic [DataBytes-1:0] transfer_lane_mask(input logic [2:0] size_i,
|
||||
input logic [2:0] address_i);
|
||||
logic [DataBytes-1:0] base_mask;
|
||||
begin
|
||||
base_mask = (size_i >= 3'(BeatSize)) ?
|
||||
{DataBytes{1'b1}} : {DataBytes{1'b1}} >> (DataBytes - (1 << size_i));
|
||||
return base_mask << (address_i & 3'(DataBytes - 1));
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic logic [31:0] saturating_increment(input logic [31:0] value_i);
|
||||
@@ -151,7 +156,7 @@ module onchip_ram #(
|
||||
(mem_axi4.arburst == `AXI4_BURST_TYPE_INCR) ||
|
||||
((mem_axi4.arburst == `AXI4_BURST_TYPE_WRAP) && wrap_length_legal(
|
||||
mem_axi4.arlen
|
||||
))) && !mem_axi4.arlock && (mem_axi4.arsize <= `AXI4_BURST_SIZE_4BYTES) &&
|
||||
))) && !mem_axi4.arlock && (mem_axi4.arsize <= 3'(BeatSize)) &&
|
||||
((mem_axi4.araddr & ((32'd1 << mem_axi4.arsize) - 1'b1)) == 32'd0) && !s_ar_last_addr[32] &&
|
||||
(mem_axi4.araddr[31:12] == s_ar_last_addr[31:12]);
|
||||
assign s_aw_protocol_legal =
|
||||
@@ -160,7 +165,7 @@ module onchip_ram #(
|
||||
(mem_axi4.awburst == `AXI4_BURST_TYPE_INCR) ||
|
||||
((mem_axi4.awburst == `AXI4_BURST_TYPE_WRAP) && wrap_length_legal(
|
||||
mem_axi4.awlen
|
||||
))) && !mem_axi4.awlock && (mem_axi4.awsize <= `AXI4_BURST_SIZE_4BYTES) &&
|
||||
))) && !mem_axi4.awlock && (mem_axi4.awsize <= 3'(BeatSize)) &&
|
||||
((mem_axi4.awaddr & ((32'd1 << mem_axi4.awsize) - 1'b1)) == 32'd0) && !s_aw_last_addr[32] &&
|
||||
(mem_axi4.awaddr[31:12] == s_aw_last_addr[31:12]);
|
||||
assign s_ar_bounds_legal = Present && (mem_axi4.araddr >= `SOC_ADDR_SRAM_BASE) &&
|
||||
@@ -176,7 +181,7 @@ module onchip_ram #(
|
||||
assign mem_axi4.awready = (s_state_q == Idle) && !mem_axi4.arvalid;
|
||||
assign mem_axi4.wready = (s_state_q == WriteData) || (s_state_q == WriteDrain);
|
||||
assign mem_axi4.rid = s_id_q;
|
||||
assign mem_axi4.rdata = (s_read_rsp_q == `AXI4_RESP_OKAY) ? s_mem_rdata : 32'd0;
|
||||
assign mem_axi4.rdata = (s_read_rsp_q == `AXI4_RESP_OKAY) ? s_mem_rdata : '0;
|
||||
assign mem_axi4.rresp = s_read_rsp_q;
|
||||
assign mem_axi4.rlast = s_read_rsp_last_q;
|
||||
assign mem_axi4.ruser = '0;
|
||||
@@ -194,8 +199,8 @@ module onchip_ram #(
|
||||
assign s_read_can_issue = !s_read_pending_q || mem_axi4.rready;
|
||||
assign s_read_issue = (s_state_q == ReadData) && s_read_issue_valid_q && s_read_can_issue;
|
||||
assign s_expected_wlast = s_beat_q == s_len_q;
|
||||
assign s_write_lane_mask = transfer_lane_mask(s_size_q, s_addr_q[1:0]);
|
||||
assign s_write_strobe_legal = (mem_axi4.wstrb & ~s_write_lane_mask) == 4'd0;
|
||||
assign s_write_lane_mask = transfer_lane_mask(s_size_q, s_addr_q[2:0]);
|
||||
assign s_write_strobe_legal = (mem_axi4.wstrb & ~s_write_lane_mask) == '0;
|
||||
assign s_write_beat_legal = s_write_strobe_legal && (mem_axi4.wlast == s_expected_wlast);
|
||||
assign s_write_terminal = s_expected_wlast || mem_axi4.wlast;
|
||||
|
||||
@@ -203,10 +208,11 @@ module onchip_ram #(
|
||||
assign s_mem_write = (s_state_q == WriteData) && s_w_accept && s_write_beat_legal &&
|
||||
(|mem_axi4.wstrb);
|
||||
assign s_mem_word_addr =
|
||||
(s_ar_accept && (s_ar_response == `AXI4_RESP_OKAY)) ? mem_axi4.araddr[16:2] :
|
||||
s_read_issue ? s_read_issue_addr_q[16:2] : s_addr_q[16:2];
|
||||
(s_ar_accept && (s_ar_response == `AXI4_RESP_OKAY)) ?
|
||||
15'(mem_axi4.araddr >> BeatSize) :
|
||||
s_read_issue ? 15'(s_read_issue_addr_q >> BeatSize) : 15'(s_addr_q >> BeatSize);
|
||||
assign s_mem_wdata = mem_axi4.wdata;
|
||||
assign s_mem_wstrb = s_mem_write ? mem_axi4.wstrb : 4'd0;
|
||||
assign s_mem_wstrb = s_mem_write ? mem_axi4.wstrb : '0;
|
||||
|
||||
assign s_err_resp_event =
|
||||
(s_b_accept && (mem_axi4.bresp != `AXI4_RESP_OKAY)) ||
|
||||
@@ -367,7 +373,7 @@ module onchip_ram #(
|
||||
end
|
||||
end
|
||||
|
||||
if (Present) begin : gen_memory
|
||||
if (Present && (DataWidth == 32)) begin : gen_memory
|
||||
logic [ NumBanks-1:0] s_bank_cs;
|
||||
logic [ 31:0] s_bank_rdata [NumBanks];
|
||||
logic [BankIndexWidth-1:0] s_read_bank_q;
|
||||
@@ -410,17 +416,86 @@ module onchip_ram #(
|
||||
|
||||
assign s_mem_rdata = s_bank_rdata[s_read_bank_q];
|
||||
|
||||
`ifdef HAVE_SVA
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i) $onehot0(s_bank_cs));
|
||||
`endif
|
||||
end else if (Present) begin : gen_memory64
|
||||
localparam int unsigned NumBankPairs = (NumBanks + 1) / 2;
|
||||
localparam int unsigned PairIndexWidth = (NumBankPairs > 1) ? $clog2(NumBankPairs) : 1;
|
||||
|
||||
logic [ NumBankPairs-1:0] s_bank_cs;
|
||||
logic [ 31:0] s_bank_lo_rdata[NumBankPairs];
|
||||
logic [ 31:0] s_bank_hi_rdata[NumBankPairs];
|
||||
logic [PairIndexWidth-1:0] s_read_bank_q;
|
||||
|
||||
for (genvar bank = 0; bank < NumBankPairs; bank++) begin : gen_bank
|
||||
assign s_bank_cs[bank] = (s_mem_read || s_mem_write) &&
|
||||
(s_mem_word_addr[14:TechnologyAddrWidth] == (15 - TechnologyAddrWidth)'(bank));
|
||||
`ifdef PDK_ICS55
|
||||
tc_sram_4096x32 u_ram_lo (
|
||||
.clk_i (clk_i),
|
||||
.cs_i (s_bank_cs[bank]),
|
||||
.addr_i(s_mem_word_addr[11:0]),
|
||||
.data_i(s_mem_wdata[31:0]),
|
||||
.mask_i(s_mem_wstrb[3:0]),
|
||||
.wren_i(s_mem_write),
|
||||
.data_o(s_bank_lo_rdata[bank])
|
||||
);
|
||||
tc_sram_4096x32 u_ram_hi (
|
||||
.clk_i (clk_i),
|
||||
.cs_i (s_bank_cs[bank]),
|
||||
.addr_i(s_mem_word_addr[11:0]),
|
||||
.data_i(s_mem_wdata[63:32]),
|
||||
.mask_i(s_mem_wstrb[7:4]),
|
||||
.wren_i(s_mem_write),
|
||||
.data_o(s_bank_hi_rdata[bank])
|
||||
);
|
||||
`else
|
||||
tc_sram_1024x32 u_ram_lo (
|
||||
.clk_i (clk_i),
|
||||
.cs_i (s_bank_cs[bank]),
|
||||
.addr_i(s_mem_word_addr[9:0]),
|
||||
.data_i(s_mem_wdata[31:0]),
|
||||
.mask_i(s_mem_wstrb[3:0]),
|
||||
.wren_i(s_mem_write),
|
||||
.data_o(s_bank_lo_rdata[bank])
|
||||
);
|
||||
tc_sram_1024x32 u_ram_hi (
|
||||
.clk_i (clk_i),
|
||||
.cs_i (s_bank_cs[bank]),
|
||||
.addr_i(s_mem_word_addr[9:0]),
|
||||
.data_i(s_mem_wdata[63:32]),
|
||||
.mask_i(s_mem_wstrb[7:4]),
|
||||
.wren_i(s_mem_write),
|
||||
.data_o(s_bank_hi_rdata[bank])
|
||||
);
|
||||
`endif
|
||||
end
|
||||
|
||||
dffer #(
|
||||
.DATA_WIDTH(PairIndexWidth)
|
||||
) u_read_bank_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_mem_read),
|
||||
.dat_i (s_mem_word_addr[PairIndexWidth+TechnologyAddrWidth-1:TechnologyAddrWidth]),
|
||||
.dat_o (s_read_bank_q)
|
||||
);
|
||||
|
||||
assign s_mem_rdata = {s_bank_hi_rdata[s_read_bank_q], s_bank_lo_rdata[s_read_bank_q]};
|
||||
|
||||
`ifdef HAVE_SVA
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i) $onehot0(s_bank_cs));
|
||||
`endif
|
||||
end else begin : gen_no_memory
|
||||
assign s_mem_rdata = {32{1'b0 & ^{s_mem_read, s_mem_write, s_mem_word_addr,
|
||||
s_mem_wdata, s_mem_wstrb}}};
|
||||
assign s_mem_rdata = {DataWidth{1'b0 & ^{s_mem_read, s_mem_write, s_mem_word_addr,
|
||||
s_mem_wdata, s_mem_wstrb}}};
|
||||
end
|
||||
|
||||
onchip_ram_reg #(
|
||||
.Present (Present),
|
||||
.CapacityKiB(CapacityKiB)
|
||||
.CapacityKiB(CapacityKiB),
|
||||
.DataBytes (DataBytes)
|
||||
) u_reg (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
@@ -442,7 +517,7 @@ module onchip_ram #(
|
||||
.dat_o (s_state_bits_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
.DATA_WIDTH(IdWidth)
|
||||
) u_id_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
@@ -619,9 +694,11 @@ module onchip_ram #(
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
if ((CapacityKiB != 4) && (CapacityKiB != 16) && (CapacityKiB != 32) &&
|
||||
(CapacityKiB != 64) && (CapacityKiB != 128)) begin
|
||||
$fatal(1, "onchip_ram: CapacityKiB must be 4, 16, 32, 64, or 128");
|
||||
if (((DataWidth != 32) && (DataWidth != 64)) || (IdWidth < 1) ||
|
||||
((DataWidth % 8) != 0) ||
|
||||
((CapacityKiB != 4) && (CapacityKiB != 16) && (CapacityKiB != 32) &&
|
||||
(CapacityKiB != 64) && (CapacityKiB != 128))) begin
|
||||
$fatal(1, "onchip_ram: invalid width, ID, or capacity geometry");
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
module onchip_ram_reg #(
|
||||
parameter bit Present = 1'b1,
|
||||
parameter int unsigned CapacityKiB = 128
|
||||
parameter int unsigned CapacityKiB = 128,
|
||||
parameter int unsigned DataBytes = 4
|
||||
) (
|
||||
// verilog_format: off -- preserve the register input grouping
|
||||
input logic clk_i,
|
||||
@@ -31,7 +32,7 @@ module onchip_ram_reg #(
|
||||
localparam int unsigned BankBytes = 4096;
|
||||
localparam int unsigned BankCount = CapacityKiB / 4;
|
||||
localparam logic [31:0] Capability =
|
||||
32'(4 << `APB4_ONCHIP_RAM__CAP_DATA_BYTES_LSB) |
|
||||
32'(DataBytes << `APB4_ONCHIP_RAM__CAP_DATA_BYTES_LSB) |
|
||||
32'(16 << `APB4_ONCHIP_RAM__CAP_MAX_BEATS_LSB) |
|
||||
32'h0000_007E | 32'(Present);
|
||||
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
module resource_controller #(
|
||||
parameter int unsigned ResourceCount = 6
|
||||
) (
|
||||
// verilog_format: off -- preserve the resource ownership boundary columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [ResourceCount-1:0] idle_i,
|
||||
input logic [ResourceCount-1:0] block_ack_i,
|
||||
input logic [ResourceCount-1:0] irq_i,
|
||||
input logic cache_request_i,
|
||||
output logic cache_clean_o,
|
||||
output logic [ResourceCount-1:0][1:0] owner_o,
|
||||
output logic [ResourceCount-1:0] quiesce_o,
|
||||
output logic [ResourceCount-1:0] reset_o,
|
||||
output logic [ResourceCount-1:0] irq_lp_o,
|
||||
output logic [ResourceCount-1:0] irq_hp_o,
|
||||
output logic fault_irq_o,
|
||||
apb4_if.slave apb4
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam logic [31:0] IpId = 32'h5253_4354;
|
||||
localparam logic [31:0] IpVersion = 32'h0001_0000;
|
||||
localparam logic [11:0] IpIdOffset = 12'h000;
|
||||
localparam logic [11:0] IpVersionOffset = 12'h004;
|
||||
localparam logic [11:0] CapabilityOffset = 12'h008;
|
||||
localparam logic [11:0] GlobalStatusOffset = 12'h00C;
|
||||
localparam logic [11:0] CacheControlOffset = 12'h010;
|
||||
localparam logic [11:0] ResourceBase = 12'h100;
|
||||
localparam logic [11:0] ResourceStride = 12'h020;
|
||||
localparam logic [11:0] OwnerOffset = 12'h000;
|
||||
localparam logic [11:0] ControlOffset = 12'h004;
|
||||
localparam logic [11:0] StatusOffset = 12'h008;
|
||||
localparam logic [11:0] FaultOffset = 12'h00C;
|
||||
localparam logic [11:0] HandoffCountOffset = 12'h010;
|
||||
localparam logic [1:0] OwnerLp = 2'd0;
|
||||
localparam logic [1:0] OwnerHp = 2'd1;
|
||||
|
||||
logic [ResourceCount-1:0][ 1:0] s_owner_q;
|
||||
logic [ResourceCount-1:0] s_owner_lock_q;
|
||||
logic [ResourceCount-1:0] s_quiesce_q;
|
||||
logic [ResourceCount-1:0] s_reset_q;
|
||||
logic [ResourceCount-1:0] s_fault_q;
|
||||
logic [ResourceCount-1:0][15:0] s_handoff_count_q;
|
||||
logic s_cache_clean_q;
|
||||
logic s_ready_q;
|
||||
logic s_resp_err_q;
|
||||
logic [ 31:0] s_rdata_q;
|
||||
logic s_request;
|
||||
logic s_aligned;
|
||||
logic s_read_valid;
|
||||
logic s_write_valid;
|
||||
logic s_write_error;
|
||||
logic [ 31:0] s_read_data;
|
||||
logic [ResourceCount-1:0] s_owner_write;
|
||||
logic [ResourceCount-1:0] s_control_write;
|
||||
logic [ResourceCount-1:0] s_fault_clear;
|
||||
logic s_cache_write;
|
||||
|
||||
function automatic logic [15:0] saturating_increment(input logic [15:0] value_i);
|
||||
return (&value_i) ? value_i : value_i + 1'b1;
|
||||
endfunction
|
||||
|
||||
assign s_request = apb4.psel && apb4.penable && !s_ready_q;
|
||||
assign s_aligned = apb4.paddr[1:0] == 2'b00;
|
||||
assign apb4.pready = s_ready_q;
|
||||
assign apb4.pslverr = s_resp_err_q;
|
||||
assign apb4.prdata = s_rdata_q;
|
||||
assign owner_o = s_owner_q;
|
||||
assign quiesce_o = s_quiesce_q;
|
||||
assign reset_o = s_reset_q;
|
||||
assign cache_clean_o = s_cache_clean_q;
|
||||
assign fault_irq_o = |s_fault_q;
|
||||
|
||||
always_comb begin
|
||||
irq_lp_o = '0;
|
||||
irq_hp_o = '0;
|
||||
for (int resource = 0; resource < ResourceCount; resource++) begin
|
||||
irq_lp_o[resource] = irq_i[resource] && (s_owner_q[resource] == OwnerLp) &&
|
||||
!s_reset_q[resource];
|
||||
irq_hp_o[resource] = irq_i[resource] && (s_owner_q[resource] == OwnerHp) &&
|
||||
!s_reset_q[resource];
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_read_valid = 1'b1;
|
||||
s_write_valid = 1'b0;
|
||||
s_write_error = 1'b0;
|
||||
s_read_data = 32'd0;
|
||||
s_owner_write = '0;
|
||||
s_control_write = '0;
|
||||
s_fault_clear = '0;
|
||||
s_cache_write = 1'b0;
|
||||
unique case (apb4.paddr[11:0])
|
||||
IpIdOffset: s_read_data = IpId;
|
||||
IpVersionOffset: s_read_data = IpVersion;
|
||||
CapabilityOffset: s_read_data = {16'd0, 8'(ResourceCount), 6'd0, 2'd1};
|
||||
GlobalStatusOffset:
|
||||
s_read_data = {
|
||||
{(25 - ResourceCount) {1'b0}}, s_fault_q, 5'd0, cache_request_i, s_cache_clean_q
|
||||
};
|
||||
CacheControlOffset: begin
|
||||
s_read_data = {30'd0, cache_request_i, s_cache_clean_q};
|
||||
s_write_valid = 1'b1;
|
||||
s_cache_write = apb4.pwrite;
|
||||
s_write_error = apb4.pwrite && ((apb4.pstrb != 4'hF) ||
|
||||
apb4.pwdata[31:1] != 31'd0 ||
|
||||
(apb4.pwdata[0] && !cache_request_i));
|
||||
end
|
||||
default: begin
|
||||
s_read_valid = 1'b0;
|
||||
for (int resource = 0; resource < ResourceCount; resource++) begin
|
||||
if (apb4.paddr[11:0] == ResourceBase + 12'(resource) * ResourceStride + OwnerOffset) begin
|
||||
s_read_valid = 1'b1;
|
||||
s_read_data = {23'd0, s_owner_lock_q[resource], 6'd0, s_owner_q[resource]};
|
||||
s_write_valid = 1'b1;
|
||||
s_owner_write[resource] = apb4.pwrite;
|
||||
s_write_error = apb4.pwrite &&
|
||||
((apb4.pstrb != 4'hF) || (apb4.pwdata[31:9] != 23'd0) ||
|
||||
(apb4.pwdata[7:2] != 6'd0) || (apb4.pwdata[1:0] > OwnerHp) ||
|
||||
s_owner_lock_q[resource] || !s_quiesce_q[resource] ||
|
||||
!block_ack_i[resource] || !idle_i[resource]);
|
||||
end else if (apb4.paddr[11:0] ==
|
||||
ResourceBase + 12'(resource) * ResourceStride + ControlOffset) begin
|
||||
s_read_valid = 1'b1;
|
||||
s_read_data = {30'd0, s_reset_q[resource], s_quiesce_q[resource]};
|
||||
s_write_valid = 1'b1;
|
||||
s_control_write[resource] = apb4.pwrite;
|
||||
s_write_error = apb4.pwrite && ((apb4.pstrb != 4'hF) || (apb4.pwdata[31:2] != 30'd0));
|
||||
end else if (apb4.paddr[11:0] ==
|
||||
ResourceBase + 12'(resource) * ResourceStride + StatusOffset) begin
|
||||
s_read_valid = 1'b1;
|
||||
s_read_data = {
|
||||
24'd0,
|
||||
block_ack_i[resource],
|
||||
irq_i[resource],
|
||||
s_fault_q[resource],
|
||||
idle_i[resource],
|
||||
s_reset_q[resource],
|
||||
s_quiesce_q[resource],
|
||||
s_owner_q[resource]
|
||||
};
|
||||
end else if (apb4.paddr[11:0] ==
|
||||
ResourceBase + 12'(resource) * ResourceStride + FaultOffset) begin
|
||||
s_read_valid = 1'b1;
|
||||
s_read_data = {31'd0, s_fault_q[resource]};
|
||||
s_write_valid = 1'b1;
|
||||
s_fault_clear[resource] = apb4.pwrite;
|
||||
s_write_error = apb4.pwrite && ((apb4.pstrb != 4'hF) || (apb4.pwdata[31:1] != 31'd0));
|
||||
end else if (apb4.paddr[11:0] ==
|
||||
ResourceBase + 12'(resource) * ResourceStride + HandoffCountOffset) begin
|
||||
s_read_valid = 1'b1;
|
||||
s_read_data = {16'd0, s_handoff_count_q[resource]};
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
if (!s_aligned || (apb4.pwrite && !s_write_valid) || (!apb4.pwrite && !s_read_valid)) begin
|
||||
s_write_error = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_owner_q <= '0;
|
||||
s_owner_lock_q <= '0;
|
||||
s_quiesce_q <= '0;
|
||||
s_reset_q <= '0;
|
||||
s_fault_q <= '0;
|
||||
s_handoff_count_q <= '0;
|
||||
s_cache_clean_q <= 1'b0;
|
||||
s_ready_q <= 1'b0;
|
||||
s_resp_err_q <= 1'b0;
|
||||
s_rdata_q <= '0;
|
||||
end else begin
|
||||
s_ready_q <= s_request;
|
||||
s_resp_err_q <= s_request && s_write_error;
|
||||
if (s_request && !apb4.pwrite && s_read_valid) s_rdata_q <= s_read_data;
|
||||
if (!cache_request_i) s_cache_clean_q <= 1'b0;
|
||||
if (s_request && s_cache_write && !s_write_error) begin
|
||||
s_cache_clean_q <= apb4.pwdata[0];
|
||||
end
|
||||
for (int resource = 0; resource < ResourceCount; resource++) begin
|
||||
if (s_request && s_owner_write[resource]) begin
|
||||
if (s_write_error) begin
|
||||
s_fault_q[resource] <= 1'b1;
|
||||
end else begin
|
||||
if (s_owner_q[resource] != apb4.pwdata[1:0]) begin
|
||||
s_handoff_count_q[resource] <= saturating_increment(s_handoff_count_q[resource]);
|
||||
end
|
||||
s_owner_q[resource] <= apb4.pwdata[1:0];
|
||||
s_owner_lock_q[resource] <= apb4.pwdata[8];
|
||||
end
|
||||
end
|
||||
if (s_request && s_control_write[resource] && !s_write_error) begin
|
||||
s_quiesce_q[resource] <= apb4.pwdata[0];
|
||||
s_reset_q[resource] <= apb4.pwdata[1];
|
||||
end
|
||||
if (s_request && s_fault_clear[resource] && !s_write_error && apb4.pwdata[0]) begin
|
||||
s_fault_q[resource] <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
if ((ResourceCount < 1) || (ResourceCount > 16)) begin
|
||||
$fatal(1, "resource_controller: ResourceCount must be in [1, 16]");
|
||||
end
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
+185
-91
@@ -61,8 +61,8 @@ module retrosoc (
|
||||
// verilog_format: off -- preserve reviewed column alignment
|
||||
// Generated fabric links use the common 32-bit AXI4 contract.
|
||||
`include "soc_fabric_interfaces.svh"
|
||||
apb4_if u_sdram_cfg_if (.pclk(clk_lp_i), .presetn(rst_lp_n_i));
|
||||
apb4_if u_sram_cfg_if (.pclk(clk_lp_i), .presetn(rst_lp_n_i));
|
||||
apb4_if u_sdram_cfg_if (.pclk(clk_mem_i), .presetn(rst_mem_n_i));
|
||||
apb4_if u_sram_cfg_if (.pclk(clk_hp_i), .presetn(rst_hp_n_i));
|
||||
apb4_if u_sdram_cfg_pclk_if (.pclk(clk_pclk_i), .presetn(rst_pclk_n_i));
|
||||
apb4_if u_sram_cfg_pclk_if (.pclk(clk_pclk_i), .presetn(rst_pclk_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||
@@ -101,10 +101,14 @@ 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))
|
||||
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_data_sram_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
|
||||
u_retired_data_sram_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||
u_data_sdram_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
|
||||
u_data_sdram_axi4_if (.aclk(clk_mem_i), .aresetn(rst_mem_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||
u_retired_data_sdram_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||
u_data_qpi_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||
@@ -202,6 +206,10 @@ module retrosoc (
|
||||
logic s_hp_lifecycle_release_hp;
|
||||
logic s_hp_lifecycle_block;
|
||||
logic s_hp_lifecycle_flush;
|
||||
logic s_hp_cache_req_aon;
|
||||
logic s_hp_cache_req_pclk;
|
||||
logic s_hp_cache_clean_pclk;
|
||||
logic s_hp_cache_clean_aon;
|
||||
logic s_hp_lifecycle_draining;
|
||||
logic s_hp_lifecycle_fault;
|
||||
logic s_hp_block_combined;
|
||||
@@ -215,6 +223,16 @@ module retrosoc (
|
||||
logic [31:0] s_ext_h_timeout;
|
||||
logic s_ext_h_irq_raw;
|
||||
logic [ 1:0] s_ext_h_owner;
|
||||
logic [ 5:0][1:0] s_resource_owner;
|
||||
logic [ 5:0] s_resource_quiesce;
|
||||
logic [ 5:0] s_resource_reset;
|
||||
logic [ 5:0] s_resource_idle_hp;
|
||||
logic [ 5:0] s_resource_idle_pclk;
|
||||
logic [ 5:0] s_resource_block_ack_hp;
|
||||
logic [ 5:0] s_resource_block_ack_pclk;
|
||||
logic [ 4:0] s_resource_irq_raw;
|
||||
logic [ 4:0] s_resource_irq_lp;
|
||||
logic [ 4:0] s_resource_irq_hp;
|
||||
logic [31:0] s_fault_addr_mux;
|
||||
logic [ 3:0] s_fault_wstrb_mux;
|
||||
logic s_fault_reserved_mux;
|
||||
@@ -400,6 +418,7 @@ core_wrapper u_core_wrapper (
|
||||
axi4_downsizer_64to32 u_hp_mmio_downsizer (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i(rst_hp_n_i),
|
||||
.clear_i(1'b0),
|
||||
.wide (u_hp_mmio_wide_axi4_if),
|
||||
.narrow (u_hp_mmio_hp_axi4_if)
|
||||
);
|
||||
@@ -443,17 +462,37 @@ core_wrapper u_core_wrapper (
|
||||
.dat_o({s_hp_release_req_aon, s_hp_debug_reset_req_aon, s_hp_idle_aon, s_hp_flush_busy_aon})
|
||||
);
|
||||
hp_lifecycle_controller u_hp_lifecycle_controller (
|
||||
.clk_i (clk_aon_i),
|
||||
.rst_n_i (rst_aon_n_i),
|
||||
.release_req_i (s_hp_release_req_aon && !s_hp_debug_reset_req_aon),
|
||||
.hp_idle_i (s_hp_idle_aon),
|
||||
.flush_busy_i (s_hp_flush_busy_aon),
|
||||
.timeout_i (16'd1024),
|
||||
.hp_release_o (s_hp_lifecycle_release_aon),
|
||||
.block_new_o (s_hp_lifecycle_block),
|
||||
.flush_o (s_hp_lifecycle_flush),
|
||||
.draining_o (s_hp_lifecycle_draining),
|
||||
.forced_fault_o(s_hp_lifecycle_fault)
|
||||
.clk_i (clk_aon_i),
|
||||
.rst_n_i (rst_aon_n_i),
|
||||
.release_req_i (s_hp_release_req_aon && !s_hp_debug_reset_req_aon),
|
||||
.hp_idle_i (s_hp_idle_aon),
|
||||
.flush_busy_i (s_hp_flush_busy_aon),
|
||||
.cache_clean_i (s_hp_cache_clean_aon),
|
||||
.timeout_i (16'd1024),
|
||||
.hp_release_o (s_hp_lifecycle_release_aon),
|
||||
.block_new_o (s_hp_lifecycle_block),
|
||||
.flush_o (s_hp_lifecycle_flush),
|
||||
.cache_request_o(s_hp_cache_req_aon),
|
||||
.draining_o (s_hp_lifecycle_draining),
|
||||
.forced_fault_o (s_hp_lifecycle_fault)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_hp_cache_req_sync (
|
||||
.clk_i (clk_pclk_i),
|
||||
.rst_n_i(rst_pclk_n_i),
|
||||
.dat_i (s_hp_cache_req_aon),
|
||||
.dat_o (s_hp_cache_req_pclk)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_hp_cache_clean_sync (
|
||||
.clk_i (clk_aon_i),
|
||||
.rst_n_i(rst_aon_n_i),
|
||||
.dat_i (s_hp_cache_clean_pclk),
|
||||
.dat_o (s_hp_cache_clean_aon)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
@@ -485,49 +524,75 @@ core_wrapper u_core_wrapper (
|
||||
);
|
||||
|
||||
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),
|
||||
.block_new_i (s_hp_block_combined),
|
||||
.recovery_i (s_hp_lifecycle_block),
|
||||
.flush_i (s_hp_lifecycle_flush),
|
||||
.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),
|
||||
.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),
|
||||
.idle_o (s_data_plane_idle),
|
||||
.flush_busy_o (s_data_plane_flush_busy),
|
||||
.ext_h_idle_o (s_ext_h_data_idle),
|
||||
.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_combined),
|
||||
.recovery_i (s_hp_lifecycle_block),
|
||||
.flush_i (s_hp_lifecycle_flush),
|
||||
.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),
|
||||
.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),
|
||||
.idle_o (s_data_plane_idle),
|
||||
.flush_busy_o (s_data_plane_flush_busy),
|
||||
.ext_h_idle_o (s_ext_h_data_idle),
|
||||
.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)
|
||||
);
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(6)
|
||||
) u_resource_idle_sync (
|
||||
.clk_i (clk_pclk_i),
|
||||
.rst_n_i(rst_pclk_n_i),
|
||||
.dat_i (s_resource_idle_hp),
|
||||
.dat_o (s_resource_idle_pclk)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(6)
|
||||
) u_resource_block_ack_sync (
|
||||
.clk_i (clk_pclk_i),
|
||||
.rst_n_i(rst_pclk_n_i),
|
||||
.dat_i (s_resource_block_ack_hp),
|
||||
.dat_o (s_resource_block_ack_pclk)
|
||||
);
|
||||
|
||||
axi4_master_idle u_idle_master (.axi4(u_idle_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_async_bridge #(
|
||||
.DataWidth(32),
|
||||
@@ -602,16 +667,16 @@ core_wrapper u_core_wrapper (
|
||||
apb4_async_bridge u_sdram_cfg_cdc (
|
||||
.src_clk_i (clk_pclk_i),
|
||||
.src_rst_n_i(rst_pclk_n_i),
|
||||
.dst_clk_i (clk_lp_i),
|
||||
.dst_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i(rst_mem_n_i),
|
||||
.src_apb4 (u_sdram_cfg_pclk_if),
|
||||
.dst_apb4 (u_sdram_cfg_if)
|
||||
);
|
||||
apb4_async_bridge u_sram_cfg_cdc (
|
||||
.src_clk_i (clk_pclk_i),
|
||||
.src_rst_n_i(rst_pclk_n_i),
|
||||
.dst_clk_i (clk_lp_i),
|
||||
.dst_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_hp_i),
|
||||
.dst_rst_n_i(rst_hp_n_i),
|
||||
.src_apb4 (u_sram_cfg_pclk_if),
|
||||
.dst_apb4 (u_sram_cfg_if)
|
||||
);
|
||||
@@ -646,22 +711,35 @@ core_wrapper u_core_wrapper (
|
||||
|
||||
onchip_ram #(
|
||||
.Present (SramPresent),
|
||||
.CapacityKiB(`SOC_ADDR_SRAM_SIZE >> 10)
|
||||
.CapacityKiB(`SOC_ADDR_SRAM_SIZE >> 10),
|
||||
.DataWidth (64),
|
||||
.IdWidth (6)
|
||||
) u_onchip_ram (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i (rst_lp_n_i),
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.perf_enable_i(s_perf_en),
|
||||
.perf_clear_i (s_perf_clear),
|
||||
.mem_axi4 (u_sram_axi4_if),
|
||||
.mem_axi4 (u_data_sram_axi4_if),
|
||||
.cfg_apb4 (u_sram_cfg_if)
|
||||
);
|
||||
|
||||
axi4_error_slave u_retired_sram_target (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i(rst_lp_n_i),
|
||||
.axi4 (u_sram_axi4_if)
|
||||
);
|
||||
axi4_error_slave u_retired_sdram_target (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i(rst_lp_n_i),
|
||||
.axi4 (u_sdram_axi4_if)
|
||||
);
|
||||
|
||||
axi4_bus u_bus (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i (rst_lp_n_i),
|
||||
.mgmt_axi4 (u_mgmt_control_axi4_if),
|
||||
.user_axi4 (u_data_sram_axi4_if),
|
||||
.dma_axi4 (u_data_sdram_axi4_if),
|
||||
.user_axi4 (u_retired_data_sram_axi4_if),
|
||||
.dma_axi4 (u_retired_data_sdram_axi4_if),
|
||||
.sdio0_axi4 (u_data_qpi_axi4_if),
|
||||
.sdio1_axi4 (u_data_xpi_axi4_if),
|
||||
.usb2_axi4 (u_hp_mmio_lp_axi4_if),
|
||||
@@ -711,6 +789,8 @@ core_wrapper u_core_wrapper (
|
||||
.debug_halted_i (s_mgmt_debug_halted),
|
||||
.timebase_tick_i (timebase_tick_i),
|
||||
.ext_h_hp_irq_i ((s_ext_h_owner == 2'd1) ? s_ext_h_irq_raw : 1'b0),
|
||||
.resource_irq_lp_i (s_resource_irq_lp),
|
||||
.resource_irq_hp_i (s_resource_irq_hp),
|
||||
.cfg_axi4 (u_cfg_pclk_axi4_if),
|
||||
.dma_axi4 (u_dma_axi4_if),
|
||||
.sdio0_axi4 (u_sdio0_axi4_if),
|
||||
@@ -750,44 +830,55 @@ core_wrapper u_core_wrapper (
|
||||
.hp_software_irq_o (s_hp_software_irq),
|
||||
.hp_machine_external_irq_o (s_hp_machine_external_irq),
|
||||
.hp_supervisor_external_irq_o(s_hp_supervisor_external_irq),
|
||||
.resource_irq_raw_o (s_resource_irq_raw),
|
||||
.irq_o (s_apb4_periph_irq)
|
||||
);
|
||||
|
||||
axi4_sdram u_axi4_sdram (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i (rst_lp_n_i),
|
||||
.axi4 (u_sdram_axi4_if),
|
||||
.clk_i (clk_mem_i),
|
||||
.rst_n_i (rst_mem_n_i),
|
||||
.axi4 (u_data_sdram_axi4_if),
|
||||
.cfg_apb4(u_sdram_cfg_if),
|
||||
.sdram (sdram)
|
||||
);
|
||||
|
||||
apb4_system u_apb4_system (
|
||||
.clk_i (clk_pclk_i),
|
||||
.rst_n_i (rst_pclk_n_i),
|
||||
.clk_aud_i (clk_aud_i),
|
||||
.rst_aud_n_i (rst_aud_n_i),
|
||||
.debug_halted_i (s_mgmt_debug_halted),
|
||||
.ext_h_data_idle_i (s_ext_h_data_idle),
|
||||
.ext_h_axi4 (u_ext_h_wide_axi4_if),
|
||||
.axi4 (u_system_pclk_axi4_if),
|
||||
.pwm (u_pwm_if),
|
||||
.ps2 (u_ps2_if),
|
||||
.ip_sel_i (u_sysctrl_if.ip_sel_o),
|
||||
.user_gpio (u_user_gpio_if),
|
||||
.rtc_wake_o (s_rtc_wake),
|
||||
.wdg_reset_req_o (wdg_reset_req_o),
|
||||
.ext_h_block_o (s_ext_h_block),
|
||||
.ext_h_read_base_o (s_ext_h_read_base),
|
||||
.ext_h_read_limit_o (s_ext_h_read_limit),
|
||||
.ext_h_write_base_o (s_ext_h_write_base),
|
||||
.clk_i(clk_pclk_i),
|
||||
.rst_n_i(rst_pclk_n_i),
|
||||
.clk_aud_i(clk_aud_i),
|
||||
.rst_aud_n_i(rst_aud_n_i),
|
||||
.debug_halted_i(s_mgmt_debug_halted),
|
||||
.ext_h_data_idle_i(s_ext_h_data_idle),
|
||||
.resource_idle_i({s_ext_h_data_idle && s_resource_idle_pclk[5], s_resource_idle_pclk[4:0]}),
|
||||
.resource_block_ack_i(s_resource_block_ack_pclk),
|
||||
.resource_irq_i(s_resource_irq_raw),
|
||||
.cache_request_i(s_hp_cache_req_pclk),
|
||||
.ext_h_axi4(u_ext_h_wide_axi4_if),
|
||||
.axi4(u_system_pclk_axi4_if),
|
||||
.pwm(u_pwm_if),
|
||||
.ps2(u_ps2_if),
|
||||
.ip_sel_i(u_sysctrl_if.ip_sel_o),
|
||||
.user_gpio(u_user_gpio_if),
|
||||
.rtc_wake_o(s_rtc_wake),
|
||||
.wdg_reset_req_o(wdg_reset_req_o),
|
||||
.ext_h_block_o(s_ext_h_block),
|
||||
.ext_h_read_base_o(s_ext_h_read_base),
|
||||
.ext_h_read_limit_o(s_ext_h_read_limit),
|
||||
.ext_h_write_base_o(s_ext_h_write_base),
|
||||
.ext_h_write_limit_o(s_ext_h_write_limit),
|
||||
.ext_h_timeout_o (s_ext_h_timeout),
|
||||
.ext_h_irq_raw_o (s_ext_h_irq_raw),
|
||||
.ext_h_owner_o (s_ext_h_owner),
|
||||
.irq_o (s_apb4_system_irq)
|
||||
.ext_h_timeout_o(s_ext_h_timeout),
|
||||
.ext_h_irq_raw_o(s_ext_h_irq_raw),
|
||||
.ext_h_owner_o(s_ext_h_owner),
|
||||
.cache_clean_o(s_hp_cache_clean_pclk),
|
||||
.resource_owner_o(s_resource_owner),
|
||||
.resource_quiesce_o(s_resource_quiesce),
|
||||
.resource_reset_o(s_resource_reset),
|
||||
.resource_irq_lp_o(s_resource_irq_lp),
|
||||
.resource_irq_hp_o(s_resource_irq_hp),
|
||||
.irq_o(s_apb4_system_irq)
|
||||
);
|
||||
|
||||
logic [31:0] s_unused_domain_inputs;
|
||||
logic [34:0] s_unused_domain_inputs;
|
||||
assign s_unused_domain_inputs = {
|
||||
clk_pclk_i,
|
||||
rst_pclk_n_i,
|
||||
@@ -801,6 +892,9 @@ core_wrapper u_core_wrapper (
|
||||
s_mgmt_router_idle,
|
||||
s_hp_lifecycle_draining,
|
||||
s_hp_lifecycle_fault,
|
||||
^s_resource_owner,
|
||||
^s_resource_quiesce,
|
||||
^s_resource_reset,
|
||||
^unused_cdc_clear_busy,
|
||||
^unused_cdc_epoch,
|
||||
^s_ext_h_timeout
|
||||
|
||||
+214
-50
@@ -9,9 +9,12 @@ module soc_data_plane (
|
||||
input logic rst_io_n_i,
|
||||
input logic clk_hp_i,
|
||||
input logic rst_hp_n_i,
|
||||
input logic clk_mem_i,
|
||||
input logic rst_mem_n_i,
|
||||
input logic block_new_i,
|
||||
input logic recovery_i,
|
||||
input logic flush_i,
|
||||
input logic [5: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,
|
||||
@@ -35,6 +38,8 @@ module soc_data_plane (
|
||||
output logic idle_o,
|
||||
output logic flush_busy_o,
|
||||
output logic ext_h_idle_o,
|
||||
output logic [5:0] resource_idle_o,
|
||||
output logic [5:0] resource_block_ack_o,
|
||||
output logic [7:0] outstanding_read_o,
|
||||
output logic [7:0] outstanding_write_o,
|
||||
output logic fault_valid_o,
|
||||
@@ -47,18 +52,37 @@ module soc_data_plane (
|
||||
);
|
||||
localparam int unsigned NumIoMasters = 3;
|
||||
localparam int unsigned NumMemoryTargets = 5;
|
||||
localparam logic [3:0] FaultTimeout = 4'd5;
|
||||
|
||||
logic s_block_new_hp;
|
||||
logic [ 1:0] s_mem_pad_mode_hp;
|
||||
logic [ NumIoMasters-1:0] s_io_clear_busy;
|
||||
logic [NumMemoryTargets-1:0] s_target_clear_busy;
|
||||
logic s_lp_clear_busy;
|
||||
logic s_ext_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 [ 2:0] s_unused_epoch;
|
||||
logic s_block_new_hp;
|
||||
logic [ 1:0] s_mem_pad_mode_hp;
|
||||
logic [ NumIoMasters-1:0] s_io_clear_busy;
|
||||
logic [NumMemoryTargets-1:0] s_target_clear_busy;
|
||||
logic [NumMemoryTargets-1:0] s_guard_clear_busy;
|
||||
logic [NumMemoryTargets-1:0] s_guard_abort;
|
||||
logic [NumMemoryTargets-1:0] s_guard_abort_done;
|
||||
logic [NumMemoryTargets-1:0] s_guard_abort_seen_q;
|
||||
logic [NumMemoryTargets-1:0] s_guard_timeout_valid;
|
||||
logic [NumMemoryTargets-1:0] s_guard_timeout_write;
|
||||
logic [NumMemoryTargets-1:0][ 5:0] s_guard_timeout_id;
|
||||
logic [NumMemoryTargets-1:0][31:0] s_guard_timeout_addr;
|
||||
logic s_sdram_abort_mem;
|
||||
logic s_crossbar_fault_valid;
|
||||
logic [ 2: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 [ 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 [ 2:0] s_unused_epoch;
|
||||
logic [ 5:0] s_resource_block_hp;
|
||||
logic [ 7:0] s_master_idle;
|
||||
logic [ 7:0] s_master_block;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
@@ -74,10 +98,28 @@ module soc_data_plane (
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) u_target_axi4[6] (
|
||||
) u_crossbar_target_axi4[6] (
|
||||
.aclk (clk_hp_i),
|
||||
.aresetn(rst_hp_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) u_target_axi4[NumMemoryTargets] (
|
||||
.aclk (clk_hp_i),
|
||||
.aresetn(rst_hp_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) u_sdram_mem_axi4 (
|
||||
.aclk (clk_mem_i),
|
||||
.aresetn(rst_mem_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
@@ -196,6 +238,33 @@ module soc_data_plane (
|
||||
.dat_i (mem_pad_mode_i),
|
||||
.dat_o (s_mem_pad_mode_hp)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(6)
|
||||
) 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)
|
||||
);
|
||||
|
||||
assign s_master_block = {
|
||||
s_resource_block_hp[5],
|
||||
2'b00,
|
||||
s_resource_block_hp[4] || s_resource_block_hp[3],
|
||||
s_resource_block_hp[2] || s_resource_block_hp[1],
|
||||
s_resource_block_hp[0],
|
||||
2'b00
|
||||
};
|
||||
assign resource_idle_o = {
|
||||
s_master_idle[7],
|
||||
s_master_idle[4],
|
||||
s_master_idle[4],
|
||||
s_master_idle[3],
|
||||
s_master_idle[3],
|
||||
s_master_idle[2]
|
||||
};
|
||||
assign resource_block_ack_o = s_resource_block_hp;
|
||||
|
||||
axi4_id_prefix #(
|
||||
.MasterIndex(3'd0)
|
||||
@@ -327,6 +396,7 @@ module soc_data_plane (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.block_new_i (s_block_new_hp),
|
||||
.master_block_i (s_master_block),
|
||||
.recovery_i (recovery_i),
|
||||
.mem_pad_mode_i (s_mem_pad_mode_hp),
|
||||
.ext_h_read_base_i (ext_h_read_base_i),
|
||||
@@ -334,41 +404,106 @@ module soc_data_plane (
|
||||
.ext_h_write_base_i (ext_h_write_base_i),
|
||||
.ext_h_write_limit_i(ext_h_write_limit_i),
|
||||
.masters (u_master_axi4),
|
||||
.targets (u_target_axi4),
|
||||
.targets (u_crossbar_target_axi4),
|
||||
.idle_o (idle_o),
|
||||
.master_idle_o (s_master_idle),
|
||||
.outstanding_read_o (outstanding_read_o),
|
||||
.outstanding_write_o(outstanding_write_o),
|
||||
.fault_valid_o (fault_valid_o),
|
||||
.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)
|
||||
.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)
|
||||
);
|
||||
|
||||
for (genvar target = 0; target < NumMemoryTargets; target++) begin : gen_memory_target
|
||||
axi4_downsizer_64to32 #(
|
||||
.WideIdWidth(6)
|
||||
) u_target_downsizer (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i(rst_hp_n_i),
|
||||
.wide (u_target_axi4[target]),
|
||||
.narrow (u_target_hp_axi4[target])
|
||||
);
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_target_cdc (
|
||||
.src_clk_i (clk_hp_i),
|
||||
.src_rst_n_i (rst_hp_n_i),
|
||||
.dst_clk_i (clk_lp_i),
|
||||
.dst_rst_n_i (rst_lp_n_i),
|
||||
.clear_i (flush_i),
|
||||
.clear_busy_o(s_target_clear_busy[target]),
|
||||
.epoch_o (unused_target_epoch[target]),
|
||||
.src_axi4 (u_target_hp_axi4[target]),
|
||||
.dst_axi4 (u_gateway_lp_axi4[target])
|
||||
localparam logic [31:0] TargetTimeout = (target == 0) ? 32'd256 :
|
||||
(target == 1) ? 32'd8192 : 32'd65535;
|
||||
|
||||
axi4_target_guard #(
|
||||
.ReadDepth (target < 2 ? 4 : 2),
|
||||
.WriteDepth(2)
|
||||
) u_target_guard (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.clear_i (flush_i),
|
||||
.timeout_i (TargetTimeout),
|
||||
.clear_busy_o (s_guard_clear_busy[target]),
|
||||
.abort_o (s_guard_abort[target]),
|
||||
.abort_done_i (s_guard_abort_done[target]),
|
||||
.timeout_valid_o(s_guard_timeout_valid[target]),
|
||||
.timeout_write_o(s_guard_timeout_write[target]),
|
||||
.timeout_id_o (s_guard_timeout_id[target]),
|
||||
.timeout_addr_o (s_guard_timeout_addr[target]),
|
||||
.source (u_crossbar_target_axi4[target]),
|
||||
.sink (u_target_axi4[target])
|
||||
);
|
||||
if (target == 0) begin : gen_native_sram
|
||||
axi4_connector u_sram_gateway_connector (
|
||||
.source(u_target_axi4[target]),
|
||||
.sink (sram_gateway_axi4)
|
||||
);
|
||||
assign s_target_clear_busy[target] = 1'b0;
|
||||
assign unused_target_epoch[target] = 8'd0;
|
||||
end else if (target == 1) begin : gen_native_sdram
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(64),
|
||||
.IdWidth (6)
|
||||
) u_target_cdc (
|
||||
.src_clk_i (clk_hp_i),
|
||||
.src_rst_n_i (rst_hp_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i (rst_mem_n_i),
|
||||
.clear_i (flush_i || s_guard_abort[target]),
|
||||
.clear_busy_o(s_target_clear_busy[target]),
|
||||
.epoch_o (unused_target_epoch[target]),
|
||||
.src_axi4 (u_target_axi4[target]),
|
||||
.dst_axi4 (u_sdram_mem_axi4)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_abort_sync (
|
||||
.clk_i (clk_mem_i),
|
||||
.rst_n_i(rst_mem_n_i),
|
||||
.dat_i (s_guard_abort[target]),
|
||||
.dat_o (s_sdram_abort_mem)
|
||||
);
|
||||
axi4_downsizer_64to32 #(
|
||||
.WideIdWidth(6)
|
||||
) u_target_downsizer (
|
||||
.clk_i (clk_mem_i),
|
||||
.rst_n_i(rst_mem_n_i),
|
||||
.clear_i(s_sdram_abort_mem),
|
||||
.wide (u_sdram_mem_axi4),
|
||||
.narrow (sdram_gateway_axi4)
|
||||
);
|
||||
end else begin : gen_legacy_memory
|
||||
axi4_downsizer_64to32 #(
|
||||
.WideIdWidth(6)
|
||||
) u_target_downsizer (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i(rst_hp_n_i),
|
||||
.clear_i(s_guard_abort[target]),
|
||||
.wide (u_target_axi4[target]),
|
||||
.narrow (u_target_hp_axi4[target])
|
||||
);
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_target_cdc (
|
||||
.src_clk_i (clk_hp_i),
|
||||
.src_rst_n_i (rst_hp_n_i),
|
||||
.dst_clk_i (clk_lp_i),
|
||||
.dst_rst_n_i (rst_lp_n_i),
|
||||
.clear_i (flush_i || s_guard_abort[target]),
|
||||
.clear_busy_o(s_target_clear_busy[target]),
|
||||
.epoch_o (unused_target_epoch[target]),
|
||||
.src_axi4 (u_target_hp_axi4[target]),
|
||||
.dst_axi4 (u_gateway_lp_axi4[target])
|
||||
);
|
||||
end
|
||||
end
|
||||
|
||||
axi4_error_slave #(
|
||||
@@ -377,23 +512,52 @@ module soc_data_plane (
|
||||
) u_data_error_slave (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i(rst_hp_n_i),
|
||||
.axi4 (u_target_axi4[5])
|
||||
.axi4 (u_crossbar_target_axi4[5])
|
||||
);
|
||||
|
||||
for (genvar target = 0; target < NumMemoryTargets; target++) begin : gen_abort_handshake
|
||||
assign s_guard_abort_done[target] = (target == 0) ? s_guard_abort[target] :
|
||||
s_guard_abort[target] && s_guard_abort_seen_q[target] &&
|
||||
!s_target_clear_busy[target];
|
||||
|
||||
always_ff @(posedge clk_hp_i or negedge rst_hp_n_i) begin
|
||||
if (!rst_hp_n_i) begin
|
||||
s_guard_abort_seen_q[target] <= 1'b0;
|
||||
end else if (!s_guard_abort[target]) begin
|
||||
s_guard_abort_seen_q[target] <= 1'b0;
|
||||
end else if (s_target_clear_busy[target]) begin
|
||||
s_guard_abort_seen_q[target] <= 1'b1;
|
||||
end
|
||||
end
|
||||
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;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign flush_busy_o = (|s_io_clear_busy) || (|s_target_clear_busy) ||
|
||||
s_lp_clear_busy || s_ext_clear_busy;
|
||||
(|s_guard_clear_busy) || s_lp_clear_busy || s_ext_clear_busy;
|
||||
assign s_unused_epoch = {
|
||||
^unused_io_epoch, ^unused_target_epoch, ^{unused_lp_epoch, unused_ext_epoch}
|
||||
};
|
||||
|
||||
axi4_connector u_sram_gateway_connector (
|
||||
.source(u_gateway_lp_axi4[0]),
|
||||
.sink (sram_gateway_axi4)
|
||||
);
|
||||
axi4_connector u_sdram_gateway_connector (
|
||||
.source(u_gateway_lp_axi4[1]),
|
||||
.sink (sdram_gateway_axi4)
|
||||
);
|
||||
axi4_connector u_qpi_gateway_connector (
|
||||
.source(u_gateway_lp_axi4[2]),
|
||||
.sink (qpi_gateway_axi4)
|
||||
|
||||
@@ -285,6 +285,7 @@
|
||||
"axi4_async_bridge.sv",
|
||||
"axi4_connector.sv",
|
||||
"axi4_data_crossbar.sv",
|
||||
"axi4_target_guard.sv",
|
||||
"axi4_downsizer_64to32.sv",
|
||||
"axi4_error_slave.sv",
|
||||
"axi4_id_prefix.sv",
|
||||
@@ -314,6 +315,7 @@
|
||||
"onchip_ram.sv",
|
||||
"pll_rcu_controller.sv",
|
||||
"rcu.sv",
|
||||
"resource_controller.sv",
|
||||
"retrosoc.sv",
|
||||
"retrosoc_asic.sv",
|
||||
"retrosoc_core.sv",
|
||||
|
||||
@@ -142,7 +142,7 @@ def build(args: argparse.Namespace) -> None:
|
||||
f"PLATFORM_DIR={external / 'opensbi'}",
|
||||
"PLATFORM_RISCV_XLEN=32",
|
||||
"PLATFORM_RISCV_ABI=ilp32d",
|
||||
"PLATFORM_RISCV_ISA=rv32imafdc_zicsr_zifencei",
|
||||
"PLATFORM_RISCV_ISA=rv32imafdc_zicbom_zicsr_zifencei",
|
||||
"FW_TEXT_START=0x38000000",
|
||||
"FW_JUMP=y",
|
||||
"FW_JUMP_ADDR=0x38400000",
|
||||
|
||||
@@ -18,7 +18,7 @@ def build(args: argparse.Namespace) -> None:
|
||||
subprocess.run(
|
||||
[
|
||||
compiler,
|
||||
"-march=rv32imafdc_zicsr_zifencei",
|
||||
"-march=rv32imafdc_zicbom_zicsr_zifencei",
|
||||
"-mabi=ilp32d",
|
||||
"-nostdlib",
|
||||
"-nostartfiles",
|
||||
|
||||
@@ -86,7 +86,7 @@ def generate(args: argparse.Namespace) -> None:
|
||||
manifest = {
|
||||
"schema_version": 1,
|
||||
"module": GENERATED_MODULE,
|
||||
"configuration": "rv32imafdc_max",
|
||||
"configuration": "rv32imafdc_zicbom_max",
|
||||
"vexiiriscv_revision": actual,
|
||||
"source_status": git_status(source),
|
||||
"submodules": submodules,
|
||||
|
||||
+14
-5
@@ -16,16 +16,25 @@ from scripts.check_c_warnings import self_owned_warnings # noqa: E402
|
||||
|
||||
|
||||
CI_SMOKE_APP_VALUE = "APP=ci_smoke"
|
||||
CI_SMOKE_SIM_VALUES = (
|
||||
CI_SMOKE_APP_VALUE,
|
||||
"LINK_TYPE=ld2_all_sram",
|
||||
CI_SMOKE_VERILATOR_VALUES = (
|
||||
"VERILATOR_SIM_ARGS=--fast-flash",
|
||||
"SOC_SIM_TIME=360",
|
||||
"SIMU=VERILATOR",
|
||||
"HAVE_SVA=YES",
|
||||
"firmware",
|
||||
"sim",
|
||||
)
|
||||
CI_SMOKE_SIM_VALUES = (
|
||||
CI_SMOKE_APP_VALUE,
|
||||
"LINK_TYPE=ld2_all_sram",
|
||||
"SOC_SIM_TIME=360",
|
||||
*CI_SMOKE_VERILATOR_VALUES,
|
||||
)
|
||||
CI_SMOKE_SDRAM_SIM_VALUES = (
|
||||
CI_SMOKE_APP_VALUE,
|
||||
"LINK_TYPE=ld2_sdram",
|
||||
"SOC_SIM_TIME=600",
|
||||
*CI_SMOKE_VERILATOR_VALUES,
|
||||
)
|
||||
RTL_LINT_VALUES = ("SIMU=VERILATOR", "HAVE_SVA=YES", "rtl-lint")
|
||||
RTL_LINT_OBSERVATION_VALUES = (
|
||||
"SIMU=VERILATOR",
|
||||
@@ -106,7 +115,7 @@ def pdk_pr_commands(profile: str) -> tuple[tuple[str, tuple[str, ...]], ...]:
|
||||
verilator_values = (
|
||||
CI_SMOKE_SIM_VALUES
|
||||
if profile == "configs/ci/ihp130.mk"
|
||||
else (CI_SMOKE_APP_VALUE, "SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim")
|
||||
else CI_SMOKE_SDRAM_SIM_VALUES
|
||||
)
|
||||
return (
|
||||
(profile, RTL_LINT_VALUES),
|
||||
|
||||
@@ -34,6 +34,7 @@ TEST_SOURCES = (
|
||||
"crt/src/hal/dma_math.c",
|
||||
"crt/src/hal/sysctrl.c",
|
||||
"crt/src/hal/clock.c",
|
||||
"crt/src/hal/resource.c",
|
||||
"crt/src/hal/extension.c",
|
||||
"crt/src/hal/user_ip.c",
|
||||
"rtl/managed/clusterip/ps2/sw/src/ps2.c",
|
||||
|
||||
@@ -20,7 +20,7 @@ object GenerateRetroSocHp extends App {
|
||||
param.physicalWidth = 32
|
||||
param.resetVector = 0x38000000L
|
||||
param.asidWidth = 9
|
||||
param.addISA("m", "a", "f", "d", "c", "s", "u", "zicntr", "zihpm")
|
||||
param.addISA("m", "a", "f", "d", "c", "s", "u", "zicbom", "zicntr", "zihpm")
|
||||
param.fixIsaParams()
|
||||
|
||||
param.decoders = 2
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <retrosoc/hal/lcd.h>
|
||||
#include <retrosoc/hal/i2s.h>
|
||||
#include <retrosoc/hal/psram.h>
|
||||
#include <retrosoc/hal/resource.h>
|
||||
#include <retrosoc/hal/sdram.h>
|
||||
#include <retrosoc/hal/sdio.h>
|
||||
#include <retrosoc/hal/spisd.h>
|
||||
@@ -846,6 +847,22 @@ static int test_extension_validation(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_resource_validation(void) {
|
||||
rs_resource_status_t status;
|
||||
|
||||
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) !=
|
||||
RS_EINVAL) ||
|
||||
(rs_resource_set_owner(RS_RESOURCE_DMA, (rs_resource_owner_t)2, false) != RS_EINVAL) ||
|
||||
(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 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_ps2_decoders(void) {
|
||||
ps2_keyboard_decoder_t keyboard;
|
||||
ps2_mouse_decoder_t mouse;
|
||||
@@ -935,6 +952,7 @@ int main(void) {
|
||||
test_opipsram_helpers(),
|
||||
test_user_ip_validation(),
|
||||
test_extension_validation(),
|
||||
test_resource_validation(),
|
||||
test_ps2_decoders(),
|
||||
test_wav_parser(),
|
||||
test_video_parser(),
|
||||
|
||||
@@ -7,6 +7,8 @@ module axi4_data_crossbar_tb;
|
||||
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 [ 7:0] outstanding_read_o;
|
||||
logic [ 7:0] outstanding_write_o;
|
||||
logic fault_valid_o;
|
||||
@@ -46,6 +48,7 @@ module axi4_data_crossbar_tb;
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.block_new_i (1'b0),
|
||||
.master_block_i (master_block_i),
|
||||
.recovery_i (1'b0),
|
||||
.mem_pad_mode_i (2'd1),
|
||||
.ext_h_read_base_i (32'h3000_0000),
|
||||
@@ -55,6 +58,7 @@ module axi4_data_crossbar_tb;
|
||||
.masters (masters),
|
||||
.targets (targets),
|
||||
.idle_o (idle_o),
|
||||
.master_idle_o (master_idle_o),
|
||||
.outstanding_read_o (outstanding_read_o),
|
||||
.outstanding_write_o(outstanding_write_o),
|
||||
.fault_valid_o (fault_valid_o),
|
||||
@@ -172,6 +176,18 @@ module axi4_data_crossbar_tb;
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
@(negedge clk_i);
|
||||
master_block_i[1] = 1'b1;
|
||||
masters[1].arid = 6'b001_111;
|
||||
masters[1].araddr = 32'h3000_0000;
|
||||
masters[1].arvalid = 1'b1;
|
||||
#1;
|
||||
if (masters[1].arready || master_idle_o[1]) begin
|
||||
$fatal(1, "blocked master was accepted or reported idle with VALID held");
|
||||
end
|
||||
masters[1].arvalid = 1'b0;
|
||||
master_block_i[1] = 1'b0;
|
||||
|
||||
issue_master1_read(6'b001_000, 32'h3000_0000);
|
||||
issue_master1_read(6'b001_001, 32'h3800_0000);
|
||||
if (outstanding_read_o != 8'd2 || idle_o) begin
|
||||
@@ -201,6 +217,35 @@ module axi4_data_crossbar_tb;
|
||||
$fatal(1, "read completion did not drain the crossbar");
|
||||
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
|
||||
$fatal(1, "same-target reads were not tracked concurrently");
|
||||
end
|
||||
fork
|
||||
return_target0_read(6'b001_011, 64'h3333_3333_3333_3333);
|
||||
begin
|
||||
wait (masters[1].rvalid);
|
||||
if ((masters[1].rid != 6'b001_011) || (masters[1].rdata != 64'h3333_3333_3333_3333)) begin
|
||||
$fatal(1, "same-target out-of-order response was misrouted");
|
||||
end
|
||||
end
|
||||
join
|
||||
@(posedge clk_i);
|
||||
fork
|
||||
return_target0_read(6'b001_010, 64'h4444_4444_4444_4444);
|
||||
begin
|
||||
wait (masters[1].rvalid);
|
||||
if ((masters[1].rid != 6'b001_010) || (masters[1].rdata != 64'h4444_4444_4444_4444)) begin
|
||||
$fatal(1, "same-target older response was misrouted");
|
||||
end
|
||||
end
|
||||
join
|
||||
@(negedge clk_i);
|
||||
if (!idle_o || (outstanding_read_o != 8'd0)) begin
|
||||
$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;
|
||||
|
||||
@@ -30,6 +30,7 @@ module axi4_downsizer_64to32_tb;
|
||||
axi4_downsizer_64to32 u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.clear_i(1'b0),
|
||||
.wide (wide),
|
||||
.narrow (narrow)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module axi4_target_guard_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic abort_o;
|
||||
logic timeout_valid_o;
|
||||
logic timeout_write_o;
|
||||
logic [ 5:0] timeout_id_o;
|
||||
logic [31:0] timeout_addr_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) source (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) sink (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
axi4_target_guard #(
|
||||
.ReadDepth (4),
|
||||
.WriteDepth(2)
|
||||
) u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.clear_i (1'b0),
|
||||
.timeout_i (32'd4),
|
||||
.clear_busy_o (),
|
||||
.abort_o (abort_o),
|
||||
.abort_done_i (abort_o),
|
||||
.timeout_valid_o(timeout_valid_o),
|
||||
.timeout_write_o(timeout_write_o),
|
||||
.timeout_id_o (timeout_id_o),
|
||||
.timeout_addr_o (timeout_addr_o),
|
||||
.source (source),
|
||||
.sink (sink)
|
||||
);
|
||||
|
||||
task automatic issue_read(input logic [5:0] id, input logic [7:0] len, input logic [31:0] addr);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
source.arid = id;
|
||||
source.arlen = len;
|
||||
source.araddr = addr;
|
||||
source.arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!source.arready);
|
||||
@(negedge clk_i);
|
||||
source.arvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic expect_error_read(input logic [5:0] id, input int unsigned beats);
|
||||
begin
|
||||
for (int beat = 0; beat < beats; beat++) begin
|
||||
do @(posedge clk_i); while (!source.rvalid);
|
||||
if ((source.rid != id) || (source.rresp != 2'b10) ||
|
||||
(source.rlast != (beat == beats - 1))) begin
|
||||
$fatal(1, "target guard synthetic read response mismatch");
|
||||
end
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
source.awid = '0;
|
||||
source.awaddr = '0;
|
||||
source.awlen = '0;
|
||||
source.awsize = 3'd3;
|
||||
source.awburst = 2'b01;
|
||||
source.awlock = 1'b0;
|
||||
source.awcache = '0;
|
||||
source.awprot = '0;
|
||||
source.awqos = '0;
|
||||
source.awregion = '0;
|
||||
source.awuser = '0;
|
||||
source.awvalid = 1'b0;
|
||||
source.wdata = '0;
|
||||
source.wstrb = '0;
|
||||
source.wlast = 1'b1;
|
||||
source.wuser = '0;
|
||||
source.wvalid = 1'b0;
|
||||
source.bready = 1'b1;
|
||||
source.arid = '0;
|
||||
source.araddr = '0;
|
||||
source.arlen = '0;
|
||||
source.arsize = 3'd3;
|
||||
source.arburst = 2'b01;
|
||||
source.arlock = 1'b0;
|
||||
source.arcache = '0;
|
||||
source.arprot = '0;
|
||||
source.arqos = '0;
|
||||
source.arregion = '0;
|
||||
source.aruser = '0;
|
||||
source.arvalid = 1'b0;
|
||||
source.rready = 1'b1;
|
||||
|
||||
sink.awready = 1'b1;
|
||||
sink.wready = 1'b1;
|
||||
sink.bid = '0;
|
||||
sink.bresp = '0;
|
||||
sink.buser = '0;
|
||||
sink.bvalid = 1'b0;
|
||||
sink.arready = 1'b1;
|
||||
sink.rid = '0;
|
||||
sink.rdata = '0;
|
||||
sink.rresp = '0;
|
||||
sink.rlast = 1'b0;
|
||||
sink.ruser = '0;
|
||||
sink.rvalid = 1'b0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
issue_read(6'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
|
||||
$fatal(1, "target guard read timeout attribution mismatch");
|
||||
end
|
||||
expect_error_read(6'h09, 2);
|
||||
|
||||
fork
|
||||
begin
|
||||
issue_read(6'h0A, 8'd0, 32'h3800_0080);
|
||||
expect_error_read(6'h0A, 1);
|
||||
end
|
||||
begin
|
||||
repeat (12) begin
|
||||
@(posedge clk_i);
|
||||
if (sink.arvalid) $fatal(1, "isolated target accepted a new read");
|
||||
end
|
||||
end
|
||||
join
|
||||
|
||||
@(negedge clk_i);
|
||||
source.awid = 6'h0B;
|
||||
source.awaddr = 32'h3800_0100;
|
||||
source.awvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!source.awready);
|
||||
@(negedge clk_i);
|
||||
source.awvalid = 1'b0;
|
||||
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 != 6'h0B) || (source.bresp != 2'b10) || sink.awvalid || sink.wvalid) begin
|
||||
$fatal(1, "isolated target write termination mismatch");
|
||||
end
|
||||
|
||||
$display("AXI4 target guard timeout and isolation test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat (200) @(posedge clk_i);
|
||||
$fatal(1, "AXI4 target guard test timed out");
|
||||
end
|
||||
endmodule
|
||||
@@ -6,26 +6,30 @@ module hp_lifecycle_controller_tb;
|
||||
logic release_req_i = 1'b0;
|
||||
logic hp_idle_i = 1'b0;
|
||||
logic flush_busy_i = 1'b0;
|
||||
logic cache_clean_i = 1'b0;
|
||||
logic hp_release_o;
|
||||
logic block_new_o;
|
||||
logic flush_o;
|
||||
logic cache_request_o;
|
||||
logic draining_o;
|
||||
logic forced_fault_o;
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
hp_lifecycle_controller u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.release_req_i (release_req_i),
|
||||
.hp_idle_i (hp_idle_i),
|
||||
.flush_busy_i (flush_busy_i),
|
||||
.timeout_i (16'd4),
|
||||
.hp_release_o (hp_release_o),
|
||||
.block_new_o (block_new_o),
|
||||
.flush_o (flush_o),
|
||||
.draining_o (draining_o),
|
||||
.forced_fault_o(forced_fault_o)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.release_req_i (release_req_i),
|
||||
.hp_idle_i (hp_idle_i),
|
||||
.flush_busy_i (flush_busy_i),
|
||||
.cache_clean_i (cache_clean_i),
|
||||
.timeout_i (16'd4),
|
||||
.hp_release_o (hp_release_o),
|
||||
.block_new_o (block_new_o),
|
||||
.flush_o (flush_o),
|
||||
.cache_request_o(cache_request_o),
|
||||
.draining_o (draining_o),
|
||||
.forced_fault_o (forced_fault_o)
|
||||
);
|
||||
|
||||
task automatic complete_flush;
|
||||
@@ -50,6 +54,14 @@ module hp_lifecycle_controller_tb;
|
||||
|
||||
@(negedge clk_i);
|
||||
release_req_i = 1'b0;
|
||||
wait (cache_request_o);
|
||||
if (block_new_o || !hp_release_o) begin
|
||||
$fatal(1, "cache-maintenance phase blocked HP before acknowledgement");
|
||||
end
|
||||
cache_clean_i = 1'b1;
|
||||
@(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
cache_clean_i = 1'b0;
|
||||
repeat (2) @(negedge clk_i);
|
||||
if (!block_new_o || !draining_o || !hp_release_o) begin
|
||||
$fatal(1, "normal shutdown did not enter drain while HP remained released");
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "axi4_define.svh"
|
||||
`include "mmap_define.svh"
|
||||
|
||||
module onchip_ram64_tb #(
|
||||
parameter int unsigned CapacityKiB = 32
|
||||
);
|
||||
localparam logic [31:0] SramBase = `SOC_ADDR_SRAM_BASE;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) mem_axi4 (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
apb4_if cfg_apb4 (
|
||||
.pclk (clk_i),
|
||||
.presetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
onchip_ram #(
|
||||
.Present (1'b1),
|
||||
.CapacityKiB(CapacityKiB),
|
||||
.DataWidth (64),
|
||||
.IdWidth (6)
|
||||
) u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.perf_enable_i(1'b1),
|
||||
.perf_clear_i (1'b0),
|
||||
.mem_axi4 (mem_axi4),
|
||||
.cfg_apb4 (cfg_apb4)
|
||||
);
|
||||
|
||||
task automatic issue_write(input logic [5: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
|
||||
@(negedge clk_i);
|
||||
mem_axi4.awid = id;
|
||||
mem_axi4.awaddr = address;
|
||||
mem_axi4.awlen = length;
|
||||
mem_axi4.awsize = size;
|
||||
mem_axi4.awvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!mem_axi4.awready);
|
||||
@(negedge clk_i);
|
||||
mem_axi4.awvalid = 1'b0;
|
||||
for (int beat = 0; beat <= int'(length); beat++) begin
|
||||
mem_axi4.wdata = seed + beat;
|
||||
mem_axi4.wstrb = strobe;
|
||||
mem_axi4.wlast = beat == int'(length);
|
||||
mem_axi4.wvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!mem_axi4.wready);
|
||||
@(negedge clk_i);
|
||||
end
|
||||
mem_axi4.wvalid = 1'b0;
|
||||
mem_axi4.wlast = 1'b0;
|
||||
mem_axi4.bready = 1'b1;
|
||||
do @(posedge clk_i); while (!mem_axi4.bvalid);
|
||||
if ((mem_axi4.bid != id) || (mem_axi4.bresp != `AXI4_RESP_OKAY)) begin
|
||||
$fatal(1, "AXI64 SRAM write response mismatch");
|
||||
end
|
||||
@(negedge clk_i);
|
||||
mem_axi4.bready = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic expect_read(input logic [5:0] id, input logic [31:0] address,
|
||||
input logic [7:0] length, input logic [63:0] seed);
|
||||
integer previous_cycle;
|
||||
integer cycle_count;
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
mem_axi4.arid = id;
|
||||
mem_axi4.araddr = address;
|
||||
mem_axi4.arlen = length;
|
||||
mem_axi4.arsize = 3'd3;
|
||||
mem_axi4.arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!mem_axi4.arready);
|
||||
@(negedge clk_i);
|
||||
mem_axi4.arvalid = 1'b0;
|
||||
mem_axi4.rready = 1'b1;
|
||||
previous_cycle = -1;
|
||||
cycle_count = 0;
|
||||
for (int beat = 0; beat <= int'(length); beat++) begin
|
||||
do begin
|
||||
@(posedge clk_i);
|
||||
cycle_count = cycle_count + 1;
|
||||
end while (!mem_axi4.rvalid);
|
||||
if ((mem_axi4.rid != id) || (mem_axi4.rresp != `AXI4_RESP_OKAY) ||
|
||||
(mem_axi4.rlast != (beat == int'(length))) ||
|
||||
(mem_axi4.rdata != (seed + beat))) begin
|
||||
$fatal(1, "AXI64 SRAM read response mismatch at beat %0d", beat);
|
||||
end
|
||||
if ((previous_cycle >= 0) && (cycle_count != previous_cycle + 1)) begin
|
||||
$fatal(1, "AXI64 SRAM read burst inserted a bubble at beat %0d", beat);
|
||||
end
|
||||
previous_cycle = cycle_count;
|
||||
end
|
||||
@(negedge clk_i);
|
||||
mem_axi4.rready = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
mem_axi4.awid = '0;
|
||||
mem_axi4.awaddr = '0;
|
||||
mem_axi4.awlen = '0;
|
||||
mem_axi4.awsize = 3'd3;
|
||||
mem_axi4.awburst = `AXI4_BURST_TYPE_INCR;
|
||||
mem_axi4.awlock = `AXI4_LOCK_NORM;
|
||||
mem_axi4.awcache = `AXI4_CACHE_NO_BUF;
|
||||
mem_axi4.awprot = `AXI4_PROT_DATA;
|
||||
mem_axi4.awqos = `AXI4_QOS_NORMAL;
|
||||
mem_axi4.awregion = `AXI4_REGION_NORMAL;
|
||||
mem_axi4.awuser = '0;
|
||||
mem_axi4.awvalid = 1'b0;
|
||||
mem_axi4.wdata = '0;
|
||||
mem_axi4.wstrb = '0;
|
||||
mem_axi4.wlast = 1'b0;
|
||||
mem_axi4.wuser = '0;
|
||||
mem_axi4.wvalid = 1'b0;
|
||||
mem_axi4.bready = 1'b0;
|
||||
mem_axi4.arid = '0;
|
||||
mem_axi4.araddr = '0;
|
||||
mem_axi4.arlen = '0;
|
||||
mem_axi4.arsize = 3'd3;
|
||||
mem_axi4.arburst = `AXI4_BURST_TYPE_INCR;
|
||||
mem_axi4.arlock = `AXI4_LOCK_NORM;
|
||||
mem_axi4.arcache = `AXI4_CACHE_NO_BUF;
|
||||
mem_axi4.arprot = `AXI4_PROT_DATA;
|
||||
mem_axi4.arqos = `AXI4_QOS_NORMAL;
|
||||
mem_axi4.arregion = `AXI4_REGION_NORMAL;
|
||||
mem_axi4.aruser = '0;
|
||||
mem_axi4.arvalid = 1'b0;
|
||||
mem_axi4.rready = 1'b0;
|
||||
cfg_apb4.paddr = '0;
|
||||
cfg_apb4.pprot = '0;
|
||||
cfg_apb4.psel = 1'b0;
|
||||
cfg_apb4.penable = 1'b0;
|
||||
cfg_apb4.pwrite = 1'b0;
|
||||
cfg_apb4.pwdata = '0;
|
||||
cfg_apb4.pstrb = '0;
|
||||
|
||||
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);
|
||||
|
||||
$display("native AXI64 on-chip SRAM test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat (400) @(posedge clk_i);
|
||||
$fatal(1, "native AXI64 on-chip SRAM test timed out");
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,146 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module resource_controller_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic [ 5:0] idle_i = '0;
|
||||
logic [ 5:0] block_ack_i = '0;
|
||||
logic [ 5:0] irq_i = '0;
|
||||
logic cache_request_i = 1'b0;
|
||||
logic cache_clean_o;
|
||||
logic [ 5:0][1:0] owner_o;
|
||||
logic [ 5:0] quiesce_o;
|
||||
logic [ 5:0] reset_o;
|
||||
logic [ 5:0] irq_lp_o;
|
||||
logic [ 5:0] irq_hp_o;
|
||||
logic fault_irq_o;
|
||||
logic [31:0] read_data;
|
||||
|
||||
apb4_if apb4 (
|
||||
.pclk (clk_i),
|
||||
.presetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
resource_controller u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.idle_i (idle_i),
|
||||
.block_ack_i (block_ack_i),
|
||||
.irq_i (irq_i),
|
||||
.cache_request_i(cache_request_i),
|
||||
.cache_clean_o (cache_clean_o),
|
||||
.owner_o (owner_o),
|
||||
.quiesce_o (quiesce_o),
|
||||
.reset_o (reset_o),
|
||||
.irq_lp_o (irq_lp_o),
|
||||
.irq_hp_o (irq_hp_o),
|
||||
.fault_irq_o (fault_irq_o),
|
||||
.apb4 (apb4)
|
||||
);
|
||||
|
||||
task automatic apb_write(input logic [11:0] offset, input logic [31:0] data,
|
||||
input logic expected_error);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, offset};
|
||||
apb4.pwrite = 1'b1;
|
||||
apb4.pwdata = data;
|
||||
apb4.pstrb = 4'hF;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
do @(posedge clk_i); while (!apb4.pready);
|
||||
if (apb4.pslverr != expected_error) begin
|
||||
$fatal(1, "resource controller write error mismatch at %h", offset);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic apb_read(input logic [11:0] offset, output logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, offset};
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
do @(posedge clk_i); while (!apb4.pready);
|
||||
if (apb4.pslverr) $fatal(1, "resource controller read failed at %h", offset);
|
||||
data = apb4.prdata;
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
apb4.paddr = '0;
|
||||
apb4.pprot = '0;
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pwdata = '0;
|
||||
apb4.pstrb = '0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
idle_i = 6'h3F;
|
||||
|
||||
apb_read(12'h000, read_data);
|
||||
if (read_data != 32'h5253_4354) $fatal(1, "resource controller ID mismatch");
|
||||
|
||||
irq_i[1] = 1'b1;
|
||||
#1;
|
||||
if (!irq_lp_o[1] || irq_hp_o[1]) $fatal(1, "default LP IRQ ownership mismatch");
|
||||
|
||||
idle_i[0] = 1'b0;
|
||||
block_ack_i[0] = 1'b1;
|
||||
apb_write(12'h104, 32'h0000_0001, 1'b0);
|
||||
apb_write(12'h100, 32'h0000_0001, 1'b1);
|
||||
if (!fault_irq_o || (owner_o[0] != 2'd0)) begin
|
||||
$fatal(1, "busy resource handoff did not fail closed");
|
||||
end
|
||||
apb_write(12'h10C, 32'h0000_0001, 1'b0);
|
||||
if (fault_irq_o) $fatal(1, "resource fault did not clear");
|
||||
|
||||
idle_i[0] = 1'b1;
|
||||
irq_i[0] = 1'b1;
|
||||
apb_write(12'h100, 32'h0000_0001, 1'b0);
|
||||
if ((owner_o[0] != 2'd1) || irq_lp_o[0] || !irq_hp_o[0]) begin
|
||||
$fatal(1, "HP resource ownership or IRQ routing mismatch");
|
||||
end
|
||||
apb_read(12'h110, read_data);
|
||||
if (read_data != 32'd1) $fatal(1, "resource handoff counter mismatch");
|
||||
|
||||
apb_write(12'h100, 32'h0000_0101, 1'b0);
|
||||
apb_write(12'h100, 32'h0000_0000, 1'b1);
|
||||
if (owner_o[0] != 2'd1) $fatal(1, "locked resource owner changed");
|
||||
|
||||
cache_request_i = 1'b1;
|
||||
apb_write(12'h010, 32'h0000_0001, 1'b0);
|
||||
if (!cache_clean_o) $fatal(1, "cache maintenance acknowledgement was not retained");
|
||||
cache_request_i = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (cache_clean_o) $fatal(1, "cache acknowledgement did not clear with request");
|
||||
|
||||
apb_write(12'h124, 32'h0000_0003, 1'b0);
|
||||
if (!quiesce_o[1] || !reset_o[1]) begin
|
||||
$fatal(1, "resource lifecycle controls did not update");
|
||||
end
|
||||
|
||||
$display("Resource Controller ownership, IRQ, and cache handshake test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat (300) @(posedge clk_i);
|
||||
$fatal(1, "Resource Controller test timed out");
|
||||
end
|
||||
endmodule
|
||||
+48
-43
@@ -20,54 +20,59 @@ module rib2apb_tb;
|
||||
apb4_pure_if user_ip ();
|
||||
apb4_pure_if ext_l ();
|
||||
apb4_pure_if ext_h ();
|
||||
apb4_pure_if resource_ctrl ();
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
assign archinfo.pready = 1'b0;
|
||||
assign archinfo.prdata = '0;
|
||||
assign archinfo.pslverr = 1'b0;
|
||||
assign rng.pready = rng_ready;
|
||||
assign rng.prdata = rng_rdata;
|
||||
assign rng.pslverr = rng_slverr;
|
||||
assign pwm.pready = 1'b0;
|
||||
assign pwm.prdata = '0;
|
||||
assign pwm.pslverr = 1'b0;
|
||||
assign ps2.pready = 1'b0;
|
||||
assign ps2.prdata = '0;
|
||||
assign ps2.pslverr = 1'b0;
|
||||
assign rtc.pready = 1'b0;
|
||||
assign rtc.prdata = '0;
|
||||
assign rtc.pslverr = 1'b0;
|
||||
assign wdg.pready = 1'b0;
|
||||
assign wdg.prdata = '0;
|
||||
assign wdg.pslverr = 1'b0;
|
||||
assign crc.pready = 1'b0;
|
||||
assign crc.prdata = '0;
|
||||
assign crc.pslverr = 1'b0;
|
||||
assign user_ip.pready = 1'b0;
|
||||
assign user_ip.prdata = '0;
|
||||
assign user_ip.pslverr = 1'b0;
|
||||
assign ext_l.pready = 1'b0;
|
||||
assign ext_l.prdata = '0;
|
||||
assign ext_l.pslverr = 1'b0;
|
||||
assign ext_h.pready = 1'b0;
|
||||
assign ext_h.prdata = '0;
|
||||
assign ext_h.pslverr = 1'b0;
|
||||
assign archinfo.pready = 1'b0;
|
||||
assign archinfo.prdata = '0;
|
||||
assign archinfo.pslverr = 1'b0;
|
||||
assign rng.pready = rng_ready;
|
||||
assign rng.prdata = rng_rdata;
|
||||
assign rng.pslverr = rng_slverr;
|
||||
assign pwm.pready = 1'b0;
|
||||
assign pwm.prdata = '0;
|
||||
assign pwm.pslverr = 1'b0;
|
||||
assign ps2.pready = 1'b0;
|
||||
assign ps2.prdata = '0;
|
||||
assign ps2.pslverr = 1'b0;
|
||||
assign rtc.pready = 1'b0;
|
||||
assign rtc.prdata = '0;
|
||||
assign rtc.pslverr = 1'b0;
|
||||
assign wdg.pready = 1'b0;
|
||||
assign wdg.prdata = '0;
|
||||
assign wdg.pslverr = 1'b0;
|
||||
assign crc.pready = 1'b0;
|
||||
assign crc.prdata = '0;
|
||||
assign crc.pslverr = 1'b0;
|
||||
assign user_ip.pready = 1'b0;
|
||||
assign user_ip.prdata = '0;
|
||||
assign user_ip.pslverr = 1'b0;
|
||||
assign ext_l.pready = 1'b0;
|
||||
assign ext_l.prdata = '0;
|
||||
assign ext_l.pslverr = 1'b0;
|
||||
assign ext_h.pready = 1'b0;
|
||||
assign ext_h.prdata = '0;
|
||||
assign ext_h.pslverr = 1'b0;
|
||||
assign resource_ctrl.pready = 1'b0;
|
||||
assign resource_ctrl.prdata = '0;
|
||||
assign resource_ctrl.pslverr = 1'b0;
|
||||
|
||||
rib2apb u_rib2apb (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.rib (rib),
|
||||
.archinfo(archinfo),
|
||||
.rng (rng),
|
||||
.pwm (pwm),
|
||||
.ps2 (ps2),
|
||||
.rtc (rtc),
|
||||
.wdg (wdg),
|
||||
.crc (crc),
|
||||
.user_ip (user_ip),
|
||||
.ext_l (ext_l),
|
||||
.ext_h (ext_h)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.rib (rib),
|
||||
.archinfo (archinfo),
|
||||
.rng (rng),
|
||||
.pwm (pwm),
|
||||
.ps2 (ps2),
|
||||
.rtc (rtc),
|
||||
.wdg (wdg),
|
||||
.crc (crc),
|
||||
.user_ip (user_ip),
|
||||
.ext_l (ext_l),
|
||||
.ext_h (ext_h),
|
||||
.resource_ctrl(resource_ctrl)
|
||||
);
|
||||
|
||||
task automatic send_command(input logic [31:0] address, input logic write,
|
||||
|
||||
@@ -58,6 +58,7 @@ module soc_irq_topology_tb;
|
||||
4: expect_irq(32'd1 << 16);
|
||||
5: expect_irq(32'd1 << 27);
|
||||
6: expect_irq(32'd1 << 28);
|
||||
7: expect_irq(32'd1 << 29);
|
||||
default: $fatal(1, "unexpected APB IRQ bit %0d", bit_index);
|
||||
endcase
|
||||
end
|
||||
@@ -68,7 +69,7 @@ module soc_irq_topology_tb;
|
||||
$fatal(1, "SDIO core IRQ bits are not low when sources are low: IRQ10=%b IRQ21=%b",
|
||||
s_irq[10], s_irq[21]);
|
||||
end
|
||||
if ((s_irq[31:29] !== '0) || (s_irq[19:18] !== '0)) begin
|
||||
if ((s_irq[31:30] !== '0) || (s_irq[19:18] !== '0)) begin
|
||||
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq);
|
||||
end
|
||||
|
||||
|
||||
@@ -271,6 +271,7 @@ def test_axi4_data_crossbar_supports_cross_target_outstanding_and_acl(tmp_path:
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/stream/round_robin_arbiter.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_data_crossbar.sv"),
|
||||
str(ROOT / "tests/rtl/axi4_data_crossbar_tb.sv"),
|
||||
"-Mdir",
|
||||
@@ -289,3 +290,43 @@ def test_axi4_data_crossbar_supports_cross_target_outstanding_and_acl(tmp_path:
|
||||
)
|
||||
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||
assert "AXI4 data crossbar concurrency and ACL test passed" in result.stdout
|
||||
|
||||
|
||||
def test_axi4_target_guard_terminates_and_isolates_timeouts(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
output = tmp_path / "axi4_target_guard_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"axi4_target_guard_tb",
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_target_guard.sv"),
|
||||
str(ROOT / "tests/rtl/axi4_target_guard_tb.sv"),
|
||||
"-Mdir",
|
||||
str(tmp_path / "obj"),
|
||||
"-o",
|
||||
str(output),
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
env={
|
||||
**os.environ,
|
||||
"CCACHE_DIR": str(ccache_tmp),
|
||||
"CCACHE_TEMPDIR": str(ccache_tmp),
|
||||
},
|
||||
)
|
||||
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||
assert "AXI4 target guard timeout and isolation test passed" in result.stdout
|
||||
@@ -20,7 +20,7 @@ def test_hp_profile_and_locked_generator_contract() -> None:
|
||||
|
||||
profile = (ROOT / "configs/ci/ihp130-hp.mk").read_text(encoding="utf-8")
|
||||
assert "HAVE_HP" in profile and "YES" in profile
|
||||
assert "rv32imafdc_max" in profile
|
||||
assert "rv32imafdc_zicbom_max" in profile
|
||||
assert "APP" in profile and "hp_boot" in profile
|
||||
assert "LINK_TYPE" in profile and "ld2_all_sram" in profile
|
||||
|
||||
@@ -28,7 +28,7 @@ def test_hp_profile_and_locked_generator_contract() -> None:
|
||||
encoding="utf-8"
|
||||
)
|
||||
for requirement in (
|
||||
'param.addISA("m", "a", "f", "d", "c", "s", "u", "zicntr", "zihpm")',
|
||||
'param.addISA("m", "a", "f", "d", "c", "s", "u", "zicbom", "zicntr", "zihpm")',
|
||||
"param.decoders = 2",
|
||||
"param.lanes = 2",
|
||||
"param.fetchL1Ways = 4",
|
||||
@@ -74,6 +74,7 @@ def test_hp_address_and_sysctrl_contract() -> None:
|
||||
assert regions["HP_PLIC"]["base"] == "0x0C000000"
|
||||
assert regions["APB4_UART1"]["base"] == "0x10018000"
|
||||
assert regions["APB4_HP_MAILBOX"]["base"] == "0x10019000"
|
||||
assert regions["APB4_RESOURCE_CTRL"]["base"] == "0x2000A000"
|
||||
|
||||
registers = {register["symbol"]: register["offset"] for register in document["sysctrl_registers"]}
|
||||
assert registers["HP_CTRL"] == "0xA4"
|
||||
@@ -151,3 +152,6 @@ def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path)
|
||||
).strip()
|
||||
assert initrd_end == "39123456"
|
||||
assert hart_id == "1"
|
||||
dts = (ROOT / "app/ports/linux/linux/retrosoc_hp.dts").read_text(encoding="utf-8")
|
||||
assert '"zicbom"' in dts
|
||||
assert "riscv,cbom-block-size = <64>;" in dts
|
||||
@@ -129,8 +129,14 @@ def test_chip_config_includes_configured_onchip_sram_banks(tmp_path: Path) -> No
|
||||
|
||||
macro = config["MACROS"]["RM_IHPSG13_1P_1024x32_c2_bm_bist"]
|
||||
assert len(macro["instances"]) == 8
|
||||
assert "u_retrosoc.u_onchip_ram.gen_memory.gen_bank[0].u_ram.u_mem" in macro["instances"]
|
||||
assert "u_retrosoc.u_onchip_ram.gen_memory.gen_bank[7].u_ram.u_mem" in macro["instances"]
|
||||
assert (
|
||||
"u_retrosoc.u_onchip_ram.gen_memory64.gen_bank[0].u_ram_lo.u_mem"
|
||||
in macro["instances"]
|
||||
)
|
||||
assert (
|
||||
"u_retrosoc.u_onchip_ram.gen_memory64.gen_bank[3].u_ram_hi.u_mem"
|
||||
in macro["instances"]
|
||||
)
|
||||
assert any(
|
||||
"gen_bank.*0.*\\.u_ram" in connection
|
||||
for connection in config["PDN_MACRO_CONNECTIONS"]
|
||||
|
||||
@@ -84,6 +84,75 @@ def test_onchip_ram_axi4_capacity_protocol_and_performance(
|
||||
assert f"on-chip SRAM AXI4 test passed capacity_kib={capacity_kib}" in result.stdout
|
||||
|
||||
|
||||
@pytest.mark.parametrize("capacity_kib", (4, 32))
|
||||
def test_onchip_ram_native_axi64_width_ids_and_lanes(
|
||||
tmp_path: Path, capacity_kib: int
|
||||
) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
generated = tmp_path / "memory_map"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(ROOT / "rtl/mini/address_map/generate_memory_map.py"),
|
||||
"--map",
|
||||
str(ROOT / "rtl/mini/address_map/memory_map.json"),
|
||||
"--output-dir",
|
||||
str(generated),
|
||||
"--have-sram-if",
|
||||
"YES",
|
||||
"--sram-size-kib",
|
||||
str(capacity_kib),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
output = tmp_path / f"onchip_ram64_{capacity_kib}"
|
||||
ccache_tmp = tmp_path / "ccache64"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"onchip_ram64_tb",
|
||||
f"-GCapacityKiB={capacity_kib}",
|
||||
"+define+PDK_BEHAV",
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
"-I" + str(generated / "rtl"),
|
||||
"-I" + str(ROOT / "rtl/mini/top"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_addr_gen.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/tech/ram.sv"),
|
||||
str(ROOT / "rtl/tech/tc_sram.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram_reg.sv"),
|
||||
str(ROOT / "rtl/mini/top/onchip_ram.sv"),
|
||||
str(ROOT / "tests/rtl/onchip_ram64_tb.sv"),
|
||||
"-Mdir",
|
||||
str(tmp_path / "obj64"),
|
||||
"-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 "native AXI64 on-chip SRAM test passed" in result.stdout
|
||||
|
||||
|
||||
def test_absent_onchip_ram_reports_capability_and_decode_errors(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
"""Directed verification for the Mini Resource Controller."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_resource_controller_ownership_irq_and_cache_handshake(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
output = tmp_path / "resource_controller_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"resource_controller_tb",
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/resource_controller.sv"),
|
||||
str(ROOT / "tests/rtl/resource_controller_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 "Resource Controller ownership, IRQ, and cache handshake test passed" in result.stdout
|
||||
@@ -1162,8 +1162,9 @@ def test_pdk_pr_regressions_cover_firmware_rtl_and_selected_netlist_target() ->
|
||||
assert "VERILATOR_SIM_ARGS=--fast-flash" in verilator_values
|
||||
assert "SOC_SIM_TIME=360" in verilator_values
|
||||
else:
|
||||
assert "LINK_TYPE=ld2_all_sram" not in verilator_values
|
||||
assert "VERILATOR_SIM_ARGS=--fast-flash" not in verilator_values
|
||||
assert "LINK_TYPE=ld2_sdram" in verilator_values
|
||||
assert "VERILATOR_SIM_ARGS=--fast-flash" in verilator_values
|
||||
assert "SOC_SIM_TIME=600" in verilator_values
|
||||
assert any("SIMU=IVERILOG" in values and "sim-asm" in values for values in command_values)
|
||||
assert any("SYNTH=YOSYS" in values and "synth" in values for values in command_values)
|
||||
assert not any(
|
||||
|
||||
@@ -170,5 +170,6 @@ def test_ci_software_covers_sdram_mapped_window() -> None:
|
||||
|
||||
assert "rs_ci_smoke_sdram_access" in smoke
|
||||
assert "RS_SOC_SDRAM_BASE" in smoke
|
||||
assert "RS_SOC_SDRAM_END - RS_CI_SMOKE_SDRAM_SPAN" in smoke
|
||||
assert "RS_SOC_SDRAM_BASE" in hello
|
||||
assert "WAIT_SDRAM_READY" in hello
|
||||
+19
-13
@@ -118,11 +118,12 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "assign u_opipsram_if.rwds_i = u_gpio_if.di_i[31];" in gpio
|
||||
assert "assign u_gpio_if.alt0_do_i[31] = u_opipsram_if.rwds_o;" in gpio
|
||||
assert "s_tmr_capch" not in gpio
|
||||
assert apb_interfaces.count("apb4_if u_") == 10
|
||||
assert apb_interfaces.count("apb4_if u_") == 11
|
||||
assert "apb4_pure_if u_archinfo_apb4_pure_if ();" in apb_interfaces
|
||||
assert "apb4_if u_resource_ctrl_apb4_if (clk_i, rst_n_i);" in apb_interfaces
|
||||
assert "assign user_ip.paddr = s_addr_q;" in apb_routes
|
||||
assert "({32{s_psel_q[7]}} & user_ip.prdata)" in apb_response
|
||||
assert "localparam int NSLV = 10;" in apb_declarations
|
||||
assert "localparam int NSLV = 11;" in apb_declarations
|
||||
assert fabric.count("axi4_if #(") == 8
|
||||
assert ".mgmt_axi4(u_mgmt_axi4_if)" in bus_fabric
|
||||
assert ".user_axi4(u_user_axi4_if)" in bus_fabric
|
||||
@@ -137,22 +138,23 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 32'h004EFBFC" in irq_config
|
||||
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 22" in irq_config
|
||||
assert "`define SOC_IRQ_APB4_SYSTEM_WIDTH 7" in irq_config
|
||||
assert "`define SOC_IRQ_APB4_SYSTEM_WIDTH 8" in irq_config
|
||||
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
|
||||
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
|
||||
assert "assign irq_o[11] = gpio.irq_o;" in rib_irq
|
||||
assert "assign irq_o[12] = i2c1.irq_o;" in rib_irq
|
||||
assert "assign irq_o[13] = s_dvp_irq;" in rib_irq
|
||||
assert "assign irq_o[14] = s_dma_irq;" in rib_irq
|
||||
assert "assign irq_o[14] = resource_irq_lp_i[0];" in rib_irq
|
||||
assert "assign irq_o[15] = opipsram.irq_o;" in rib_irq
|
||||
assert "assign irq_o[16] = sdio0.irq_o;" in rib_irq
|
||||
assert "assign irq_o[17] = sdio1.irq_o;" in rib_irq
|
||||
assert "assign irq_o[16] = resource_irq_lp_i[2];" in rib_irq
|
||||
assert "assign irq_o[17] = resource_irq_lp_i[3];" in rib_irq
|
||||
assert "assign irq_o[18] = s_crypto_irq;" in rib_irq
|
||||
assert "assign irq_o[19] = s_usb2_irq;" in rib_irq
|
||||
assert "assign irq_o[19] = resource_irq_lp_i[1];" in rib_irq
|
||||
assert "assign irq_o[0] = pwm.irq_o;" in apb_irq
|
||||
assert "assign irq_o[4] = s_rng_irq;" in apb_irq
|
||||
assert "assign irq_o[5] = s_ext_l_irq;" in apb_irq
|
||||
assert "assign irq_o[6] = s_ext_h_irq;" in apb_irq
|
||||
assert "assign irq_o[7] = s_resource_fault_irq;" in apb_irq
|
||||
assert "s_irq[10] = s_apb4_periph_irq[16];" in irq_wiring
|
||||
assert "s_irq[15] = s_apb4_periph_irq[13];" in irq_wiring
|
||||
assert "s_irq[16] = s_apb4_system_irq[4];" in irq_wiring
|
||||
@@ -163,6 +165,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "s_irq[24] = s_apb4_periph_irq[19];" in irq_wiring
|
||||
assert "s_irq[27] = s_apb4_system_irq[5];" in irq_wiring
|
||||
assert "s_irq[28] = s_apb4_system_irq[6];" in irq_wiring
|
||||
assert "s_irq[29] = s_apb4_system_irq[7];" in irq_wiring
|
||||
assert "irq_i[10] == apb4_periph_irq_i[16]" in irq_sva
|
||||
assert "irq_i[15] == apb4_periph_irq_i[13]" in irq_sva
|
||||
assert "irq_i[20] == apb4_periph_irq_i[14]" in irq_sva
|
||||
@@ -172,6 +175,8 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "irq_i[24] == apb4_periph_irq_i[19]" in irq_sva
|
||||
assert "irq_i[31] == 1'b0" in irq_sva
|
||||
assert "bind retrosoc soc_irq_topology_sva" in irq_sva
|
||||
assert ".clk_i(clk_lp_i)" in irq_sva
|
||||
assert ".rst_n_i(rst_lp_n_i)" in irq_sva
|
||||
assert filelist.startswith("+incdir+")
|
||||
|
||||
|
||||
@@ -195,11 +200,11 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("timer0", "apb4_periph", 3, 3, "s_tim0_irq"),
|
||||
("timer1", "apb4_periph", 4, 4, "s_tim1_irq"),
|
||||
("psram", "apb4_periph", 5, 5, "psram.irq_o"),
|
||||
("spisd", "apb4_periph", 6, 6, "spisd.irq_o"),
|
||||
("spisd", "apb4_periph", 6, 6, "resource_irq_lp_i[4]"),
|
||||
("i2c0", "apb4_periph", 7, 7, "i2c0.irq_o"),
|
||||
("i2s", "apb4_periph", 8, 8, "i2s.irq_o"),
|
||||
("xpi", "apb4_periph", 9, 9, "s_xpi_irq"),
|
||||
("sdio0", "apb4_periph", 16, 10, "sdio0.irq_o"),
|
||||
("sdio0", "apb4_periph", 16, 10, "resource_irq_lp_i[2]"),
|
||||
("pwm", "apb4_system", 0, 11, "pwm.irq_o"),
|
||||
("ps2", "apb4_system", 1, 12, "ps2.irq_o"),
|
||||
("rtc", "apb4_system", 2, 13, "u_rtc_if.irq_o"),
|
||||
@@ -209,15 +214,16 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("gpio", "apb4_periph", 11, 18, "gpio.irq_o"),
|
||||
("i2c1", "apb4_periph", 12, 19, "i2c1.irq_o"),
|
||||
("dvp", "apb4_periph", 13, 15, "s_dvp_irq"),
|
||||
("dma", "apb4_periph", 14, 20, "s_dma_irq"),
|
||||
("dma", "apb4_periph", 14, 20, "resource_irq_lp_i[0]"),
|
||||
("opipsram", "apb4_periph", 15, 22, "opipsram.irq_o"),
|
||||
("sdio1", "apb4_periph", 17, 21, "sdio1.irq_o"),
|
||||
("sdio1", "apb4_periph", 17, 21, "resource_irq_lp_i[3]"),
|
||||
("crypto", "apb4_periph", 18, 23, "s_crypto_irq"),
|
||||
("usb2", "apb4_periph", 19, 24, "s_usb2_irq"),
|
||||
("usb2", "apb4_periph", 19, 24, "resource_irq_lp_i[1]"),
|
||||
("hp_mailbox_lp", "apb4_periph", 20, 25, "s_mailbox_lp_irq"),
|
||||
("uart1", "apb4_periph", 21, 26, "uart1.irq_o"),
|
||||
("extension_l", "apb4_system", 5, 27, "s_ext_l_irq"),
|
||||
("extension_h", "apb4_system", 6, 28, "s_ext_h_irq"),
|
||||
("resource_fault", "apb4_system", 7, 29, "s_resource_fault_irq"),
|
||||
]
|
||||
|
||||
|
||||
@@ -233,7 +239,7 @@ def test_topology_always_adds_the_user_apb_target(tmp_path: Path) -> None:
|
||||
)
|
||||
|
||||
assert "apb4_if u_user_ip_apb4_if (clk_i, rst_n_i);" in interfaces
|
||||
assert "localparam int NSLV = 10;" in declarations
|
||||
assert "localparam int NSLV = 11;" in declarations
|
||||
assert "s_psel_q[7]" in response
|
||||
assert "apb4_pure_if user_ip ();" in formal_design
|
||||
assert ".user_ip (user_ip)" in formal_design
|
||||
|
||||
Reference in new issue
Block a user