mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add comprehensive tests for AXI4 components and lifecycle controllers
- Implemented tests for AXI4 async bridge functionality, including transfer and warm flush scenarios. - Added tests for AXI4 data crossbar to validate concurrent outstanding requests and ACL handling. - Introduced clock frequency monitor tests to ensure detection of clock stop and restart events. - Developed tests for extension DMA master to verify copy operations, tail strobe behavior, and timeout handling. - Created tests for HP lifecycle controller to validate drain, flush, and forced reset functionalities. - Updated existing test scripts to include new RTL components and ensure proper simulation configurations.
This commit is contained in:
67 files changed
+4165
-612
No files matched your search
@@ -81,3 +81,5 @@ socver.*
|
||||
/rtl/managed/mpw/
|
||||
/rtl/managed/third_party/
|
||||
*result.json
|
||||
*.pdf
|
||||
/publications/datasheets/assets/
|
||||
@@ -337,7 +337,7 @@ include physical/ecc/Makefile
|
||||
|
||||
.PHONY: help config doctor setup setup-regression setup-mpw setup-vexiiriscv setup-clusterip setup-ip setup-pdk setup-app setup-hp-linux hp-linux hp-bundle hp-linux-sim hp-smoke-bundle hp-smoke-sim \
|
||||
clean-all purge-cache manifest check-warnings metrics check-metrics package commercial-package \
|
||||
regress-smoke regress-pr regress-nightly sim-asm format format-check sw-format sw-format-check mk-format \
|
||||
regress-smoke regress-rtl regress-pr regress-nightly sim-asm format format-check sw-format sw-format-check mk-format \
|
||||
mk-format-check rtl-format rtl-format-check rtl-style-check rtl-migrate-connections rtl-migrate-names sw-policy-check sw-host-test \
|
||||
benchmark-report coremark-report \
|
||||
hp-performance-check \
|
||||
@@ -671,6 +671,9 @@ commercial-package: $(MPW_VARIANT_DEP) $(FILELIST_STAMP) manifest
|
||||
regress-smoke:
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite smoke --pdk IHP130
|
||||
|
||||
regress-rtl:
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite rtl --pdk IHP130
|
||||
|
||||
regress-pr:
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr --pdk IHP130 $(if $(filter YES,$(REGRESS_NETSIM_BOOT_ONLY)),--netsim-boot-only)
|
||||
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite pr --pdk GF180 $(if $(filter YES,$(REGRESS_NETSIM_BOOT_ONLY)),--netsim-boot-only)
|
||||
|
||||
@@ -99,12 +99,18 @@ CI Verilator firmware simulations explicitly select the `ci_smoke`
|
||||
application, which checks UART, archinfo APB readback, macro-backed on-chip SRAM,
|
||||
RNG fail-closed behavior, and test-status
|
||||
completion without the verbose startup report. ARCHINFO checks include its
|
||||
ABI and the build/configuration identifiers generated for that variant. The profiles retain `bringup`
|
||||
ABI and the build/configuration identifiers generated for that variant. The
|
||||
IHP130 PR run links this image into the 32 KiB SRAM, explicitly enables the
|
||||
fast-flash backend, and allows 360 seconds; Icarus keeps the real serial XPI
|
||||
boot-model check. The profiles retain `bringup`
|
||||
as their default for manual diagnostics. To run the full report in Verilator,
|
||||
use:
|
||||
|
||||
```sh
|
||||
make CONFIG=configs/ci/ihp130.mk APP=bringup SIMU=VERILATOR SOC_SIM_TIME=300 firmware sim
|
||||
|
||||
# Firmware, RTL lint, debug, and behavioral simulation without synthesis/STA
|
||||
make regress-rtl
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
@@ -198,8 +204,10 @@ variant identifier; `make help` lists all available targets. Netlist simulation
|
||||
analysis consume the Yosys netlist, so run the synthesis command first. The CI-proven netlist
|
||||
regression uses the assembly self-test image:
|
||||
|
||||
Verilator simulations run for 180 seconds by default. Set `SOC_SIM_TIME` explicitly only when
|
||||
an exploratory local run needs a different limit.
|
||||
Verilator simulations run for 180 seconds by default. The IHP130 `ci_smoke`
|
||||
regression explicitly uses 360 seconds because its LP memory accesses traverse
|
||||
the asynchronous data gateway. Set `SOC_SIM_TIME` explicitly only when an
|
||||
exploratory local run needs a different limit.
|
||||
|
||||
VCS flow commands use `bsub -Is` by default: this includes parse-time Python helpers used to
|
||||
calculate the variant and dependency-lock digest, generated-flow Python helpers, VCS, `simv`, and
|
||||
|
||||
@@ -52,6 +52,13 @@ 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/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
|
||||
cache visibility, and the controller fault summary by composing the existing
|
||||
per-controller HALs. It does not merge heterogeneous memories into one
|
||||
allocator or provide hardware cache coherency.
|
||||
|
||||
`<retrosoc/hal/dma.h>` provides the channel-aware direct and linked-list DMA
|
||||
API. UART0, I2C0, I2C1, bulk/media clients, and the HP boot loader have
|
||||
deterministic channel assignments; see the [DMA V2 contract](../docs/ip/dma.md).
|
||||
|
||||
@@ -46,6 +46,12 @@ typedef struct {
|
||||
uint32_t timeout_cycles;
|
||||
} rs_extension_acl_t;
|
||||
|
||||
typedef struct {
|
||||
bool busy;
|
||||
bool done;
|
||||
bool fault;
|
||||
} rs_extension_dma_status_t;
|
||||
|
||||
rs_status_t rs_extension_probe(rs_extension_slot_t slot, rs_extension_capabilities_t *capabilities);
|
||||
rs_status_t rs_extension_get_status(rs_extension_slot_t slot, rs_extension_status_t *status);
|
||||
rs_status_t rs_extension_set_owner(rs_extension_slot_t slot, rs_extension_owner_t owner, bool lock);
|
||||
@@ -54,5 +60,8 @@ rs_status_t rs_extension_set_lifecycle(rs_extension_slot_t slot, bool quiesce, b
|
||||
rs_status_t rs_extension_configure_acl(rs_extension_slot_t slot,
|
||||
const rs_extension_acl_t *configuration);
|
||||
rs_status_t rs_extension_read(rs_extension_slot_t slot, uint32_t offset, uint32_t *value);
|
||||
rs_status_t rs_extension_dma_start(uintptr_t source, uintptr_t destination, uint32_t byte_count);
|
||||
rs_status_t rs_extension_dma_abort(void);
|
||||
rs_status_t rs_extension_dma_get_status(rs_extension_dma_status_t *status);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef RETROSOC_HAL_MEMORY_H
|
||||
#define RETROSOC_HAL_MEMORY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
typedef enum {
|
||||
RS_MEMORY_SRAM = 0,
|
||||
RS_MEMORY_SDRAM = 1,
|
||||
RS_MEMORY_QPI_PSRAM = 2,
|
||||
RS_MEMORY_OPI_PSRAM = 3,
|
||||
RS_MEMORY_XPI = 4,
|
||||
} rs_memory_target_t;
|
||||
|
||||
typedef enum {
|
||||
RS_MEMORY_PAD_NONE = 0,
|
||||
RS_MEMORY_PAD_QPI = 1,
|
||||
RS_MEMORY_PAD_OPI = 2,
|
||||
} rs_memory_pad_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RS_MEMORY_LATENCY_ONCHIP = 0,
|
||||
RS_MEMORY_LATENCY_PARALLEL = 1,
|
||||
RS_MEMORY_LATENCY_SERIAL = 2,
|
||||
} rs_memory_latency_t;
|
||||
|
||||
typedef struct {
|
||||
uintptr_t base;
|
||||
uint32_t size;
|
||||
uint32_t fault_code;
|
||||
rs_memory_target_t target;
|
||||
rs_memory_pad_mode_t pad_mode;
|
||||
rs_memory_latency_t latency;
|
||||
bool controller_present;
|
||||
bool device_present;
|
||||
bool initialized;
|
||||
bool ready;
|
||||
bool active;
|
||||
bool cacheable;
|
||||
bool dma_visible;
|
||||
bool fault;
|
||||
} rs_memory_info_t;
|
||||
|
||||
rs_status_t rs_memory_get_info(rs_memory_target_t target, rs_memory_info_t *info);
|
||||
|
||||
#endif
|
||||
@@ -54,6 +54,9 @@ typedef struct {
|
||||
bool present;
|
||||
bool released;
|
||||
bool reset_asserted;
|
||||
bool draining;
|
||||
bool forced_fault;
|
||||
bool actual_released;
|
||||
} rs_sysctrl_hp_status_t;
|
||||
|
||||
rs_status_t rs_sysctrl_get_core_select(uint8_t *core_id);
|
||||
|
||||
+65
-16
@@ -4,23 +4,33 @@
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/extension.h>
|
||||
|
||||
#define RS_EXTENSION_IDENTIFICATION_OFFSET UINT32_C(0x000)
|
||||
#define RS_EXTENSION_VERSION_OFFSET UINT32_C(0x004)
|
||||
#define RS_EXTENSION_CAPABILITY_OFFSET UINT32_C(0x008)
|
||||
#define RS_EXTENSION_OWNER_OFFSET UINT32_C(0x00C)
|
||||
#define RS_EXTENSION_COMMAND_OFFSET UINT32_C(0x010)
|
||||
#define RS_EXTENSION_STATUS_OFFSET UINT32_C(0x014)
|
||||
#define RS_EXTENSION_READ_BASE_OFFSET UINT32_C(0x018)
|
||||
#define RS_EXTENSION_READ_LIMIT_OFFSET UINT32_C(0x01C)
|
||||
#define RS_EXTENSION_WRITE_BASE_OFFSET UINT32_C(0x020)
|
||||
#define RS_EXTENSION_WRITE_LIMIT_OFFSET UINT32_C(0x024)
|
||||
#define RS_EXTENSION_TIMEOUT_OFFSET UINT32_C(0x028)
|
||||
#define RS_EXTENSION_IDENTIFICATION_OFFSET UINT32_C(0x000)
|
||||
#define RS_EXTENSION_VERSION_OFFSET UINT32_C(0x004)
|
||||
#define RS_EXTENSION_CAPABILITY_OFFSET UINT32_C(0x008)
|
||||
#define RS_EXTENSION_OWNER_OFFSET UINT32_C(0x00C)
|
||||
#define RS_EXTENSION_COMMAND_OFFSET UINT32_C(0x010)
|
||||
#define RS_EXTENSION_STATUS_OFFSET UINT32_C(0x014)
|
||||
#define RS_EXTENSION_READ_BASE_OFFSET UINT32_C(0x018)
|
||||
#define RS_EXTENSION_READ_LIMIT_OFFSET UINT32_C(0x01C)
|
||||
#define RS_EXTENSION_WRITE_BASE_OFFSET UINT32_C(0x020)
|
||||
#define RS_EXTENSION_WRITE_LIMIT_OFFSET UINT32_C(0x024)
|
||||
#define RS_EXTENSION_TIMEOUT_OFFSET UINT32_C(0x028)
|
||||
#define RS_EXTENSION_DMA_SOURCE_OFFSET UINT32_C(0x100)
|
||||
#define RS_EXTENSION_DMA_DESTINATION_OFFSET UINT32_C(0x104)
|
||||
#define RS_EXTENSION_DMA_LENGTH_OFFSET UINT32_C(0x108)
|
||||
#define RS_EXTENSION_DMA_COMMAND_OFFSET UINT32_C(0x10C)
|
||||
#define RS_EXTENSION_DMA_STATUS_OFFSET UINT32_C(0x110)
|
||||
|
||||
#define RS_EXTENSION_REGISTER_SIZE UINT32_C(4)
|
||||
#define RS_EXTENSION_OWNER_LOCK UINT32_C(0x00000100)
|
||||
#define RS_EXTENSION_COMMAND_QUIESCE UINT32_C(0x00000001)
|
||||
#define RS_EXTENSION_COMMAND_RESET UINT32_C(0x00000002)
|
||||
#define RS_EXTENSION_COMMAND_CLEAR_FAULT UINT32_C(0x00000004)
|
||||
#define RS_EXTENSION_REGISTER_SIZE UINT32_C(4)
|
||||
#define RS_EXTENSION_OWNER_LOCK UINT32_C(0x00000100)
|
||||
#define RS_EXTENSION_COMMAND_QUIESCE UINT32_C(0x00000001)
|
||||
#define RS_EXTENSION_COMMAND_RESET UINT32_C(0x00000002)
|
||||
#define RS_EXTENSION_COMMAND_CLEAR_FAULT UINT32_C(0x00000004)
|
||||
#define RS_EXTENSION_DMA_START UINT32_C(0x00000001)
|
||||
#define RS_EXTENSION_DMA_ABORT UINT32_C(0x00000002)
|
||||
#define RS_EXTENSION_DMA_STATUS_BUSY UINT32_C(0x00000001)
|
||||
#define RS_EXTENSION_DMA_STATUS_DONE UINT32_C(0x00000002)
|
||||
#define RS_EXTENSION_DMA_STATUS_FAULT UINT32_C(0x00000004)
|
||||
|
||||
static bool rs_extension_slot_valid(rs_extension_slot_t slot) {
|
||||
return (slot == RS_EXTENSION_SLOT_L) || (slot == RS_EXTENSION_SLOT_H);
|
||||
@@ -152,3 +162,42 @@ rs_status_t rs_extension_configure_acl(rs_extension_slot_t slot,
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_extension_dma_start(uintptr_t source, uintptr_t destination, uint32_t byte_count) {
|
||||
if (((source | destination) & (uintptr_t)UINT32_C(0x7)) != (uintptr_t)0U ||
|
||||
(byte_count == 0U) || (source > (uintptr_t)UINT32_MAX) ||
|
||||
(destination > (uintptr_t)UINT32_MAX)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((rs_extension_write(RS_EXTENSION_SLOT_H, RS_EXTENSION_DMA_SOURCE_OFFSET,
|
||||
(uint32_t)source) != RS_OK) ||
|
||||
(rs_extension_write(RS_EXTENSION_SLOT_H, RS_EXTENSION_DMA_DESTINATION_OFFSET,
|
||||
(uint32_t)destination) != RS_OK) ||
|
||||
(rs_extension_write(RS_EXTENSION_SLOT_H, RS_EXTENSION_DMA_LENGTH_OFFSET, byte_count) !=
|
||||
RS_OK) ||
|
||||
(rs_extension_write(RS_EXTENSION_SLOT_H, RS_EXTENSION_DMA_COMMAND_OFFSET,
|
||||
RS_EXTENSION_DMA_START) != RS_OK)) {
|
||||
return RS_EIO;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_extension_dma_abort(void) {
|
||||
return rs_extension_write(RS_EXTENSION_SLOT_H, RS_EXTENSION_DMA_COMMAND_OFFSET,
|
||||
RS_EXTENSION_DMA_ABORT);
|
||||
}
|
||||
|
||||
rs_status_t rs_extension_dma_get_status(rs_extension_dma_status_t *status) {
|
||||
uint32_t value;
|
||||
|
||||
if (status == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if (rs_extension_read(RS_EXTENSION_SLOT_H, RS_EXTENSION_DMA_STATUS_OFFSET, &value) != RS_OK) {
|
||||
return RS_EIO;
|
||||
}
|
||||
status->busy = (value & RS_EXTENSION_DMA_STATUS_BUSY) != 0U;
|
||||
status->done = (value & RS_EXTENSION_DMA_STATUS_DONE) != 0U;
|
||||
status->fault = (value & RS_EXTENSION_DMA_STATUS_FAULT) != 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/memory.h>
|
||||
#include <retrosoc/hal/onchip_sram.h>
|
||||
#include <retrosoc/hal/opipsram.h>
|
||||
#include <retrosoc/hal/psram.h>
|
||||
#include <retrosoc/hal/sdram.h>
|
||||
#include <retrosoc/hal/xpi.h>
|
||||
|
||||
#define RS_MEMORY_PAD_MODE_MASK UINT32_C(0x00000003)
|
||||
|
||||
static volatile uint32_t *rs_memory_sysctrl_register(uint32_t offset) {
|
||||
return (volatile uint32_t *)(RS_SOC_APB4_SYSCTRL_BASE + (uintptr_t)offset);
|
||||
}
|
||||
|
||||
static rs_memory_pad_mode_t rs_memory_pad_mode(void) {
|
||||
const uint32_t value =
|
||||
*rs_memory_sysctrl_register(RS_SOC_SYSCTRL_MEM_PAD_STATUS_OFFSET) & RS_MEMORY_PAD_MODE_MASK;
|
||||
return (rs_memory_pad_mode_t)value;
|
||||
}
|
||||
|
||||
static void rs_memory_static_info(rs_memory_target_t target, rs_memory_info_t *info) {
|
||||
info->target = target;
|
||||
info->controller_present = true;
|
||||
info->cacheable = true;
|
||||
info->dma_visible = true;
|
||||
switch (target) {
|
||||
case RS_MEMORY_SRAM:
|
||||
info->base = (uintptr_t)RS_SOC_SRAM_BASE;
|
||||
info->size = RS_SOC_SRAM_END - RS_SOC_SRAM_BASE + UINT32_C(1);
|
||||
info->latency = RS_MEMORY_LATENCY_ONCHIP;
|
||||
break;
|
||||
case RS_MEMORY_SDRAM:
|
||||
info->base = (uintptr_t)RS_SOC_SDRAM_BASE;
|
||||
info->size = RS_SOC_SDRAM_END - RS_SOC_SDRAM_BASE + UINT32_C(1);
|
||||
info->latency = RS_MEMORY_LATENCY_PARALLEL;
|
||||
break;
|
||||
case RS_MEMORY_QPI_PSRAM:
|
||||
info->base = (uintptr_t)RS_SOC_PSRAM_BASE;
|
||||
info->size = RS_SOC_PSRAM_END - RS_SOC_PSRAM_BASE + UINT32_C(1);
|
||||
info->latency = RS_MEMORY_LATENCY_SERIAL;
|
||||
break;
|
||||
case RS_MEMORY_OPI_PSRAM:
|
||||
info->base = (uintptr_t)RS_SOC_OPIPSRAM_BASE;
|
||||
info->size = RS_SOC_OPIPSRAM_END - RS_SOC_OPIPSRAM_BASE + UINT32_C(1);
|
||||
info->latency = RS_MEMORY_LATENCY_SERIAL;
|
||||
break;
|
||||
case RS_MEMORY_XPI:
|
||||
info->base = (uintptr_t)RS_SOC_XPI_BASE;
|
||||
info->size = RS_SOC_XPI_END - RS_SOC_XPI_BASE + UINT32_C(1);
|
||||
info->latency = RS_MEMORY_LATENCY_SERIAL;
|
||||
break;
|
||||
default:
|
||||
info->controller_present = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rs_status_t rs_memory_get_info(rs_memory_target_t target, rs_memory_info_t *info) {
|
||||
rs_status_t result = RS_OK;
|
||||
|
||||
if ((info == NULL) || (target > RS_MEMORY_XPI)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*info = (rs_memory_info_t){0};
|
||||
rs_memory_static_info(target, info);
|
||||
info->pad_mode = rs_memory_pad_mode();
|
||||
|
||||
switch (target) {
|
||||
case RS_MEMORY_SRAM: {
|
||||
rs_onchip_sram_info_t status;
|
||||
result = rs_onchip_sram_probe(&status);
|
||||
if (result == RS_OK) {
|
||||
info->controller_present = status.present;
|
||||
info->device_present = status.present;
|
||||
info->initialized = status.present;
|
||||
info->ready = status.present;
|
||||
info->active = status.present;
|
||||
info->size = status.memory_bytes;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RS_MEMORY_SDRAM: {
|
||||
rs_sdram_status_t status;
|
||||
result = rs_sdram_get_status(&status);
|
||||
if (result == RS_OK) {
|
||||
info->device_present = status.ready;
|
||||
info->initialized = status.ready;
|
||||
info->ready = status.ready;
|
||||
info->active = status.ready;
|
||||
info->fault = status.error;
|
||||
info->fault_code = (uint32_t)status.last_error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RS_MEMORY_QPI_PSRAM: {
|
||||
rs_psram_status_t status;
|
||||
result = rs_psram_get_status(&status);
|
||||
if (result == RS_OK) {
|
||||
info->device_present = status.chip_present != UINT8_C(0);
|
||||
info->initialized = status.chip_ready != UINT8_C(0);
|
||||
info->ready = status.ready;
|
||||
info->active = status.ready && (info->pad_mode == RS_MEMORY_PAD_QPI);
|
||||
info->fault = status.chip_error != UINT8_C(0);
|
||||
info->fault_code = (uint32_t)status.last_error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RS_MEMORY_OPI_PSRAM: {
|
||||
rs_opipsram_status_t status;
|
||||
result = rs_opipsram_get_status(&status);
|
||||
if (result == RS_OK) {
|
||||
info->device_present = status.initialized;
|
||||
info->initialized = status.initialized;
|
||||
info->ready = status.ready;
|
||||
info->active = status.ready && (info->pad_mode == RS_MEMORY_PAD_OPI);
|
||||
info->fault = status.error;
|
||||
info->fault_code = status.last_error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RS_MEMORY_XPI:
|
||||
result = rs_xpi_probe();
|
||||
info->device_present = result == RS_OK;
|
||||
info->initialized = result == RS_OK;
|
||||
info->ready = result == RS_OK;
|
||||
info->active = result == RS_OK;
|
||||
info->fault = result != RS_OK;
|
||||
break;
|
||||
default:
|
||||
result = RS_EINVAL;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -72,6 +72,9 @@
|
||||
#define RS_SYSCTRL_HP_PRESENT UINT32_C(0x00000001)
|
||||
#define RS_SYSCTRL_HP_RELEASED UINT32_C(0x00000002)
|
||||
#define RS_SYSCTRL_HP_RESET_ASSERTED UINT32_C(0x00000004)
|
||||
#define RS_SYSCTRL_HP_DRAINING UINT32_C(0x00000008)
|
||||
#define RS_SYSCTRL_HP_FORCED_FAULT UINT32_C(0x00000010)
|
||||
#define RS_SYSCTRL_HP_ACTUAL_RELEASED UINT32_C(0x00000020)
|
||||
|
||||
static volatile uint32_t *rs_sysctrl_register(uint32_t offset) {
|
||||
return (volatile uint32_t *)(RS_SOC_APB4_SYSCTRL_BASE + (uintptr_t)offset);
|
||||
@@ -301,6 +304,9 @@ rs_status_t rs_sysctrl_get_hp_status(rs_sysctrl_hp_status_t *status) {
|
||||
status->present = (value & RS_SYSCTRL_HP_PRESENT) != 0U;
|
||||
status->released = (value & RS_SYSCTRL_HP_RELEASED) != 0U;
|
||||
status->reset_asserted = (value & RS_SYSCTRL_HP_RESET_ASSERTED) != 0U;
|
||||
status->draining = (value & RS_SYSCTRL_HP_DRAINING) != 0U;
|
||||
status->forced_fault = (value & RS_SYSCTRL_HP_FORCED_FAULT) != 0U;
|
||||
status->actual_released = (value & RS_SYSCTRL_HP_ACTUAL_RELEASED) != 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ the root README and subsystem guides.
|
||||
Debug Module integration, reset boundary, and Verilator/OpenOCD/GDB flow.
|
||||
- [lp-hp-architecture.md](lp-hp-architecture.md) defines the current Mini
|
||||
product AON/LP/HP/PCLK, AXI64 data-plane, memory-pad, and extension contract.
|
||||
- [commercial-soc-alignment.md](commercial-soc-alignment.md) records the
|
||||
selected commercial architecture patterns and their reuse boundaries.
|
||||
- [mini-high-performance-traceability.md](mini-high-performance-traceability.md)
|
||||
maps Mini architecture requirements to implementation and evidence status.
|
||||
- [coremark.md](coremark.md) defines the SRAM-resident Hazard3 CoreMark quick
|
||||
measurement, optional standard hardware run, and structured result format.
|
||||
- [soc-family-positioning.md](soc-family-positioning.md) defines the planned
|
||||
|
||||
+14
-12
@@ -33,16 +33,17 @@ IDs. It has eight masters:
|
||||
| 0 | Vexii I-cache | native AXI64, source ID preserved |
|
||||
| 1 | Vexii D-cache | native AXI64, source ID preserved |
|
||||
| 2 | central DMA | PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 3 | SDIO0 | PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 4 | SDIO1 | PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 5 | SPI-SD | PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 6 | USB2 | PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 3 | I/O gateway A | USB2 and SDIO0, PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 4 | I/O gateway B | SDIO1 and SPI-SD, PCLK-to-HP CDC, AXI32-to-64 |
|
||||
| 5 | LP data gateway | Hazard3 memory traffic, LP-to-HP CDC, AXI32-to-64 |
|
||||
| 6 | reserved | permanently idle and denied |
|
||||
| 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. It accepts one outstanding transaction in each
|
||||
direction per master; it does not reorder responses within a source.
|
||||
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.
|
||||
|
||||
| Target | Current backend |
|
||||
| --- | --- |
|
||||
@@ -63,18 +64,19 @@ fail-closed according to the synchronized AON pad mode.
|
||||
- `axi4_downsizer_64to32` splits 64-bit beats for current memory frontends and
|
||||
recombines read responses.
|
||||
- `axi4_async_bridge` carries AW, W, B, AR, and R through independent Common
|
||||
`cdc_fifo` channels with a two-sided reset barrier.
|
||||
coordinated warm-flush FIFOs and reports clear-busy and epoch state.
|
||||
- `apb4_async_bridge` converts one APB request into a request/response CDC
|
||||
transaction and guarantees a finite APB completion when the destination runs.
|
||||
|
||||
Async bridges flush protocol state when either side resets. Clock-stop timeout
|
||||
and full hot-reset recovery are not yet claimed; callers must quiesce before
|
||||
reset or DFS.
|
||||
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.
|
||||
|
||||
## 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 multi-outstanding reordering, cache coherency,
|
||||
formal crossbar proof, CDC signoff, or physical bandwidth closure.
|
||||
implementation does not claim same-target multi-outstanding reordering, cache
|
||||
coherency, formal crossbar proof, CDC signoff, or physical bandwidth closure.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Mini Commercial SoC Alignment
|
||||
|
||||
## Purpose
|
||||
|
||||
This document records the commercial architecture references used for the
|
||||
Mini high-performance implementation. It is a design input, not a claim that
|
||||
retroSoC has the qualification, safety case, analogue IP, or software
|
||||
ecosystem of the referenced devices.
|
||||
|
||||
## Selected references
|
||||
|
||||
| Reference | Problem addressed | Architecture reused by Mini | Boundary |
|
||||
| --- | --- | --- | --- |
|
||||
| [NXP i.MX RT1180](https://www.nxp.com/products/i.MX-RT1180) | Heterogeneous lifecycle control, external-memory boot, and DVFS | Management-owned lifecycle, stable peripheral clocks while changing a CPU PLL, and resource-domain access control | Mini does not implement voltage scaling or the NXP security lifecycle |
|
||||
| [ST STM32H7R/S RM0477](https://www.st.com/resource/en/reference_manual/rm0477-stm32h7rx7sx-armbased-32bit-mcus-stmicroelectronics.pdf) | Concurrent CPU, DMA, graphics, and external-memory traffic | Layered AXI/AHB/APB planes, independent memory targets, programmable QoS, and functional clock roots | Mini adds starvation aging instead of relying on unbounded static priority |
|
||||
| [TI AM263x](https://www.ti.com/product/AM2632) | Freedom from interference and recoverable interconnect faults | Initiator/target firewalls, initiator identity, first-fault attribution, clock monitoring, and directed fault injection | Mini does not claim lockstep, ASIL, SIL, or redundant-bus coverage |
|
||||
| [Arm CoreLink NIC-400](https://developer.arm.com/community/arm-community-blogs/b/soc-design-and-simulation-blog/posts/corelink-nic-400-a-great-interconnect-for-wearables-and-entry-level-smartphones) | Scalable AXI integration across widths and clock domains | Target-aware outstanding credits, independent channel buffering, register slices, and hierarchical I/O gateways | Mini remains a small crossbar and does not use a packetized NoC |
|
||||
|
||||
Primary sources are the NXP i.MX RT1180 product documentation, ST RM0477,
|
||||
the [TI AM263x TRM](https://www.ti.com/lit/ug/spruj17h/spruj17h.pdf), and Arm
|
||||
CoreLink Network Interconnect documentation. Web references were reviewed on
|
||||
2026-08-30. The referenced products and documentation were active at review
|
||||
time; this date is retained so a later architecture review can detect changes.
|
||||
|
||||
## Mini selection
|
||||
|
||||
Mini uses a performance-first, non-coherent architecture. Hazard3 retains
|
||||
root lifecycle control. VexiiRiscv caches, DMA, I/O gateways, the LP data
|
||||
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.
|
||||
|
||||
No release may describe the implementation as timing closed, CDC signed off,
|
||||
silicon qualified, functionally safe, or cache coherent until the separate
|
||||
physical and product evidence exists.
|
||||
+5
-1
@@ -14,7 +14,11 @@
|
||||
| Cluster | `configs/cluster/ics55.mk` | compatibility profile for site-specific ICS55 runs |
|
||||
|
||||
Regression Verilator firmware simulations override the profiles' manual
|
||||
`bringup` default with `APP=ci_smoke`. This application verifies UART output,
|
||||
`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,
|
||||
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;
|
||||
|
||||
+14
-3
@@ -25,12 +25,23 @@ generating register definitions.
|
||||
| `0x02C` | `FAULT` | RO | sticky fault state |
|
||||
| `0x030` | `FAULT_ADDRESS` | RO | first rejected control address |
|
||||
| `0x034` | `REQUEST_COUNT` | RO | saturating accepted APB request count |
|
||||
| `0x100` | `DMA_SOURCE` | EXT-H RW | aligned memory-copy source |
|
||||
| `0x104` | `DMA_DESTINATION` | EXT-H RW | aligned memory-copy destination |
|
||||
| `0x108` | `DMA_LENGTH` | EXT-H RW | nonzero byte count |
|
||||
| `0x10C` | `DMA_COMMAND` | EXT-H WO | start or abort |
|
||||
| `0x110` | `DMA_STATUS` | EXT-H RO | busy, done pulse, and fault |
|
||||
|
||||
EXT-L rejects ACL and timeout writes. Invalid or read-only writes complete with
|
||||
APB `PSLVERR`, set the slot fault, and record the first offending address.
|
||||
The reference EXT-H master is idle; connecting a real accelerator must retain
|
||||
the control-plane deny policy and implement the programmed ranges before it can
|
||||
issue payload traffic.
|
||||
The reference EXT-H master performs sequential 64-bit memory copies. It
|
||||
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
|
||||
does not report idle until the DMA and address gate have drained.
|
||||
|
||||
`<retrosoc/hal/extension.h>` provides discovery, status, ownership, lifecycle,
|
||||
and EXT-H ACL operations. Register constants remain independently handwritten
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ offset macros.
|
||||
| `0x084` | `TEST_STATUS` | RW-once/RO | Full-word write with bit 31 set records sticky done, bit 0 pass, and bits `[15:8]` result code. |
|
||||
| `0x088` | `RTC_WAKE_STATUS` | RW1C/RO | Bit 0 synchronized live wake; bit 1 sticky wake, cleared by writing one to bit 1. |
|
||||
| `0x0A4` | `HP_CTRL` | RW | Bit 0 releases HP reset when the HP profile is present. Reset value 0. |
|
||||
| `0x0A8` | `HP_STATUS` | RO | Bits 0/1/2 report present, released, and reset asserted. |
|
||||
| `0x0A8` | `HP_STATUS` | RO | Bits 0/1/2 preserve present and requested release/reset; bits 3/4/5 report draining, forced fault, and actual release. |
|
||||
| `0x0AC` | `DEBUG_SELECT` | RW | Bit 0 selects HP on shared JTAG only while HP remains in reset. Reset value 0 selects LP. |
|
||||
| `0x0B0` | `CLK_HP_REQ` | RW/WO command | HP P-state; bits 31/30 apply PLL/force safe. |
|
||||
| `0x0B4` | `CLK_HP_CURRENT` | RO | Current HP source/P-state and LP/PCLK/gate configuration. |
|
||||
|
||||
+29
-23
@@ -66,37 +66,40 @@ HP uncached MMIO is downsized to AXI32 and crosses HP to LP through
|
||||
watchdog, and GPIO administration windows with `SLVERR`; Hazard3 retains full
|
||||
management access.
|
||||
|
||||
The LP control fabric remains the compatibility path for Hazard3 boot and
|
||||
external-memory accesses. HP, DMA, and accelerator payload traffic uses the
|
||||
native data plane described below. Moving the remaining controller protocol
|
||||
engines from LP/PCLK to the exported memory root is an explicit follow-up; the
|
||||
present RTL does not claim that migration or its physical CDC signoff.
|
||||
`axi4_mgmt_router` keeps APB/control addresses on this path and routes every
|
||||
memory window through an LP-to-HP data gateway. Hazard3 therefore shares the
|
||||
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. Each direction permits one active
|
||||
transaction per master and per target; global IDs contain a fixed master
|
||||
prefix plus the source ID.
|
||||
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.
|
||||
|
||||
| Master | Entry path |
|
||||
| --- | --- |
|
||||
| HP I-cache | native AXI64, ID prefix 0 |
|
||||
| HP D-cache | native AXI64, ID prefix 1 |
|
||||
| central DMA | PCLK-to-HP async bridge, AXI32-to-64 upsizer |
|
||||
| SDIO0 / SDIO1 | PCLK-to-HP async bridge, upsizer |
|
||||
| SPI-SD / USB2 | PCLK-to-HP async bridge, upsizer |
|
||||
| I/O gateway A | USB2 and SDIO0, then PCLK-to-HP CDC and upsizer |
|
||||
| I/O gateway B | SDIO1 and SPI-SD, then PCLK-to-HP CDC and upsizer |
|
||||
| LP data gateway | Hazard3 memory traffic, LP-to-HP CDC and upsizer |
|
||||
| EXT-H | PCLK-to-HP AXI64 async bridge, ID prefix 7 |
|
||||
|
||||
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 followed by HP-to-LP async bridges. Inactive QPI/OPI windows route
|
||||
to `SLVERR`. HP I-cache, D-cache, and MMIO no longer share the retired
|
||||
`hp_axi4_mux3` path.
|
||||
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`.
|
||||
|
||||
All async AXI channels use Common `cdc_fifo` storage and a reset barrier. A
|
||||
single-ended reset aborts the link epoch rather than returning a stale response.
|
||||
All async AXI channels use Common coordinated warm-flush FIFOs and expose a
|
||||
source-domain epoch. HP shutdown holds a flush request until every bridge sees
|
||||
it, then waits for bridge recovery before resetting the core.
|
||||
|
||||
## Memory and shared pads
|
||||
|
||||
@@ -123,9 +126,10 @@ Product Mini has fixed control windows:
|
||||
|
||||
Each slot exposes identification, version, capability, owner/lock, lifecycle,
|
||||
status, timeout, first fault, fault address, and request count. EXT-H adds read
|
||||
and write ACL ranges. The current reference slot is idle and issues no data
|
||||
traffic; its interface and isolation contract are live. Software discovers it
|
||||
through `<retrosoc/hal/extension.h>`.
|
||||
and write ACL ranges that are enforced at data-plane admission. The reference
|
||||
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 old `APB4_USER_IP` window is a read-only compatibility/capability window.
|
||||
Product writes to `CORESEL`, `IPSEL`, `USER_CORE_RESET`, or
|
||||
@@ -143,8 +147,10 @@ so absolute commercial paths are never tracked.
|
||||
|
||||
## Evidence boundary
|
||||
|
||||
Behavioral RTL, firmware, directed PLL/SYSCTRL tests, manifest parity, and
|
||||
quality checks are the evidence for this implementation. It must not be called
|
||||
cache coherent, power isolated, hot-reset safe, timing closed, CDC/RDC signed
|
||||
off, or silicon-qualified. Synthesis, netlist simulation, STA, MMMC, clock-tree,
|
||||
DFT, and analogue PLL qualification are separate gates.
|
||||
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
|
||||
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.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Mini High-Performance Traceability
|
||||
|
||||
## Status vocabulary
|
||||
|
||||
- `implemented`: RTL and software-visible behavior exist and directed tests pass.
|
||||
- `partial`: a bounded subset is implemented and the missing boundary is stated.
|
||||
- `verified`: the required simulation and formal evidence pass.
|
||||
- `physical-pending`: digital behavior exists but synthesis or later evidence is required.
|
||||
- `planned`: the implementation is not complete.
|
||||
|
||||
## Requirement matrix
|
||||
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
The architecture report under `/nfs/share/home/miaoyuchi/plan` is the design
|
||||
input. This matrix and executable configuration are the repository status
|
||||
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.
|
||||
- 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.
|
||||
|
||||
The strict IHP130 warning-baseline comparison remains an observation: the
|
||||
baseline predates the fixed HP/product topology and does not contain many
|
||||
generated VexiiRiscv, newly enabled peripheral, and PDK signatures. New warning
|
||||
signatures introduced directly by the data-plane, lifecycle, extension, and
|
||||
CDC integration were removed; the baseline was intentionally not regenerated
|
||||
or hand-edited in this change.
|
||||
|
||||
Synthesis, netlist simulation, STA, CDC/RDC signoff, gate-level power intent,
|
||||
and PVT characterization are intentionally outside this delivery, as required
|
||||
by the implementation scope.
|
||||
@@ -21,7 +21,8 @@ Applications use `rs_clock_set_frequency()` and `rs_clock_get_status()` from
|
||||
|
||||
1. Run the transition routine from SRAM, disable interrupts, and quiesce DMA,
|
||||
serial transfers, and other frequency-sensitive transactions.
|
||||
2. Call `rs_clock_set_frequency()` and wait with a bounded timeout.
|
||||
2. Call `rs_clock_set_frequency()` and wait with a bounded timeout. The
|
||||
programmed `CLK_TIMEOUT` is also the AON quiesce and PLL-lock budget.
|
||||
3. On success, reprogram UART, SPI, I2C, timer, and other divider-dependent
|
||||
peripherals for the new frequency before restoring normal operation.
|
||||
4. `RS_ENOTSUP` means the current PDK has no integrated dynamic PLL or
|
||||
@@ -32,3 +33,9 @@ Applications use `rs_clock_set_frequency()` and `rs_clock_get_status()` from
|
||||
must integrate a characterized PLL macro, lock timing, and glitch-free clock
|
||||
switch before setting capability to 1. The ICS55 hard wrapper advertises only
|
||||
the qualified selector-0 configuration; requests for other selectors fail safe.
|
||||
|
||||
AON Gray-counter monitors track EXT72, HP root, PCLK, and the stable memory
|
||||
root without sampling their pulses directly at 24 MHz. A stopped clock sets a
|
||||
sticky clock fault. `CLK_GATE[0]` drives the HP-core leaf ICG; the AXI64 fabric
|
||||
and memory root remain active for management recovery and DMA. Technology
|
||||
timing, scan force-on, and analogue PLL qualification remain physical gates.
|
||||
@@ -0,0 +1,376 @@
|
||||
#set document(
|
||||
title: "retroSoC Mini Gen2 Datasheet",
|
||||
author: "Yuchi Miao",
|
||||
keywords: "retroSoC",
|
||||
)
|
||||
#set page(
|
||||
header: align(center)[
|
||||
https://github.com/retroSoC
|
||||
],
|
||||
numbering: "1/1",
|
||||
columns: 1,
|
||||
)
|
||||
|
||||
#set par(justify: true)
|
||||
#set text(font: "Inter", size: 11pt)
|
||||
#set heading(numbering: "1.")
|
||||
|
||||
|
||||
#show title: set text(size: 17pt)
|
||||
#show link: underline
|
||||
|
||||
#title[
|
||||
retroSoC Mini Series Gen2/Gen2+
|
||||
]
|
||||
|
||||
#place(
|
||||
top + right,
|
||||
dx: 0pt,
|
||||
// square(size: 36pt, fill: none, stroke: black),
|
||||
rect(height: 66pt, width: 140pt, fill: none, stroke: black),
|
||||
)
|
||||
|
||||
Datasheet (rev.3 – 2026.02.15) \
|
||||
*Author:* Yuchi Miao (#link("miaoyuchi@ict.ac.cn")) \
|
||||
*Maintained by* _ECOS Team, ICT, CAS_
|
||||
|
||||
#line(length: 100%)
|
||||
A *Lightweight* RV32I/EMC *MCU Framework* with *128KiB* OCM, 1xXPI, 2xSPISD/SDIO, 2xPSRAM(SDR/DTR), 1xSDRAM, 24xGPIO, 1xDMA, 3xTIMER, 1xRTC, 1xWDG, 4xPWM, 2xUART, 2xI2C, 1xONEWIRE, 1xPS2, 1xARCHINFO, 1xSYSCTRL, 1xRCU, 1xRNG, 1xCRC, 1xI2S, 1xDVP, 1xAPU\*, 1xGA\*, 1xCRC, 1xRNG
|
||||
#line(length: 100%)
|
||||
|
||||
|
||||
= Product Brief
|
||||
#place(
|
||||
top + right,
|
||||
dx: 0pt,
|
||||
dy: 168pt,
|
||||
grid(
|
||||
columns: auto,
|
||||
align: center,
|
||||
gutter: 3pt,
|
||||
// stroke: black,
|
||||
rect(height: 27pt, width: 250pt, fill: white, stroke: black, radius: 6pt)[
|
||||
#grid(
|
||||
columns: (1fr, 1fr, 1fr, 1fr),
|
||||
align: center,
|
||||
gutter: 3pt,
|
||||
// stroke: black,
|
||||
text("Available", size: 8pt, weight: "medium"),
|
||||
text("Functional", size: 8pt, weight: "medium"),
|
||||
text("Reproduced", size: 8pt, weight: "medium"),
|
||||
text("Tapedout", size: 8pt, weight: "medium"),
|
||||
circle(radius: 4pt, stroke: black, fill: yellow.lighten(60%)),
|
||||
circle(radius: 4pt, stroke: black, fill: white),
|
||||
circle(radius: 4pt, stroke: black, fill: white),
|
||||
circle(radius: 4pt, stroke: black, fill: white),
|
||||
)
|
||||
],
|
||||
text("Artifact Evaluation", size: 7pt, weight: "medium")
|
||||
),
|
||||
)
|
||||
|
||||
== Feature
|
||||
#columns(2)[
|
||||
|
||||
- Core – PicoRV32/Hazard3
|
||||
- *196MHz* maximum frequency
|
||||
- 2-pipeline RV32I/E\[MAC\], 16xIRQ
|
||||
- Hardware multiplication and division
|
||||
|
||||
- Memories
|
||||
- *0\~128KiB* On-Chip-RAM *(OCM)*
|
||||
- *32MiB* XPI NOR Flash Controller
|
||||
- *8/32MiB* PSRAM Controller
|
||||
- *64MiB* 16bit SDRAM Controller
|
||||
|
||||
- Bus – Async. *No-burst* Protocol
|
||||
- Native Memory Interface *(NMI)*
|
||||
- AXI4-Lite master, APB3 slave
|
||||
- NMI, AXI4L, APB3 Interconnect
|
||||
|
||||
- Reset Clock Unit *(RCU)*
|
||||
- *4\~50MHz* Active Crystal Oscillator
|
||||
- PLL for core clock *(24\~192MHz)*
|
||||
- PLL or Bypass mode
|
||||
|
||||
- XPI *(SDR mode only)*
|
||||
- Half-duplex, SPI/DPI/QSPI/QPI mode
|
||||
- 32x32b TX/RX dual FIFO Integrated
|
||||
- Register/Memory-mapped/DMA
|
||||
|
||||
- SPISD/SDIO (SDHC, 4\~32GB)
|
||||
- *1GiB* Memory-mapped access
|
||||
- 1/4-wire SPI or SDIO mode *(SDv2.0)*
|
||||
- 512B cache, 50MHz maximum freq.
|
||||
|
||||
- I2S (HQ, Hi-Res audio)
|
||||
- Stereo input/output mode
|
||||
- max *24b/96KHz* format support
|
||||
- Full-duplex, I2S Phillips only
|
||||
|
||||
#colbreak()
|
||||
|
||||
- DVP (Camera interface)
|
||||
- 8-bit parallel input mode
|
||||
- max *2M* image sensor support
|
||||
- RGB565 format support only
|
||||
|
||||
- APU/GA\* *(Experimental integrate)*
|
||||
- Audio Keyword Wake-Up (CNN)
|
||||
- Simple 2D/3D graphics render
|
||||
- High performance DMA engine
|
||||
|
||||
- Other Communication Interfaces
|
||||
- 2xUARTs (FIFO/No FIFO)
|
||||
- 3xTIMER, 1xRTC, 1xWDG, 4xPWM
|
||||
- 1xRNG, 1xARCHINFO, 1xSYSCTRL
|
||||
- 1xONEWIRE, 1xCRC, 1xI2C, 1xPS2
|
||||
|
||||
- *GDS Merge Template*
|
||||
- *0\~32* master designs (Core)
|
||||
- *0\~256* slave designs (digital module)
|
||||
- 16xGPIO, max 5000 cells per design
|
||||
|
||||
- Development
|
||||
- *Open source* and full synthesizable
|
||||
- Static synchronous design
|
||||
- *ICS55*, IHP130 PDK support
|
||||
- RV32I/E\[MAC\] C Running Time *(CRT)*
|
||||
|
||||
- Tools & Flows
|
||||
- VCS, Verilator, iVerilog (TBD)
|
||||
- Yosys, ECC, Pristine (TBD)
|
||||
- *QFN128* (12.3x12.3mm) Package
|
||||
|
||||
- Application
|
||||
- *Wearables*;, IoT services, E-readers
|
||||
- Education, ASIC Prototype
|
||||
]
|
||||
|
||||
|
||||
#figure(
|
||||
image(
|
||||
"retroSoC-mini-block-diagram.svg",
|
||||
width: 100%,
|
||||
),
|
||||
caption: [
|
||||
*_retroSoC Mini Gen2/Gen2+_* block diagram
|
||||
],
|
||||
)<block-diagram>
|
||||
|
||||
|
||||
== Overview
|
||||
_*retroSoC*_ is a fully open-source and customizable ASIC framework for _*“retro-style”*_ applications(handheld game consoles, system). And of ECOS Team.\
|
||||
(story, target, my thinking, be dedicated to retro multimedia area, full open source, focus on funny)
|
||||
(insert a retro poster/diagram to descripte the motivation[why])
|
||||
|
||||
- *Open source*: It is both straightforward to use and highly compatible with EDA toolchains — specifically targeting open-source EDA *(iEDA, OpenROAD, etc)*.
|
||||
|
||||
- *HW-SW co*:
|
||||
|
||||
- *Time to market*: focus on the funcitonality, seprate into 4 series
|
||||
|
||||
- *Lower the price*: Additionally, retroSoC can also serve as a flexible, reconfigurable *SoC template* for end customers or students who want to integrate their own design into a shared fabrication wafer *(shuttle)*.
|
||||
|
||||
- *Well documented*: balba
|
||||
|
||||
The _*retroSoC Mini Series*_ is a family of highly integrated, lightweight MCU designed for Internet of Things *(IoT)* scenarios. _*retroSoC Mini Gen2/Gen2+*_ adopts the PicoRV32/Hazard3 core and integrates DMA, SPISD/SDIO, SDRAM, I2S and XPI IPs. It can be used for a wide variety of applications as wearables, education or ASIC prototype verification.
|
||||
#lorem(380)
|
||||
|
||||
== Product Series
|
||||
#lorem(100)
|
||||
#figure(
|
||||
image(
|
||||
"retroSoC-Product-Series.svg",
|
||||
width: 100%,
|
||||
),
|
||||
caption: [
|
||||
*_retroSoC_* Product series
|
||||
],
|
||||
)<product-series>
|
||||
|
||||
== Roadmap
|
||||
#lorem(100)
|
||||
#figure(
|
||||
image(
|
||||
"retroSoC-Roadmap.svg",
|
||||
width: 100%,
|
||||
),
|
||||
caption: [
|
||||
*_retroSoC_* Roadmap
|
||||
],
|
||||
)<product-rodamap>
|
||||
|
||||
|
||||
== Revision History
|
||||
|
||||
#set table(
|
||||
stroke: black,
|
||||
gutter: 0em,
|
||||
fill: (x, y) => if y == 0 { yellow.lighten(60%) },
|
||||
)
|
||||
|
||||
#show table.cell: it => {
|
||||
if it.y == 0 {
|
||||
set text(black)
|
||||
strong(it)
|
||||
} else if it.body == [] {
|
||||
pad(..it.inset)[_N/A_]
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
#table(
|
||||
columns: (1fr, 1fr, 1fr, 1fr),
|
||||
[Date], [Version], [Release Note], [Author],
|
||||
[2025-09-28], [v0.1], [Create document], [Yuchi Miao],
|
||||
[2025-12-02], [v0.2], [Initial draft], [Yuchi Miao],
|
||||
[2026-02-15], [v0.3], [Initial release], [Yuchi Miao],
|
||||
)
|
||||
|
||||
== License
|
||||
#lorem(60)
|
||||
#pagebreak()
|
||||
|
||||
#outline()
|
||||
|
||||
= System Architecture
|
||||
== Introduction
|
||||
=== SoC Architecture
|
||||
=== Management Processor
|
||||
==== PicoRV32
|
||||
==== Hazard3
|
||||
|
||||
== Interconnect
|
||||
=== Native Memory Interface *(NMI)*
|
||||
=== Interconnect Matrix
|
||||
=== Address Mapping
|
||||
|
||||
== Clock and Reset
|
||||
=== Architecture
|
||||
=== Reset and Logic
|
||||
|
||||
== Interrupt System
|
||||
== Packaging
|
||||
=== Pin Mapping
|
||||
=== Package Dimensions
|
||||
=== Graded Reflow Soldering
|
||||
=== Ordering Information
|
||||
|
||||
== Peripherals
|
||||
|
||||
=== Memory Interface
|
||||
==== Non-Volatile Memory *(NVM)*
|
||||
===== XPI Universal Controller *(XPI)*
|
||||
===== SPI SD Card Controller *(SPISD)*
|
||||
===== SD Card Controller *(SDIO0)*
|
||||
==== Volatile Memory *(VM)*
|
||||
===== On Chip Memory *(OCM)*
|
||||
===== PSRAM Controller *(PSRAM)*
|
||||
===== SDRAM Controller *(SDRAM)*
|
||||
|
||||
=== General-Purpose Input Output *(GPIO)*
|
||||
==== System IO *(GPIO0)*
|
||||
==== User Custom IO *(GPIO1)*
|
||||
|
||||
=== Direct Memory Access *(DMA)*
|
||||
==== Architecture
|
||||
==== Hardware Trigger Channels
|
||||
|
||||
=== Timers
|
||||
==== General-Purpose Timer *(TIM0, TIM1)*
|
||||
==== Advanced Timer *(TIM2)*
|
||||
==== Real Time Clock *(RTC)*
|
||||
==== Watchdog *(WDG)*
|
||||
==== Pulse Width Modulation *(PWM)*
|
||||
|
||||
=== IO Interface
|
||||
==== Universal Async. Receiver/Transmitter *(UART)*
|
||||
===== Simple No-FIFO Version *(UART0)*
|
||||
===== Advanced FIFO Version *(UART1)*
|
||||
==== Inter-Integrated Circuit *(I2C)*
|
||||
==== One Wire Serial Bus *(ONEWIRE)*
|
||||
==== Personal System/2 *(PS2)*
|
||||
==== SDIO Controller *(SDIO1)*
|
||||
==== Architecture Information *(ARCHINFO)*
|
||||
==== System Controller *(SYSCTRL)*
|
||||
==== Reset Clock Unit *(RCU)*
|
||||
|
||||
=== Multimedia
|
||||
==== Inter-Integrated Circuit Sound *(I2S)*
|
||||
==== Extended Peripheral Interface *(XPI)*
|
||||
==== Digital Video Port *(DVP)*
|
||||
==== Audio Processing Unit\* *(APU)*
|
||||
==== Graphic Accelerator\* *(GA)*
|
||||
|
||||
=== Encryption
|
||||
==== Cyclic Redundancy Check *(CRC)*
|
||||
==== Random Number Generator *(RNG)*
|
||||
|
||||
== Software
|
||||
=== Boot Sequence
|
||||
=== TinySDK and TinyShell
|
||||
=== Application
|
||||
|
||||
== SoC Template
|
||||
=== Architecture
|
||||
=== User Guide
|
||||
|
||||
== Implementation
|
||||
=== SoC Integration
|
||||
=== RTL Simulation
|
||||
=== FPGA Verification
|
||||
=== Physical Design
|
||||
=== PCB Hardware
|
||||
|
||||
= Technical Report (ongoing)
|
||||
== First Shuttle *(2026.06.01, ICS55nm)*
|
||||
|
||||
Overview(written in SystemVerilog)
|
||||
|
||||
1. Introduction (arch info first)
|
||||
|
||||
1.1 core(info, wavedorm)
|
||||
|
||||
1.2 bus(nmi intro, matrix, addr mmap)
|
||||
|
||||
1.3 clock&reset (block diagram, wavedorm)
|
||||
|
||||
1.4 IO/Package(voltage, IO pad speed, IO pos)
|
||||
|
||||
2. Peripherals
|
||||
|
||||
2.1 Memory
|
||||
|
||||
2.2 DMA
|
||||
|
||||
2.3 Timer
|
||||
|
||||
2.4 IO perip
|
||||
|
||||
2.5 Encryption
|
||||
|
||||
3. Software
|
||||
|
||||
3.1 boot sequ.
|
||||
|
||||
3.2 application
|
||||
|
||||
4. SoC Template
|
||||
|
||||
4.1 intro four mode(bakcend GDS)
|
||||
|
||||
4.2 how to integrate 'core' or 'IP design'
|
||||
|
||||
5. Implemention
|
||||
|
||||
5.1 FPGA
|
||||
|
||||
5.2 Backend(SDC, ICS55 example)
|
||||
|
||||
5.3 PCB+
|
||||
|
||||
6. Resource &
|
||||
|
||||
6.1
|
||||
@@ -683,7 +683,13 @@ module sysctrl_core (
|
||||
HpCtrl: read_data_o = {31'd0, s_hp_release_q};
|
||||
HpStatus:
|
||||
read_data_o = {
|
||||
29'd0, sysctrl.hp_present_i && !s_hp_release_q, s_hp_release_q, sysctrl.hp_present_i
|
||||
26'd0,
|
||||
sysctrl.hp_actual_released_i,
|
||||
sysctrl.hp_forced_fault_i,
|
||||
sysctrl.hp_draining_i,
|
||||
sysctrl.hp_present_i && !s_hp_release_q,
|
||||
s_hp_release_q,
|
||||
sysctrl.hp_present_i
|
||||
};
|
||||
DebugSelect: read_data_o = {31'd0, s_debug_hp_sel_q};
|
||||
ClockHpReq: read_data_o = {29'd0, s_pll_cfg_q};
|
||||
|
||||
@@ -37,6 +37,9 @@ interface sysctrl_if ();
|
||||
logic [ 7:0] test_code_o;
|
||||
logic [ `USER_IPSEL_WIDTH-1:0] ip_sel_o;
|
||||
logic hp_present_i;
|
||||
logic hp_actual_released_i;
|
||||
logic hp_draining_i;
|
||||
logic hp_forced_fault_i;
|
||||
logic hp_release_o;
|
||||
logic debug_hp_select_o;
|
||||
|
||||
@@ -58,6 +61,9 @@ interface sysctrl_if ();
|
||||
input perf_flash_wait_i,
|
||||
input rtc_wake_i,
|
||||
input hp_present_i,
|
||||
input hp_actual_released_i,
|
||||
input hp_draining_i,
|
||||
input hp_forced_fault_i,
|
||||
output core_sel_o,
|
||||
output core_reset_o,
|
||||
output user_bus_enable_o,
|
||||
|
||||
@@ -95,24 +95,25 @@ bind rib2apb rib2apb_sva #(
|
||||
module soc_pll_rcu_sva (
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [2:0] state_i,
|
||||
input logic [3:0] state_i,
|
||||
input logic pll_capable_i,
|
||||
input logic pll_apply_i,
|
||||
input logic select_ext_clk_i
|
||||
);
|
||||
|
||||
localparam logic [2:0] PLL_SAFE = 3'd1;
|
||||
localparam logic [2:0] PLL_APPLY = 3'd2;
|
||||
localparam logic [2:0] PLL_WAIT_LOCK = 3'd3;
|
||||
localparam logic [2:0] PLL_RESPOND = 3'd5;
|
||||
localparam logic [3:0] PLL_VALIDATE = 4'd1;
|
||||
localparam logic [3:0] PLL_APPLY = 4'd4;
|
||||
localparam logic [3:0] PLL_WAIT_LOCK_LOW = 4'd5;
|
||||
localparam logic [3:0] PLL_QUALIFY_LOCK = 4'd6;
|
||||
localparam logic [3:0] PLL_FAIL_SAFE = 4'd10;
|
||||
|
||||
// The output remains on the external clock until the PLL switch stage completes.
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
state_i == PLL_SAFE |-> select_ext_clk_i);
|
||||
((state_i == PLL_APPLY) || (state_i == PLL_WAIT_LOCK_LOW) ||
|
||||
(state_i == PLL_QUALIFY_LOCK)) |-> select_ext_clk_i);
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i) pll_apply_i |-> state_i == PLL_APPLY);
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
pll_apply_i |-> state_i inside {PLL_APPLY, PLL_WAIT_LOCK});
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
state_i == PLL_SAFE && !pll_capable_i |=> state_i == PLL_RESPOND);
|
||||
state_i == PLL_VALIDATE && !pll_capable_i |=> state_i == PLL_FAIL_SAFE);
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -122,7 +123,7 @@ bind pll_rcu_controller soc_pll_rcu_sva u_soc_pll_rcu_sva (
|
||||
.state_i (s_state_q),
|
||||
.pll_capable_i (pll_capable_i),
|
||||
.pll_apply_i (pll_apply_o),
|
||||
.select_ext_clk_i(select_ext_clk_o)
|
||||
.select_ext_clk_i(sel_ext_clk_o)
|
||||
);
|
||||
|
||||
module soc_gpio_user_handoff_sva #(
|
||||
|
||||
@@ -250,6 +250,19 @@ module retrosoc_tb;
|
||||
if ($value$plusargs("sim_timeout=%d", sim_runtime) && sim_runtime > 0) begin
|
||||
$display("Simulation timeout set to: %0dns", sim_runtime);
|
||||
#sim_runtime;
|
||||
$display("CLOCK_RESET_DIAG aon=%0b lp=%0b hp=%0b pclk=%0b mem=%0b",
|
||||
u_retrosoc_asic.s_aon_rst_n, u_retrosoc_asic.s_sys_rst_n, u_retrosoc_asic.s_hp_rst_n,
|
||||
u_retrosoc_asic.s_pclk_rst_n, u_retrosoc_asic.s_mem_rst_n);
|
||||
$display("DATA_PLANE_DIAG rcu_block=%0b lifecycle_block=%0b flush=%0b busy=%0b idle=%0b",
|
||||
u_retrosoc_asic.s_hp_block, u_retrosoc_asic.u_retrosoc.s_hp_lifecycle_block,
|
||||
u_retrosoc_asic.u_retrosoc.s_hp_lifecycle_flush,
|
||||
u_retrosoc_asic.u_retrosoc.s_data_plane_flush_busy,
|
||||
u_retrosoc_asic.u_retrosoc.s_data_plane_idle);
|
||||
$display("LP_GATEWAY_DIAG src_arvalid=%0b src_arready=%0b dst_arvalid=%0b dst_arready=%0b",
|
||||
u_retrosoc_asic.u_retrosoc.u_mgmt_data_axi4_if.arvalid,
|
||||
u_retrosoc_asic.u_retrosoc.u_mgmt_data_axi4_if.arready,
|
||||
u_retrosoc_asic.u_retrosoc.u_data_plane.u_lp_data_hp_axi4.arvalid,
|
||||
u_retrosoc_asic.u_retrosoc.u_data_plane.u_lp_data_hp_axi4.arready);
|
||||
$fatal(1, "SIM_TEST_TIMEOUT");
|
||||
end
|
||||
$display("Simulation timeout disabled; waiting for terminal software status");
|
||||
|
||||
@@ -85,7 +85,7 @@ module retrosoc_top (
|
||||
wire s_jtag_trst_n;
|
||||
wire s_jtag_tdo;
|
||||
wire s_uart1_tx;
|
||||
tri1 s_uart1_rx;
|
||||
wire s_uart1_rx;
|
||||
wire s_usb2_ulpi_clk;
|
||||
tri0 s_usb2_ulpi_dir;
|
||||
tri0 s_usb2_ulpi_nxt;
|
||||
@@ -103,6 +103,7 @@ module retrosoc_top (
|
||||
assign s_jtag_tms = jtag_tms_i;
|
||||
assign s_jtag_tdi = jtag_tdi_i;
|
||||
assign s_jtag_trst_n = jtag_trst_n_i;
|
||||
assign s_uart1_rx = s_uart1_tx;
|
||||
assign jtag_tdo_o = s_jtag_tdo;
|
||||
assign test_done_o = u_retrosoc_asic.s_test_done;
|
||||
assign test_pass_o = u_retrosoc_asic.s_test_pass;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
/top/rib2apb.sv
|
||||
/top/axi4_connector.sv
|
||||
/top/axi4_master_idle.sv
|
||||
/top/axi4_mgmt_router.sv
|
||||
/top/axi4_async_bridge.sv
|
||||
/top/axi4_address_gate.sv
|
||||
/top/axi4_upsizer_32to64.sv
|
||||
@@ -38,8 +39,11 @@
|
||||
/top/rcu.sv
|
||||
/top/pll_rcu_controller.sv
|
||||
/top/clock_config_controller.sv
|
||||
/top/clock_frequency_monitor.sv
|
||||
/top/soc_clock_gate.sv
|
||||
/top/soc_clock_reset_subsystem.sv
|
||||
/top/mgmt_debug_reset.sv
|
||||
/top/hp_lifecycle_controller.sv
|
||||
/top/mgmt_debug_wrapper.sv
|
||||
/top/mgmt_core_wrapper.sv
|
||||
/top/hp_core_wrapper.sv
|
||||
@@ -50,6 +54,7 @@
|
||||
/top/user_ip_top.sv
|
||||
/top/user_ip_wrapper.sv
|
||||
/top/extension_slot.sv
|
||||
/top/extension_dma_master.sv
|
||||
/top/extension_compat.sv
|
||||
/top/extension_subsystem.sv
|
||||
/sva/rib_protocol_sva.sv
|
||||
|
||||
@@ -28,6 +28,8 @@ TOP = ROOT / "rtl/mini/top"
|
||||
def target_defines(target: str) -> list[str]:
|
||||
if target in {"onchip_ram", "opipsram"}:
|
||||
return ["+define+PDK_BEHAV"]
|
||||
if target == "sysctrl":
|
||||
return ["+define+SV_ASSRT_DISABLE", "+define+MINI_PRODUCT"]
|
||||
return ["+define+SV_ASSRT_DISABLE"]
|
||||
|
||||
|
||||
@@ -72,6 +74,7 @@ def source_files(target: str) -> list[Path]:
|
||||
*common,
|
||||
COMMON_RTL / "cdc/cdc_sync.sv",
|
||||
PERIPHERAL / "pll_ctrl_if.sv",
|
||||
PERIPHERAL / "clock_ctrl_if.sv",
|
||||
PERIPHERAL / "sysctrl_if.sv",
|
||||
PERIPHERAL / "sysctrl_define.svh",
|
||||
PERIPHERAL / "sysctrl_reg.sv",
|
||||
@@ -89,6 +92,7 @@ def source_files(target: str) -> list[Path]:
|
||||
COMMON_RTL / "clkrst/counter.sv",
|
||||
COMMON_RTL / "utils/edge_det.sv",
|
||||
PERIPHERAL / "pll_ctrl_if.sv",
|
||||
PERIPHERAL / "clock_ctrl_if.sv",
|
||||
PERIPHERAL / "clint_timebase.sv",
|
||||
TOP / "rcu.sv",
|
||||
TOP / "pll_rcu_controller.sv",
|
||||
|
||||
@@ -19,13 +19,12 @@ module pll_rcu_formal_design (
|
||||
output logic rsp_ready,
|
||||
output logic pll_lock,
|
||||
output logic pll_capable,
|
||||
output logic [2:0] state,
|
||||
output logic [3:0] state,
|
||||
output logic pll_apply,
|
||||
output logic select_ext_clk,
|
||||
output logic active_valid,
|
||||
output logic safe_clk,
|
||||
output logic active_lock,
|
||||
output logic lock_seen_low,
|
||||
output logic [1:0] error
|
||||
);
|
||||
|
||||
@@ -47,13 +46,10 @@ module pll_rcu_formal_design (
|
||||
assign rsp_ready = pll_ctrl.rsp_ready_o;
|
||||
assign pll_lock = f_pll_lock;
|
||||
assign pll_capable = f_pll_capable;
|
||||
assign state = u_dut.s_state_q;
|
||||
assign pll_apply = u_dut.s_pll_apply_q;
|
||||
assign select_ext_clk = u_dut.s_sel_ext_clk_q;
|
||||
assign state = u_dut.s_state_bits_q;
|
||||
assign active_valid = u_dut.s_active_valid_q;
|
||||
assign safe_clk = u_dut.s_safe_clk_q;
|
||||
assign active_lock = u_dut.s_lock_q;
|
||||
assign lock_seen_low = u_dut.s_lock_seen_low_q;
|
||||
assign error = u_dut.s_err_q;
|
||||
|
||||
// Both controller domains share the formal clock. This proves the control
|
||||
@@ -61,16 +57,24 @@ module pll_rcu_formal_design (
|
||||
pll_rcu_controller #(
|
||||
.LockTimeout(4)
|
||||
) u_dut (
|
||||
.sys_clk_i (clk_i),
|
||||
.sys_rst_n_i (rst_n_i),
|
||||
.ext_clk_i (clk_i),
|
||||
.ext_rst_n_i (rst_n_i),
|
||||
.pll_lock_i (f_pll_lock),
|
||||
.pll_capable_i (f_pll_capable),
|
||||
.pll_sel_o (),
|
||||
.pll_apply_o (),
|
||||
.select_ext_clk_o(),
|
||||
.pll_ctrl (pll_ctrl)
|
||||
.sys_clk_i (clk_i),
|
||||
.sys_rst_n_i (rst_n_i),
|
||||
.ext_clk_i (clk_i),
|
||||
.ext_rst_n_i (rst_n_i),
|
||||
.pll_lock_i (f_pll_lock),
|
||||
.pll_capable_i (f_pll_capable),
|
||||
.hp_idle_i (1'b1),
|
||||
.pclk_idle_i (1'b1),
|
||||
.timeout_i (16'd16),
|
||||
.force_safe_i (1'b0),
|
||||
.clear_fault_i (1'b0),
|
||||
.pll_sel_o (),
|
||||
.pll_apply_o (pll_apply),
|
||||
.sel_ext_clk_o (select_ext_clk),
|
||||
.hp_block_o (),
|
||||
.lp_force_ref_o(),
|
||||
.pll_fault_o (),
|
||||
.pll_ctrl (pll_ctrl)
|
||||
);
|
||||
|
||||
initial begin
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
|
||||
module pll_rcu_formal;
|
||||
|
||||
localparam [2:0] PLL_IDLE = 3'd0;
|
||||
localparam [2:0] PLL_SAFE = 3'd1;
|
||||
localparam [2:0] PLL_APPLY = 3'd2;
|
||||
localparam [2:0] PLL_WAIT_LOCK = 3'd3;
|
||||
localparam [2:0] PLL_SWITCH = 3'd4;
|
||||
localparam [2:0] PLL_RESPOND = 3'd5;
|
||||
localparam [3:0] PLL_APPLY = 4'd4;
|
||||
localparam [3:0] PLL_WAIT_LOCK_LOW = 4'd5;
|
||||
localparam [3:0] PLL_QUALIFY_LOCK = 4'd6;
|
||||
localparam [3:0] PLL_SWITCH = 4'd7;
|
||||
localparam [3:0] PLL_RESTORE_LP = 4'd8;
|
||||
localparam [3:0] PLL_RESPOND = 4'd9;
|
||||
localparam [3:0] PLL_FAIL_SAFE = 4'd10;
|
||||
|
||||
(* anyseq *) (* gclk *)reg clk_i;
|
||||
wire rst_n_i;
|
||||
@@ -27,13 +28,12 @@ module pll_rcu_formal;
|
||||
wire rsp_ready;
|
||||
wire pll_lock;
|
||||
wire pll_capable;
|
||||
wire [2:0] state;
|
||||
wire [3:0] state;
|
||||
wire pll_apply;
|
||||
wire select_ext_clk;
|
||||
wire active_valid;
|
||||
wire safe_clk;
|
||||
wire active_lock;
|
||||
wire lock_seen_low;
|
||||
wire [1:0] error;
|
||||
|
||||
pll_rcu_formal_design u_design (
|
||||
@@ -53,7 +53,6 @@ module pll_rcu_formal;
|
||||
.active_valid (active_valid),
|
||||
.safe_clk (safe_clk),
|
||||
.active_lock (active_lock),
|
||||
.lock_seen_low (lock_seen_low),
|
||||
.error (error)
|
||||
);
|
||||
|
||||
@@ -64,25 +63,30 @@ module pll_rcu_formal;
|
||||
end
|
||||
|
||||
if (rst_n_i) begin
|
||||
assert(!(state == PLL_SAFE || state == PLL_APPLY || state == PLL_WAIT_LOCK) ||
|
||||
select_ext_clk);
|
||||
assert (!pll_apply || state != PLL_IDLE && state != PLL_SAFE);
|
||||
if (f_past_valid && $past(state == PLL_SAFE && !pll_capable)) begin
|
||||
assert (state == PLL_RESPOND);
|
||||
assert (safe_clk);
|
||||
assert (!active_valid);
|
||||
assert (error == 2'd1);
|
||||
end
|
||||
if (f_past_valid && $past(state == PLL_WAIT_LOCK && pll_lock && lock_seen_low)) begin
|
||||
assert (state == PLL_SWITCH);
|
||||
assert (!(state == PLL_APPLY || state == PLL_WAIT_LOCK_LOW ||
|
||||
state == PLL_QUALIFY_LOCK) || (select_ext_clk && safe_clk));
|
||||
assert (!(state == PLL_APPLY || state == PLL_WAIT_LOCK_LOW ||
|
||||
state == PLL_QUALIFY_LOCK) ||
|
||||
(error == 2'd0 && !active_valid && !active_lock));
|
||||
assert (!pll_apply || state == PLL_WAIT_LOCK_LOW);
|
||||
if (state == PLL_SWITCH) begin
|
||||
assert (active_valid);
|
||||
assert (!safe_clk);
|
||||
assert (select_ext_clk);
|
||||
assert (safe_clk);
|
||||
assert (active_lock);
|
||||
assert (error == 2'd0);
|
||||
end
|
||||
if (f_past_valid && $past(state == PLL_SWITCH)) begin
|
||||
assert (state == PLL_RESPOND);
|
||||
assert (state == PLL_RESTORE_LP);
|
||||
assert (!select_ext_clk);
|
||||
assert (!safe_clk);
|
||||
end
|
||||
if (f_past_valid && $past(state == PLL_FAIL_SAFE)) begin
|
||||
assert (state == PLL_RESPOND);
|
||||
assert (select_ext_clk);
|
||||
assert (safe_clk);
|
||||
assert (!active_valid);
|
||||
assert (!active_lock);
|
||||
end
|
||||
cover (state == PLL_SWITCH && active_valid && active_lock);
|
||||
cover (state == PLL_RESPOND && error == 2'd1);
|
||||
|
||||
@@ -53,6 +53,7 @@ module sysctrl_formal_design (
|
||||
);
|
||||
sysctrl_if sysctrl ();
|
||||
pll_ctrl_if pll_ctrl ();
|
||||
clock_ctrl_if clock_ctrl ();
|
||||
|
||||
(* anyseq *)logic f_apb_sel;
|
||||
(* anyseq *)logic [31:0] f_apb_addr;
|
||||
@@ -70,6 +71,12 @@ module sysctrl_formal_design (
|
||||
(* anyseq *)logic [31:0] f_fault_addr;
|
||||
(* anyseq *)logic [ 3:0] f_fault_wstrb;
|
||||
(* anyseq *)logic f_fault_reserved;
|
||||
(* anyseq *)logic f_clock_req_ready;
|
||||
(* anyseq *)logic f_clock_rsp_valid;
|
||||
(* anyseq *)logic [31:0] f_clock_rsp_data;
|
||||
(* anyseq *)logic [31:0] f_clock_current;
|
||||
(* anyseq *)logic [31:0] f_clock_fault;
|
||||
(* anyseq *)logic [31:0] f_clock_memory;
|
||||
|
||||
assign apb4.psel = f_apb_sel;
|
||||
assign apb4.penable = f_apb_sel;
|
||||
@@ -95,6 +102,9 @@ module sysctrl_formal_design (
|
||||
assign sysctrl.perf_flash_wait_i = '0;
|
||||
assign sysctrl.rtc_wake_i = 1'b0;
|
||||
assign sysctrl.hp_present_i = 1'b1;
|
||||
assign sysctrl.hp_actual_released_i = 1'b0;
|
||||
assign sysctrl.hp_draining_i = 1'b0;
|
||||
assign sysctrl.hp_forced_fault_i = 1'b0;
|
||||
assign pll_ctrl.req_ready_i = f_pll_req_ready;
|
||||
assign pll_ctrl.rsp_active_sel_i = f_pll_active_sel;
|
||||
assign pll_ctrl.rsp_active_valid_i = f_pll_active_valid;
|
||||
@@ -103,6 +113,12 @@ module sysctrl_formal_design (
|
||||
assign pll_ctrl.rsp_error_i = f_pll_rsp_error;
|
||||
assign pll_ctrl.rsp_valid_i = f_pll_rsp_valid;
|
||||
assign pll_ctrl.capable_i = f_pll_capable;
|
||||
assign clock_ctrl.req_ready_i = f_clock_req_ready;
|
||||
assign clock_ctrl.rsp_valid_i = f_clock_rsp_valid;
|
||||
assign clock_ctrl.rsp_data_i = f_clock_rsp_data;
|
||||
assign clock_ctrl.current_i = f_clock_current;
|
||||
assign clock_ctrl.fault_i = f_clock_fault;
|
||||
assign clock_ctrl.memory_i = f_clock_memory;
|
||||
|
||||
assign rib_valid = apb4.psel;
|
||||
assign rib_addr = apb4.paddr;
|
||||
@@ -111,8 +127,12 @@ module sysctrl_formal_design (
|
||||
assign rib_ready = apb4.pready;
|
||||
assign ip_sel = sysctrl.ip_sel_o;
|
||||
assign core_sel = u_dut.u_sysctrl_core.s_sysctrl_coresel_q;
|
||||
assign user_reset = {{(32 - `USER_CORE_COUNT) {1'b0}}, u_dut.u_sysctrl_core.s_user_reset_q};
|
||||
assign user_reset_mask = {{(32 - `USER_CORE_COUNT) {1'b0}}, {`USER_CORE_COUNT{1'b1}}};
|
||||
assign user_reset = {
|
||||
{(32 - `USER_CORE_STORAGE_COUNT) {1'b0}}, u_dut.u_sysctrl_core.s_user_reset_q
|
||||
};
|
||||
assign user_reset_mask = {
|
||||
{(32 - `USER_CORE_STORAGE_COUNT) {1'b0}}, {`USER_CORE_STORAGE_COUNT{1'b1}}
|
||||
};
|
||||
assign user_core_count = `USER_CORE_COUNT;
|
||||
assign user_bus_enable = u_dut.u_sysctrl_core.s_user_running_q;
|
||||
assign user_config_error = u_dut.u_sysctrl_core.s_user_config_err_q;
|
||||
@@ -147,7 +167,8 @@ module sysctrl_formal_design (
|
||||
.fault_reserved_i(f_fault_reserved),
|
||||
.apb4 (apb4),
|
||||
.sysctrl (sysctrl),
|
||||
.pll_ctrl (pll_ctrl)
|
||||
.pll_ctrl (pll_ctrl),
|
||||
.clock_ctrl (clock_ctrl)
|
||||
);
|
||||
|
||||
initial begin
|
||||
|
||||
@@ -107,6 +107,11 @@ module sysctrl_formal;
|
||||
end
|
||||
|
||||
if (rst_n_i && f_past_valid) begin
|
||||
if (user_core_count == 0) begin
|
||||
assert (user_reset == user_reset_mask);
|
||||
assert (!user_bus_enable);
|
||||
assert (ip_sel == 0);
|
||||
end
|
||||
if ($past(
|
||||
rst_n_i && rib_valid && !rib_ready && rib_wstrb[0] &&
|
||||
rib_addr[7:0] == 8'h00 && rib_wdata[4:0] < user_core_count &&
|
||||
@@ -123,6 +128,7 @@ module sysctrl_formal;
|
||||
end
|
||||
if ($past(
|
||||
rst_n_i && rib_valid && !rib_ready && rib_wstrb[0] &&
|
||||
user_core_count != 0 &&
|
||||
rib_addr[7:0] == SYSCTRL_USER_CORE_RESET_OFFSET &&
|
||||
(rib_wdata & user_reset_mask) == user_reset_mask
|
||||
)) begin
|
||||
@@ -130,7 +136,7 @@ module sysctrl_formal;
|
||||
assert (!user_bus_enable);
|
||||
end
|
||||
if ($past(
|
||||
rst_n_i && rib_valid && !rib_ready && |rib_wstrb &&
|
||||
rst_n_i && user_core_count != 0 && rib_valid && !rib_ready && |rib_wstrb &&
|
||||
rib_addr[7:0] == SYSCTRL_IPSEL_OFFSET
|
||||
)) begin
|
||||
assert (ip_sel == $past(rib_wdata[7:0]));
|
||||
|
||||
@@ -5,6 +5,7 @@ FORMAL_SOLVER := bitwuzla
|
||||
FORMAL_SOLVER_DIR := $(FORMAL_DIR)/bin
|
||||
FORMAL_SOLVER_WRAPPER := $(FORMAL_SOLVER_DIR)/bitwuzla
|
||||
FORMAL_DEPTH ?= 20
|
||||
FORMAL_PLL_RCU_DEPTH ?= 32
|
||||
FORMAL_WS2812_DEPTH ?= 120
|
||||
FORMAL_I2C_DEPTH ?= 80
|
||||
FORMAL_CLINT_DEPTH ?= 32
|
||||
@@ -76,6 +77,7 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/gpio_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/apb4_gpio.sv \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/pll_ctrl_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/clock_ctrl_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_define.svh \
|
||||
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_reg.sv \
|
||||
@@ -175,7 +177,7 @@ $(FORMAL_DIR)/%/formal.fl: $(FORMAL_FILELIST_GENERATOR) $(FORMAL_SOURCE_FILES) \
|
||||
--user-extensions-dir $(USER_EXTENSIONS_DIR)
|
||||
|
||||
$(FORMAL_DIR)/%/design.v: $(FORMAL_DIR)/%/formal.fl $(RTL_PATH)/script/convt_sv2v.py \
|
||||
$(RTL_PATH)/script/filelist.py
|
||||
$(RTL_PATH)/script/filelist.py $(FORMAL_SOURCE_FILES)
|
||||
python3 $(ROOT_PATH)/scripts/run_flow.py --tool formal-sv2v \
|
||||
--log $(@D)/sv2v.log --result $(@D)/result-sv2v.json \
|
||||
-- python3 $(RTL_PATH)/script/convt_sv2v.py -f $< --output $@
|
||||
@@ -184,14 +186,14 @@ $(FORMAL_DIR)/%/prove.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_
|
||||
$(FORMAL_SBY_GENERATOR)
|
||||
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
|
||||
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
|
||||
--mode $(if $(filter dma sdio onchip_ram,$*),bmc,prove) --depth $(if $(filter dma,$*),$(FORMAL_DMA_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH)))))))) --output $@
|
||||
--mode $(if $(filter dma sdio onchip_ram,$*),bmc,prove) --depth $(if $(filter pll_rcu,$*),$(FORMAL_PLL_RCU_DEPTH),$(if $(filter dma,$*),$(FORMAL_DMA_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH))))))))) --output $@
|
||||
@if [ "$*" = opipsram ]; then sed -i '/^async2sync/i clk2fflogic' $@; fi
|
||||
|
||||
$(FORMAL_DIR)/%/cover.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_props.sv \
|
||||
$(FORMAL_SBY_GENERATOR)
|
||||
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
|
||||
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
|
||||
--mode cover --depth $(if $(filter dma,$*),$(FORMAL_DMA_COVER_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_COVER_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH)))))))) \
|
||||
--mode cover --depth $(if $(filter pll_rcu,$*),$(FORMAL_PLL_RCU_DEPTH),$(if $(filter dma,$*),$(FORMAL_DMA_COVER_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_COVER_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH))))))))) \
|
||||
$(if $(filter $(FORMAL_COMPACT_COVER_TARGETS),$*),--no-vcd) --output $@
|
||||
@if [ "$*" = opipsram ]; then sed -i '/^async2sync/i clk2fflogic' $@; fi
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/perf.c \
|
||||
$(ROOT_PATH)/crt/src/hal/lcd.c \
|
||||
$(ROOT_PATH)/crt/src/hal/onchip_sram.c \
|
||||
$(ROOT_PATH)/crt/src/hal/memory.c \
|
||||
$(ROOT_PATH)/crt/src/hal/psram_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/psram.c \
|
||||
$(ROOT_PATH)/crt/src/hal/opipsram_math.c \
|
||||
|
||||
+111
-19
@@ -18,8 +18,11 @@ module apb4_periph (
|
||||
input logic clk_aud_i,
|
||||
input logic rst_aud_n_i,
|
||||
input logic clk_ulpi_i,
|
||||
input logic clk_mem_i,
|
||||
input logic rst_mem_n_i,
|
||||
input logic debug_halted_i,
|
||||
input logic timebase_tick_i,
|
||||
input logic ext_h_hp_irq_i,
|
||||
axi4_if.slave cfg_axi4,
|
||||
axi4_if.slave psram_axi4,
|
||||
axi4_if.slave xpi_axi4,
|
||||
@@ -116,6 +119,20 @@ axi4_stream_if #(
|
||||
clint_if u_clint_if ();
|
||||
clint_if #(.HartNum(2)) u_hp_clint_if ();
|
||||
dma_req_if u_dma_req_if ();
|
||||
apb4_if u_psram_mem_apb4_if (
|
||||
.pclk (clk_mem_i),
|
||||
.presetn(rst_mem_n_i)
|
||||
);
|
||||
apb4_if u_xpi_mem_apb4_if (
|
||||
.pclk (clk_mem_i),
|
||||
.presetn(rst_mem_n_i)
|
||||
);
|
||||
apb4_if u_opipsram_mem_apb4_if (
|
||||
.pclk (clk_mem_i),
|
||||
.presetn(rst_mem_n_i)
|
||||
);
|
||||
psram_if u_psram_mem_if ();
|
||||
opipsram_if u_opipsram_mem_if ();
|
||||
|
||||
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
|
||||
logic s_dma_xpi_tx_stall, s_dma_xpi_rx_stall;
|
||||
@@ -131,9 +148,16 @@ axi4_stream_if #(
|
||||
logic s_tim0_irq, s_tim1_irq;
|
||||
logic s_dvp_irq;
|
||||
logic s_xpi_irq;
|
||||
logic s_xpi_irq_mem;
|
||||
logic s_psram_irq_mem;
|
||||
logic s_opipsram_irq_mem;
|
||||
logic s_dma_xfer_done_mem;
|
||||
logic s_dma_xpi_tx_stall_mem;
|
||||
logic s_dma_xpi_rx_stall_mem;
|
||||
logic s_mailbox_lp_irq, s_mailbox_hp_irq;
|
||||
logic [31:0] s_hp_plic_source;
|
||||
logic [ 1:0] s_hp_plic_context_irq;
|
||||
logic [ 3:0] s_unused_optional_status;
|
||||
|
||||
`ifdef PDK_GF180
|
||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
||||
@@ -178,10 +202,78 @@ axi4_stream_if #(
|
||||
assign hp_machine_external_irq_o = s_hp_plic_context_irq[0];
|
||||
assign hp_supervisor_external_irq_o = s_hp_plic_context_irq[1];
|
||||
|
||||
apb4_async_bridge u_psram_cfg_mem_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
.src_rst_n_i(rst_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i(rst_mem_n_i),
|
||||
.src_apb4 (u_psram_apb4_if),
|
||||
.dst_apb4 (u_psram_mem_apb4_if)
|
||||
);
|
||||
apb4_async_bridge u_xpi_cfg_mem_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
.src_rst_n_i(rst_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i(rst_mem_n_i),
|
||||
.src_apb4 (u_xpi_apb4_if),
|
||||
.dst_apb4 (u_xpi_mem_apb4_if)
|
||||
);
|
||||
apb4_async_bridge u_opipsram_cfg_mem_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
.src_rst_n_i(rst_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i(rst_mem_n_i),
|
||||
.src_apb4 (u_opipsram_apb4_if),
|
||||
.dst_apb4 (u_opipsram_mem_apb4_if)
|
||||
);
|
||||
|
||||
cdc_event_bridge u_xpi_dma_done_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
.src_rst_n_i (rst_n_i),
|
||||
.event_i (s_dma_xfer_done),
|
||||
.source_ready_o(s_unused_optional_status[0]),
|
||||
.source_busy_o (s_unused_optional_status[1]),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i (rst_mem_n_i),
|
||||
.event_o (s_dma_xfer_done_mem)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(5)
|
||||
) u_memory_status_sync (
|
||||
.clk_i(clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i({
|
||||
s_xpi_irq_mem,
|
||||
s_psram_irq_mem,
|
||||
s_opipsram_irq_mem,
|
||||
s_dma_xpi_tx_stall_mem,
|
||||
s_dma_xpi_rx_stall_mem
|
||||
}),
|
||||
.dat_o({s_xpi_irq, psram.irq_o, opipsram.irq_o, s_dma_xpi_tx_stall, s_dma_xpi_rx_stall})
|
||||
);
|
||||
|
||||
assign psram.sck_o = u_psram_mem_if.sck_o;
|
||||
assign psram.nss_o = u_psram_mem_if.nss_o;
|
||||
assign psram.io_oe_o = u_psram_mem_if.io_oe_o;
|
||||
assign psram.io_do_o = u_psram_mem_if.io_do_o;
|
||||
assign u_psram_mem_if.io_di_i = psram.io_di_i;
|
||||
assign s_psram_irq_mem = u_psram_mem_if.irq_o;
|
||||
assign opipsram.ck_o = u_opipsram_mem_if.ck_o;
|
||||
assign opipsram.cs_n_o = u_opipsram_mem_if.cs_n_o;
|
||||
assign opipsram.dq_oe_o = u_opipsram_mem_if.dq_oe_o;
|
||||
assign opipsram.dq_o = u_opipsram_mem_if.dq_o;
|
||||
assign opipsram.rwds_oe_o = u_opipsram_mem_if.rwds_oe_o;
|
||||
assign opipsram.rwds_o = u_opipsram_mem_if.rwds_o;
|
||||
assign u_opipsram_mem_if.dq_i = opipsram.dq_i;
|
||||
assign u_opipsram_mem_if.rwds_i = opipsram.rwds_i;
|
||||
assign s_opipsram_irq_mem = u_opipsram_mem_if.irq_o;
|
||||
|
||||
always_comb begin
|
||||
s_hp_plic_source = '0;
|
||||
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;
|
||||
end
|
||||
|
||||
`include "apb4_periph_irq_bindings.svh"
|
||||
@@ -215,8 +307,8 @@ axi4_stream_if #(
|
||||
apb4_uart u_apb4_uart1 (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.dma_tx_stall_o(),
|
||||
.dma_rx_stall_o(),
|
||||
.dma_tx_stall_o(s_unused_optional_status[2]),
|
||||
.dma_rx_stall_o(s_unused_optional_status[3]),
|
||||
.apb4 (u_uart1_apb4_if),
|
||||
.uart (uart1)
|
||||
);
|
||||
@@ -264,11 +356,11 @@ axi4_stream_if #(
|
||||
);
|
||||
|
||||
apb4_psram u_apb4_psram (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.cfg_apb4(u_psram_apb4_if),
|
||||
.clk_i (clk_mem_i),
|
||||
.rst_n_i (rst_mem_n_i),
|
||||
.cfg_apb4(u_psram_mem_apb4_if),
|
||||
.mem_axi4(psram_axi4),
|
||||
.psram (psram)
|
||||
.psram (u_psram_mem_if)
|
||||
);
|
||||
|
||||
apb4_spisd u_apb4_spisd (
|
||||
@@ -309,13 +401,13 @@ axi4_stream_if #(
|
||||
);
|
||||
|
||||
apb4_xpi u_apb4_xpi (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.dma_xfer_done_i(s_dma_xfer_done),
|
||||
.dma_tx_stall_o (s_dma_xpi_tx_stall),
|
||||
.dma_rx_stall_o (s_dma_xpi_rx_stall),
|
||||
.irq_o (s_xpi_irq),
|
||||
.apb4 (u_xpi_apb4_if),
|
||||
.clk_i (clk_mem_i),
|
||||
.rst_n_i (rst_mem_n_i),
|
||||
.dma_xfer_done_i(s_dma_xfer_done_mem),
|
||||
.dma_tx_stall_o (s_dma_xpi_tx_stall_mem),
|
||||
.dma_rx_stall_o (s_dma_xpi_rx_stall_mem),
|
||||
.irq_o (s_xpi_irq_mem),
|
||||
.apb4 (u_xpi_mem_apb4_if),
|
||||
.mem_axi4 (xpi_axi4),
|
||||
.xpi (xpi)
|
||||
);
|
||||
@@ -406,13 +498,13 @@ axi4_stream_if #(
|
||||
);
|
||||
|
||||
apb4_opipsram u_apb4_opipsram (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.clk_phy_i (clk_i),
|
||||
.rst_phy_n_i(rst_n_i),
|
||||
.cfg_apb4 (u_opipsram_apb4_if),
|
||||
.clk_i (clk_mem_i),
|
||||
.rst_n_i (rst_mem_n_i),
|
||||
.clk_phy_i (clk_mem_i),
|
||||
.rst_phy_n_i(rst_mem_n_i),
|
||||
.cfg_apb4 (u_opipsram_mem_apb4_if),
|
||||
.mem_axi4 (opipsram_axi4),
|
||||
.psram (opipsram)
|
||||
.psram (u_opipsram_mem_if)
|
||||
);
|
||||
|
||||
apb4_i2c u_apb4_i2c1 (
|
||||
|
||||
@@ -22,6 +22,7 @@ module apb4_system (
|
||||
input logic clk_aud_i,
|
||||
input logic rst_aud_n_i,
|
||||
input logic debug_halted_i,
|
||||
input logic ext_h_data_idle_i,
|
||||
axi4_if.slave axi4,
|
||||
axi4_if.master ext_h_axi4,
|
||||
pwm_if.dut pwm,
|
||||
@@ -30,6 +31,14 @@ module apb4_system (
|
||||
user_gpio_if.user_ip user_gpio,
|
||||
output logic rtc_wake_o,
|
||||
output logic wdg_reset_req_o,
|
||||
output logic ext_h_block_o,
|
||||
output logic [31:0] ext_h_read_base_o,
|
||||
output logic [31:0] ext_h_read_limit_o,
|
||||
output logic [31:0] ext_h_write_base_o,
|
||||
output logic [31:0] ext_h_write_limit_o,
|
||||
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 [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
@@ -75,10 +84,16 @@ module apb4_system (
|
||||
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;
|
||||
`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;
|
||||
|
||||
`ifdef PDK_IHP130
|
||||
localparam logic [31:0] ARCHINFO_TECHNOLOGY = 32'h0201_0082;
|
||||
`elsif PDK_GF180
|
||||
@@ -219,13 +234,21 @@ axi42apb4_system u_axi42apb4_system (
|
||||
`endif
|
||||
|
||||
extension_subsystem u_extension_subsystem (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ext_l_apb4 (u_ext_l_apb4_if),
|
||||
.ext_h_apb4 (u_ext_h_apb4_if),
|
||||
.ext_h_axi4 (ext_h_axi4),
|
||||
.ext_l_irq_o(s_ext_l_irq),
|
||||
.ext_h_irq_o(s_ext_h_irq)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ext_h_data_idle_i (ext_h_data_idle_i),
|
||||
.ext_l_apb4 (u_ext_l_apb4_if),
|
||||
.ext_h_apb4 (u_ext_h_apb4_if),
|
||||
.ext_h_axi4 (ext_h_axi4),
|
||||
.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_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),
|
||||
.ext_h_write_limit_o(ext_h_write_limit_o),
|
||||
.ext_h_timeout_o (ext_h_timeout_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -13,6 +13,9 @@ module axi4_async_bridge #(
|
||||
input logic src_rst_n_i,
|
||||
input logic dst_clk_i,
|
||||
input logic dst_rst_n_i,
|
||||
input logic clear_i,
|
||||
output logic clear_busy_o,
|
||||
output logic [7:0] epoch_o,
|
||||
axi4_if.slave src_axi4,
|
||||
axi4_if.master dst_axi4
|
||||
// verilog_format: on
|
||||
@@ -34,6 +37,40 @@ module axi4_async_bridge #(
|
||||
logic [ArWidth-1:0] s_ar_dst_data;
|
||||
logic [ RWidth-1:0] s_r_dst_data;
|
||||
logic [ RWidth-1:0] s_r_src_data;
|
||||
logic s_clear_src;
|
||||
logic s_clear_dst;
|
||||
logic s_clear_q;
|
||||
logic s_clear_dst_q;
|
||||
logic s_clear_src_pulse;
|
||||
logic s_clear_dst_pulse;
|
||||
logic [7:0] s_epoch_d, s_epoch_q;
|
||||
logic s_aw_src_clear_busy, s_aw_dst_clear_busy;
|
||||
logic s_w_src_clear_busy, s_w_dst_clear_busy;
|
||||
logic s_b_src_clear_busy, s_b_dst_clear_busy;
|
||||
logic s_ar_src_clear_busy, s_ar_dst_clear_busy;
|
||||
logic s_r_src_clear_busy, s_r_dst_clear_busy;
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_clear_src_sync (
|
||||
.clk_i (src_clk_i),
|
||||
.rst_n_i(src_rst_n_i),
|
||||
.dat_i (clear_i),
|
||||
.dat_o (s_clear_src)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_clear_sync (
|
||||
.clk_i (dst_clk_i),
|
||||
.rst_n_i(dst_rst_n_i),
|
||||
.dat_i (clear_i),
|
||||
.dat_o (s_clear_dst)
|
||||
);
|
||||
|
||||
assign s_clear_src_pulse = s_clear_src && !s_clear_q;
|
||||
assign s_clear_dst_pulse = s_clear_dst && !s_clear_dst_q;
|
||||
|
||||
assign s_aw_src_data = {
|
||||
src_axi4.awid,
|
||||
@@ -62,58 +99,67 @@ module axi4_async_bridge #(
|
||||
dst_axi4.awuser
|
||||
} = s_aw_dst_data;
|
||||
|
||||
cdc_fifo #(
|
||||
cdc_fifo_warm_flush #(
|
||||
.DATA_WIDTH (AwWidth),
|
||||
.BUFFER_DEPTH(FifoDepth)
|
||||
) u_aw_fifo (
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i(src_rst_n_i),
|
||||
.src_data_i (s_aw_src_data),
|
||||
.src_valid_i(src_axi4.awvalid),
|
||||
.src_ready_o(src_axi4.awready),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i(dst_rst_n_i),
|
||||
.dst_data_o (s_aw_dst_data),
|
||||
.dst_valid_o(dst_axi4.awvalid),
|
||||
.dst_ready_i(dst_axi4.awready)
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i (src_rst_n_i),
|
||||
.src_clear_i (s_clear_src_pulse),
|
||||
.src_clear_busy_o(s_aw_src_clear_busy),
|
||||
.src_data_i (s_aw_src_data),
|
||||
.src_valid_i (src_axi4.awvalid),
|
||||
.src_ready_o (src_axi4.awready),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i (dst_rst_n_i),
|
||||
.dst_clear_busy_o(s_aw_dst_clear_busy),
|
||||
.dst_data_o (s_aw_dst_data),
|
||||
.dst_valid_o (dst_axi4.awvalid),
|
||||
.dst_ready_i (dst_axi4.awready)
|
||||
);
|
||||
|
||||
assign s_w_src_data = {src_axi4.wdata, src_axi4.wstrb, src_axi4.wlast, src_axi4.wuser};
|
||||
assign {dst_axi4.wdata, dst_axi4.wstrb, dst_axi4.wlast, dst_axi4.wuser} = s_w_dst_data;
|
||||
|
||||
cdc_fifo #(
|
||||
cdc_fifo_warm_flush #(
|
||||
.DATA_WIDTH (WWidth),
|
||||
.BUFFER_DEPTH(FifoDepth)
|
||||
) u_w_fifo (
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i(src_rst_n_i),
|
||||
.src_data_i (s_w_src_data),
|
||||
.src_valid_i(src_axi4.wvalid),
|
||||
.src_ready_o(src_axi4.wready),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i(dst_rst_n_i),
|
||||
.dst_data_o (s_w_dst_data),
|
||||
.dst_valid_o(dst_axi4.wvalid),
|
||||
.dst_ready_i(dst_axi4.wready)
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i (src_rst_n_i),
|
||||
.src_clear_i (s_clear_src_pulse),
|
||||
.src_clear_busy_o(s_w_src_clear_busy),
|
||||
.src_data_i (s_w_src_data),
|
||||
.src_valid_i (src_axi4.wvalid),
|
||||
.src_ready_o (src_axi4.wready),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i (dst_rst_n_i),
|
||||
.dst_clear_busy_o(s_w_dst_clear_busy),
|
||||
.dst_data_o (s_w_dst_data),
|
||||
.dst_valid_o (dst_axi4.wvalid),
|
||||
.dst_ready_i (dst_axi4.wready)
|
||||
);
|
||||
|
||||
assign s_b_dst_data = {dst_axi4.bid, dst_axi4.bresp, dst_axi4.buser};
|
||||
assign {src_axi4.bid, src_axi4.bresp, src_axi4.buser} = s_b_src_data;
|
||||
|
||||
cdc_fifo #(
|
||||
cdc_fifo_warm_flush #(
|
||||
.DATA_WIDTH (BWidth),
|
||||
.BUFFER_DEPTH(FifoDepth)
|
||||
) u_b_fifo (
|
||||
.src_clk_i (dst_clk_i),
|
||||
.src_rst_n_i(dst_rst_n_i),
|
||||
.src_data_i (s_b_dst_data),
|
||||
.src_valid_i(dst_axi4.bvalid),
|
||||
.src_ready_o(dst_axi4.bready),
|
||||
.dst_clk_i (src_clk_i),
|
||||
.dst_rst_n_i(src_rst_n_i),
|
||||
.dst_data_o (s_b_src_data),
|
||||
.dst_valid_o(src_axi4.bvalid),
|
||||
.dst_ready_i(src_axi4.bready)
|
||||
.src_clk_i (dst_clk_i),
|
||||
.src_rst_n_i (dst_rst_n_i),
|
||||
.src_clear_i (s_clear_dst_pulse),
|
||||
.src_clear_busy_o(s_b_dst_clear_busy),
|
||||
.src_data_i (s_b_dst_data),
|
||||
.src_valid_i (dst_axi4.bvalid),
|
||||
.src_ready_o (dst_axi4.bready),
|
||||
.dst_clk_i (src_clk_i),
|
||||
.dst_rst_n_i (src_rst_n_i),
|
||||
.dst_clear_busy_o(s_b_src_clear_busy),
|
||||
.dst_data_o (s_b_src_data),
|
||||
.dst_valid_o (src_axi4.bvalid),
|
||||
.dst_ready_i (src_axi4.bready)
|
||||
);
|
||||
|
||||
assign s_ar_src_data = {
|
||||
@@ -143,20 +189,23 @@ module axi4_async_bridge #(
|
||||
dst_axi4.aruser
|
||||
} = s_ar_dst_data;
|
||||
|
||||
cdc_fifo #(
|
||||
cdc_fifo_warm_flush #(
|
||||
.DATA_WIDTH (ArWidth),
|
||||
.BUFFER_DEPTH(FifoDepth)
|
||||
) u_ar_fifo (
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i(src_rst_n_i),
|
||||
.src_data_i (s_ar_src_data),
|
||||
.src_valid_i(src_axi4.arvalid),
|
||||
.src_ready_o(src_axi4.arready),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i(dst_rst_n_i),
|
||||
.dst_data_o (s_ar_dst_data),
|
||||
.dst_valid_o(dst_axi4.arvalid),
|
||||
.dst_ready_i(dst_axi4.arready)
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i (src_rst_n_i),
|
||||
.src_clear_i (s_clear_src_pulse),
|
||||
.src_clear_busy_o(s_ar_src_clear_busy),
|
||||
.src_data_i (s_ar_src_data),
|
||||
.src_valid_i (src_axi4.arvalid),
|
||||
.src_ready_o (src_axi4.arready),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i (dst_rst_n_i),
|
||||
.dst_clear_busy_o(s_ar_dst_clear_busy),
|
||||
.dst_data_o (s_ar_dst_data),
|
||||
.dst_valid_o (dst_axi4.arvalid),
|
||||
.dst_ready_i (dst_axi4.arready)
|
||||
);
|
||||
|
||||
assign s_r_dst_data = {
|
||||
@@ -165,22 +214,51 @@ module axi4_async_bridge #(
|
||||
assign {src_axi4.rid, src_axi4.rdata, src_axi4.rresp, src_axi4.rlast,
|
||||
src_axi4.ruser} = s_r_src_data;
|
||||
|
||||
cdc_fifo #(
|
||||
cdc_fifo_warm_flush #(
|
||||
.DATA_WIDTH (RWidth),
|
||||
.BUFFER_DEPTH(FifoDepth)
|
||||
) u_r_fifo (
|
||||
.src_clk_i (dst_clk_i),
|
||||
.src_rst_n_i(dst_rst_n_i),
|
||||
.src_data_i (s_r_dst_data),
|
||||
.src_valid_i(dst_axi4.rvalid),
|
||||
.src_ready_o(dst_axi4.rready),
|
||||
.dst_clk_i (src_clk_i),
|
||||
.dst_rst_n_i(src_rst_n_i),
|
||||
.dst_data_o (s_r_src_data),
|
||||
.dst_valid_o(src_axi4.rvalid),
|
||||
.dst_ready_i(src_axi4.rready)
|
||||
.src_clk_i (dst_clk_i),
|
||||
.src_rst_n_i (dst_rst_n_i),
|
||||
.src_clear_i (s_clear_dst_pulse),
|
||||
.src_clear_busy_o(s_r_dst_clear_busy),
|
||||
.src_data_i (s_r_dst_data),
|
||||
.src_valid_i (dst_axi4.rvalid),
|
||||
.src_ready_o (dst_axi4.rready),
|
||||
.dst_clk_i (src_clk_i),
|
||||
.dst_rst_n_i (src_rst_n_i),
|
||||
.dst_clear_busy_o(s_r_src_clear_busy),
|
||||
.dst_data_o (s_r_src_data),
|
||||
.dst_valid_o (src_axi4.rvalid),
|
||||
.dst_ready_i (src_axi4.rready)
|
||||
);
|
||||
|
||||
assign clear_busy_o = s_aw_src_clear_busy || s_aw_dst_clear_busy ||
|
||||
s_w_src_clear_busy || s_w_dst_clear_busy ||
|
||||
s_b_src_clear_busy || s_b_dst_clear_busy ||
|
||||
s_ar_src_clear_busy || s_ar_dst_clear_busy ||
|
||||
s_r_src_clear_busy || s_r_dst_clear_busy;
|
||||
assign s_epoch_d = (s_clear_src_pulse && !clear_busy_o) ? s_epoch_q + 1'b1 : s_epoch_q;
|
||||
assign epoch_o = s_epoch_q;
|
||||
|
||||
always_ff @(posedge src_clk_i or negedge src_rst_n_i) begin
|
||||
if (!src_rst_n_i) begin
|
||||
s_clear_q <= 1'b0;
|
||||
s_epoch_q <= '0;
|
||||
end else begin
|
||||
s_clear_q <= s_clear_src;
|
||||
s_epoch_q <= s_epoch_d;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge dst_clk_i or negedge dst_rst_n_i) begin
|
||||
if (!dst_rst_n_i) begin
|
||||
s_clear_dst_q <= 1'b0;
|
||||
end else begin
|
||||
s_clear_dst_q <= s_clear_dst;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
if ((AddrWidth < 1) || (DataWidth < 8) || ((DataWidth % 8) != 0) ||
|
||||
|
||||
+589
-154
@@ -4,19 +4,40 @@
|
||||
`include "mmap_define.svh"
|
||||
|
||||
module axi4_data_crossbar #(
|
||||
parameter int unsigned NumMasters = 8,
|
||||
parameter int unsigned NumTargets = 6
|
||||
parameter int unsigned NumMasters = 8,
|
||||
parameter int unsigned NumTargets = 6,
|
||||
parameter int unsigned StarvationCycles = 256
|
||||
) (
|
||||
// verilog_format: off -- preserve the data-plane contract columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic block_new_i,
|
||||
input logic recovery_i,
|
||||
input logic [1:0] mem_pad_mode_i,
|
||||
axi4_if.slave masters [NumMasters],
|
||||
axi4_if.master targets [NumTargets],
|
||||
output logic idle_o
|
||||
input logic [31:0] ext_h_read_base_i,
|
||||
input logic [31:0] ext_h_read_limit_i,
|
||||
input logic [31:0] ext_h_write_base_i,
|
||||
input logic [31:0] ext_h_write_limit_i,
|
||||
axi4_if.slave masters [NumMasters],
|
||||
axi4_if.master targets [NumTargets],
|
||||
output logic idle_o,
|
||||
output logic [7:0] outstanding_read_o,
|
||||
output logic [7:0] outstanding_write_o,
|
||||
output logic fault_valid_o,
|
||||
output logic [2:0] fault_master_o,
|
||||
output logic [2:0] fault_target_o,
|
||||
output logic [31:0] fault_addr_o,
|
||||
output logic fault_write_o,
|
||||
output logic [3:0] fault_reason_o
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam int unsigned MasterWidth = $clog2(NumMasters);
|
||||
localparam int unsigned TargetWidth = $clog2(NumTargets);
|
||||
localparam int unsigned SourceIds = 8;
|
||||
localparam int unsigned RouteDepth = 2;
|
||||
localparam int unsigned CountWidth = 3;
|
||||
localparam int unsigned AgeWidth = $clog2(StarvationCycles + 1);
|
||||
|
||||
localparam logic [TargetWidth-1:0] TargetSram = TargetWidth'(0);
|
||||
localparam logic [TargetWidth-1:0] TargetSdram = TargetWidth'(1);
|
||||
localparam logic [TargetWidth-1:0] TargetQpi = TargetWidth'(2);
|
||||
@@ -24,6 +45,11 @@ module axi4_data_crossbar #(
|
||||
localparam logic [TargetWidth-1:0] TargetXpi = TargetWidth'(4);
|
||||
localparam logic [TargetWidth-1:0] TargetError = TargetWidth'(5);
|
||||
|
||||
localparam logic [3:0] FaultUnmapped = 4'd1;
|
||||
localparam logic [3:0] FaultInactivePad = 4'd2;
|
||||
localparam logic [3:0] FaultAccess = 4'd3;
|
||||
localparam logic [3:0] FaultProtocol = 4'd4;
|
||||
|
||||
typedef struct packed {
|
||||
logic [5:0] id;
|
||||
logic [31:0] addr;
|
||||
@@ -59,11 +85,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;
|
||||
@@ -75,11 +101,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;
|
||||
@@ -93,31 +119,70 @@ module axi4_data_crossbar #(
|
||||
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] s_read_req;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] s_write_req;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] s_read_grant;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] s_write_grant;
|
||||
logic s_unused_grant;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] s_read_priority_req;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] s_write_priority_req;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] unused_read_grant;
|
||||
logic [NumTargets-1:0][ NumMasters-1:0] unused_write_grant;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_read_selected;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_write_selected;
|
||||
logic [NumTargets-1:0] s_read_grant_valid;
|
||||
logic [NumTargets-1:0] s_write_grant_valid;
|
||||
logic [NumTargets-1:0] s_read_capture;
|
||||
logic [NumTargets-1:0] s_write_capture;
|
||||
logic [NumTargets-1:0] s_read_terminal;
|
||||
logic [NumTargets-1:0] s_write_terminal;
|
||||
logic [NumTargets-1:0] s_read_owner_valid_d;
|
||||
logic [NumTargets-1:0] s_read_owner_valid_q;
|
||||
logic [NumTargets-1:0] s_write_owner_valid_d;
|
||||
logic [NumTargets-1:0] s_write_owner_valid_q;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_read_owner_d;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_read_owner_q;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_write_owner_d;
|
||||
logic [NumTargets-1:0][MasterWidth-1:0] s_write_owner_q;
|
||||
logic [NumMasters-1:0] s_master_read_busy_d;
|
||||
logic [NumMasters-1:0] s_master_read_busy_q;
|
||||
logic [NumMasters-1:0] s_master_write_busy_d;
|
||||
logic [NumMasters-1:0] s_master_write_busy_q;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_master_read_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_master_write_target;
|
||||
|
||||
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_req;
|
||||
logic [NumMasters-1:0][ NumTargets-1:0] s_write_resp_req;
|
||||
logic [NumMasters-1:0][ NumTargets-1:0] unused_read_resp_grant;
|
||||
logic [NumMasters-1:0][ NumTargets-1:0] unused_write_resp_grant;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_selected;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_write_resp_selected;
|
||||
logic [NumMasters-1:0] s_read_resp_valid;
|
||||
logic [NumMasters-1:0] s_write_resp_valid;
|
||||
logic [NumMasters-1:0] s_read_terminal;
|
||||
logic [NumMasters-1:0] s_write_terminal;
|
||||
|
||||
logic [NumTargets-1:0] s_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 [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 [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;
|
||||
logic [NumTargets-1:0][NumMasters-1:0][AgeWidth-1:0] s_write_age_d, s_write_age_q;
|
||||
|
||||
logic [NumMasters-1:0][RouteDepth-1:0][TargetWidth-1:0] s_write_route_d;
|
||||
logic [NumMasters-1:0][RouteDepth-1:0][TargetWidth-1:0] s_write_route_q;
|
||||
logic [NumMasters-1:0] s_route_read_ptr_d, s_route_read_ptr_q;
|
||||
logic [NumMasters-1:0] s_route_write_ptr_d, s_route_write_ptr_q;
|
||||
logic [NumMasters-1:0][1:0] s_route_count_d, s_route_count_q;
|
||||
logic [NumMasters-1:0] s_write_data_terminal;
|
||||
|
||||
logic [NumMasters-1:0] s_read_accept;
|
||||
logic [NumMasters-1:0] s_write_accept;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_read_accept_target;
|
||||
logic [NumMasters-1:0][TargetWidth-1:0] s_write_accept_target;
|
||||
logic [NumMasters-1:0][ 2:0] s_read_accept_id;
|
||||
logic [NumMasters-1:0][ 2:0] s_write_accept_id;
|
||||
logic [NumMasters-1:0][ 2:0] s_read_complete_id;
|
||||
logic [NumMasters-1:0][ 2:0] s_write_complete_id;
|
||||
logic [NumTargets-1:0][ 3:0] s_read_max_priority;
|
||||
logic [NumTargets-1:0][ 3:0] s_write_max_priority;
|
||||
logic s_fault_valid_d;
|
||||
logic [ 2:0] s_fault_master_d;
|
||||
logic [ 2:0] s_fault_target_d;
|
||||
logic [ 31:0] s_fault_addr_d;
|
||||
logic s_fault_write_d;
|
||||
logic [ 3:0] s_fault_reason_d;
|
||||
|
||||
function automatic logic [TargetWidth-1:0] decode_target(input logic [31:0] addr,
|
||||
input logic [1:0] pad_mode);
|
||||
@@ -129,6 +194,89 @@ module axi4_data_crossbar #(
|
||||
return TargetError;
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] decode_fault_reason(input logic [31:0] addr,
|
||||
input logic [1:0] pad_mode);
|
||||
if (`SOC_ADDR_IS_PSRAM(addr) && (pad_mode != 2'd1)) return FaultInactivePad;
|
||||
if (`SOC_ADDR_IS_OPIPSRAM(addr) && (pad_mode != 2'd2)) return FaultInactivePad;
|
||||
if (!(
|
||||
`SOC_ADDR_IS_SRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_SDRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_PSRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_OPIPSRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_FLASH(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_XPI(addr)
|
||||
)) begin
|
||||
return FaultUnmapped;
|
||||
end
|
||||
return 4'd0;
|
||||
endfunction
|
||||
|
||||
function automatic logic access_allowed(
|
||||
input int unsigned master, input logic [31:0] addr, input logic write_access,
|
||||
input logic [31:0] ext_read_base, input logic [31:0] ext_read_limit,
|
||||
input logic [31:0] ext_write_base, input logic [31:0] ext_write_limit);
|
||||
if (master == 6) return 1'b0;
|
||||
if ((master == 0) && write_access) return 1'b0;
|
||||
if ((master == 7) && write_access && ((addr < ext_write_base) || (addr > ext_write_limit)))
|
||||
return 1'b0;
|
||||
if ((master == 7) && !write_access && ((addr < ext_read_base) || (addr > ext_read_limit)))
|
||||
return 1'b0;
|
||||
return 1'b1;
|
||||
endfunction
|
||||
|
||||
function automatic logic burst_legal(input logic [31:0] addr, input logic [7:0] len,
|
||||
input logic [2:0] size, input logic [1:0] burst,
|
||||
input logic lock);
|
||||
logic [32:0] beat_bytes;
|
||||
logic [32:0] burst_bytes;
|
||||
logic [32:0] last_addr;
|
||||
logic [32:0] window_limit;
|
||||
beat_bytes = 33'd1 << size;
|
||||
burst_bytes = beat_bytes * ({25'd0, len} + 1'b1);
|
||||
last_addr = (burst == 2'b00) ?
|
||||
({1'b0, addr} + beat_bytes - 1'b1) :
|
||||
({1'b0, addr} + burst_bytes - 1'b1);
|
||||
window_limit = {1'b0, addr[31:12], 12'd0} + 33'd4096;
|
||||
return !lock && (size <= 3'd3) &&
|
||||
((burst == 2'b00) || (burst == 2'b01) ||
|
||||
((burst == 2'b10) &&
|
||||
((len == 8'd1) || (len == 8'd3) || (len == 8'd7) || (len == 8'd15)))) &&
|
||||
(last_addr < window_limit);
|
||||
endfunction
|
||||
|
||||
function automatic logic [CountWidth-1:0] master_read_limit(input int unsigned master);
|
||||
if ((master <= 2) || (master == 7)) return CountWidth'(4);
|
||||
if ((master == 3) || (master == 4)) return CountWidth'(2);
|
||||
if (master == 5) return CountWidth'(1);
|
||||
return '0;
|
||||
endfunction
|
||||
|
||||
function automatic logic [CountWidth-1:0] master_write_limit(input int unsigned master);
|
||||
if ((master == 1) || (master == 2) || (master == 7)) return CountWidth'(2);
|
||||
if ((master >= 3) && (master <= 5)) return CountWidth'(1);
|
||||
return '0;
|
||||
endfunction
|
||||
|
||||
function automatic logic [3:0] master_priority(input int unsigned master,
|
||||
input logic [3:0] request_qos, input logic aged,
|
||||
input logic recovery);
|
||||
logic [3:0] base_priority;
|
||||
unique case (master)
|
||||
0, 1: base_priority = 4'd12;
|
||||
3, 4: base_priority = 4'd10;
|
||||
2, 7: base_priority = 4'd8;
|
||||
5: base_priority = recovery ? 4'd15 : 4'd2;
|
||||
default: base_priority = 4'd0;
|
||||
endcase
|
||||
if (aged) return 4'd15;
|
||||
return (request_qos > base_priority) ? request_qos : base_priority;
|
||||
endfunction
|
||||
|
||||
for (genvar master = 0; master < NumMasters; master++) begin : gen_master_ports
|
||||
assign m_aw[master] = {
|
||||
masters[master].awid,
|
||||
@@ -177,6 +325,29 @@ module axi4_data_crossbar #(
|
||||
assign masters[master].ruser = m_r[master].user;
|
||||
assign masters[master].rvalid = m_rvalid[master];
|
||||
assign m_rready[master] = masters[master].rready;
|
||||
|
||||
round_robin_arbiter #(
|
||||
.CLIENTS(NumTargets)
|
||||
) u_read_response_arbiter (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.advance_i (s_read_terminal[master]),
|
||||
.request_i (s_read_resp_req[master]),
|
||||
.grant_o (unused_read_resp_grant[master]),
|
||||
.selected_o(s_read_resp_selected[master]),
|
||||
.valid_o (s_read_resp_valid[master])
|
||||
);
|
||||
round_robin_arbiter #(
|
||||
.CLIENTS(NumTargets)
|
||||
) u_write_response_arbiter (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.advance_i (s_write_terminal[master]),
|
||||
.request_i (s_write_resp_req[master]),
|
||||
.grant_o (unused_write_resp_grant[master]),
|
||||
.selected_o(s_write_resp_selected[master]),
|
||||
.valid_o (s_write_resp_valid[master])
|
||||
);
|
||||
end
|
||||
|
||||
for (genvar target = 0; target < NumTargets; target++) begin : gen_target_ports
|
||||
@@ -227,80 +398,177 @@ module axi4_data_crossbar #(
|
||||
|
||||
round_robin_arbiter #(
|
||||
.CLIENTS(NumMasters)
|
||||
) u_read_arbiter (
|
||||
) u_read_address_arbiter (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.advance_i (s_read_capture[target]),
|
||||
.request_i (s_read_req[target]),
|
||||
.grant_o (s_read_grant[target]),
|
||||
.request_i (s_read_priority_req[target]),
|
||||
.grant_o (unused_read_grant[target]),
|
||||
.selected_o(s_read_selected[target]),
|
||||
.valid_o (s_read_grant_valid[target])
|
||||
);
|
||||
round_robin_arbiter #(
|
||||
.CLIENTS(NumMasters)
|
||||
) u_write_arbiter (
|
||||
) u_write_address_arbiter (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.advance_i (s_write_capture[target]),
|
||||
.request_i (s_write_req[target]),
|
||||
.grant_o (s_write_grant[target]),
|
||||
.request_i (s_write_priority_req[target]),
|
||||
.grant_o (unused_write_grant[target]),
|
||||
.selected_o(s_write_selected[target]),
|
||||
.valid_o (s_write_grant_valid[target])
|
||||
);
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_read_req = '0;
|
||||
s_write_req = '0;
|
||||
s_master_read_target = '0;
|
||||
s_master_write_target = '0;
|
||||
|
||||
always_comb begin
|
||||
s_read_req = '0;
|
||||
s_write_req = '0;
|
||||
s_read_decoded_target = '0;
|
||||
s_write_decoded_target = '0;
|
||||
s_read_routed_target = '0;
|
||||
s_write_routed_target = '0;
|
||||
s_read_fault_reason = '0;
|
||||
s_write_fault_reason = '0;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
s_master_read_target[master] = decode_target(m_ar[master].addr, mem_pad_mode_i);
|
||||
s_master_write_target[master] = decode_target(m_aw[master].addr, mem_pad_mode_i);
|
||||
if (!block_new_i && !s_master_read_busy_q[master] && m_arvalid[master]) begin
|
||||
s_read_req[s_master_read_target[master]][master] = 1'b1;
|
||||
s_read_decoded_target[master] = decode_target(m_ar[master].addr, mem_pad_mode_i);
|
||||
s_write_decoded_target[master] = decode_target(m_aw[master].addr, mem_pad_mode_i);
|
||||
s_read_fault_reason[master] = decode_fault_reason(m_ar[master].addr, mem_pad_mode_i);
|
||||
s_write_fault_reason[master] = decode_fault_reason(m_aw[master].addr, mem_pad_mode_i);
|
||||
if (!access_allowed(
|
||||
master,
|
||||
m_ar[master].addr,
|
||||
1'b0,
|
||||
ext_h_read_base_i,
|
||||
ext_h_read_limit_i,
|
||||
ext_h_write_base_i,
|
||||
ext_h_write_limit_i
|
||||
)) begin
|
||||
s_read_fault_reason[master] = FaultAccess;
|
||||
end else if (!burst_legal(
|
||||
m_ar[master].addr,
|
||||
m_ar[master].len,
|
||||
m_ar[master].size,
|
||||
m_ar[master].burst,
|
||||
m_ar[master].lock
|
||||
)) begin
|
||||
s_read_fault_reason[master] = FaultProtocol;
|
||||
end
|
||||
if (!block_new_i && !s_master_write_busy_q[master] && m_awvalid[master]) begin
|
||||
s_write_req[s_master_write_target[master]][master] = 1'b1;
|
||||
if (!access_allowed(
|
||||
master,
|
||||
m_aw[master].addr,
|
||||
1'b1,
|
||||
ext_h_read_base_i,
|
||||
ext_h_read_limit_i,
|
||||
ext_h_write_base_i,
|
||||
ext_h_write_limit_i
|
||||
)) begin
|
||||
s_write_fault_reason[master] = FaultAccess;
|
||||
end else if (!burst_legal(
|
||||
m_aw[master].addr,
|
||||
m_aw[master].len,
|
||||
m_aw[master].size,
|
||||
m_aw[master].burst,
|
||||
m_aw[master].lock
|
||||
)) begin
|
||||
s_write_fault_reason[master] = FaultProtocol;
|
||||
end
|
||||
s_read_routed_target[master] = (s_read_fault_reason[master] == 4'd0) ?
|
||||
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(
|
||||
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(
|
||||
master
|
||||
))) && (s_route_count_q[master] < 2'(RouteDepth)) &&
|
||||
!s_write_id_busy_q[master][m_aw[master].id[2:0]]) begin
|
||||
s_write_req[s_write_routed_target[master]][master] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_read_priority_req = '0;
|
||||
s_write_priority_req = '0;
|
||||
s_read_max_priority = '0;
|
||||
s_write_max_priority = '0;
|
||||
for (int target = 0; target < NumTargets; target++) begin
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
if (s_read_req[target][master] && (master_priority(
|
||||
master,
|
||||
m_ar[master].qos,
|
||||
s_read_age_q[target][master] == AgeWidth'(StarvationCycles),
|
||||
recovery_i
|
||||
) > s_read_max_priority[target])) begin
|
||||
s_read_max_priority[target] = master_priority(
|
||||
master,
|
||||
m_ar[master].qos,
|
||||
s_read_age_q[target][master] == AgeWidth'(StarvationCycles),
|
||||
recovery_i
|
||||
);
|
||||
end
|
||||
if (s_write_req[target][master] && (master_priority(
|
||||
master,
|
||||
m_aw[master].qos,
|
||||
s_write_age_q[target][master] == AgeWidth'(StarvationCycles),
|
||||
recovery_i
|
||||
) > s_write_max_priority[target])) begin
|
||||
s_write_max_priority[target] = master_priority(
|
||||
master,
|
||||
m_aw[master].qos,
|
||||
s_write_age_q[target][master] == AgeWidth'(StarvationCycles),
|
||||
recovery_i
|
||||
);
|
||||
end
|
||||
end
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
s_read_priority_req[target][master] = s_read_req[target][master] && (master_priority(
|
||||
master,
|
||||
m_ar[master].qos,
|
||||
s_read_age_q[target][master] == AgeWidth'(StarvationCycles),
|
||||
recovery_i
|
||||
) == s_read_max_priority[target]);
|
||||
s_write_priority_req[target][master] = s_write_req[target][master] && (master_priority(
|
||||
master,
|
||||
m_aw[master].qos,
|
||||
s_write_age_q[target][master] == AgeWidth'(StarvationCycles),
|
||||
recovery_i
|
||||
) == s_write_max_priority[target]);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
m_arready = '0;
|
||||
m_r = '{default: '0};
|
||||
m_rvalid = '0;
|
||||
t_ar = '{default: '0};
|
||||
t_arvalid = '0;
|
||||
t_rready = '0;
|
||||
s_read_capture = '0;
|
||||
s_read_terminal = '0;
|
||||
s_read_owner_valid_d = s_read_owner_valid_q;
|
||||
s_read_owner_d = s_read_owner_q;
|
||||
s_master_read_busy_d = s_master_read_busy_q;
|
||||
|
||||
s_read_accept = '0;
|
||||
s_read_accept_target = '0;
|
||||
s_read_accept_id = '0;
|
||||
for (int target = 0; target < NumTargets; target++) begin
|
||||
if (!s_read_owner_valid_q[target] && s_read_grant_valid[target]) begin
|
||||
if (s_read_grant_valid[target]) begin
|
||||
automatic logic [MasterWidth-1:0] owner = s_read_selected[target];
|
||||
t_ar[target] = m_ar[owner];
|
||||
t_arvalid[target] = m_arvalid[owner];
|
||||
m_arready[owner] = t_arready[target];
|
||||
s_read_capture[target] = t_arvalid[target] && t_arready[target];
|
||||
if (s_read_capture[target]) begin
|
||||
s_read_owner_valid_d[target] = 1'b1;
|
||||
s_read_owner_d[target] = owner;
|
||||
s_master_read_busy_d[owner] = 1'b1;
|
||||
end
|
||||
end else if (s_read_owner_valid_q[target]) begin
|
||||
automatic logic [MasterWidth-1:0] owner = s_read_owner_q[target];
|
||||
m_r[owner] = t_r[target];
|
||||
m_rvalid[owner] = t_rvalid[target];
|
||||
t_rready[target] = m_rready[owner];
|
||||
s_read_terminal[target] = t_rvalid[target] && t_rready[target] && t_r[target].last;
|
||||
if (s_read_terminal[target]) begin
|
||||
s_read_owner_valid_d[target] = 1'b0;
|
||||
s_master_read_busy_d[owner] = 1'b0;
|
||||
s_read_accept[owner] = 1'b1;
|
||||
s_read_accept_target[owner] = TargetWidth'(target);
|
||||
s_read_accept_id[owner] = m_ar[owner].id[2:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -308,106 +576,273 @@ module axi4_data_crossbar #(
|
||||
|
||||
always_comb begin
|
||||
m_awready = '0;
|
||||
m_wready = '0;
|
||||
m_b = '{default: '0};
|
||||
m_bvalid = '0;
|
||||
t_aw = '{default: '0};
|
||||
t_awvalid = '0;
|
||||
t_w = '{default: '0};
|
||||
t_wvalid = '0;
|
||||
t_bready = '0;
|
||||
s_write_capture = '0;
|
||||
s_write_terminal = '0;
|
||||
s_write_owner_valid_d = s_write_owner_valid_q;
|
||||
s_write_owner_d = s_write_owner_q;
|
||||
s_master_write_busy_d = s_master_write_busy_q;
|
||||
|
||||
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_owner_valid_q[target] && s_write_grant_valid[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];
|
||||
if (s_write_capture[target]) begin
|
||||
s_write_owner_valid_d[target] = 1'b1;
|
||||
s_write_owner_d[target] = owner;
|
||||
s_master_write_busy_d[owner] = 1'b1;
|
||||
end
|
||||
end else if (s_write_owner_valid_q[target]) begin
|
||||
automatic logic [MasterWidth-1:0] owner = s_write_owner_q[target];
|
||||
t_w[target] = m_w[owner];
|
||||
t_wvalid[target] = m_wvalid[owner];
|
||||
m_wready[owner] = t_wready[target];
|
||||
m_b[owner] = t_b[target];
|
||||
m_bvalid[owner] = t_bvalid[target];
|
||||
t_bready[target] = m_bready[owner];
|
||||
s_write_terminal[target] = t_bvalid[target] && t_bready[target];
|
||||
if (s_write_terminal[target]) begin
|
||||
s_write_owner_valid_d[target] = 1'b0;
|
||||
s_master_write_busy_d[owner] = 1'b0;
|
||||
s_write_accept[owner] = 1'b1;
|
||||
s_write_accept_target[owner] = TargetWidth'(target);
|
||||
s_write_accept_id[owner] = m_aw[owner].id[2:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign idle_o = !(|s_master_read_busy_q) && !(|s_master_write_busy_q) &&
|
||||
!(|s_read_owner_valid_q) && !(|s_write_owner_valid_q);
|
||||
assign s_unused_grant = ^{s_read_grant, s_write_grant};
|
||||
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];
|
||||
s_write_data_terminal[master] = t_wvalid[target] && t_wready[target] && t_w[target].last;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dffr #(
|
||||
.DATA_WIDTH(NumTargets)
|
||||
) u_read_owner_valid_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_read_owner_valid_d),
|
||||
.dat_o (s_read_owner_valid_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(NumTargets)
|
||||
) u_write_owner_valid_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_write_owner_valid_d),
|
||||
.dat_o (s_write_owner_valid_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(NumTargets * MasterWidth)
|
||||
) u_read_owner_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_read_owner_d),
|
||||
.dat_o (s_read_owner_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(NumTargets * MasterWidth)
|
||||
) u_write_owner_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_write_owner_d),
|
||||
.dat_o (s_write_owner_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(NumMasters)
|
||||
) u_master_read_busy_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_master_read_busy_d),
|
||||
.dat_o (s_master_read_busy_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(NumMasters)
|
||||
) u_master_write_busy_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_master_write_busy_d),
|
||||
.dat_o (s_master_write_busy_q)
|
||||
);
|
||||
always_comb begin
|
||||
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;
|
||||
end
|
||||
if (s_write_owner_valid_q[target] && t_bvalid[target]) begin
|
||||
s_write_resp_req[s_write_owner_q[target]][target] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
m_r = '{default: '0};
|
||||
m_rvalid = '0;
|
||||
t_rready = '0;
|
||||
s_read_terminal = '0;
|
||||
s_read_complete_id = '0;
|
||||
m_b = '{default: '0};
|
||||
m_bvalid = '0;
|
||||
t_bready = '0;
|
||||
s_write_terminal = '0;
|
||||
s_write_complete_id = '0;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
if (s_read_resp_valid[master]) begin
|
||||
automatic logic [TargetWidth-1:0] target = s_read_resp_selected[master];
|
||||
m_r[master] = t_r[target];
|
||||
m_rvalid[master] = t_rvalid[target];
|
||||
t_rready[target] = m_rready[master];
|
||||
s_read_terminal[master] = m_rvalid[master] && m_rready[master] && m_r[master].last;
|
||||
s_read_complete_id[master] = m_r[master].id[2:0];
|
||||
end
|
||||
if (s_write_resp_valid[master]) begin
|
||||
automatic logic [TargetWidth-1:0] target = s_write_resp_selected[master];
|
||||
m_b[master] = t_b[target];
|
||||
m_bvalid[master] = t_bvalid[target];
|
||||
t_bready[target] = m_bready[master];
|
||||
s_write_terminal[master] = m_bvalid[master] && m_bready[master];
|
||||
s_write_complete_id[master] = m_b[master].id[2:0];
|
||||
end
|
||||
end
|
||||
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_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_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_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_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_write_id_busy_d[master][s_write_accept_id[master]] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_write_route_d = s_write_route_q;
|
||||
s_route_read_ptr_d = s_route_read_ptr_q;
|
||||
s_route_write_ptr_d = s_route_write_ptr_q;
|
||||
s_route_count_d = s_route_count_q;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
unique case ({
|
||||
s_write_accept[master], s_write_data_terminal[master]
|
||||
})
|
||||
2'b10: s_route_count_d[master] = s_route_count_q[master] + 1'b1;
|
||||
2'b01: s_route_count_d[master] = s_route_count_q[master] - 1'b1;
|
||||
default: s_route_count_d[master] = s_route_count_q[master];
|
||||
endcase
|
||||
if (s_write_accept[master]) begin
|
||||
s_write_route_d[master][s_route_write_ptr_q[master]] = s_write_accept_target[master];
|
||||
s_route_write_ptr_d[master] = ~s_route_write_ptr_q[master];
|
||||
end
|
||||
if (s_write_data_terminal[master]) begin
|
||||
s_route_read_ptr_d[master] = ~s_route_read_ptr_q[master];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_read_age_d = s_read_age_q;
|
||||
s_write_age_d = s_write_age_q;
|
||||
for (int target = 0; target < NumTargets; target++) begin
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
if (!s_read_req[target][master] ||
|
||||
(s_read_capture[target] && (s_read_selected[target] == MasterWidth'(master)))) begin
|
||||
s_read_age_d[target][master] = '0;
|
||||
end else if (s_read_age_q[target][master] < AgeWidth'(StarvationCycles)) begin
|
||||
s_read_age_d[target][master] = s_read_age_q[target][master] + 1'b1;
|
||||
end
|
||||
if (!s_write_req[target][master] ||
|
||||
(s_write_capture[target] && (s_write_selected[target] == MasterWidth'(master)))) begin
|
||||
s_write_age_d[target][master] = '0;
|
||||
end else if (s_write_age_q[target][master] < AgeWidth'(StarvationCycles)) begin
|
||||
s_write_age_d[target][master] = s_write_age_q[target][master] + 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_fault_valid_d = 1'b0;
|
||||
s_fault_master_d = '0;
|
||||
s_fault_target_d = '0;
|
||||
s_fault_addr_d = '0;
|
||||
s_fault_write_d = 1'b0;
|
||||
s_fault_reason_d = '0;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
if (!s_fault_valid_d && s_read_accept[master] && (s_read_fault_reason[master] != 4'd0)) begin
|
||||
s_fault_valid_d = 1'b1;
|
||||
s_fault_master_d = 3'(master);
|
||||
s_fault_target_d = 3'(s_read_decoded_target[master]);
|
||||
s_fault_addr_d = m_ar[master].addr;
|
||||
s_fault_reason_d = s_read_fault_reason[master];
|
||||
end
|
||||
if (!s_fault_valid_d && s_write_accept[master] &&
|
||||
(s_write_fault_reason[master] != 4'd0)) begin
|
||||
s_fault_valid_d = 1'b1;
|
||||
s_fault_master_d = 3'(master);
|
||||
s_fault_target_d = 3'(s_write_decoded_target[master]);
|
||||
s_fault_addr_d = m_aw[master].addr;
|
||||
s_fault_write_d = 1'b1;
|
||||
s_fault_reason_d = s_write_fault_reason[master];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
outstanding_read_o = '0;
|
||||
outstanding_write_o = '0;
|
||||
for (int master = 0; master < NumMasters; master++) begin
|
||||
outstanding_read_o = outstanding_read_o + 8'(s_master_read_count_q[master]);
|
||||
outstanding_write_o = outstanding_write_o + 8'(s_master_write_count_q[master]);
|
||||
end
|
||||
end
|
||||
|
||||
assign idle_o = (outstanding_read_o == 8'd0) && (outstanding_write_o == 8'd0) &&
|
||||
!(|s_route_count_q);
|
||||
|
||||
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_read_id_busy_q <= '0;
|
||||
s_write_id_busy_q <= '0;
|
||||
s_write_route_q <= '0;
|
||||
s_route_read_ptr_q <= '0;
|
||||
s_route_write_ptr_q <= '0;
|
||||
s_route_count_q <= '0;
|
||||
s_read_age_q <= '0;
|
||||
s_write_age_q <= '0;
|
||||
fault_valid_o <= 1'b0;
|
||||
fault_master_o <= '0;
|
||||
fault_target_o <= '0;
|
||||
fault_addr_o <= '0;
|
||||
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_read_id_busy_q <= s_read_id_busy_d;
|
||||
s_write_id_busy_q <= s_write_id_busy_d;
|
||||
s_write_route_q <= s_write_route_d;
|
||||
s_route_read_ptr_q <= s_route_read_ptr_d;
|
||||
s_route_write_ptr_q <= s_route_write_ptr_d;
|
||||
s_route_count_q <= s_route_count_d;
|
||||
s_read_age_q <= s_read_age_d;
|
||||
s_write_age_q <= s_write_age_d;
|
||||
fault_valid_o <= s_fault_valid_d;
|
||||
fault_master_o <= s_fault_master_d;
|
||||
fault_target_o <= s_fault_target_d;
|
||||
fault_addr_o <= s_fault_addr_d;
|
||||
fault_write_o <= s_fault_write_d;
|
||||
fault_reason_o <= s_fault_reason_d;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
always_ff @(posedge clk_i) begin
|
||||
if (rst_n_i && $test$plusargs("trace_mgmt")) begin
|
||||
if (m_arvalid[5] && m_arready[5]) begin
|
||||
$display("DATA_M5_AR addr=%08x target=%0d", m_ar[5].addr, s_read_routed_target[5]);
|
||||
end
|
||||
if (m_rvalid[5] && m_rready[5] && m_r[5].last) begin
|
||||
$display("DATA_M5_R resp=%0d data=%016x", m_r[5].resp, m_r[5].data);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
initial begin
|
||||
if ((NumMasters != 8) || (NumTargets != 6)) begin
|
||||
$fatal(1, "axi4_data_crossbar: product topology must be 8x6");
|
||||
if ((NumMasters != 8) || (NumTargets != 6) || (StarvationCycles < 2) ||
|
||||
((StarvationCycles & (StarvationCycles - 1)) != 0)) begin
|
||||
$fatal(1, "axi4_data_crossbar: invalid product topology or aging interval");
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
@@ -459,6 +459,10 @@ module axi4_interconnect #(
|
||||
`SOC_ADDR_IS_APB4_WDG(addr)
|
||||
&& !
|
||||
`SOC_ADDR_IS_APB4_GPIO_ADMIN(addr)
|
||||
&& !
|
||||
`SOC_ADDR_IS_APB4_EXT_L(addr)
|
||||
&& !
|
||||
`SOC_ADDR_IS_APB4_EXT_H(addr)
|
||||
);
|
||||
`else
|
||||
s_access_allowed[master] = (master != 1) || ((read_req &&
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
`include "mmap_define.svh"
|
||||
|
||||
module axi4_mgmt_router (
|
||||
// verilog_format: off -- preserve the control/data route columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
axi4_if.slave source,
|
||||
axi4_if.master control,
|
||||
axi4_if.master data,
|
||||
output logic idle_o
|
||||
// verilog_format: on
|
||||
);
|
||||
logic s_read_active_d, s_read_active_q;
|
||||
logic s_read_data_d, s_read_data_q;
|
||||
logic s_write_active_d, s_write_active_q;
|
||||
logic s_write_data_d, s_write_data_q;
|
||||
logic s_read_data_sel;
|
||||
logic s_write_data_sel;
|
||||
logic s_read_accept;
|
||||
logic s_write_accept;
|
||||
logic s_read_terminal;
|
||||
logic s_write_terminal;
|
||||
|
||||
function automatic logic is_data_addr(input logic [31:0] addr);
|
||||
return
|
||||
`SOC_ADDR_IS_FLASH(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_SRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_SDRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_PSRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_OPIPSRAM(addr)
|
||||
||
|
||||
`SOC_ADDR_IS_XPI(addr)
|
||||
;
|
||||
endfunction
|
||||
|
||||
assign s_read_data_sel = is_data_addr(source.araddr);
|
||||
assign s_write_data_sel = is_data_addr(source.awaddr);
|
||||
|
||||
assign control.arid = source.arid;
|
||||
assign data.arid = source.arid;
|
||||
assign control.araddr = source.araddr;
|
||||
assign data.araddr = source.araddr;
|
||||
assign control.arlen = source.arlen;
|
||||
assign data.arlen = source.arlen;
|
||||
assign control.arsize = source.arsize;
|
||||
assign data.arsize = source.arsize;
|
||||
assign control.arburst = source.arburst;
|
||||
assign data.arburst = source.arburst;
|
||||
assign control.arlock = source.arlock;
|
||||
assign data.arlock = source.arlock;
|
||||
assign control.arcache = source.arcache;
|
||||
assign data.arcache = source.arcache;
|
||||
assign control.arprot = source.arprot;
|
||||
assign data.arprot = source.arprot;
|
||||
assign control.arqos = source.arqos;
|
||||
assign data.arqos = source.arqos;
|
||||
assign control.arregion = source.arregion;
|
||||
assign data.arregion = source.arregion;
|
||||
assign control.aruser = source.aruser;
|
||||
assign data.aruser = source.aruser;
|
||||
assign control.arvalid = !s_read_active_q && !s_read_data_sel && source.arvalid;
|
||||
assign data.arvalid = !s_read_active_q && s_read_data_sel && source.arvalid;
|
||||
assign source.arready = !s_read_active_q && (s_read_data_sel ? data.arready : control.arready);
|
||||
|
||||
assign source.rid = s_read_data_q ? data.rid : control.rid;
|
||||
assign source.rdata = s_read_data_q ? data.rdata : control.rdata;
|
||||
assign source.rresp = s_read_data_q ? data.rresp : control.rresp;
|
||||
assign source.rlast = s_read_data_q ? data.rlast : control.rlast;
|
||||
assign source.ruser = s_read_data_q ? data.ruser : control.ruser;
|
||||
assign source.rvalid = s_read_active_q && (s_read_data_q ? data.rvalid : control.rvalid);
|
||||
assign control.rready = s_read_active_q && !s_read_data_q && source.rready;
|
||||
assign data.rready = s_read_active_q && s_read_data_q && source.rready;
|
||||
|
||||
assign control.awid = source.awid;
|
||||
assign data.awid = source.awid;
|
||||
assign control.awaddr = source.awaddr;
|
||||
assign data.awaddr = source.awaddr;
|
||||
assign control.awlen = source.awlen;
|
||||
assign data.awlen = source.awlen;
|
||||
assign control.awsize = source.awsize;
|
||||
assign data.awsize = source.awsize;
|
||||
assign control.awburst = source.awburst;
|
||||
assign data.awburst = source.awburst;
|
||||
assign control.awlock = source.awlock;
|
||||
assign data.awlock = source.awlock;
|
||||
assign control.awcache = source.awcache;
|
||||
assign data.awcache = source.awcache;
|
||||
assign control.awprot = source.awprot;
|
||||
assign data.awprot = source.awprot;
|
||||
assign control.awqos = source.awqos;
|
||||
assign data.awqos = source.awqos;
|
||||
assign control.awregion = source.awregion;
|
||||
assign data.awregion = source.awregion;
|
||||
assign control.awuser = source.awuser;
|
||||
assign data.awuser = source.awuser;
|
||||
assign control.awvalid = !s_write_active_q && !s_write_data_sel && source.awvalid;
|
||||
assign data.awvalid = !s_write_active_q && s_write_data_sel && source.awvalid;
|
||||
assign source.awready = !s_write_active_q && (s_write_data_sel ? data.awready : control.awready);
|
||||
|
||||
assign control.wdata = source.wdata;
|
||||
assign data.wdata = source.wdata;
|
||||
assign control.wstrb = source.wstrb;
|
||||
assign data.wstrb = source.wstrb;
|
||||
assign control.wlast = source.wlast;
|
||||
assign data.wlast = source.wlast;
|
||||
assign control.wuser = source.wuser;
|
||||
assign data.wuser = source.wuser;
|
||||
assign control.wvalid = s_write_active_q && !s_write_data_q && source.wvalid;
|
||||
assign data.wvalid = s_write_active_q && s_write_data_q && source.wvalid;
|
||||
assign source.wready = s_write_active_q && (s_write_data_q ? data.wready : control.wready);
|
||||
|
||||
assign source.bid = s_write_data_q ? data.bid : control.bid;
|
||||
assign source.bresp = s_write_data_q ? data.bresp : control.bresp;
|
||||
assign source.buser = s_write_data_q ? data.buser : control.buser;
|
||||
assign source.bvalid = s_write_active_q && (s_write_data_q ? data.bvalid : control.bvalid);
|
||||
assign control.bready = s_write_active_q && !s_write_data_q && source.bready;
|
||||
assign data.bready = s_write_active_q && s_write_data_q && source.bready;
|
||||
|
||||
assign s_read_accept = source.arvalid && source.arready;
|
||||
assign s_write_accept = source.awvalid && source.awready;
|
||||
assign s_read_terminal = source.rvalid && source.rready && source.rlast;
|
||||
assign s_write_terminal = source.bvalid && source.bready;
|
||||
assign idle_o = !s_read_active_q && !s_write_active_q;
|
||||
|
||||
always_comb begin
|
||||
s_read_active_d = s_read_active_q;
|
||||
s_read_data_d = s_read_data_q;
|
||||
s_write_active_d = s_write_active_q;
|
||||
s_write_data_d = s_write_data_q;
|
||||
if (s_read_terminal) s_read_active_d = 1'b0;
|
||||
if (s_read_accept) begin
|
||||
s_read_active_d = 1'b1;
|
||||
s_read_data_d = s_read_data_sel;
|
||||
end
|
||||
if (s_write_terminal) s_write_active_d = 1'b0;
|
||||
if (s_write_accept) begin
|
||||
s_write_active_d = 1'b1;
|
||||
s_write_data_d = s_write_data_sel;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_read_active_q <= 1'b0;
|
||||
s_read_data_q <= 1'b0;
|
||||
s_write_active_q <= 1'b0;
|
||||
s_write_data_q <= 1'b0;
|
||||
end else begin
|
||||
s_read_active_q <= s_read_active_d;
|
||||
s_read_data_q <= s_read_data_d;
|
||||
s_write_active_q <= s_write_active_d;
|
||||
s_write_data_q <= s_write_data_d;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
always_ff @(posedge clk_i) begin
|
||||
if (rst_n_i && $test$plusargs("trace_mgmt")) begin
|
||||
if (source.arvalid && source.arready) begin
|
||||
$display("MGMT_AR addr=%08x data=%0d", source.araddr, s_read_data_sel);
|
||||
end
|
||||
if (source.rvalid && source.rready && source.rlast) begin
|
||||
$display("MGMT_R resp=%0d data=%08x", source.rresp, source.rdata);
|
||||
end
|
||||
if (source.awvalid && source.awready) begin
|
||||
$display("MGMT_AW addr=%08x data=%0d", source.awaddr, s_write_data_sel);
|
||||
end
|
||||
if (source.bvalid && source.bready) begin
|
||||
$display("MGMT_B resp=%0d", source.bresp);
|
||||
end
|
||||
end
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
module clock_frequency_monitor #(
|
||||
parameter int unsigned CounterWidth = 16,
|
||||
parameter int unsigned WindowCycles = 256
|
||||
) (
|
||||
// verilog_format: off -- preserve the monitored/reference domain columns
|
||||
input logic ref_clk_i,
|
||||
input logic ref_rst_n_i,
|
||||
input logic monitored_clk_i,
|
||||
input logic monitored_rst_n_i,
|
||||
input logic clear_fault_i,
|
||||
output logic alive_o,
|
||||
output logic fault_o,
|
||||
output logic [CounterWidth-1:0] edge_delta_o
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam int unsigned WindowWidth = $clog2(WindowCycles);
|
||||
|
||||
logic [CounterWidth-1:0] s_monitored_count_q;
|
||||
logic [CounterWidth-1:0] s_monitored_gray;
|
||||
logic [CounterWidth-1:0] s_monitored_gray_ref;
|
||||
logic [CounterWidth-1:0] s_monitored_count_ref;
|
||||
logic [CounterWidth-1:0] s_last_count_q;
|
||||
logic [ WindowWidth-1:0] s_window_count_q;
|
||||
logic s_window_valid_q;
|
||||
|
||||
function automatic logic [CounterWidth-1:0] gray_to_bin(input logic [CounterWidth-1:0] value_i);
|
||||
logic [CounterWidth-1:0] result;
|
||||
result[CounterWidth-1] = value_i[CounterWidth-1];
|
||||
for (int bit_index = CounterWidth - 2; bit_index >= 0; bit_index--) begin
|
||||
result[bit_index] = result[bit_index+1] ^ value_i[bit_index];
|
||||
end
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
assign s_monitored_gray = s_monitored_count_q ^ (s_monitored_count_q >> 1);
|
||||
assign s_monitored_count_ref = gray_to_bin(s_monitored_gray_ref);
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(CounterWidth)
|
||||
) u_count_sync (
|
||||
.clk_i (ref_clk_i),
|
||||
.rst_n_i(ref_rst_n_i),
|
||||
.dat_i (s_monitored_gray),
|
||||
.dat_o (s_monitored_gray_ref)
|
||||
);
|
||||
|
||||
always_ff @(posedge monitored_clk_i or negedge monitored_rst_n_i) begin
|
||||
if (!monitored_rst_n_i) begin
|
||||
s_monitored_count_q <= '0;
|
||||
end else begin
|
||||
s_monitored_count_q <= s_monitored_count_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge ref_clk_i or negedge ref_rst_n_i) begin
|
||||
if (!ref_rst_n_i) begin
|
||||
s_last_count_q <= '0;
|
||||
s_window_count_q <= '0;
|
||||
s_window_valid_q <= 1'b0;
|
||||
edge_delta_o <= '0;
|
||||
alive_o <= 1'b0;
|
||||
fault_o <= 1'b0;
|
||||
end else begin
|
||||
if (clear_fault_i) fault_o <= 1'b0;
|
||||
if (s_window_count_q == WindowWidth'(WindowCycles - 1)) begin
|
||||
edge_delta_o <= s_monitored_count_ref - s_last_count_q;
|
||||
alive_o <= s_monitored_count_ref != s_last_count_q;
|
||||
if (!clear_fault_i && s_window_valid_q && (s_monitored_count_ref == s_last_count_q)) begin
|
||||
fault_o <= 1'b1;
|
||||
end
|
||||
s_last_count_q <= s_monitored_count_ref;
|
||||
s_window_count_q <= '0;
|
||||
s_window_valid_q <= 1'b1;
|
||||
end else begin
|
||||
s_window_count_q <= s_window_count_q + 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
if ((CounterWidth < 4) || (WindowCycles < 4) ||
|
||||
((WindowCycles & (WindowCycles - 1)) != 0)) begin
|
||||
$fatal(1, "clock_frequency_monitor: invalid counter or window geometry");
|
||||
end
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
`include "axi4_define.svh"
|
||||
|
||||
module extension_dma_master (
|
||||
// verilog_format: off -- preserve the extension command/status columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic start_i,
|
||||
input logic abort_i,
|
||||
input logic quiesce_i,
|
||||
input logic [31:0] src_addr_i,
|
||||
input logic [31:0] dst_addr_i,
|
||||
input logic [31:0] len_i,
|
||||
input logic [31:0] timeout_i,
|
||||
output logic busy_o,
|
||||
output logic done_o,
|
||||
output logic err_o,
|
||||
output logic [31:0] fault_addr_o,
|
||||
axi4_if.master axi4
|
||||
// verilog_format: on
|
||||
);
|
||||
typedef enum logic [2:0] {
|
||||
Idle,
|
||||
ReadAddr,
|
||||
ReadData,
|
||||
WriteAddr,
|
||||
WriteData,
|
||||
WriteResp
|
||||
} state_e;
|
||||
|
||||
state_e s_state_d, s_state_q;
|
||||
logic [31:0] s_src_addr_d, s_src_addr_q;
|
||||
logic [31:0] s_dst_addr_d, s_dst_addr_q;
|
||||
logic [31:0] s_remaining_d, s_remaining_q;
|
||||
logic [63:0] s_data_d, s_data_q;
|
||||
logic [31:0] s_timeout_cnt_d, s_timeout_cnt_q;
|
||||
logic s_done_d, s_done_q;
|
||||
logic s_err_d, s_err_q;
|
||||
logic [31:0] s_fault_addr_d, s_fault_addr_q;
|
||||
logic [7:0] s_tail_strobe;
|
||||
logic s_progress;
|
||||
|
||||
always_comb begin
|
||||
if (s_remaining_q >= 32'd8) begin
|
||||
s_tail_strobe = 8'hFF;
|
||||
end else begin
|
||||
s_tail_strobe = 8'((9'd1 << s_remaining_q[3:0]) - 1'b1);
|
||||
end
|
||||
end
|
||||
|
||||
assign axi4.awid = 3'd0;
|
||||
assign axi4.awaddr = s_dst_addr_q;
|
||||
assign axi4.awlen = 8'd0;
|
||||
assign axi4.awsize = 3'd3;
|
||||
assign axi4.awburst = `AXI4_BURST_TYPE_INCR;
|
||||
assign axi4.awlock = 1'b0;
|
||||
assign axi4.awcache = 4'd0;
|
||||
assign axi4.awprot = 3'd0;
|
||||
assign axi4.awqos = 4'd8;
|
||||
assign axi4.awregion = 4'd0;
|
||||
assign axi4.awuser = 1'b0;
|
||||
assign axi4.awvalid = s_state_q == WriteAddr;
|
||||
assign axi4.wdata = s_data_q;
|
||||
assign axi4.wstrb = s_tail_strobe;
|
||||
assign axi4.wlast = 1'b1;
|
||||
assign axi4.wuser = 1'b0;
|
||||
assign axi4.wvalid = s_state_q == WriteData;
|
||||
assign axi4.bready = s_state_q == WriteResp;
|
||||
assign axi4.arid = 3'd0;
|
||||
assign axi4.araddr = s_src_addr_q;
|
||||
assign axi4.arlen = 8'd0;
|
||||
assign axi4.arsize = 3'd3;
|
||||
assign axi4.arburst = `AXI4_BURST_TYPE_INCR;
|
||||
assign axi4.arlock = 1'b0;
|
||||
assign axi4.arcache = 4'd0;
|
||||
assign axi4.arprot = 3'd0;
|
||||
assign axi4.arqos = 4'd8;
|
||||
assign axi4.arregion = 4'd0;
|
||||
assign axi4.aruser = 1'b0;
|
||||
assign axi4.arvalid = s_state_q == ReadAddr;
|
||||
assign axi4.rready = s_state_q == ReadData;
|
||||
assign busy_o = s_state_q != Idle;
|
||||
assign done_o = s_done_q;
|
||||
assign err_o = s_err_q;
|
||||
assign fault_addr_o = s_fault_addr_q;
|
||||
|
||||
assign s_progress = (axi4.arvalid && axi4.arready) ||
|
||||
(axi4.rvalid && axi4.rready) ||
|
||||
(axi4.awvalid && axi4.awready) ||
|
||||
(axi4.wvalid && axi4.wready) ||
|
||||
(axi4.bvalid && axi4.bready);
|
||||
|
||||
always_comb begin
|
||||
s_state_d = s_state_q;
|
||||
s_src_addr_d = s_src_addr_q;
|
||||
s_dst_addr_d = s_dst_addr_q;
|
||||
s_remaining_d = s_remaining_q;
|
||||
s_data_d = s_data_q;
|
||||
s_timeout_cnt_d = s_timeout_cnt_q;
|
||||
s_done_d = 1'b0;
|
||||
s_err_d = 1'b0;
|
||||
s_fault_addr_d = s_fault_addr_q;
|
||||
|
||||
if (s_state_q == Idle) begin
|
||||
s_timeout_cnt_d = '0;
|
||||
if (start_i && !quiesce_i) begin
|
||||
if ((len_i == 32'd0) || (src_addr_i[2:0] != 3'd0) || (dst_addr_i[2:0] != 3'd0)) begin
|
||||
s_done_d = 1'b1;
|
||||
s_err_d = 1'b1;
|
||||
s_fault_addr_d = (src_addr_i[2:0] != 3'd0) ? src_addr_i : dst_addr_i;
|
||||
end else begin
|
||||
s_src_addr_d = src_addr_i;
|
||||
s_dst_addr_d = dst_addr_i;
|
||||
s_remaining_d = len_i;
|
||||
s_state_d = ReadAddr;
|
||||
end
|
||||
end
|
||||
end else if (abort_i) begin
|
||||
s_state_d = Idle;
|
||||
s_done_d = 1'b1;
|
||||
s_err_d = 1'b1;
|
||||
s_fault_addr_d = (s_state_q == ReadAddr || s_state_q == ReadData) ?
|
||||
s_src_addr_q : s_dst_addr_q;
|
||||
end else if (!s_progress && (timeout_i != 32'd0) && (s_timeout_cnt_q == timeout_i - 1'b1)) begin
|
||||
s_state_d = Idle;
|
||||
s_done_d = 1'b1;
|
||||
s_err_d = 1'b1;
|
||||
s_fault_addr_d = (s_state_q == ReadAddr || s_state_q == ReadData) ?
|
||||
s_src_addr_q : s_dst_addr_q;
|
||||
s_timeout_cnt_d = '0;
|
||||
end else begin
|
||||
s_timeout_cnt_d = s_progress ? 32'd0 : s_timeout_cnt_q + 1'b1;
|
||||
unique case (s_state_q)
|
||||
ReadAddr: if (axi4.arvalid && axi4.arready) s_state_d = ReadData;
|
||||
ReadData: begin
|
||||
if (axi4.rvalid && axi4.rready) begin
|
||||
if ((axi4.rresp != `AXI4_RESP_OKAY) || !axi4.rlast) begin
|
||||
s_state_d = Idle;
|
||||
s_done_d = 1'b1;
|
||||
s_err_d = 1'b1;
|
||||
s_fault_addr_d = s_src_addr_q;
|
||||
end else begin
|
||||
s_data_d = axi4.rdata;
|
||||
s_state_d = WriteAddr;
|
||||
end
|
||||
end
|
||||
end
|
||||
WriteAddr: if (axi4.awvalid && axi4.awready) s_state_d = WriteData;
|
||||
WriteData: if (axi4.wvalid && axi4.wready) s_state_d = WriteResp;
|
||||
WriteResp: begin
|
||||
if (axi4.bvalid && axi4.bready) begin
|
||||
if (axi4.bresp != `AXI4_RESP_OKAY) begin
|
||||
s_state_d = Idle;
|
||||
s_done_d = 1'b1;
|
||||
s_err_d = 1'b1;
|
||||
s_fault_addr_d = s_dst_addr_q;
|
||||
end else if (s_remaining_q <= 32'd8) begin
|
||||
s_state_d = Idle;
|
||||
s_done_d = 1'b1;
|
||||
end else begin
|
||||
s_src_addr_d = s_src_addr_q + 32'd8;
|
||||
s_dst_addr_d = s_dst_addr_q + 32'd8;
|
||||
s_remaining_d = s_remaining_q - 32'd8;
|
||||
s_state_d = ReadAddr;
|
||||
end
|
||||
end
|
||||
end
|
||||
default: s_state_d = Idle;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_state_q <= Idle;
|
||||
s_src_addr_q <= '0;
|
||||
s_dst_addr_q <= '0;
|
||||
s_remaining_q <= '0;
|
||||
s_data_q <= '0;
|
||||
s_timeout_cnt_q <= '0;
|
||||
s_done_q <= 1'b0;
|
||||
s_err_q <= 1'b0;
|
||||
s_fault_addr_q <= '0;
|
||||
end else begin
|
||||
s_state_q <= s_state_d;
|
||||
s_src_addr_q <= s_src_addr_d;
|
||||
s_dst_addr_q <= s_dst_addr_d;
|
||||
s_remaining_q <= s_remaining_d;
|
||||
s_data_q <= s_data_d;
|
||||
s_timeout_cnt_q <= s_timeout_cnt_d;
|
||||
s_done_q <= s_done_d;
|
||||
s_err_q <= s_err_d;
|
||||
s_fault_addr_q <= s_fault_addr_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
+137
-18
@@ -7,13 +7,31 @@ module extension_slot #(
|
||||
parameter int unsigned IrqCount = 1,
|
||||
parameter int unsigned ResetTimeoutCycles = 1024
|
||||
) (
|
||||
// verilog_format: off -- preserve the extension lifecycle/data contract columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic data_idle_i,
|
||||
input logic dma_busy_i,
|
||||
input logic dma_done_i,
|
||||
input logic dma_err_i,
|
||||
input logic [31:0] dma_fault_addr_i,
|
||||
apb4_if.slave cfg_apb4,
|
||||
output logic irq_o,
|
||||
output logic idle_o,
|
||||
output logic quiesce_o,
|
||||
output logic reset_o
|
||||
output logic reset_o,
|
||||
output logic [1:0] owner_o,
|
||||
output logic [31:0] read_base_o,
|
||||
output logic [31:0] read_limit_o,
|
||||
output logic [31:0] write_base_o,
|
||||
output logic [31:0] write_limit_o,
|
||||
output logic [31:0] timeout_o,
|
||||
output logic dma_start_o,
|
||||
output logic dma_abort_o,
|
||||
output logic [31:0] dma_src_addr_o,
|
||||
output logic [31:0] dma_dst_addr_o,
|
||||
output logic [31:0] dma_len_o
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam logic [11:0] Identification = 12'h000;
|
||||
localparam logic [11:0] Version = 12'h004;
|
||||
@@ -29,6 +47,11 @@ module extension_slot #(
|
||||
localparam logic [11:0] Fault = 12'h02C;
|
||||
localparam logic [11:0] FaultAddress = 12'h030;
|
||||
localparam logic [11:0] RequestCount = 12'h034;
|
||||
localparam logic [11:0] DmaSource = 12'h100;
|
||||
localparam logic [11:0] DmaDestination = 12'h104;
|
||||
localparam logic [11:0] DmaLength = 12'h108;
|
||||
localparam logic [11:0] DmaCommand = 12'h10C;
|
||||
localparam logic [11:0] DmaStatus = 12'h110;
|
||||
|
||||
localparam logic [31:0] Identifier = KindExtH ? 32'h4558_5448 : 32'h4558_544C;
|
||||
localparam logic [31:0] Capabilities = {
|
||||
@@ -65,16 +88,32 @@ module extension_slot #(
|
||||
logic [31:0] s_fault_addr_q;
|
||||
logic [31:0] s_req_count_d;
|
||||
logic [31:0] s_req_count_q;
|
||||
logic s_req_accept;
|
||||
logic s_write;
|
||||
logic s_cfg_write_legal;
|
||||
logic [31:0] s_dma_src_addr_d, s_dma_src_addr_q;
|
||||
logic [31:0] s_dma_dst_addr_d, s_dma_dst_addr_q;
|
||||
logic [31:0] s_dma_len_d, s_dma_len_q;
|
||||
logic s_dma_start_d, s_dma_start_q;
|
||||
logic s_dma_abort_d, s_dma_abort_q;
|
||||
logic s_req_accept;
|
||||
logic s_write;
|
||||
logic s_cfg_write_legal;
|
||||
|
||||
assign s_req_accept = cfg_apb4.psel && cfg_apb4.penable && !s_apb4_ready_q;
|
||||
assign s_write = s_req_accept && (|cfg_apb4.pstrb);
|
||||
assign idle_o = 1'b1;
|
||||
assign idle_o = KindExtH ? (data_idle_i && !dma_busy_i) : 1'b1;
|
||||
assign quiesce_o = s_quiesce_q;
|
||||
assign reset_o = s_reset_q;
|
||||
assign irq_o = s_fault_sticky_q;
|
||||
assign owner_o = s_owner_q;
|
||||
assign read_base_o = s_read_base_q;
|
||||
assign read_limit_o = s_read_limit_q;
|
||||
assign write_base_o = s_write_base_q;
|
||||
assign write_limit_o = s_write_limit_q;
|
||||
assign timeout_o = s_timeout_q;
|
||||
assign dma_start_o = s_dma_start_q;
|
||||
assign dma_abort_o = s_dma_abort_q;
|
||||
assign dma_src_addr_o = s_dma_src_addr_q;
|
||||
assign dma_dst_addr_o = s_dma_dst_addr_q;
|
||||
assign dma_len_o = s_dma_len_q;
|
||||
assign irq_o = s_fault_sticky_q || dma_done_i;
|
||||
assign cfg_apb4.pready = s_apb4_ready_q;
|
||||
assign cfg_apb4.prdata = s_apb4_rdata_q;
|
||||
assign cfg_apb4.pslverr = s_apb4_resp_err_q;
|
||||
@@ -89,6 +128,11 @@ module extension_slot #(
|
||||
s_write_base_d = s_write_base_q;
|
||||
s_write_limit_d = s_write_limit_q;
|
||||
s_timeout_d = s_timeout_q;
|
||||
s_dma_src_addr_d = s_dma_src_addr_q;
|
||||
s_dma_dst_addr_d = s_dma_dst_addr_q;
|
||||
s_dma_len_d = s_dma_len_q;
|
||||
s_dma_start_d = 1'b0;
|
||||
s_dma_abort_d = 1'b0;
|
||||
s_fault_sticky_d = s_fault_sticky_q;
|
||||
s_fault_addr_d = s_fault_addr_q;
|
||||
s_req_count_d = s_req_count_q;
|
||||
@@ -135,6 +179,26 @@ module extension_slot #(
|
||||
s_cfg_write_legal = KindExtH && (cfg_apb4.pwdata != 32'd0);
|
||||
if (s_cfg_write_legal) s_timeout_d = cfg_apb4.pwdata;
|
||||
end
|
||||
DmaSource: begin
|
||||
s_cfg_write_legal = KindExtH && !dma_busy_i;
|
||||
if (s_cfg_write_legal) s_dma_src_addr_d = cfg_apb4.pwdata;
|
||||
end
|
||||
DmaDestination: begin
|
||||
s_cfg_write_legal = KindExtH && !dma_busy_i;
|
||||
if (s_cfg_write_legal) s_dma_dst_addr_d = cfg_apb4.pwdata;
|
||||
end
|
||||
DmaLength: begin
|
||||
s_cfg_write_legal = KindExtH && !dma_busy_i && (cfg_apb4.pwdata != 32'd0);
|
||||
if (s_cfg_write_legal) s_dma_len_d = cfg_apb4.pwdata;
|
||||
end
|
||||
DmaCommand: begin
|
||||
s_cfg_write_legal = KindExtH && ((cfg_apb4.pwdata & 32'hFFFF_FFFC) == 32'd0) &&
|
||||
!(cfg_apb4.pwdata[0] && dma_busy_i);
|
||||
if (s_cfg_write_legal) begin
|
||||
s_dma_start_d = cfg_apb4.pwdata[0];
|
||||
s_dma_abort_d = cfg_apb4.pwdata[1];
|
||||
end
|
||||
end
|
||||
default: s_cfg_write_legal = 1'b0;
|
||||
endcase
|
||||
if (!s_cfg_write_legal) begin
|
||||
@@ -142,6 +206,10 @@ module extension_slot #(
|
||||
s_fault_addr_d = cfg_apb4.paddr;
|
||||
end
|
||||
end
|
||||
if (dma_err_i && !s_fault_sticky_q) begin
|
||||
s_fault_sticky_d = 1'b1;
|
||||
s_fault_addr_d = dma_fault_addr_i;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
@@ -161,6 +229,13 @@ module extension_slot #(
|
||||
Fault: s_apb4_rdata_d = {31'd0, s_fault_sticky_q};
|
||||
FaultAddress: s_apb4_rdata_d = s_fault_addr_q;
|
||||
RequestCount: s_apb4_rdata_d = s_req_count_q;
|
||||
DmaSource: s_apb4_rdata_d = KindExtH ? s_dma_src_addr_q : 32'd0;
|
||||
DmaDestination: s_apb4_rdata_d = KindExtH ? s_dma_dst_addr_q : 32'd0;
|
||||
DmaLength: s_apb4_rdata_d = KindExtH ? s_dma_len_q : 32'd0;
|
||||
DmaCommand: s_apb4_rdata_d = 32'd0;
|
||||
DmaStatus: begin
|
||||
s_apb4_rdata_d = KindExtH ? {29'd0, s_fault_sticky_q, dma_done_i, dma_busy_i} : 32'd0;
|
||||
end
|
||||
default: s_apb4_rdata_d = '0;
|
||||
endcase
|
||||
end
|
||||
@@ -225,33 +300,37 @@ module extension_slot #(
|
||||
.dat_i (s_reset_d),
|
||||
.dat_o (s_reset_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_read_base_dffr (
|
||||
dffrc #(
|
||||
.DATA_WIDTH(32),
|
||||
.RESET_VAL (32'h3000_0000)
|
||||
) u_read_base_dffrc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_read_base_d),
|
||||
.dat_o (s_read_base_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_read_limit_dffr (
|
||||
dffrc #(
|
||||
.DATA_WIDTH(32),
|
||||
.RESET_VAL (32'h4FFF_FFFF)
|
||||
) u_read_limit_dffrc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_read_limit_d),
|
||||
.dat_o (s_read_limit_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_write_base_dffr (
|
||||
dffrc #(
|
||||
.DATA_WIDTH(32),
|
||||
.RESET_VAL (32'h3000_0000)
|
||||
) u_write_base_dffrc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_write_base_d),
|
||||
.dat_o (s_write_base_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_write_limit_dffr (
|
||||
dffrc #(
|
||||
.DATA_WIDTH(32),
|
||||
.RESET_VAL (32'h4FFF_FFFF)
|
||||
) u_write_limit_dffrc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_write_limit_d),
|
||||
@@ -290,6 +369,46 @@ module extension_slot #(
|
||||
.dat_i (s_req_count_d),
|
||||
.dat_o (s_req_count_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_dma_src_addr_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_src_addr_d),
|
||||
.dat_o (s_dma_src_addr_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_dma_dst_addr_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_dst_addr_d),
|
||||
.dat_o (s_dma_dst_addr_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_dma_len_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_len_d),
|
||||
.dat_o (s_dma_len_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_dma_start_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_start_d),
|
||||
.dat_o (s_dma_start_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_dma_abort_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_abort_d),
|
||||
.dat_o (s_dma_abort_q)
|
||||
);
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
|
||||
@@ -2,33 +2,79 @@
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
module extension_subsystem (
|
||||
// verilog_format: off -- preserve the slot control/data contract columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic ext_h_data_idle_i,
|
||||
apb4_if.slave ext_l_apb4,
|
||||
apb4_if.slave ext_h_apb4,
|
||||
axi4_if.master ext_h_axi4,
|
||||
output logic ext_l_irq_o,
|
||||
output logic ext_h_irq_o
|
||||
output logic ext_h_irq_o,
|
||||
output logic ext_h_block_o,
|
||||
output logic [1:0] ext_h_owner_o,
|
||||
output logic [31:0] ext_h_read_base_o,
|
||||
output logic [31:0] ext_h_read_limit_o,
|
||||
output logic [31:0] ext_h_write_base_o,
|
||||
output logic [31:0] ext_h_write_limit_o,
|
||||
output logic [31:0] ext_h_timeout_o
|
||||
// verilog_format: on
|
||||
);
|
||||
logic s_ext_l_idle;
|
||||
logic s_ext_l_quiesce;
|
||||
logic s_ext_l_reset;
|
||||
logic s_ext_h_idle;
|
||||
logic s_ext_h_quiesce;
|
||||
logic s_ext_h_reset;
|
||||
logic s_ext_l_idle;
|
||||
logic s_ext_l_quiesce;
|
||||
logic s_ext_l_reset;
|
||||
logic s_ext_h_idle;
|
||||
logic s_ext_h_quiesce;
|
||||
logic s_ext_h_reset;
|
||||
logic s_ext_h_dma_busy;
|
||||
logic s_ext_h_dma_done;
|
||||
logic s_ext_h_dma_err;
|
||||
logic [31:0] s_ext_h_dma_fault_addr;
|
||||
logic s_ext_h_dma_start;
|
||||
logic s_ext_h_dma_abort;
|
||||
logic [31:0] s_ext_h_dma_src_addr;
|
||||
logic [31:0] s_ext_h_dma_dst_addr;
|
||||
logic [31:0] s_ext_h_dma_len;
|
||||
logic [ 1:0] unused_ext_l_owner;
|
||||
logic [31:0] unused_ext_l_read_base;
|
||||
logic [31:0] unused_ext_l_read_limit;
|
||||
logic [31:0] unused_ext_l_write_base;
|
||||
logic [31:0] unused_ext_l_write_limit;
|
||||
logic [31:0] unused_ext_l_timeout;
|
||||
logic unused_ext_l_dma_start;
|
||||
logic unused_ext_l_dma_abort;
|
||||
logic [31:0] unused_ext_l_dma_src_addr;
|
||||
logic [31:0] unused_ext_l_dma_dst_addr;
|
||||
logic [31:0] unused_ext_l_dma_len;
|
||||
|
||||
extension_slot #(
|
||||
.SlotId (0),
|
||||
.KindExtH(1'b0),
|
||||
.IrqCount(1)
|
||||
) u_ext_l_slot (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.cfg_apb4 (ext_l_apb4),
|
||||
.irq_o (ext_l_irq_o),
|
||||
.idle_o (s_ext_l_idle),
|
||||
.quiesce_o(s_ext_l_quiesce),
|
||||
.reset_o (s_ext_l_reset)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.data_idle_i (1'b1),
|
||||
.dma_busy_i (1'b0),
|
||||
.dma_done_i (1'b0),
|
||||
.dma_err_i (1'b0),
|
||||
.dma_fault_addr_i(32'd0),
|
||||
.cfg_apb4 (ext_l_apb4),
|
||||
.irq_o (ext_l_irq_o),
|
||||
.idle_o (s_ext_l_idle),
|
||||
.quiesce_o (s_ext_l_quiesce),
|
||||
.reset_o (s_ext_l_reset),
|
||||
.owner_o (unused_ext_l_owner),
|
||||
.read_base_o (unused_ext_l_read_base),
|
||||
.read_limit_o (unused_ext_l_read_limit),
|
||||
.write_base_o (unused_ext_l_write_base),
|
||||
.write_limit_o (unused_ext_l_write_limit),
|
||||
.timeout_o (unused_ext_l_timeout),
|
||||
.dma_start_o (unused_ext_l_dma_start),
|
||||
.dma_abort_o (unused_ext_l_dma_abort),
|
||||
.dma_src_addr_o (unused_ext_l_dma_src_addr),
|
||||
.dma_dst_addr_o (unused_ext_l_dma_dst_addr),
|
||||
.dma_len_o (unused_ext_l_dma_len)
|
||||
);
|
||||
|
||||
extension_slot #(
|
||||
@@ -36,49 +82,68 @@ module extension_subsystem (
|
||||
.KindExtH(1'b1),
|
||||
.IrqCount(1)
|
||||
) u_ext_h_slot (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.cfg_apb4 (ext_h_apb4),
|
||||
.irq_o (ext_h_irq_o),
|
||||
.idle_o (s_ext_h_idle),
|
||||
.quiesce_o(s_ext_h_quiesce),
|
||||
.reset_o (s_ext_h_reset)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.data_idle_i (ext_h_data_idle_i),
|
||||
.dma_busy_i (s_ext_h_dma_busy),
|
||||
.dma_done_i (s_ext_h_dma_done),
|
||||
.dma_err_i (s_ext_h_dma_err),
|
||||
.dma_fault_addr_i(s_ext_h_dma_fault_addr),
|
||||
.cfg_apb4 (ext_h_apb4),
|
||||
.irq_o (ext_h_irq_o),
|
||||
.idle_o (s_ext_h_idle),
|
||||
.quiesce_o (s_ext_h_quiesce),
|
||||
.reset_o (s_ext_h_reset),
|
||||
.owner_o (ext_h_owner_o),
|
||||
.read_base_o (ext_h_read_base_o),
|
||||
.read_limit_o (ext_h_read_limit_o),
|
||||
.write_base_o (ext_h_write_base_o),
|
||||
.write_limit_o (ext_h_write_limit_o),
|
||||
.timeout_o (ext_h_timeout_o),
|
||||
.dma_start_o (s_ext_h_dma_start),
|
||||
.dma_abort_o (s_ext_h_dma_abort),
|
||||
.dma_src_addr_o (s_ext_h_dma_src_addr),
|
||||
.dma_dst_addr_o (s_ext_h_dma_dst_addr),
|
||||
.dma_len_o (s_ext_h_dma_len)
|
||||
);
|
||||
|
||||
assign ext_h_axi4.awid = '0;
|
||||
assign ext_h_axi4.awaddr = '0;
|
||||
assign ext_h_axi4.awlen = '0;
|
||||
assign ext_h_axi4.awsize = '0;
|
||||
assign ext_h_axi4.awburst = '0;
|
||||
assign ext_h_axi4.awlock = 1'b0;
|
||||
assign ext_h_axi4.awcache = '0;
|
||||
assign ext_h_axi4.awprot = '0;
|
||||
assign ext_h_axi4.awqos = '0;
|
||||
assign ext_h_axi4.awregion = '0;
|
||||
assign ext_h_axi4.awuser = '0;
|
||||
assign ext_h_axi4.awvalid = 1'b0;
|
||||
assign ext_h_axi4.wdata = '0;
|
||||
assign ext_h_axi4.wstrb = '0;
|
||||
assign ext_h_axi4.wlast = 1'b0;
|
||||
assign ext_h_axi4.wuser = '0;
|
||||
assign ext_h_axi4.wvalid = 1'b0;
|
||||
assign ext_h_axi4.bready = 1'b1;
|
||||
assign ext_h_axi4.arid = '0;
|
||||
assign ext_h_axi4.araddr = '0;
|
||||
assign ext_h_axi4.arlen = '0;
|
||||
assign ext_h_axi4.arsize = '0;
|
||||
assign ext_h_axi4.arburst = '0;
|
||||
assign ext_h_axi4.arlock = 1'b0;
|
||||
assign ext_h_axi4.arcache = '0;
|
||||
assign ext_h_axi4.arprot = '0;
|
||||
assign ext_h_axi4.arqos = '0;
|
||||
assign ext_h_axi4.arregion = '0;
|
||||
assign ext_h_axi4.aruser = '0;
|
||||
assign ext_h_axi4.arvalid = 1'b0;
|
||||
assign ext_h_axi4.rready = 1'b1;
|
||||
assign ext_h_block_o = s_ext_h_quiesce || s_ext_h_reset;
|
||||
|
||||
logic [5:0] s_unused_status;
|
||||
extension_dma_master u_ext_h_dma (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.start_i (s_ext_h_dma_start),
|
||||
.abort_i (s_ext_h_dma_abort || s_ext_h_reset),
|
||||
.quiesce_i (s_ext_h_quiesce),
|
||||
.src_addr_i (s_ext_h_dma_src_addr),
|
||||
.dst_addr_i (s_ext_h_dma_dst_addr),
|
||||
.len_i (s_ext_h_dma_len),
|
||||
.timeout_i (ext_h_timeout_o),
|
||||
.busy_o (s_ext_h_dma_busy),
|
||||
.done_o (s_ext_h_dma_done),
|
||||
.err_o (s_ext_h_dma_err),
|
||||
.fault_addr_o(s_ext_h_dma_fault_addr),
|
||||
.axi4 (ext_h_axi4)
|
||||
);
|
||||
|
||||
logic [16:0] s_unused_status;
|
||||
assign s_unused_status = {
|
||||
s_ext_l_idle, s_ext_l_quiesce, s_ext_l_reset, s_ext_h_idle, s_ext_h_quiesce, s_ext_h_reset
|
||||
s_ext_l_idle,
|
||||
s_ext_l_quiesce,
|
||||
s_ext_l_reset,
|
||||
s_ext_h_idle,
|
||||
s_ext_h_quiesce,
|
||||
s_ext_h_reset,
|
||||
^unused_ext_l_owner,
|
||||
^unused_ext_l_read_base,
|
||||
^unused_ext_l_read_limit,
|
||||
^unused_ext_l_write_base,
|
||||
^unused_ext_l_write_limit,
|
||||
^unused_ext_l_timeout,
|
||||
unused_ext_l_dma_start,
|
||||
unused_ext_l_dma_abort,
|
||||
^unused_ext_l_dma_src_addr,
|
||||
^unused_ext_l_dma_dst_addr,
|
||||
^unused_ext_l_dma_len
|
||||
};
|
||||
endmodule
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
module hp_lifecycle_controller (
|
||||
// verilog_format: off -- preserve the AON lifecycle contract columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic release_req_i,
|
||||
input logic hp_idle_i,
|
||||
input logic flush_busy_i,
|
||||
input logic [15:0] timeout_i,
|
||||
output logic hp_release_o,
|
||||
output logic block_new_o,
|
||||
output logic flush_o,
|
||||
output logic draining_o,
|
||||
output logic forced_fault_o
|
||||
// verilog_format: on
|
||||
);
|
||||
typedef enum logic [2:0] {
|
||||
Held,
|
||||
Running,
|
||||
Quiesce,
|
||||
FlushRequest,
|
||||
FlushWait
|
||||
} state_e;
|
||||
|
||||
state_e s_state_d, s_state_q;
|
||||
logic s_hp_release_d, s_hp_release_q;
|
||||
logic s_block_new_d, s_block_new_q;
|
||||
logic s_flush_d, s_flush_q;
|
||||
logic s_forced_fault_d, s_forced_fault_q;
|
||||
logic [15:0] s_timeout_cnt_d, s_timeout_cnt_q;
|
||||
logic [15:0] s_timeout_limit;
|
||||
|
||||
assign s_timeout_limit = (timeout_i < 16'd2) ? 16'd2 : timeout_i;
|
||||
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 forced_fault_o = s_forced_fault_q;
|
||||
|
||||
always_comb begin
|
||||
s_state_d = s_state_q;
|
||||
s_hp_release_d = s_hp_release_q;
|
||||
s_block_new_d = s_block_new_q;
|
||||
s_flush_d = s_flush_q;
|
||||
s_forced_fault_d = s_forced_fault_q;
|
||||
s_timeout_cnt_d = s_timeout_cnt_q;
|
||||
unique case (s_state_q)
|
||||
Held: begin
|
||||
s_hp_release_d = 1'b0;
|
||||
s_block_new_d = 1'b0;
|
||||
s_flush_d = 1'b0;
|
||||
s_timeout_cnt_d = '0;
|
||||
if (release_req_i) begin
|
||||
s_hp_release_d = 1'b1;
|
||||
s_forced_fault_d = 1'b0;
|
||||
s_state_d = Running;
|
||||
end
|
||||
end
|
||||
Running: begin
|
||||
s_hp_release_d = 1'b1;
|
||||
s_block_new_d = 1'b0;
|
||||
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;
|
||||
end
|
||||
end
|
||||
Quiesce: begin
|
||||
s_block_new_d = 1'b1;
|
||||
if (hp_idle_i) begin
|
||||
s_flush_d = 1'b1;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = FlushRequest;
|
||||
end else if (s_timeout_cnt_q == s_timeout_limit - 1'b1) begin
|
||||
s_forced_fault_d = 1'b1;
|
||||
s_flush_d = 1'b1;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = FlushRequest;
|
||||
end else begin
|
||||
s_timeout_cnt_d = s_timeout_cnt_q + 1'b1;
|
||||
end
|
||||
end
|
||||
FlushRequest: begin
|
||||
s_block_new_d = 1'b1;
|
||||
s_flush_d = 1'b1;
|
||||
if (flush_busy_i) begin
|
||||
s_flush_d = 1'b0;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = FlushWait;
|
||||
end else if (s_timeout_cnt_q == s_timeout_limit - 1'b1) begin
|
||||
s_forced_fault_d = 1'b1;
|
||||
s_flush_d = 1'b0;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = FlushWait;
|
||||
end else begin
|
||||
s_timeout_cnt_d = s_timeout_cnt_q + 1'b1;
|
||||
end
|
||||
end
|
||||
FlushWait: begin
|
||||
s_block_new_d = 1'b1;
|
||||
s_flush_d = 1'b0;
|
||||
if (!flush_busy_i || (s_timeout_cnt_q == s_timeout_limit - 1'b1)) begin
|
||||
if (flush_busy_i) s_forced_fault_d = 1'b1;
|
||||
s_hp_release_d = 1'b0;
|
||||
s_block_new_d = 1'b0;
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = Held;
|
||||
end else begin
|
||||
s_timeout_cnt_d = s_timeout_cnt_q + 1'b1;
|
||||
end
|
||||
end
|
||||
default: s_state_d = Held;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_state_q <= Held;
|
||||
s_hp_release_q <= 1'b0;
|
||||
s_block_new_q <= 1'b0;
|
||||
s_flush_q <= 1'b0;
|
||||
s_forced_fault_q <= 1'b0;
|
||||
s_timeout_cnt_q <= '0;
|
||||
end else begin
|
||||
s_state_q <= s_state_d;
|
||||
s_hp_release_q <= s_hp_release_d;
|
||||
s_block_new_q <= s_block_new_d;
|
||||
s_flush_q <= s_flush_d;
|
||||
s_forced_fault_q <= s_forced_fault_d;
|
||||
s_timeout_cnt_q <= s_timeout_cnt_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
@@ -15,6 +15,7 @@ module pll_rcu_controller #(
|
||||
input logic pll_capable_i,
|
||||
input logic hp_idle_i,
|
||||
input logic pclk_idle_i,
|
||||
input logic [15:0] timeout_i,
|
||||
input logic force_safe_i,
|
||||
input logic clear_fault_i,
|
||||
output logic [2:0] pll_sel_o,
|
||||
@@ -79,6 +80,7 @@ module pll_rcu_controller #(
|
||||
logic s_fault_sticky_q;
|
||||
logic s_rsp_valid_d;
|
||||
logic s_rsp_valid_q;
|
||||
logic [15:0] s_timeout_limit;
|
||||
|
||||
assign s_state_q = state_e'(s_state_bits_q);
|
||||
|
||||
@@ -127,6 +129,7 @@ module pll_rcu_controller #(
|
||||
assign hp_block_o = s_hp_block_q;
|
||||
assign lp_force_ref_o = s_lp_force_ref_q;
|
||||
assign pll_fault_o = s_fault_sticky_q;
|
||||
assign s_timeout_limit = (timeout_i < 16'd2) ? 16'd2 : timeout_i;
|
||||
|
||||
always_comb begin
|
||||
s_state_d = s_state_q;
|
||||
@@ -182,7 +185,7 @@ module pll_rcu_controller #(
|
||||
if (hp_idle_i && pclk_idle_i) begin
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = ParkLp;
|
||||
end else if (s_timeout_cnt_q == 16'(QuiesceTimeout - 1)) begin
|
||||
end else if (s_timeout_cnt_q == s_timeout_limit - 1'b1) begin
|
||||
s_err_d = 2'd2;
|
||||
s_fault_sticky_d = 1'b1;
|
||||
s_state_d = FailSafe;
|
||||
@@ -208,7 +211,7 @@ module pll_rcu_controller #(
|
||||
if (!pll_lock_i) begin
|
||||
s_timeout_cnt_d = '0;
|
||||
s_state_d = QualifyLock;
|
||||
end else if (s_timeout_cnt_q == 16'(LockTimeout - 1)) begin
|
||||
end else if (s_timeout_cnt_q == s_timeout_limit - 1'b1) begin
|
||||
s_err_d = 2'd2;
|
||||
s_fault_sticky_d = 1'b1;
|
||||
s_state_d = FailSafe;
|
||||
@@ -227,7 +230,7 @@ module pll_rcu_controller #(
|
||||
end else begin
|
||||
s_lock_qual_cnt_d = s_lock_qual_cnt_q + 1'b1;
|
||||
end
|
||||
if (s_timeout_cnt_q == 16'(LockTimeout - 1)) begin
|
||||
if (s_timeout_cnt_q == s_timeout_limit - 1'b1) begin
|
||||
s_err_d = 2'd2;
|
||||
s_fault_sticky_d = 1'b1;
|
||||
s_state_d = FailSafe;
|
||||
|
||||
@@ -22,6 +22,7 @@ module rcu #(
|
||||
output logic sys_clk_o,
|
||||
output logic sys_rst_n_o,
|
||||
output logic hp_clk_o,
|
||||
output logic hp_core_clk_o,
|
||||
output logic hp_rst_n_o,
|
||||
output logic pclk_o,
|
||||
output logic pclk_rst_n_o,
|
||||
@@ -55,6 +56,7 @@ module rcu #(
|
||||
.lp_clk_o (sys_clk_o),
|
||||
.lp_rst_n_o (sys_rst_n_o),
|
||||
.hp_clk_o (hp_clk_o),
|
||||
.hp_core_clk_o (hp_core_clk_o),
|
||||
.hp_rst_n_o (hp_rst_n_o),
|
||||
.pclk_o (pclk_o),
|
||||
.pclk_rst_n_o (pclk_rst_n_o),
|
||||
|
||||
+292
-121
@@ -14,9 +14,12 @@
|
||||
|
||||
module retrosoc (
|
||||
// verilog_format: off -- preserve reviewed column alignment
|
||||
input logic clk_aon_i,
|
||||
input logic rst_aon_n_i,
|
||||
input logic clk_lp_i,
|
||||
input logic rst_lp_n_i,
|
||||
input logic clk_hp_i,
|
||||
input logic clk_hp_core_i,
|
||||
input logic rst_hp_n_i,
|
||||
input logic clk_pclk_i,
|
||||
input logic rst_pclk_n_i,
|
||||
@@ -79,11 +82,11 @@ module retrosoc (
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
|
||||
u_opipsram_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_psram_pclk_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
|
||||
u_psram_pclk_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_xpi_pclk_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
|
||||
u_xpi_pclk_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_opipsram_pclk_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
|
||||
u_opipsram_pclk_axi4_if (.aclk(clk_mem_i), .aresetn(rst_mem_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
|
||||
u_ext_h_wide_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
|
||||
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
|
||||
@@ -110,6 +113,10 @@ module retrosoc (
|
||||
u_data_xpi_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_idle_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_mgmt_control_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_mgmt_data_axi4_if (.aclk(clk_lp_i), .aresetn(rst_lp_n_i));
|
||||
user_gpio_if u_user_gpio_if ();
|
||||
// ip interface
|
||||
gpio_if u_gpio_if ();
|
||||
@@ -161,22 +168,58 @@ module retrosoc (
|
||||
`else
|
||||
logic s_unused_product_legacy;
|
||||
`endif
|
||||
logic s_rtc_wake;
|
||||
logic s_hp_jtag_tdo;
|
||||
logic s_hp_debug_reset_req;
|
||||
logic s_lp_jtag_tdo;
|
||||
logic s_debug_hp_sel_jtag;
|
||||
logic [63:0] s_hp_time;
|
||||
logic s_hp_timer_irq;
|
||||
logic s_hp_software_irq;
|
||||
logic s_hp_machine_external_irq;
|
||||
logic s_hp_supervisor_external_irq;
|
||||
logic s_data_plane_idle;
|
||||
logic s_hp_mmio_idle;
|
||||
logic [ 3:0] s_pclk_pending_d;
|
||||
logic [ 3:0] s_pclk_pending_q;
|
||||
logic [ 1:0] s_mem_pad_mode_lp;
|
||||
logic s_mem_pad_lock_lp;
|
||||
logic s_rtc_wake;
|
||||
logic s_hp_jtag_tdo;
|
||||
logic s_hp_debug_reset_req;
|
||||
logic s_lp_jtag_tdo;
|
||||
logic s_debug_hp_sel_jtag;
|
||||
logic [63:0] s_hp_time;
|
||||
logic s_hp_timer_irq;
|
||||
logic s_hp_software_irq;
|
||||
logic s_hp_machine_external_irq;
|
||||
logic s_hp_supervisor_external_irq;
|
||||
logic s_data_plane_idle;
|
||||
logic s_data_plane_flush_busy;
|
||||
logic s_mgmt_router_idle;
|
||||
logic [ 7:0] s_data_plane_outstanding_read;
|
||||
logic [ 7:0] s_data_plane_outstanding_write;
|
||||
logic s_data_plane_fault_valid;
|
||||
logic [ 2:0] s_data_plane_fault_master;
|
||||
logic [ 2:0] s_data_plane_fault_target;
|
||||
logic [31:0] s_data_plane_fault_addr;
|
||||
logic s_data_plane_fault_write;
|
||||
logic [ 3:0] s_data_plane_fault_reason;
|
||||
logic s_hp_mmio_idle;
|
||||
logic [ 3:0] s_pclk_pending_d;
|
||||
logic [ 3:0] s_pclk_pending_q;
|
||||
logic [ 1:0] s_mem_pad_mode_lp;
|
||||
logic s_mem_pad_lock_lp;
|
||||
logic s_hp_release_req_aon;
|
||||
logic s_hp_debug_reset_req_aon;
|
||||
logic s_hp_idle_aon;
|
||||
logic s_hp_flush_busy_aon;
|
||||
logic s_hp_lifecycle_release_aon;
|
||||
logic s_hp_lifecycle_release_hp;
|
||||
logic s_hp_lifecycle_block;
|
||||
logic s_hp_lifecycle_flush;
|
||||
logic s_hp_lifecycle_draining;
|
||||
logic s_hp_lifecycle_fault;
|
||||
logic s_hp_block_combined;
|
||||
logic [ 2:0] s_hp_lifecycle_stat_pclk;
|
||||
logic s_ext_h_data_idle;
|
||||
logic s_ext_h_block;
|
||||
logic [31:0] s_ext_h_read_base;
|
||||
logic [31:0] s_ext_h_read_limit;
|
||||
logic [31:0] s_ext_h_write_base;
|
||||
logic [31:0] s_ext_h_write_limit;
|
||||
logic [31:0] s_ext_h_timeout;
|
||||
logic s_ext_h_irq_raw;
|
||||
logic [ 1:0] s_ext_h_owner;
|
||||
logic [31:0] s_fault_addr_mux;
|
||||
logic [ 3:0] s_fault_wstrb_mux;
|
||||
logic s_fault_reserved_mux;
|
||||
logic [ 5:0] unused_cdc_clear_busy;
|
||||
logic [ 5:0][7:0] unused_cdc_epoch;
|
||||
|
||||
`ifdef HAVE_SRAM_IF
|
||||
localparam bit SramPresent = 1'b1;
|
||||
@@ -184,36 +227,46 @@ module retrosoc (
|
||||
localparam bit SramPresent = 1'b0;
|
||||
`endif
|
||||
|
||||
assign u_sysctrl_if.fault_access_i = s_bus_fault_access;
|
||||
assign u_sysctrl_if.fault_master_i = s_bus_fault_master;
|
||||
assign u_sysctrl_if.fault_code_i = s_bus_fault_code;
|
||||
assign s_perf_en = u_sysctrl_if.perf_enable_o;
|
||||
assign s_perf_clear = u_sysctrl_if.perf_clear_o;
|
||||
assign test_done_o = u_sysctrl_if.test_done_o;
|
||||
assign test_pass_o = u_sysctrl_if.test_pass_o;
|
||||
assign test_code_o = u_sysctrl_if.test_code_o;
|
||||
assign u_sysctrl_if.perf_mgmt_wait_i = s_perf_mgmt_wait;
|
||||
assign u_sysctrl_if.perf_user_wait_i = s_perf_user_wait;
|
||||
assign u_sysctrl_if.perf_dma_wait_i = s_perf_dma_wait;
|
||||
assign u_sysctrl_if.perf_sdio0_wait_i = s_perf_sdio0_wait;
|
||||
assign u_sysctrl_if.perf_sdio1_wait_i = s_perf_sdio1_wait;
|
||||
assign u_sysctrl_if.perf_usb2_wait_i = s_perf_usb2_wait;
|
||||
assign u_sysctrl_if.fault_access_i = s_data_plane_fault_valid ?
|
||||
s_data_plane_fault_write : s_bus_fault_access;
|
||||
assign u_sysctrl_if.fault_master_i = s_data_plane_fault_valid ?
|
||||
s_data_plane_fault_master : s_bus_fault_master;
|
||||
assign u_sysctrl_if.fault_code_i = s_data_plane_fault_valid ?
|
||||
s_data_plane_fault_reason[2:0] : s_bus_fault_code;
|
||||
assign s_perf_en = u_sysctrl_if.perf_enable_o;
|
||||
assign s_perf_clear = u_sysctrl_if.perf_clear_o;
|
||||
assign test_done_o = u_sysctrl_if.test_done_o;
|
||||
assign test_pass_o = u_sysctrl_if.test_pass_o;
|
||||
assign test_code_o = u_sysctrl_if.test_code_o;
|
||||
assign u_sysctrl_if.perf_mgmt_wait_i = s_perf_mgmt_wait;
|
||||
assign u_sysctrl_if.perf_user_wait_i = s_perf_user_wait;
|
||||
assign u_sysctrl_if.perf_dma_wait_i = s_perf_dma_wait;
|
||||
assign u_sysctrl_if.perf_sdio0_wait_i = s_perf_sdio0_wait;
|
||||
assign u_sysctrl_if.perf_sdio1_wait_i = s_perf_sdio1_wait;
|
||||
assign u_sysctrl_if.perf_usb2_wait_i = s_perf_usb2_wait;
|
||||
assign u_sysctrl_if.perf_apb4_periph_wait_i = s_perf_apb4_periph_wait;
|
||||
assign u_sysctrl_if.perf_apb4_system_wait_i = s_perf_apb4_system_wait;
|
||||
assign u_sysctrl_if.perf_sdram_wait_i = s_perf_sdram_wait;
|
||||
assign u_sysctrl_if.perf_sdram_wait_i = s_perf_sdram_wait;
|
||||
// The SYSCTRL PSRAM statistic aggregates the legacy and OPI PSRAM windows.
|
||||
assign u_sysctrl_if.perf_psram_wait_i = s_perf_psram_wait + s_perf_opipsram_wait;
|
||||
assign u_sysctrl_if.perf_flash_wait_i = s_perf_flash_wait;
|
||||
assign u_sysctrl_if.rtc_wake_i = s_rtc_wake;
|
||||
assign u_sysctrl_if.perf_psram_wait_i = s_perf_psram_wait + s_perf_opipsram_wait;
|
||||
assign u_sysctrl_if.perf_flash_wait_i = s_perf_flash_wait;
|
||||
assign u_sysctrl_if.rtc_wake_i = s_rtc_wake;
|
||||
`ifdef HAVE_HP
|
||||
assign u_sysctrl_if.hp_present_i = 1'b1;
|
||||
`else
|
||||
assign u_sysctrl_if.hp_present_i = 1'b0;
|
||||
`endif
|
||||
assign u_sysctrl_if.hp_actual_released_i = s_hp_lifecycle_stat_pclk[2];
|
||||
assign u_sysctrl_if.hp_draining_i = s_hp_lifecycle_stat_pclk[1];
|
||||
assign u_sysctrl_if.hp_forced_fault_i = s_hp_lifecycle_stat_pclk[0];
|
||||
assign s_fault_addr_mux = s_data_plane_fault_valid ? s_data_plane_fault_addr : s_bus_fault_addr;
|
||||
assign s_fault_wstrb_mux = s_data_plane_fault_valid && s_data_plane_fault_write ?
|
||||
4'hF : s_bus_fault_wstrb;
|
||||
assign s_fault_reserved_mux = s_data_plane_fault_valid ? 1'b0 : s_bus_fault_reserved;
|
||||
assign u_uart0_if.rx_i = uart_rx_i;
|
||||
assign uart_tx_o = u_uart0_if.tx_o;
|
||||
assign uart_tx_o = u_uart0_if.tx_o;
|
||||
assign u_uart1_if.rx_i = uart1_rx_i;
|
||||
assign uart1_tx_o = u_uart1_if.tx_o;
|
||||
assign uart1_tx_o = u_uart1_if.tx_o;
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
@@ -318,9 +371,9 @@ core_wrapper u_core_wrapper (
|
||||
|
||||
`ifdef HAVE_HP
|
||||
hp_subsystem u_hp_subsystem (
|
||||
.clk_i (clk_hp_i),
|
||||
.clk_i (clk_hp_core_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.core_reset_i (!u_sysctrl_if.hp_release_o || s_hp_debug_reset_req),
|
||||
.core_reset_i (!s_hp_lifecycle_release_hp),
|
||||
.time_i (s_hp_time),
|
||||
.timer_irq_i (s_hp_timer_irq),
|
||||
.software_irq_i (s_hp_software_irq),
|
||||
@@ -355,46 +408,123 @@ core_wrapper u_core_wrapper (
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_hp_mmio_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),
|
||||
.src_axi4 (u_hp_mmio_gated_axi4_if),
|
||||
.dst_axi4 (u_hp_mmio_lp_axi4_if)
|
||||
.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 (1'b0),
|
||||
.clear_busy_o(unused_cdc_clear_busy[0]),
|
||||
.epoch_o (unused_cdc_epoch[0]),
|
||||
.src_axi4 (u_hp_mmio_gated_axi4_if),
|
||||
.dst_axi4 (u_hp_mmio_lp_axi4_if)
|
||||
);
|
||||
|
||||
axi4_address_gate u_hp_mmio_gate (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.block_new_i(hp_block_i),
|
||||
.block_new_i(s_hp_block_combined),
|
||||
.source (u_hp_mmio_hp_axi4_if),
|
||||
.sink (u_hp_mmio_gated_axi4_if),
|
||||
.idle_o (s_hp_mmio_idle)
|
||||
);
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(4)
|
||||
) u_hp_lifecycle_input_sync (
|
||||
.clk_i(clk_aon_i),
|
||||
.rst_n_i(rst_aon_n_i),
|
||||
.dat_i({
|
||||
u_sysctrl_if.hp_release_o,
|
||||
s_hp_debug_reset_req,
|
||||
s_data_plane_idle && s_hp_mmio_idle,
|
||||
s_data_plane_flush_busy
|
||||
}),
|
||||
.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)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_hp_release_sync (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i(rst_hp_n_i),
|
||||
.dat_i (s_hp_lifecycle_release_aon),
|
||||
.dat_o (s_hp_lifecycle_release_hp)
|
||||
);
|
||||
assign s_hp_block_combined = hp_block_i || s_hp_lifecycle_block;
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(3)
|
||||
) u_hp_lifecycle_status_sync (
|
||||
.clk_i (clk_pclk_i),
|
||||
.rst_n_i(rst_pclk_n_i),
|
||||
.dat_i ({s_hp_lifecycle_release_aon, s_hp_lifecycle_draining, s_hp_lifecycle_fault}),
|
||||
.dat_o (s_hp_lifecycle_stat_pclk)
|
||||
);
|
||||
|
||||
axi4_mgmt_router u_mgmt_router (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i(rst_lp_n_i),
|
||||
.source (u_mgmt_axi4_if),
|
||||
.control(u_mgmt_control_axi4_if),
|
||||
.data (u_mgmt_data_axi4_if),
|
||||
.idle_o (s_mgmt_router_idle)
|
||||
);
|
||||
|
||||
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 (hp_block_i),
|
||||
.mem_pad_mode_i (s_mem_pad_mode_lp),
|
||||
.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),
|
||||
.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)
|
||||
.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)
|
||||
);
|
||||
|
||||
axi4_master_idle u_idle_master (.axi4(u_idle_axi4_if));
|
||||
@@ -403,56 +533,71 @@ core_wrapper u_core_wrapper (
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_cfg_pclk_cdc (
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i(rst_pclk_n_i),
|
||||
.src_axi4 (u_cfg_axi4_if),
|
||||
.dst_axi4 (u_cfg_pclk_axi4_if)
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i (rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i (rst_pclk_n_i),
|
||||
.clear_i (1'b0),
|
||||
.clear_busy_o(unused_cdc_clear_busy[1]),
|
||||
.epoch_o (unused_cdc_epoch[1]),
|
||||
.src_axi4 (u_cfg_axi4_if),
|
||||
.dst_axi4 (u_cfg_pclk_axi4_if)
|
||||
);
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_system_pclk_cdc (
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i(rst_pclk_n_i),
|
||||
.src_axi4 (u_system_axi4_if),
|
||||
.dst_axi4 (u_system_pclk_axi4_if)
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i (rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i (rst_pclk_n_i),
|
||||
.clear_i (1'b0),
|
||||
.clear_busy_o(unused_cdc_clear_busy[2]),
|
||||
.epoch_o (unused_cdc_epoch[2]),
|
||||
.src_axi4 (u_system_axi4_if),
|
||||
.dst_axi4 (u_system_pclk_axi4_if)
|
||||
);
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_psram_target_cdc (
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i(rst_pclk_n_i),
|
||||
.src_axi4 (u_psram_axi4_if),
|
||||
.dst_axi4 (u_psram_pclk_axi4_if)
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i (rst_lp_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i (rst_mem_n_i),
|
||||
.clear_i (1'b0),
|
||||
.clear_busy_o(unused_cdc_clear_busy[3]),
|
||||
.epoch_o (unused_cdc_epoch[3]),
|
||||
.src_axi4 (u_psram_axi4_if),
|
||||
.dst_axi4 (u_psram_pclk_axi4_if)
|
||||
);
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_xpi_target_cdc (
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i(rst_pclk_n_i),
|
||||
.src_axi4 (u_xpi_axi4_if),
|
||||
.dst_axi4 (u_xpi_pclk_axi4_if)
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i (rst_lp_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i (rst_mem_n_i),
|
||||
.clear_i (1'b0),
|
||||
.clear_busy_o(unused_cdc_clear_busy[4]),
|
||||
.epoch_o (unused_cdc_epoch[4]),
|
||||
.src_axi4 (u_xpi_axi4_if),
|
||||
.dst_axi4 (u_xpi_pclk_axi4_if)
|
||||
);
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_opi_target_cdc (
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i(rst_lp_n_i),
|
||||
.dst_clk_i (clk_pclk_i),
|
||||
.dst_rst_n_i(rst_pclk_n_i),
|
||||
.src_axi4 (u_opipsram_axi4_if),
|
||||
.dst_axi4 (u_opipsram_pclk_axi4_if)
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i (rst_lp_n_i),
|
||||
.dst_clk_i (clk_mem_i),
|
||||
.dst_rst_n_i (rst_mem_n_i),
|
||||
.clear_i (1'b0),
|
||||
.clear_busy_o(unused_cdc_clear_busy[5]),
|
||||
.epoch_o (unused_cdc_epoch[5]),
|
||||
.src_axi4 (u_opipsram_axi4_if),
|
||||
.dst_axi4 (u_opipsram_pclk_axi4_if)
|
||||
);
|
||||
apb4_async_bridge u_sdram_cfg_cdc (
|
||||
.src_clk_i (clk_pclk_i),
|
||||
@@ -514,7 +659,7 @@ core_wrapper u_core_wrapper (
|
||||
axi4_bus u_bus (
|
||||
.clk_i (clk_lp_i),
|
||||
.rst_n_i (rst_lp_n_i),
|
||||
.mgmt_axi4 (u_mgmt_axi4_if),
|
||||
.mgmt_axi4 (u_mgmt_control_axi4_if),
|
||||
.user_axi4 (u_data_sram_axi4_if),
|
||||
.dma_axi4 (u_data_sdram_axi4_if),
|
||||
.sdio0_axi4 (u_data_qpi_axi4_if),
|
||||
@@ -561,8 +706,11 @@ core_wrapper u_core_wrapper (
|
||||
.clk_aud_i (clk_aud_i),
|
||||
.rst_aud_n_i (rst_aud_n_i),
|
||||
.clk_ulpi_i (clk_ulpi_i),
|
||||
.clk_mem_i (clk_mem_i),
|
||||
.rst_mem_n_i (rst_mem_n_i),
|
||||
.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),
|
||||
.cfg_axi4 (u_cfg_pclk_axi4_if),
|
||||
.dma_axi4 (u_dma_axi4_if),
|
||||
.sdio0_axi4 (u_sdio0_axi4_if),
|
||||
@@ -593,10 +741,10 @@ core_wrapper u_core_wrapper (
|
||||
.usb2 (usb2),
|
||||
.opipsram (u_opipsram_raw_if),
|
||||
.i2c1 (u_i2c1_if),
|
||||
.fault_valid_i (s_bus_fault_valid),
|
||||
.fault_addr_i (s_bus_fault_addr),
|
||||
.fault_wstrb_i (s_bus_fault_wstrb),
|
||||
.fault_reserved_i (s_bus_fault_reserved),
|
||||
.fault_valid_i (s_data_plane_fault_valid || s_bus_fault_valid),
|
||||
.fault_addr_i (s_fault_addr_mux),
|
||||
.fault_wstrb_i (s_fault_wstrb_mux),
|
||||
.fault_reserved_i (s_fault_reserved_mux),
|
||||
.hp_time_o (s_hp_time),
|
||||
.hp_timer_irq_o (s_hp_timer_irq),
|
||||
.hp_software_irq_o (s_hp_software_irq),
|
||||
@@ -614,25 +762,48 @@ core_wrapper u_core_wrapper (
|
||||
);
|
||||
|
||||
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_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),
|
||||
.irq_o (s_apb4_system_irq)
|
||||
.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),
|
||||
.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)
|
||||
);
|
||||
|
||||
logic [3:0] s_unused_domain_inputs;
|
||||
logic [31:0] s_unused_domain_inputs;
|
||||
assign s_unused_domain_inputs = {
|
||||
clk_pclk_i, rst_pclk_n_i, clk_mem_i, rst_mem_n_i ^ s_mem_pad_lock_lp
|
||||
clk_pclk_i,
|
||||
rst_pclk_n_i,
|
||||
clk_mem_i,
|
||||
rst_mem_n_i ^ s_mem_pad_lock_lp,
|
||||
s_data_plane_outstanding_read,
|
||||
s_data_plane_outstanding_write,
|
||||
s_data_plane_fault_target,
|
||||
s_data_plane_fault_addr[1:0],
|
||||
s_data_plane_fault_reason[3],
|
||||
s_mgmt_router_idle,
|
||||
s_hp_lifecycle_draining,
|
||||
s_hp_lifecycle_fault,
|
||||
^unused_cdc_clear_busy,
|
||||
^unused_cdc_epoch,
|
||||
^s_ext_h_timeout
|
||||
};
|
||||
|
||||
endmodule
|
||||
@@ -67,6 +67,7 @@ module retrosoc_asic (
|
||||
logic s_aon_rst_n;
|
||||
logic s_sys_clk;
|
||||
logic s_hp_clk;
|
||||
logic s_hp_core_clk;
|
||||
logic s_hp_rst_n;
|
||||
logic s_pclk;
|
||||
logic s_pclk_rst_n;
|
||||
@@ -124,6 +125,7 @@ rcu #(
|
||||
.sys_clk_o (s_sys_clk),
|
||||
.sys_rst_n_o (s_sys_rst_n),
|
||||
.hp_clk_o (s_hp_clk),
|
||||
.hp_core_clk_o (s_hp_core_clk),
|
||||
.hp_rst_n_o (s_hp_rst_n),
|
||||
.pclk_o (s_pclk),
|
||||
.pclk_rst_n_o (s_pclk_rst_n),
|
||||
@@ -140,9 +142,12 @@ rcu #(
|
||||
);
|
||||
|
||||
retrosoc u_retrosoc (
|
||||
.clk_aon_i (s_aon_clk),
|
||||
.rst_aon_n_i (s_aon_rst_n),
|
||||
.clk_lp_i (s_sys_clk),
|
||||
.rst_lp_n_i (s_sys_rst_n),
|
||||
.clk_hp_i (s_hp_clk),
|
||||
.clk_hp_core_i (s_hp_core_clk),
|
||||
.rst_hp_n_i (s_hp_rst_n),
|
||||
.clk_pclk_i (s_pclk),
|
||||
.rst_pclk_n_i (s_pclk_rst_n),
|
||||
|
||||
@@ -26,6 +26,7 @@ module retrosoc_core (
|
||||
logic s_aon_rst_n;
|
||||
logic s_sys_clk;
|
||||
logic s_hp_clk;
|
||||
logic s_hp_core_clk;
|
||||
logic s_hp_rst_n;
|
||||
logic s_pclk;
|
||||
logic s_pclk_rst_n;
|
||||
@@ -83,6 +84,7 @@ rcu #(
|
||||
.sys_clk_o (s_sys_clk),
|
||||
.sys_rst_n_o (s_sys_rst_n),
|
||||
.hp_clk_o (s_hp_clk),
|
||||
.hp_core_clk_o (s_hp_core_clk),
|
||||
.hp_rst_n_o (s_hp_rst_n),
|
||||
.pclk_o (s_pclk),
|
||||
.pclk_rst_n_o (s_pclk_rst_n),
|
||||
@@ -99,9 +101,12 @@ rcu #(
|
||||
);
|
||||
|
||||
retrosoc u_retrosoc (
|
||||
.clk_aon_i (s_aon_clk),
|
||||
.rst_aon_n_i (s_aon_rst_n),
|
||||
.clk_lp_i (s_sys_clk),
|
||||
.rst_lp_n_i (s_sys_rst_n),
|
||||
.clk_hp_i (s_hp_clk),
|
||||
.clk_hp_core_i (s_hp_core_clk),
|
||||
.rst_hp_n_i (s_hp_rst_n),
|
||||
.clk_pclk_i (s_pclk),
|
||||
.rst_pclk_n_i (s_pclk_rst_n),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
module soc_clock_gate (
|
||||
input logic clk_i,
|
||||
input logic en_i,
|
||||
input logic test_en_i,
|
||||
output logic clk_o
|
||||
);
|
||||
logic s_en_q;
|
||||
|
||||
always_latch begin
|
||||
if (!clk_i) begin
|
||||
// Intentional low-phase latch for glitch-free clock gating.
|
||||
// verilator lint_off COMBDLY
|
||||
s_en_q <= en_i || test_en_i;
|
||||
// verilator lint_on COMBDLY
|
||||
end
|
||||
end
|
||||
|
||||
assign clk_o = clk_i && s_en_q;
|
||||
endmodule
|
||||
@@ -20,6 +20,7 @@ module soc_clock_reset_subsystem #(
|
||||
output logic lp_clk_o,
|
||||
output logic lp_rst_n_o,
|
||||
output logic hp_clk_o,
|
||||
output logic hp_core_clk_o,
|
||||
output logic hp_rst_n_o,
|
||||
output logic pclk_o,
|
||||
output logic pclk_rst_n_o,
|
||||
@@ -50,6 +51,7 @@ module soc_clock_reset_subsystem #(
|
||||
logic s_pll_force_lp_ref;
|
||||
logic s_lp_force_ref;
|
||||
logic s_hp_root_clk;
|
||||
logic s_hp_core_clk;
|
||||
logic s_hp_div2_clk;
|
||||
logic s_hp_div4_clk;
|
||||
logic s_lp_perf_div2_or_more_clk;
|
||||
@@ -79,6 +81,10 @@ module soc_clock_reset_subsystem #(
|
||||
logic s_pclk_second_trigger;
|
||||
logic s_hp_idle_aon;
|
||||
logic s_pclk_idle_aon;
|
||||
logic s_pll_fault;
|
||||
logic [ 3:0] s_clock_alive;
|
||||
logic [ 3:0] s_clock_fault;
|
||||
logic [63:0] s_clock_edge_delta;
|
||||
|
||||
tc_clk_buf u_ref24_clk_buf (
|
||||
.clk_i(ref24_clk_i),
|
||||
@@ -149,6 +155,13 @@ module soc_clock_reset_subsystem #(
|
||||
.clk_o (s_hp_root_clk)
|
||||
);
|
||||
|
||||
soc_clock_gate u_hp_core_clock_gate (
|
||||
.clk_i (s_hp_root_clk),
|
||||
.en_i (!s_gate_mask[0]),
|
||||
.test_en_i(1'b0),
|
||||
.clk_o (s_hp_core_clk)
|
||||
);
|
||||
|
||||
clk_int_even_div_static #(
|
||||
.DIV_VALUE_WIDTH(1)
|
||||
) u_hp_div2 (
|
||||
@@ -266,6 +279,47 @@ module soc_clock_reset_subsystem #(
|
||||
.clk_o (s_lp_clk_div4)
|
||||
);
|
||||
|
||||
clock_frequency_monitor u_ext72_monitor (
|
||||
.ref_clk_i (s_ref24_clk_buf),
|
||||
.ref_rst_n_i (s_aon_rst_n),
|
||||
.monitored_clk_i (s_ext72_clk_buf),
|
||||
.monitored_rst_n_i(s_aon_rst_n),
|
||||
.clear_fault_i (s_clear_fault),
|
||||
.alive_o (s_clock_alive[0]),
|
||||
.fault_o (s_clock_fault[0]),
|
||||
.edge_delta_o (s_clock_edge_delta[15:0])
|
||||
);
|
||||
clock_frequency_monitor u_hp_monitor (
|
||||
.ref_clk_i (s_ref24_clk_buf),
|
||||
.ref_rst_n_i (s_aon_rst_n),
|
||||
.monitored_clk_i (s_hp_root_clk),
|
||||
.monitored_rst_n_i(s_aon_rst_n),
|
||||
.clear_fault_i (s_clear_fault),
|
||||
.alive_o (s_clock_alive[1]),
|
||||
.fault_o (s_clock_fault[1]),
|
||||
.edge_delta_o (s_clock_edge_delta[31:16])
|
||||
);
|
||||
clock_frequency_monitor u_pclk_monitor (
|
||||
.ref_clk_i (s_ref24_clk_buf),
|
||||
.ref_rst_n_i (s_aon_rst_n),
|
||||
.monitored_clk_i (s_pclk),
|
||||
.monitored_rst_n_i(s_aon_rst_n),
|
||||
.clear_fault_i (s_clear_fault),
|
||||
.alive_o (s_clock_alive[2]),
|
||||
.fault_o (s_clock_fault[2]),
|
||||
.edge_delta_o (s_clock_edge_delta[47:32])
|
||||
);
|
||||
clock_frequency_monitor u_memory_monitor (
|
||||
.ref_clk_i (s_ref24_clk_buf),
|
||||
.ref_rst_n_i (s_aon_rst_n),
|
||||
.monitored_clk_i (s_mem_clk_div2),
|
||||
.monitored_rst_n_i(s_aon_rst_n),
|
||||
.clear_fault_i (s_clear_fault),
|
||||
.alive_o (s_clock_alive[3]),
|
||||
.fault_o (s_clock_fault[3]),
|
||||
.edge_delta_o (s_clock_edge_delta[63:48])
|
||||
);
|
||||
|
||||
pll_rcu_controller u_pll_rcu_controller (
|
||||
.sys_clk_i (s_pclk),
|
||||
.sys_rst_n_i (pclk_rst_n_o),
|
||||
@@ -275,6 +329,7 @@ module soc_clock_reset_subsystem #(
|
||||
.pll_capable_i (s_pll_capable),
|
||||
.hp_idle_i (s_hp_idle_aon),
|
||||
.pclk_idle_i (s_pclk_idle_aon),
|
||||
.timeout_i (s_timeout),
|
||||
.force_safe_i (s_force_safe),
|
||||
.clear_fault_i (s_clear_fault),
|
||||
.pll_sel_o (s_pll_sel),
|
||||
@@ -282,7 +337,7 @@ module soc_clock_reset_subsystem #(
|
||||
.sel_ext_clk_o (s_sel_ext_clk),
|
||||
.hp_block_o (hp_block_o),
|
||||
.lp_force_ref_o(s_pll_force_lp_ref),
|
||||
.pll_fault_o (pll_fault_o),
|
||||
.pll_fault_o (s_pll_fault),
|
||||
.pll_ctrl (pll_ctrl)
|
||||
);
|
||||
|
||||
@@ -293,7 +348,7 @@ module soc_clock_reset_subsystem #(
|
||||
.aon_rst_n_i (s_aon_rst_n),
|
||||
.hp_pstate_i (s_pll_sel),
|
||||
.hp_pll_sel_i (!s_sel_ext_clk),
|
||||
.pll_fault_i (pll_fault_o),
|
||||
.pll_fault_i (s_pll_fault || (|s_clock_fault)),
|
||||
.pclk_idle_i (s_pclk_idle_aon),
|
||||
.clock_ctrl (clock_ctrl),
|
||||
.lp_mode_o (s_lp_mode),
|
||||
@@ -357,23 +412,25 @@ module soc_clock_reset_subsystem #(
|
||||
.tick_o (timebase_tick_o)
|
||||
);
|
||||
|
||||
assign aon_clk_o = s_ref24_clk_buf;
|
||||
assign aon_rst_n_o = s_aon_rst_n;
|
||||
assign lp_clk_o = s_lp_root_clk;
|
||||
assign hp_clk_o = s_hp_root_clk;
|
||||
assign pclk_o = s_pclk;
|
||||
assign mem_clk_o = s_mem_clk_div2;
|
||||
assign aud_clk_o = s_aud_clk_buf;
|
||||
assign lp_clkdiv4_o = s_lp_clk_div4;
|
||||
assign aon_clk_o = s_ref24_clk_buf;
|
||||
assign aon_rst_n_o = s_aon_rst_n;
|
||||
assign lp_clk_o = s_lp_root_clk;
|
||||
assign hp_clk_o = s_hp_root_clk;
|
||||
assign hp_core_clk_o = s_hp_core_clk;
|
||||
assign pclk_o = s_pclk;
|
||||
assign mem_clk_o = s_mem_clk_div2;
|
||||
assign aud_clk_o = s_aud_clk_buf;
|
||||
assign lp_clkdiv4_o = s_lp_clk_div4;
|
||||
assign pll_fault_o = s_pll_fault || (|s_clock_fault);
|
||||
|
||||
logic [31:0] s_unused_clock_config;
|
||||
logic [16:0] s_unused_clock_config;
|
||||
assign s_unused_clock_config = {
|
||||
2'd0,
|
||||
s_gate_mask,
|
||||
s_timeout,
|
||||
s_pclk_count,
|
||||
^{s_pclk_div_done, s_pclk_first_trigger, s_pclk_second_trigger, s_pclk_cfg_src_ready,
|
||||
s_pll_apply}
|
||||
s_pll_apply},
|
||||
^{s_clock_alive, s_clock_edge_delta}
|
||||
};
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
|
||||
@@ -17,5 +17,6 @@
|
||||
`include "cdc_fifo.sv"
|
||||
`include "async_reqack.sv"
|
||||
`include "cdc_warm_flush.sv"
|
||||
`include "cdc_advanced.sv"
|
||||
/* verilator lint_on SYNCASYNCNET */
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
+159
-43
@@ -10,7 +10,14 @@ module soc_data_plane (
|
||||
input logic clk_hp_i,
|
||||
input logic rst_hp_n_i,
|
||||
input logic block_new_i,
|
||||
input logic recovery_i,
|
||||
input logic flush_i,
|
||||
input logic [1:0] mem_pad_mode_i,
|
||||
input logic ext_h_block_i,
|
||||
input logic [31:0] ext_h_read_base_i,
|
||||
input logic [31:0] ext_h_read_limit_i,
|
||||
input logic [31:0] ext_h_write_base_i,
|
||||
input logic [31:0] ext_h_write_limit_i,
|
||||
axi4_if.slave hp_icache_axi4,
|
||||
axi4_if.slave hp_dcache_axi4,
|
||||
axi4_if.slave dma_axi4,
|
||||
@@ -18,20 +25,40 @@ module soc_data_plane (
|
||||
axi4_if.slave sdio1_axi4,
|
||||
axi4_if.slave spisd_axi4,
|
||||
axi4_if.slave usb2_axi4,
|
||||
axi4_if.slave lp_data_axi4,
|
||||
axi4_if.slave ext_h_axi4,
|
||||
axi4_if.master sram_gateway_axi4,
|
||||
axi4_if.master sdram_gateway_axi4,
|
||||
axi4_if.master qpi_gateway_axi4,
|
||||
axi4_if.master opi_gateway_axi4,
|
||||
axi4_if.master xpi_gateway_axi4,
|
||||
output logic idle_o
|
||||
output logic idle_o,
|
||||
output logic flush_busy_o,
|
||||
output logic ext_h_idle_o,
|
||||
output logic [7:0] outstanding_read_o,
|
||||
output logic [7:0] outstanding_write_o,
|
||||
output logic fault_valid_o,
|
||||
output logic [2:0] fault_master_o,
|
||||
output logic [2:0] fault_target_o,
|
||||
output logic [31:0] fault_addr_o,
|
||||
output logic fault_write_o,
|
||||
output logic [3:0] fault_reason_o
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam int unsigned NumIoMasters = 5;
|
||||
localparam int unsigned NumIoMasters = 3;
|
||||
localparam int unsigned NumMemoryTargets = 5;
|
||||
|
||||
logic s_block_new_hp;
|
||||
logic [1:0] s_mem_pad_mode_hp;
|
||||
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;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
@@ -87,6 +114,24 @@ module soc_data_plane (
|
||||
.aclk (clk_hp_i),
|
||||
.aresetn(rst_hp_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) u_io_idle_axi4[2] (
|
||||
.aclk (clk_io_i),
|
||||
.aresetn(rst_io_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) u_lp_data_hp_axi4 (
|
||||
.aclk (clk_hp_i),
|
||||
.aresetn(rst_hp_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
@@ -96,6 +141,15 @@ module soc_data_plane (
|
||||
.aclk (clk_hp_i),
|
||||
.aresetn(rst_hp_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (3),
|
||||
.USER_WIDTH(1)
|
||||
) u_ext_h_gated_axi4 (
|
||||
.aclk (clk_io_i),
|
||||
.aresetn(rst_io_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
@@ -168,34 +222,39 @@ module soc_data_plane (
|
||||
.source(dma_axi4),
|
||||
.sink (u_io_lp_axi4[0])
|
||||
);
|
||||
axi4_connector u_sdio0_source_connector (
|
||||
.source(sdio0_axi4),
|
||||
.sink (u_io_lp_axi4[1])
|
||||
hp_axi4_mux3 u_io_gateway_a (
|
||||
.clk_i (clk_io_i),
|
||||
.rst_n_i(rst_io_n_i),
|
||||
.icache (u_io_idle_axi4[0]),
|
||||
.dcache (sdio0_axi4),
|
||||
.mmio (usb2_axi4),
|
||||
.axi4 (u_io_lp_axi4[1])
|
||||
);
|
||||
axi4_connector u_sdio1_source_connector (
|
||||
.source(sdio1_axi4),
|
||||
.sink (u_io_lp_axi4[2])
|
||||
);
|
||||
axi4_connector u_spisd_source_connector (
|
||||
.source(spisd_axi4),
|
||||
.sink (u_io_lp_axi4[3])
|
||||
);
|
||||
axi4_connector u_usb2_source_connector (
|
||||
.source(usb2_axi4),
|
||||
.sink (u_io_lp_axi4[4])
|
||||
hp_axi4_mux3 u_io_gateway_b (
|
||||
.clk_i (clk_io_i),
|
||||
.rst_n_i(rst_io_n_i),
|
||||
.icache (u_io_idle_axi4[1]),
|
||||
.dcache (spisd_axi4),
|
||||
.mmio (sdio1_axi4),
|
||||
.axi4 (u_io_lp_axi4[2])
|
||||
);
|
||||
axi4_master_idle u_io_gateway_a_idle (.axi4(u_io_idle_axi4[0]));
|
||||
axi4_master_idle u_io_gateway_b_idle (.axi4(u_io_idle_axi4[1]));
|
||||
|
||||
for (genvar master = 0; master < NumIoMasters; master++) begin : gen_io_master
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_io_cdc (
|
||||
.src_clk_i (clk_io_i),
|
||||
.src_rst_n_i(rst_io_n_i),
|
||||
.dst_clk_i (clk_hp_i),
|
||||
.dst_rst_n_i(rst_hp_n_i),
|
||||
.src_axi4 (u_io_lp_axi4[master]),
|
||||
.dst_axi4 (u_io_hp_axi4[master])
|
||||
.src_clk_i (clk_io_i),
|
||||
.src_rst_n_i (rst_io_n_i),
|
||||
.dst_clk_i (clk_hp_i),
|
||||
.dst_rst_n_i (rst_hp_n_i),
|
||||
.clear_i (flush_i),
|
||||
.clear_busy_o(s_io_clear_busy[master]),
|
||||
.epoch_o (unused_io_epoch[master]),
|
||||
.src_axi4 (u_io_lp_axi4[master]),
|
||||
.dst_axi4 (u_io_hp_axi4[master])
|
||||
);
|
||||
axi4_upsizer_32to64 #(
|
||||
.MasterIndex(3'(master + 2))
|
||||
@@ -207,16 +266,51 @@ module soc_data_plane (
|
||||
);
|
||||
end
|
||||
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(32),
|
||||
.IdWidth (1)
|
||||
) u_lp_data_cdc (
|
||||
.src_clk_i (clk_lp_i),
|
||||
.src_rst_n_i (rst_lp_n_i),
|
||||
.dst_clk_i (clk_hp_i),
|
||||
.dst_rst_n_i (rst_hp_n_i),
|
||||
.clear_i (flush_i),
|
||||
.clear_busy_o(s_lp_clear_busy),
|
||||
.epoch_o (unused_lp_epoch),
|
||||
.src_axi4 (lp_data_axi4),
|
||||
.dst_axi4 (u_lp_data_hp_axi4)
|
||||
);
|
||||
axi4_upsizer_32to64 #(
|
||||
.MasterIndex(3'd5)
|
||||
) u_lp_data_upsizer (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i(rst_hp_n_i),
|
||||
.narrow (u_lp_data_hp_axi4),
|
||||
.wide (u_master_axi4[5])
|
||||
);
|
||||
axi4_master_idle u_reserved_master_idle (.axi4(u_master_axi4[6]));
|
||||
|
||||
axi4_async_bridge #(
|
||||
.DataWidth(64),
|
||||
.IdWidth (3)
|
||||
) u_ext_h_cdc (
|
||||
.src_clk_i (clk_io_i),
|
||||
.src_rst_n_i(rst_io_n_i),
|
||||
.dst_clk_i (clk_hp_i),
|
||||
.dst_rst_n_i(rst_hp_n_i),
|
||||
.src_axi4 (ext_h_axi4),
|
||||
.dst_axi4 (u_ext_h_hp_axi4)
|
||||
.src_clk_i (clk_io_i),
|
||||
.src_rst_n_i (rst_io_n_i),
|
||||
.dst_clk_i (clk_hp_i),
|
||||
.dst_rst_n_i (rst_hp_n_i),
|
||||
.clear_i (flush_i),
|
||||
.clear_busy_o(s_ext_clear_busy),
|
||||
.epoch_o (unused_ext_epoch),
|
||||
.src_axi4 (u_ext_h_gated_axi4),
|
||||
.dst_axi4 (u_ext_h_hp_axi4)
|
||||
);
|
||||
axi4_address_gate u_ext_h_address_gate (
|
||||
.clk_i (clk_io_i),
|
||||
.rst_n_i (rst_io_n_i),
|
||||
.block_new_i(ext_h_block_i),
|
||||
.source (ext_h_axi4),
|
||||
.sink (u_ext_h_gated_axi4),
|
||||
.idle_o (ext_h_idle_o)
|
||||
);
|
||||
axi4_id_prefix #(
|
||||
.MasterIndex(3'd7)
|
||||
@@ -230,13 +324,26 @@ module soc_data_plane (
|
||||
);
|
||||
|
||||
axi4_data_crossbar u_data_crossbar (
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.block_new_i (s_block_new_hp),
|
||||
.mem_pad_mode_i(s_mem_pad_mode_hp),
|
||||
.masters (u_master_axi4),
|
||||
.targets (u_target_axi4),
|
||||
.idle_o (idle_o)
|
||||
.clk_i (clk_hp_i),
|
||||
.rst_n_i (rst_hp_n_i),
|
||||
.block_new_i (s_block_new_hp),
|
||||
.recovery_i (recovery_i),
|
||||
.mem_pad_mode_i (s_mem_pad_mode_hp),
|
||||
.ext_h_read_base_i (ext_h_read_base_i),
|
||||
.ext_h_read_limit_i (ext_h_read_limit_i),
|
||||
.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),
|
||||
.idle_o (idle_o),
|
||||
.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)
|
||||
);
|
||||
|
||||
for (genvar target = 0; target < NumMemoryTargets; target++) begin : gen_memory_target
|
||||
@@ -252,12 +359,15 @@ module soc_data_plane (
|
||||
.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),
|
||||
.src_axi4 (u_target_hp_axi4[target]),
|
||||
.dst_axi4 (u_gateway_lp_axi4[target])
|
||||
.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])
|
||||
);
|
||||
end
|
||||
|
||||
@@ -270,6 +380,12 @@ module soc_data_plane (
|
||||
.axi4 (u_target_axi4[5])
|
||||
);
|
||||
|
||||
assign flush_busy_o = (|s_io_clear_busy) || (|s_target_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)
|
||||
|
||||
@@ -290,17 +290,21 @@
|
||||
"axi4_id_prefix.sv",
|
||||
"axi4_interconnect.sv",
|
||||
"axi4_master_idle.sv",
|
||||
"axi4_mgmt_router.sv",
|
||||
"axi4_upsizer_32to64.sv",
|
||||
"axi4_word_bridge.sv",
|
||||
"core_wrapper.sv",
|
||||
"clock_config_controller.sv",
|
||||
"clock_frequency_monitor.sv",
|
||||
"extension_compat.sv",
|
||||
"extension_dma_master.sv",
|
||||
"extension_slot.sv",
|
||||
"extension_subsystem.sv",
|
||||
"gpio_pad_bridge.sv",
|
||||
"hp_axi4_mux3.sv",
|
||||
"hp_core_wrapper.sv",
|
||||
"hp_subsystem.sv",
|
||||
"hp_lifecycle_controller.sv",
|
||||
"mgmt_core_wrapper.sv",
|
||||
"mgmt_debug_reset.sv",
|
||||
"mgmt_debug_wrapper.sv",
|
||||
@@ -325,6 +329,7 @@
|
||||
"ribp2rib.sv",
|
||||
"ribp_arbiter2.sv",
|
||||
"soc_clock_config.svh",
|
||||
"soc_clock_gate.sv",
|
||||
"soc_clock_reset_subsystem.sv",
|
||||
"soc_common_cdc.sv",
|
||||
"soc_common_fifo.sv",
|
||||
|
||||
+25
-6
@@ -16,6 +16,16 @@ 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",
|
||||
"VERILATOR_SIM_ARGS=--fast-flash",
|
||||
"SOC_SIM_TIME=360",
|
||||
"SIMU=VERILATOR",
|
||||
"HAVE_SVA=YES",
|
||||
"firmware",
|
||||
"sim",
|
||||
)
|
||||
RTL_LINT_VALUES = ("SIMU=VERILATOR", "HAVE_SVA=YES", "rtl-lint")
|
||||
RTL_LINT_OBSERVATION_VALUES = (
|
||||
"SIMU=VERILATOR",
|
||||
@@ -31,7 +41,7 @@ PR_COMMANDS = (
|
||||
("configs/ci/ihp130-shell.mk", ("firmware",)),
|
||||
(
|
||||
"configs/ci/ihp130.mk",
|
||||
(CI_SMOKE_APP_VALUE, "SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
CI_SMOKE_SIM_VALUES,
|
||||
),
|
||||
("configs/ci/ihp130-debug.mk", ("SIMU=VERILATOR", "debug-sim")),
|
||||
("configs/ci/ihp130.mk", ("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm")),
|
||||
@@ -47,6 +57,7 @@ PR_COMMANDS = (
|
||||
),
|
||||
("configs/ci/ihp130.mk", ("STA=OPENSTA", "sta")),
|
||||
)
|
||||
RTL_COMMANDS = PR_COMMANDS[:6]
|
||||
SMOKE_COMMANDS = (
|
||||
("configs/ci/ihp130.mk", RTL_LINT_VALUES),
|
||||
("configs/ci/ihp130.mk", (CI_SMOKE_APP_VALUE, "firmware")),
|
||||
@@ -92,13 +103,15 @@ NETSIM_BOOT_PROFILES = frozenset(
|
||||
|
||||
def pdk_pr_commands(profile: str) -> tuple[tuple[str, tuple[str, ...]], ...]:
|
||||
netsim_target = "netsim-boot" if profile in NETSIM_BOOT_PROFILES else "netsim"
|
||||
verilator_values = (
|
||||
CI_SMOKE_SIM_VALUES
|
||||
if profile == "configs/ci/ihp130.mk"
|
||||
else (CI_SMOKE_APP_VALUE, "SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim")
|
||||
)
|
||||
return (
|
||||
(profile, RTL_LINT_VALUES),
|
||||
(profile, (CI_SMOKE_APP_VALUE, "firmware")),
|
||||
(
|
||||
profile,
|
||||
(CI_SMOKE_APP_VALUE, "SIMU=VERILATOR", "HAVE_SVA=YES", "firmware", "sim"),
|
||||
),
|
||||
(profile, verilator_values),
|
||||
(profile, ("SIMU=IVERILOG", "RTL_SIM_TIMEOUT=5200000", "sim-asm")),
|
||||
(profile, ("SYNTH=YOSYS", "synth")),
|
||||
(profile, ("STA=OPENSTA", "sta")),
|
||||
@@ -121,6 +134,10 @@ def select_regression(
|
||||
if pdk is not None and pdk != "IHP130":
|
||||
raise ValueError("smoke regression supports only --pdk IHP130")
|
||||
return SMOKE_COMMANDS, SMOKE_PROFILES
|
||||
if suite == "rtl":
|
||||
if pdk is not None and pdk != "IHP130":
|
||||
raise ValueError("rtl regression supports only --pdk IHP130")
|
||||
return RTL_COMMANDS, PR_PROFILES
|
||||
if suite == "nightly-extra":
|
||||
if pdk is not None and pdk != "IHP130":
|
||||
raise ValueError("nightly-extra regression supports only --pdk IHP130")
|
||||
@@ -207,7 +224,9 @@ def run_observation(command: list[str], root: Path, environment: dict[str, str])
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Run a supported retroSoC regression suite")
|
||||
parser.add_argument("--root", type=Path, required=True)
|
||||
parser.add_argument("--suite", choices=("smoke", "pr", "nightly", "nightly-extra"), required=True)
|
||||
parser.add_argument(
|
||||
"--suite", choices=("smoke", "rtl", "pr", "nightly", "nightly-extra"), required=True
|
||||
)
|
||||
parser.add_argument("--pdk", choices=tuple(PDK_PR_PROFILES), help="run one PDK matrix")
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
parser.add_argument(
|
||||
|
||||
@@ -836,6 +836,13 @@ static int test_extension_validation(void) {
|
||||
if (rs_extension_configure_acl(RS_EXTENSION_SLOT_H, &invalid_acl) != RS_EINVAL) {
|
||||
return 5;
|
||||
}
|
||||
if ((rs_extension_dma_start((uintptr_t)UINT32_C(0x30000001), (uintptr_t)UINT32_C(0x30000008),
|
||||
UINT32_C(8)) != RS_EINVAL) ||
|
||||
(rs_extension_dma_start((uintptr_t)UINT32_C(0x30000000), (uintptr_t)UINT32_C(0x30000008),
|
||||
0U) != RS_EINVAL) ||
|
||||
(rs_extension_dma_get_status(NULL) != RS_EINVAL)) {
|
||||
return 6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module axi4_async_bridge_tb;
|
||||
logic src_clk_i = 1'b0;
|
||||
logic dst_clk_i = 1'b0;
|
||||
logic src_rst_n_i = 1'b0;
|
||||
logic dst_rst_n_i = 1'b0;
|
||||
logic clear_i = 1'b0;
|
||||
logic clear_busy_o;
|
||||
logic [7:0] epoch_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) source (
|
||||
.aclk (src_clk_i),
|
||||
.aresetn(src_rst_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) sink (
|
||||
.aclk (dst_clk_i),
|
||||
.aresetn(dst_rst_n_i)
|
||||
);
|
||||
|
||||
always #5 src_clk_i = ~src_clk_i;
|
||||
always #7 dst_clk_i = ~dst_clk_i;
|
||||
|
||||
axi4_async_bridge u_dut (
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i (src_rst_n_i),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i (dst_rst_n_i),
|
||||
.clear_i (clear_i),
|
||||
.clear_busy_o(clear_busy_o),
|
||||
.epoch_o (epoch_o),
|
||||
.src_axi4 (source),
|
||||
.dst_axi4 (sink)
|
||||
);
|
||||
|
||||
initial begin
|
||||
source.awid = 0;
|
||||
source.awaddr = 0;
|
||||
source.awlen = 0;
|
||||
source.awsize = 2;
|
||||
source.awburst = 1;
|
||||
source.awlock = 0;
|
||||
source.awcache = 0;
|
||||
source.awprot = 0;
|
||||
source.awqos = 0;
|
||||
source.awregion = 0;
|
||||
source.awuser = 0;
|
||||
source.awvalid = 0;
|
||||
source.wdata = 0;
|
||||
source.wstrb = 0;
|
||||
source.wlast = 1;
|
||||
source.wuser = 0;
|
||||
source.wvalid = 0;
|
||||
source.bready = 1;
|
||||
source.arid = 0;
|
||||
source.araddr = 0;
|
||||
source.arlen = 0;
|
||||
source.arsize = 2;
|
||||
source.arburst = 1;
|
||||
source.arlock = 0;
|
||||
source.arcache = 0;
|
||||
source.arprot = 0;
|
||||
source.arqos = 0;
|
||||
source.arregion = 0;
|
||||
source.aruser = 0;
|
||||
source.arvalid = 0;
|
||||
source.rready = 1;
|
||||
sink.awready = 1;
|
||||
sink.wready = 1;
|
||||
sink.bid = 0;
|
||||
sink.bresp = 0;
|
||||
sink.buser = 0;
|
||||
sink.bvalid = 0;
|
||||
sink.arready = 1;
|
||||
sink.rid = 0;
|
||||
sink.rdata = 32'hCAFE_BABE;
|
||||
sink.rresp = 0;
|
||||
sink.rlast = 1;
|
||||
sink.ruser = 0;
|
||||
sink.rvalid = 0;
|
||||
|
||||
repeat (3) @(posedge src_clk_i);
|
||||
src_rst_n_i = 1;
|
||||
dst_rst_n_i = 1;
|
||||
repeat (8) @(posedge src_clk_i);
|
||||
@(negedge src_clk_i);
|
||||
source.araddr = 32'h5000_0040;
|
||||
source.arvalid = 1;
|
||||
do @(posedge src_clk_i); while (!source.arready);
|
||||
@(negedge src_clk_i);
|
||||
source.arvalid = 0;
|
||||
wait (sink.arvalid);
|
||||
if (sink.araddr != 32'h5000_0040) $fatal(1, "async bridge address mismatch");
|
||||
@(posedge dst_clk_i);
|
||||
@(negedge dst_clk_i);
|
||||
sink.rvalid = 1;
|
||||
do @(posedge dst_clk_i); while (!sink.rready);
|
||||
@(negedge dst_clk_i);
|
||||
sink.rvalid = 0;
|
||||
wait (source.rvalid);
|
||||
if (source.rdata != 32'hCAFE_BABE) $fatal(1, "async bridge response mismatch");
|
||||
@(posedge src_clk_i);
|
||||
|
||||
@(negedge src_clk_i);
|
||||
clear_i = 1;
|
||||
wait (clear_busy_o);
|
||||
clear_i = 0;
|
||||
wait (!clear_busy_o);
|
||||
if (epoch_o != 8'd1) $fatal(1, "async bridge epoch did not advance");
|
||||
|
||||
$display("AXI4 async bridge transfer and warm flush test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#20000;
|
||||
$fatal(1, "AXI4 async bridge test timed out");
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,230 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module axi4_data_crossbar_tb;
|
||||
localparam int NumMasters = 8;
|
||||
localparam int NumTargets = 6;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic idle_o;
|
||||
logic [ 7:0] outstanding_read_o;
|
||||
logic [ 7:0] outstanding_write_o;
|
||||
logic fault_valid_o;
|
||||
logic [ 2:0] fault_master_o;
|
||||
logic [ 2:0] fault_target_o;
|
||||
logic [31:0] fault_addr_o;
|
||||
logic fault_write_o;
|
||||
logic [ 3:0] fault_reason_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) masters[NumMasters] (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) targets[NumTargets] (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
initial begin
|
||||
repeat (500) @(posedge clk_i);
|
||||
$fatal(1, "AXI4 data crossbar test timed out");
|
||||
end
|
||||
|
||||
axi4_data_crossbar u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.block_new_i (1'b0),
|
||||
.recovery_i (1'b0),
|
||||
.mem_pad_mode_i (2'd1),
|
||||
.ext_h_read_base_i (32'h3000_0000),
|
||||
.ext_h_read_limit_i (32'h4FFF_FFFF),
|
||||
.ext_h_write_base_i (32'h3000_0000),
|
||||
.ext_h_write_limit_i(32'h4FFF_FFFF),
|
||||
.masters (masters),
|
||||
.targets (targets),
|
||||
.idle_o (idle_o),
|
||||
.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)
|
||||
);
|
||||
|
||||
task automatic issue_master1_read(input logic [5:0] id, input logic [31:0] addr);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
masters[1].arid = id;
|
||||
masters[1].araddr = addr;
|
||||
masters[1].arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!masters[1].arready);
|
||||
@(negedge clk_i);
|
||||
masters[1].arvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic return_target0_read(input logic [5:0] id, input logic [63:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
targets[0].rid = id;
|
||||
targets[0].rdata = data;
|
||||
targets[0].rresp = 2'b00;
|
||||
targets[0].rlast = 1'b1;
|
||||
targets[0].rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!targets[0].rready);
|
||||
@(negedge clk_i);
|
||||
targets[0].rvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic return_target1_read(input logic [5:0] id, input logic [63:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
targets[1].rid = id;
|
||||
targets[1].rdata = data;
|
||||
targets[1].rresp = 2'b00;
|
||||
targets[1].rlast = 1'b1;
|
||||
targets[1].rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!targets[1].rready);
|
||||
@(negedge clk_i);
|
||||
targets[1].rvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
`define INIT_MASTER(index) \
|
||||
masters[index].awid = '0; \
|
||||
masters[index].awaddr = '0; \
|
||||
masters[index].awlen = '0; \
|
||||
masters[index].awsize = 3'd3; \
|
||||
masters[index].awburst = 2'b01; \
|
||||
masters[index].awlock = 1'b0; \
|
||||
masters[index].awcache = '0; \
|
||||
masters[index].awprot = '0; \
|
||||
masters[index].awqos = '0; \
|
||||
masters[index].awregion = '0; \
|
||||
masters[index].awuser = '0; \
|
||||
masters[index].awvalid = 1'b0; \
|
||||
masters[index].wdata = '0; \
|
||||
masters[index].wstrb = '0; \
|
||||
masters[index].wlast = 1'b1; \
|
||||
masters[index].wuser = '0; \
|
||||
masters[index].wvalid = 1'b0; \
|
||||
masters[index].bready = 1'b1; \
|
||||
masters[index].arid = '0; \
|
||||
masters[index].araddr = '0; \
|
||||
masters[index].arlen = '0; \
|
||||
masters[index].arsize = 3'd3; \
|
||||
masters[index].arburst = 2'b01; \
|
||||
masters[index].arlock = 1'b0; \
|
||||
masters[index].arcache = '0; \
|
||||
masters[index].arprot = '0; \
|
||||
masters[index].arqos = '0; \
|
||||
masters[index].arregion = '0; \
|
||||
masters[index].aruser = '0; \
|
||||
masters[index].arvalid = 1'b0; \
|
||||
masters[index].rready = 1'b1;
|
||||
|
||||
`define INIT_TARGET(index) \
|
||||
targets[index].awready = 1'b1; \
|
||||
targets[index].wready = 1'b1; \
|
||||
targets[index].bid = '0; \
|
||||
targets[index].bresp = '0; \
|
||||
targets[index].buser = '0; \
|
||||
targets[index].bvalid = 1'b0; \
|
||||
targets[index].arready = 1'b1; \
|
||||
targets[index].rid = '0; \
|
||||
targets[index].rdata = '0; \
|
||||
targets[index].rresp = '0; \
|
||||
targets[index].rlast = 1'b1; \
|
||||
targets[index].ruser = '0; \
|
||||
targets[index].rvalid = 1'b0;
|
||||
|
||||
initial begin
|
||||
`INIT_MASTER(0)
|
||||
`INIT_MASTER(1)
|
||||
`INIT_MASTER(2)
|
||||
`INIT_MASTER(3)
|
||||
`INIT_MASTER(4)
|
||||
`INIT_MASTER(5)
|
||||
`INIT_MASTER(6)
|
||||
`INIT_MASTER(7)
|
||||
`INIT_TARGET(0)
|
||||
`INIT_TARGET(1)
|
||||
`INIT_TARGET(2)
|
||||
`INIT_TARGET(3)
|
||||
`INIT_TARGET(4)
|
||||
`INIT_TARGET(5)
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
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
|
||||
$fatal(1, "different-target reads were not tracked concurrently");
|
||||
end
|
||||
|
||||
@(negedge clk_i);
|
||||
masters[1].arid = 6'b001_000;
|
||||
masters[1].araddr = 32'h4000_0000;
|
||||
masters[1].arvalid = 1'b1;
|
||||
#1;
|
||||
if (masters[1].arready) $fatal(1, "same source ID was accepted before completion");
|
||||
masters[1].arvalid = 1'b0;
|
||||
|
||||
fork
|
||||
return_target1_read(6'b001_001, 64'h2222_2222_2222_2222);
|
||||
begin
|
||||
wait (masters[1].rvalid);
|
||||
if ((masters[1].rid != 6'b001_001) || (masters[1].rdata != 64'h2222_2222_2222_2222)) begin
|
||||
$fatal(1, "out-of-order different-ID response was misrouted");
|
||||
end
|
||||
end
|
||||
join
|
||||
return_target0_read(6'b001_000, 64'h1111_1111_1111_1111);
|
||||
@(negedge clk_i);
|
||||
if (!idle_o || (outstanding_read_o != 8'd0)) begin
|
||||
$fatal(1, "read completion did not drain the crossbar");
|
||||
end
|
||||
|
||||
@(negedge clk_i);
|
||||
masters[6].arid = 6'b110_000;
|
||||
masters[6].araddr = 32'h3000_0000;
|
||||
masters[6].arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!masters[6].arready);
|
||||
#1;
|
||||
if (!fault_valid_o || (fault_master_o != 3'd6) ||
|
||||
(fault_reason_o != 4'd3) || fault_write_o) begin
|
||||
$fatal(1, "reserved-master ACL fault attribution mismatch");
|
||||
end
|
||||
@(negedge clk_i);
|
||||
masters[6].arvalid = 1'b0;
|
||||
targets[5].rid = 6'b110_000;
|
||||
targets[5].rresp = 2'b10;
|
||||
targets[5].rlast = 1'b1;
|
||||
targets[5].rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!targets[5].rready);
|
||||
@(negedge clk_i);
|
||||
targets[5].rvalid = 1'b0;
|
||||
|
||||
$display("AXI4 data crossbar concurrency and ACL test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
`undef INIT_MASTER
|
||||
`undef INIT_TARGET
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module clock_frequency_monitor_tb;
|
||||
logic ref_clk_i = 1'b0;
|
||||
logic monitored_clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic clear_fault_i = 1'b0;
|
||||
logic run_monitored = 1'b1;
|
||||
logic alive_o;
|
||||
logic fault_o;
|
||||
logic [7:0] edge_delta_o;
|
||||
|
||||
always #5 ref_clk_i = ~ref_clk_i;
|
||||
always begin
|
||||
#2;
|
||||
if (run_monitored) monitored_clk_i = ~monitored_clk_i;
|
||||
else monitored_clk_i = 1'b0;
|
||||
end
|
||||
|
||||
clock_frequency_monitor #(
|
||||
.CounterWidth(8),
|
||||
.WindowCycles(8)
|
||||
) u_dut (
|
||||
.ref_clk_i (ref_clk_i),
|
||||
.ref_rst_n_i (rst_n_i),
|
||||
.monitored_clk_i (monitored_clk_i),
|
||||
.monitored_rst_n_i(rst_n_i),
|
||||
.clear_fault_i (clear_fault_i),
|
||||
.alive_o (alive_o),
|
||||
.fault_o (fault_o),
|
||||
.edge_delta_o (edge_delta_o)
|
||||
);
|
||||
|
||||
initial begin
|
||||
repeat (2) @(posedge ref_clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
repeat (20) @(posedge ref_clk_i);
|
||||
if (!alive_o || fault_o || (edge_delta_o == 8'd0)) begin
|
||||
$fatal(1, "running clock was not measured as alive");
|
||||
end
|
||||
|
||||
run_monitored = 1'b0;
|
||||
wait (fault_o);
|
||||
if (alive_o) $fatal(1, "stopped clock remained alive");
|
||||
@(negedge ref_clk_i);
|
||||
clear_fault_i = 1'b1;
|
||||
@(negedge ref_clk_i);
|
||||
clear_fault_i = 1'b0;
|
||||
@(negedge ref_clk_i);
|
||||
if (fault_o) $fatal(1, "clock fault did not clear");
|
||||
run_monitored = 1'b1;
|
||||
repeat (12) @(posedge ref_clk_i);
|
||||
if (!alive_o) $fatal(1, "restarted clock did not recover activity status");
|
||||
|
||||
$display("Clock frequency activity and sticky fault test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,125 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module extension_dma_master_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic start_i = 1'b0;
|
||||
logic abort_i = 1'b0;
|
||||
logic quiesce_i = 1'b0;
|
||||
logic [31:0] src_addr_i = 32'h3000_0000;
|
||||
logic [31:0] dst_addr_i = 32'h3000_0100;
|
||||
logic [31:0] len_i = 32'd12;
|
||||
logic [31:0] timeout_i = 32'd16;
|
||||
logic busy_o;
|
||||
logic done_o;
|
||||
logic err_o;
|
||||
logic [31:0] fault_addr_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (3),
|
||||
.USER_WIDTH(1)
|
||||
) axi4 (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
extension_dma_master u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.start_i (start_i),
|
||||
.abort_i (abort_i),
|
||||
.quiesce_i (quiesce_i),
|
||||
.src_addr_i (src_addr_i),
|
||||
.dst_addr_i (dst_addr_i),
|
||||
.len_i (len_i),
|
||||
.timeout_i (timeout_i),
|
||||
.busy_o (busy_o),
|
||||
.done_o (done_o),
|
||||
.err_o (err_o),
|
||||
.fault_addr_o(fault_addr_o),
|
||||
.axi4 (axi4)
|
||||
);
|
||||
|
||||
task automatic start_dma;
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
start_i = 1'b1;
|
||||
@(negedge clk_i);
|
||||
start_i = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic serve_beat(input logic [31:0] expected_src, input logic [31:0] expected_dst,
|
||||
input logic [63:0] data, input logic [7:0] expected_strobe);
|
||||
begin
|
||||
wait (axi4.arvalid);
|
||||
if (axi4.araddr != expected_src) $fatal(1, "DMA read address mismatch");
|
||||
@(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
axi4.rid = 3'd0;
|
||||
axi4.rdata = data;
|
||||
axi4.rresp = 2'b00;
|
||||
axi4.rlast = 1'b1;
|
||||
axi4.rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.rready);
|
||||
@(negedge clk_i);
|
||||
axi4.rvalid = 1'b0;
|
||||
wait (axi4.awvalid);
|
||||
if (axi4.awaddr != expected_dst) $fatal(1, "DMA write address mismatch");
|
||||
@(posedge clk_i);
|
||||
wait (axi4.wvalid);
|
||||
if ((axi4.wdata != data) || (axi4.wstrb != expected_strobe) || !axi4.wlast) begin
|
||||
$fatal(1, "DMA write data or tail strobe mismatch");
|
||||
end
|
||||
@(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
axi4.bid = 3'd0;
|
||||
axi4.bresp = 2'b00;
|
||||
axi4.bvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.bready);
|
||||
@(negedge clk_i);
|
||||
axi4.bvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
axi4.awready = 1'b1;
|
||||
axi4.wready = 1'b1;
|
||||
axi4.bid = '0;
|
||||
axi4.bresp = '0;
|
||||
axi4.buser = '0;
|
||||
axi4.bvalid = 1'b0;
|
||||
axi4.arready = 1'b1;
|
||||
axi4.rid = '0;
|
||||
axi4.rdata = '0;
|
||||
axi4.rresp = '0;
|
||||
axi4.rlast = 1'b1;
|
||||
axi4.ruser = '0;
|
||||
axi4.rvalid = 1'b0;
|
||||
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
start_dma();
|
||||
serve_beat(32'h3000_0000, 32'h3000_0100, 64'h1122_3344_5566_7788, 8'hFF);
|
||||
serve_beat(32'h3000_0008, 32'h3000_0108, 64'hAABB_CCDD_EEFF_0011, 8'h0F);
|
||||
wait (done_o);
|
||||
if (err_o || busy_o) $fatal(1, "successful DMA copy reported an error");
|
||||
|
||||
@(negedge clk_i);
|
||||
timeout_i = 32'd4;
|
||||
len_i = 32'd8;
|
||||
axi4.arready = 1'b0;
|
||||
start_dma();
|
||||
wait (done_o);
|
||||
if (!err_o || (fault_addr_o != src_addr_i)) begin
|
||||
$fatal(1, "DMA no-progress timeout was not attributed to the source address");
|
||||
end
|
||||
|
||||
$display("Extension DMA copy, tail strobe, and timeout test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,74 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module hp_lifecycle_controller_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic release_req_i = 1'b0;
|
||||
logic hp_idle_i = 1'b0;
|
||||
logic flush_busy_i = 1'b0;
|
||||
logic hp_release_o;
|
||||
logic block_new_o;
|
||||
logic flush_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)
|
||||
);
|
||||
|
||||
task automatic complete_flush;
|
||||
begin
|
||||
wait (flush_o);
|
||||
@(negedge clk_i);
|
||||
flush_busy_i = 1'b1;
|
||||
wait (!flush_o);
|
||||
repeat (2) @(negedge clk_i);
|
||||
flush_busy_i = 1'b0;
|
||||
wait (!hp_release_o);
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
@(negedge clk_i);
|
||||
release_req_i = 1'b1;
|
||||
wait (hp_release_o);
|
||||
if (block_new_o || draining_o) $fatal(1, "released HP was unexpectedly blocked");
|
||||
|
||||
@(negedge clk_i);
|
||||
release_req_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");
|
||||
end
|
||||
hp_idle_i = 1'b1;
|
||||
complete_flush();
|
||||
if (forced_fault_o || block_new_o) $fatal(1, "normal shutdown reported a forced fault");
|
||||
|
||||
@(negedge clk_i);
|
||||
hp_idle_i = 1'b0;
|
||||
release_req_i = 1'b1;
|
||||
wait (hp_release_o);
|
||||
@(negedge clk_i);
|
||||
release_req_i = 1'b0;
|
||||
wait (flush_o);
|
||||
if (!forced_fault_o) $fatal(1, "quiesce timeout did not record a forced fault");
|
||||
complete_flush();
|
||||
|
||||
$display("HP lifecycle drain, flush, and forced reset test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -164,6 +164,9 @@ module pll_ctrl_tb;
|
||||
sysctrl.perf_flash_wait_i = '0;
|
||||
sysctrl.rtc_wake_i = 1'b0;
|
||||
sysctrl.hp_present_i = 1'b0;
|
||||
sysctrl.hp_actual_released_i = 1'b0;
|
||||
sysctrl.hp_draining_i = 1'b0;
|
||||
sysctrl.hp_forced_fault_i = 1'b0;
|
||||
rst_n_i = 1'b1;
|
||||
#10;
|
||||
rst_n_i = 1'b0;
|
||||
|
||||
@@ -118,6 +118,9 @@ module sysctrl_tb;
|
||||
sysctrl.perf_flash_wait_i = 64'd18;
|
||||
sysctrl.rtc_wake_i = 1'b0;
|
||||
sysctrl.hp_present_i = 1'b0;
|
||||
sysctrl.hp_actual_released_i = 1'b0;
|
||||
sysctrl.hp_draining_i = 1'b0;
|
||||
sysctrl.hp_forced_fault_i = 1'b0;
|
||||
pll_ctrl.req_ready_i = 1'b1;
|
||||
pll_ctrl.rsp_active_sel_i = '0;
|
||||
pll_ctrl.rsp_active_valid_i = 1'b0;
|
||||
|
||||
@@ -32,6 +32,8 @@ def test_axi4_address_gate_blocks_new_and_drains_accepted_requests(tmp_path: Pat
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/xchecker.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/spill_register.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_address_gate.sv"),
|
||||
str(ROOT / "tests/rtl/axi4_address_gate_tb.sv"),
|
||||
"-Mdir",
|
||||
@@ -48,6 +50,44 @@ def test_axi4_address_gate_blocks_new_and_drains_accepted_requests(tmp_path: Pat
|
||||
assert "AXI4 address gate quiesce test passed" in result.stdout
|
||||
|
||||
|
||||
def test_axi4_async_bridge_transfers_and_warm_flushes(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
output = tmp_path / "axi4_async_bridge_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator, "--binary", "--timing", "-Wno-fatal", "--top-module",
|
||||
"axi4_async_bridge_tb",
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/cdc"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/xchecker.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/spill_register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/bin2gray.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/gray2bin.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_rst_ctrlr.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_2phase.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/rst_sync.sv"),
|
||||
str(ROOT / "rtl/mini/top/soc_common_cdc.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_async_bridge.sv"),
|
||||
str(ROOT / "tests/rtl/axi4_async_bridge_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 async bridge transfer and warm flush test passed" in result.stdout
|
||||
|
||||
|
||||
def test_axi4_downsizer_preserves_bursts_lanes_and_backpressure(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
@@ -191,3 +231,61 @@ def test_axi4_interconnect_classifies_decode_protocol_and_access_errors(
|
||||
)
|
||||
result = subprocess.run([output], check=True, text=True, capture_output=True)
|
||||
assert "AXI4 interconnect fault classification test passed" in result.stdout
|
||||
|
||||
|
||||
def test_axi4_data_crossbar_supports_cross_target_outstanding_and_acl(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
memory_map = tmp_path / "memory_map"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(ROOT / "rtl/mini/address_map/generate_memory_map.py"),
|
||||
"--map",
|
||||
str(ROOT / "rtl/mini/address_map/memory_map.json"),
|
||||
"--output-dir",
|
||||
str(memory_map),
|
||||
"--have-sram-if",
|
||||
"YES",
|
||||
"--sram-size-kib",
|
||||
"32",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
output = tmp_path / "axi4_data_crossbar_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"axi4_data_crossbar_tb",
|
||||
"-I" + str(memory_map / "rtl"),
|
||||
"-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/stream/round_robin_arbiter.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/mini/top/axi4_data_crossbar.sv"),
|
||||
str(ROOT / "tests/rtl/axi4_data_crossbar_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 data crossbar concurrency and ACL test passed" in result.stdout
|
||||
@@ -265,6 +265,7 @@ def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path:
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/counter.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/clk_int_div.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/clock/safe_clock_mux.sv"),
|
||||
str(ROOT / "rtl/mini/top/soc_clock_gate.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/edge_det.sv"),
|
||||
str(ROOT / "rtl/ip/peripheral/pll_ctrl_if.sv"),
|
||||
str(ROOT / "rtl/ip/peripheral/clock_ctrl_if.sv"),
|
||||
@@ -279,6 +280,7 @@ def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path:
|
||||
str(ROOT / "rtl/mini/top/rcu.sv"),
|
||||
str(ROOT / "rtl/mini/top/pll_rcu_controller.sv"),
|
||||
str(ROOT / "rtl/mini/top/clock_config_controller.sv"),
|
||||
str(ROOT / "rtl/mini/top/clock_frequency_monitor.sv"),
|
||||
str(ROOT / "rtl/mini/top/soc_clock_reset_subsystem.sv"),
|
||||
str(ROOT / "tests/rtl/pll_ctrl_tb.sv"),
|
||||
"",
|
||||
@@ -360,3 +362,55 @@ def test_sysctrl_does_not_expose_unused_i2c_or_qspi_select_registers() -> None:
|
||||
):
|
||||
assert symbol not in rtl
|
||||
assert "reg_sysctrl_" not in header
|
||||
|
||||
|
||||
def test_hp_lifecycle_controller_drains_and_forces_bounded_reset(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or vvp is None:
|
||||
return
|
||||
|
||||
simulation = tmp_path / "hp_lifecycle_controller_tb"
|
||||
subprocess.run(
|
||||
[
|
||||
iverilog,
|
||||
"-g2012",
|
||||
"-s",
|
||||
"hp_lifecycle_controller_tb",
|
||||
"-o",
|
||||
str(simulation),
|
||||
str(ROOT / "rtl/mini/top/hp_lifecycle_controller.sv"),
|
||||
str(ROOT / "tests/rtl/hp_lifecycle_controller_tb.sv"),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
assert "HP lifecycle drain, flush, and forced reset test passed" in result.stdout
|
||||
|
||||
|
||||
def test_clock_frequency_monitor_detects_stop_and_restart(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or vvp is None:
|
||||
return
|
||||
|
||||
simulation = tmp_path / "clock_frequency_monitor_tb"
|
||||
subprocess.run(
|
||||
[
|
||||
iverilog,
|
||||
"-g2012",
|
||||
"-s",
|
||||
"clock_frequency_monitor_tb",
|
||||
"-I",
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-o",
|
||||
str(simulation),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv"),
|
||||
str(ROOT / "rtl/mini/top/clock_frequency_monitor.sv"),
|
||||
str(ROOT / "tests/rtl/clock_frequency_monitor_tb.sv"),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
assert "Clock frequency activity and sticky fault test passed" in result.stdout
|
||||
@@ -50,6 +50,7 @@ from scripts.regress import ( # noqa: E402
|
||||
NIGHTLY_EXTRA_COMMANDS,
|
||||
PDK_PR_PROFILES,
|
||||
PR_COMMANDS,
|
||||
RTL_COMMANDS,
|
||||
RTL_LINT_VALUES,
|
||||
SMOKE_COMMANDS,
|
||||
pdk_pr_commands,
|
||||
@@ -955,7 +956,13 @@ def test_verilator_simulations_use_uniform_timeout() -> None:
|
||||
regression_commands = (*SMOKE_COMMANDS, *PR_COMMANDS, *NIGHTLY_COMMANDS)
|
||||
for _, values in regression_commands:
|
||||
if "SIMU=VERILATOR" in values:
|
||||
assert not any(value.startswith("SOC_SIM_TIME=") for value in values)
|
||||
simulation_timeout = [value for value in values if value.startswith("SOC_SIM_TIME=")]
|
||||
if "APP=ci_smoke" in values and "sim" in values:
|
||||
assert simulation_timeout == ["SOC_SIM_TIME=360"]
|
||||
assert "LINK_TYPE=ld2_all_sram" in values
|
||||
assert "VERILATOR_SIM_ARGS=--fast-flash" in values
|
||||
else:
|
||||
assert not simulation_timeout
|
||||
if "debug-sim" not in values:
|
||||
assert "HAVE_SVA=YES" in values
|
||||
|
||||
@@ -1107,6 +1114,37 @@ def test_smoke_regression_uses_ihp130_behavioral_coverage_only() -> None:
|
||||
assert "smoke regression supports only --pdk IHP130" in invalid.stderr
|
||||
|
||||
|
||||
def test_rtl_regression_excludes_synthesis_and_timing() -> None:
|
||||
commands, profiles = select_regression("rtl", "IHP130")
|
||||
|
||||
assert commands == RTL_COMMANDS
|
||||
assert profiles == ("configs/ci/ihp130.mk",)
|
||||
values = [value for _, command_values in commands for value in command_values]
|
||||
assert "sim" in values
|
||||
assert "sim-asm" in values
|
||||
assert "debug-sim" in values
|
||||
assert "synth" not in values
|
||||
assert "netsim" not in values
|
||||
assert "sta" not in values
|
||||
|
||||
dry_run = run(
|
||||
sys.executable,
|
||||
str(ROOT / "scripts/regress.py"),
|
||||
"--root",
|
||||
str(ROOT),
|
||||
"--suite",
|
||||
"rtl",
|
||||
"--pdk",
|
||||
"IHP130",
|
||||
"--dry-run",
|
||||
)
|
||||
assert "SIMU=VERILATOR" in dry_run.stdout
|
||||
assert "SIMU=IVERILOG" in dry_run.stdout
|
||||
assert "synth" not in dry_run.stdout
|
||||
assert "netsim" not in dry_run.stdout
|
||||
assert "STA=OPENSTA" not in dry_run.stdout
|
||||
|
||||
|
||||
def test_pdk_pr_regressions_cover_firmware_rtl_and_selected_netlist_target() -> None:
|
||||
assert set(PDK_PR_PROFILES) == {"GF180", "IHP130", "ICS55", "SKY130"}
|
||||
for pdk, profile in PDK_PR_PROFILES.items():
|
||||
@@ -1118,6 +1156,14 @@ def test_pdk_pr_regressions_cover_firmware_rtl_and_selected_netlist_target() ->
|
||||
CI_SMOKE_APP_VALUE in values and "SIMU=VERILATOR" in values and "firmware" in values
|
||||
for values in command_values
|
||||
)
|
||||
verilator_values = next(values for values in command_values if "sim" in values)
|
||||
if pdk == "IHP130":
|
||||
assert "LINK_TYPE=ld2_all_sram" in verilator_values
|
||||
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 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(
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -142,3 +144,43 @@ def test_extensions_reject_duplicate_regions_and_irqs(tmp_path: Path) -> None:
|
||||
result = validate(write_invalid_extensions(tmp_path, document))
|
||||
assert result.returncode != 0
|
||||
assert "overlapping or out-of-range IRQs" in result.stderr
|
||||
|
||||
|
||||
def test_extension_dma_executes_copy_tail_and_timeout(tmp_path: Path) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
return
|
||||
|
||||
output = tmp_path / "extension_dma_master_tb"
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
"extension_dma_master_tb",
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
|
||||
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl/interface"),
|
||||
"-I" + str(ROOT / "rtl/mini/top"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/extension_dma_master.sv"),
|
||||
str(ROOT / "tests/rtl/extension_dma_master_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 "Extension DMA copy, tail strobe, and timeout test passed" in result.stdout
|
||||
Reference in new issue
Block a user