feat: add APU-P1 support and enhance test coverage

- Introduced new task  in  for handling high-performance APU writes with access fault checks.
- Updated  to support an expanded resource count, including ownership and IRQ routing for the new APU resource.
- Enhanced  to validate IRQ expectations for the newly added APU resource.
- Created  for directed verification of APU-P1 APB4 register shell and integrated IRQ ownership topology.
- Added  to ensure synchronization between RTL and SDK register ABI.
- Modified  to parameterize tests for product modes, improving flexibility in testing.
- Updated  to reflect changes in APU memory mapping and ensure correct assertions.
- Enhanced  to validate the complete IRQ and resource allocations for the APU.
This commit is contained in:
maksyuki committed 2026-09-02 22:00:45 +08:00
1 parent eb47bdef4c
commit 52f619b9dc
41 files changed
+2385 -134

No files matched your search

+13
View File
@@ -1,6 +1,7 @@
#include <archinfo_regs.h>
#include <retrosoc/core/archinfo.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/apu.h>
#include <retrosoc/hal/clint.h>
#include <retrosoc/hal/crypto.h>
#include <retrosoc/hal/extension.h>
@@ -25,6 +26,14 @@ static bool rs_ci_smoke_archinfo_v2(void) {
(rs_archinfo_read_device_id(device_id) == RS_ENOTSUP) && (rs_rtc_probe() == RS_OK);
}
static bool rs_ci_smoke_apu_p1(void) {
rs_apu_info_t info;
return (rs_apu_probe(&info) == RS_OK) && (info.capability0 == RS_APU_CAPABILITY0_IMPLEMENTED) &&
(info.capability1 == RS_APU_CAPABILITY1_IMPLEMENTED) &&
(info.abi_digest == RS_APU_DIGEST_IMPLEMENTED);
}
static bool rs_ci_smoke_onchip_sram(void) {
rs_onchip_sram_info_t info;
rs_onchip_sram_perf_t performance;
@@ -376,6 +385,10 @@ int main(void) {
rs_test_finish(RS_TEST_FAILED, 1U);
}
printf("ci_smoke: archinfo passed\n");
if (!rs_ci_smoke_apu_p1()) {
rs_test_finish(RS_TEST_FAILED, 14U);
}
printf("ci_smoke: APU-P1 discovery passed\n");
if (!rs_ci_smoke_fabric_monitor_start()) {
rs_test_finish(RS_TEST_FAILED, 13U);
}
+6 -1
View File
@@ -53,10 +53,15 @@ See the [extension contract](../docs/ip/extensions.md) and
[legacy user-IP contract](../docs/ip/user-ip.md).
`<retrosoc/hal/resource.h>` owns the central DMA, USB2, SDIO0/1, SPI-SD,
EXT-H, and JPEG owner/lock, lifecycle-request, fault, and HP cache-maintenance
EXT-H, JPEG, and APU owner/lock, lifecycle-request, fault, and HP cache-maintenance
handshake.
See the [Resource Controller contract](../docs/ip/resource-controller.md).
`<retrosoc/hal/apu.h>` provides APU-P1 identity, ABI version, capability, and
ABI-digest discovery. The current shell reports zero datapath capabilities;
job, DMA, stream, microcode, codec, and KWS APIs remain unavailable until their
frozen implementation phases.
`<retrosoc/hal/fabric_monitor.h>` owns root-management access to native AXI64
master/target counters, stable snapshots, warm-flush counts, target isolation,
and the sticky first-fault record. See the
+19
View File
@@ -0,0 +1,19 @@
#ifndef RETROSOC_HAL_APU_H
#define RETROSOC_HAL_APU_H
#include <stdint.h>
#include <retrosoc/core/status.h>
#include <retrosoc/hal/apu_regs.h>
typedef struct {
uint32_t ip_id;
uint32_t version;
uint32_t capability0;
uint32_t capability1;
uint32_t abi_digest;
} rs_apu_info_t;
rs_status_t rs_apu_probe(rs_apu_info_t *info);
#endif
+210
View File
@@ -0,0 +1,210 @@
#ifndef RETROSOC_HAL_APU_REGS_H
#define RETROSOC_HAL_APU_REGS_H
#include <stdint.h>
#include <retrosoc/core/soc.h>
/* Independently handwritten mirror of rtl/ip/multimedia/apu_define.svh. */
#define RS_APU_ABI_IP_ID UINT32_C(0x000)
#define RS_APU_ABI_IP_VERSION UINT32_C(0x004)
#define RS_APU_ABI_CAPABILITY0 UINT32_C(0x008)
#define RS_APU_ABI_CAPABILITY1 UINT32_C(0x00C)
#define RS_APU_ABI_COMMAND UINT32_C(0x010)
#define RS_APU_ABI_STATUS UINT32_C(0x014)
#define RS_APU_ABI_IRQ_STATE UINT32_C(0x018)
#define RS_APU_ABI_IRQ_ENABLE UINT32_C(0x01C)
#define RS_APU_ABI_IRQ_TEST UINT32_C(0x020)
#define RS_APU_ABI_ERROR_STATUS UINT32_C(0x024)
#define RS_APU_ABI_ERROR_ADDRESS UINT32_C(0x028)
#define RS_APU_ABI_ERROR_DETAIL UINT32_C(0x02C)
#define RS_APU_ABI_SEQUENCER_TIMEOUT UINT32_C(0x030)
#define RS_APU_ABI_STREAM_ROUTE UINT32_C(0x034)
#define RS_APU_ABI_STREAM_STATUS UINT32_C(0x038)
#define RS_APU_ABI_OWNER_STATUS UINT32_C(0x03C)
#define RS_APU_ABI_READ_BASE UINT32_C(0x040)
#define RS_APU_ABI_READ_LIMIT UINT32_C(0x044)
#define RS_APU_ABI_WRITE_BASE UINT32_C(0x048)
#define RS_APU_ABI_WRITE_LIMIT UINT32_C(0x04C)
#define RS_APU_ABI_DMA_TIMEOUT UINT32_C(0x050)
#define RS_APU_ABI_ABI_DIGEST UINT32_C(0x054)
#define RS_APU_ABI_SEQUENCER_STATUS UINT32_C(0x058)
#define RS_APU_ABI_SEQUENCER_RETIRED UINT32_C(0x05C)
#define RS_APU_ABI_MC_IMAGE_ADDRESS UINT32_C(0x080)
#define RS_APU_ABI_MC_IMAGE_SIZE UINT32_C(0x084)
#define RS_APU_ABI_MC_EXPECTED_CRC UINT32_C(0x088)
#define RS_APU_ABI_MC_STATUS UINT32_C(0x08C)
#define RS_APU_ABI_MC_ABI UINT32_C(0x090)
#define RS_APU_ABI_MC_BUILD_ID_LO UINT32_C(0x094)
#define RS_APU_ABI_MC_BUILD_ID_HI UINT32_C(0x098)
#define RS_APU_ABI_MC_LOCK UINT32_C(0x09C)
#define RS_APU_ABI_MC_ACTUAL_CRC UINT32_C(0x0A0)
#define RS_APU_ABI_MC_LOAD_COUNT UINT32_C(0x0A4)
#define RS_APU_ABI_JOB_CONTROL UINT32_C(0x100)
#define RS_APU_ABI_JOB_INPUT_ADDRESS UINT32_C(0x104)
#define RS_APU_ABI_JOB_INPUT_LENGTH UINT32_C(0x108)
#define RS_APU_ABI_JOB_OUTPUT_ADDRESS UINT32_C(0x10C)
#define RS_APU_ABI_JOB_OUTPUT_CAPACITY UINT32_C(0x110)
#define RS_APU_ABI_JOB_INPUT_CONFIG UINT32_C(0x114)
#define RS_APU_ABI_JOB_OUTPUT_CONFIG UINT32_C(0x118)
#define RS_APU_ABI_JOB_FLAGS UINT32_C(0x11C)
#define RS_APU_ABI_JOB_STATUS UINT32_C(0x120)
#define RS_APU_ABI_JOB_INPUT_USED UINT32_C(0x124)
#define RS_APU_ABI_JOB_OUTPUT_BYTES UINT32_C(0x128)
#define RS_APU_ABI_JOB_FRAMES UINT32_C(0x12C)
#define RS_APU_ABI_JOB_SOURCE_INFO UINT32_C(0x130)
#define RS_APU_ABI_JOB_CYCLES UINT32_C(0x134)
#define RS_APU_ABI_JOB_DETAIL UINT32_C(0x138)
#define RS_APU_ABI_RING_BASE UINT32_C(0x180)
#define RS_APU_ABI_RING_SIZE UINT32_C(0x184)
#define RS_APU_ABI_RING_HEAD UINT32_C(0x188)
#define RS_APU_ABI_RING_TAIL UINT32_C(0x18C)
#define RS_APU_ABI_RING_CONTROL UINT32_C(0x190)
#define RS_APU_ABI_RING_STATUS UINT32_C(0x194)
#define RS_APU_ABI_RING_COMPLETED UINT32_C(0x198)
#define RS_APU_ABI_RING_COALESCE UINT32_C(0x19C)
#define RS_APU_ABI_RING_DOORBELL UINT32_C(0x1A0)
#define RS_APU_ABI_KWS_MODEL_ADDRESS UINT32_C(0x200)
#define RS_APU_ABI_KWS_MODEL_SIZE UINT32_C(0x204)
#define RS_APU_ABI_KWS_MODEL_EXPECTED_CRC UINT32_C(0x208)
#define RS_APU_ABI_KWS_CONTROL UINT32_C(0x20C)
#define RS_APU_ABI_KWS_CONFIG UINT32_C(0x210)
#define RS_APU_ABI_KWS_STATUS UINT32_C(0x214)
#define RS_APU_ABI_KWS_RESULT UINT32_C(0x218)
#define RS_APU_ABI_KWS_TIMESTAMP_LO UINT32_C(0x21C)
#define RS_APU_ABI_KWS_TIMESTAMP_HI UINT32_C(0x220)
#define RS_APU_ABI_KWS_FRAME_COUNT UINT32_C(0x224)
#define RS_APU_ABI_KWS_INFERENCE_COUNT UINT32_C(0x228)
#define RS_APU_ABI_KWS_HIT_COUNT UINT32_C(0x22C)
#define RS_APU_ABI_KWS_OVERRUN_COUNT UINT32_C(0x230)
#define RS_APU_ABI_KWS_MODEL_STATUS UINT32_C(0x234)
#define RS_APU_ABI_KWS_MODEL_ACTUAL_CRC UINT32_C(0x238)
#define RS_APU_ABI_PERF_CONTROL UINT32_C(0x300)
#define RS_APU_ABI_PERF_STATUS UINT32_C(0x304)
#define RS_APU_ABI_PERF_ACTIVE_CYCLES_LO UINT32_C(0x308)
#define RS_APU_ABI_PERF_ACTIVE_CYCLES_HI UINT32_C(0x30C)
#define RS_APU_ABI_PERF_INPUT_BYTES_LO UINT32_C(0x310)
#define RS_APU_ABI_PERF_INPUT_BYTES_HI UINT32_C(0x314)
#define RS_APU_ABI_PERF_OUTPUT_BYTES_LO UINT32_C(0x318)
#define RS_APU_ABI_PERF_OUTPUT_BYTES_HI UINT32_C(0x31C)
#define RS_APU_ABI_PERF_DECODED_FRAMES_LO UINT32_C(0x320)
#define RS_APU_ABI_PERF_DECODED_FRAMES_HI UINT32_C(0x324)
#define RS_APU_ABI_PERF_DMA_READ_STALLS_LO UINT32_C(0x328)
#define RS_APU_ABI_PERF_DMA_READ_STALLS_HI UINT32_C(0x32C)
#define RS_APU_ABI_PERF_DMA_WRITE_STALLS_LO UINT32_C(0x330)
#define RS_APU_ABI_PERF_DMA_WRITE_STALLS_HI UINT32_C(0x334)
#define RS_APU_ABI_PERF_STREAM_STALLS_LO UINT32_C(0x338)
#define RS_APU_ABI_PERF_STREAM_STALLS_HI UINT32_C(0x33C)
#define RS_APU_ABI_PERF_SEQUENCER_INSTR_LO UINT32_C(0x340)
#define RS_APU_ABI_PERF_SEQUENCER_INSTR_HI UINT32_C(0x344)
#define RS_APU_ABI_PERF_KWS_CYCLES_LO UINT32_C(0x348)
#define RS_APU_ABI_PERF_KWS_CYCLES_HI UINT32_C(0x34C)
#define RS_APU_ABI_PERF_FAULTS_LO UINT32_C(0x350)
#define RS_APU_ABI_PERF_FAULTS_HI UINT32_C(0x354)
#define RS_APU_ABI_CAPABILITY0_WAV 0U
#define RS_APU_ABI_CAPABILITY0_MP3 1U
#define RS_APU_ABI_CAPABILITY0_FLAC 2U
#define RS_APU_ABI_CAPABILITY0_PRIVATE_DMA 3U
#define RS_APU_ABI_CAPABILITY0_RING 4U
#define RS_APU_ABI_CAPABILITY0_STREAMS 5U
#define RS_APU_ABI_CAPABILITY0_KWS 6U
#define RS_APU_ABI_CAPABILITY0_SEQUENCER 7U
#define RS_APU_ABI_CAPABILITY0_RESAMPLER 8U
#define RS_APU_ABI_CAPABILITY1_CONTROL_KIB 0U
#define RS_APU_ABI_CAPABILITY1_DATA_KIB 8U
#define RS_APU_ABI_CAPABILITY1_MAX_CHANNELS 16U
#define RS_APU_ABI_CAPABILITY1_MAX_RATE_KHZ 18U
#define RS_APU_ABI_COMMAND_START_DIRECT 0U
#define RS_APU_ABI_COMMAND_ABORT 1U
#define RS_APU_ABI_COMMAND_SOFT_RESET 2U
#define RS_APU_ABI_COMMAND_RING_KICK 3U
#define RS_APU_ABI_COMMAND_MICROCODE_LOAD 4U
#define RS_APU_ABI_COMMAND_MODEL_LOAD 5U
#define RS_APU_ABI_COMMAND_CLEAR_COUNTERS 6U
#define RS_APU_ABI_STATUS_MICROCODE_VALID 0U
#define RS_APU_ABI_STATUS_MODEL_VALID 1U
#define RS_APU_ABI_STATUS_BUSY 2U
#define RS_APU_ABI_STATUS_RING 3U
#define RS_APU_ABI_STATUS_DECODE 4U
#define RS_APU_ABI_STATUS_KWS_LISTENING 5U
#define RS_APU_ABI_STATUS_QUIESCED 6U
#define RS_APU_ABI_STATUS_ABORTING 7U
#define RS_APU_ABI_STATUS_IDLE 8U
#define RS_APU_ABI_STATUS_SEQUENCER_TRAPPED 9U
#define RS_APU_ABI_IRQ_DIRECT_DONE 0U
#define RS_APU_ABI_IRQ_RING_EVENT 1U
#define RS_APU_ABI_IRQ_KWS_HIT 2U
#define RS_APU_ABI_IRQ_MICROCODE_LOAD_DONE 3U
#define RS_APU_ABI_IRQ_MODEL_LOAD_DONE 4U
#define RS_APU_ABI_IRQ_ABORT_DONE 5U
#define RS_APU_ABI_IRQ_INPUT_WATERMARK 6U
#define RS_APU_ABI_IRQ_OUTPUT_WATERMARK 7U
#define RS_APU_ABI_IRQ_FIRST_ERROR 8U
#define RS_APU_ABI_IRQ_STREAM_XRUN 9U
#define RS_APU_ABI_IRQ_SEQUENCER_TRAP 10U
#define RS_APU_ABI_ERROR_VALID 0U
#define RS_APU_ABI_ERROR_CODE 1U
#define RS_APU_ABI_ERROR_STAGE 7U
#define RS_APU_ABI_ERROR_AXI_RESPONSE 11U
#define RS_APU_ABI_ERROR_DESCRIPTOR_INDEX 13U
#define RS_APU_ABI_ERROR_CODE_NONE 0U
#define RS_APU_ABI_ERROR_CODE_INVALID_CONFIG 1U
#define RS_APU_ABI_ERROR_CODE_INVALID_RING 2U
#define RS_APU_ABI_ERROR_CODE_UNSUPPORTED 3U
#define RS_APU_ABI_ERROR_CODE_MALFORMED 4U
#define RS_APU_ABI_ERROR_CODE_TRUNCATED 5U
#define RS_APU_ABI_ERROR_CODE_CODEC_CRC 6U
#define RS_APU_ABI_ERROR_CODE_DECODE 7U
#define RS_APU_ABI_ERROR_CODE_RECONSTRUCTION 8U
#define RS_APU_ABI_ERROR_CODE_MICROCODE 9U
#define RS_APU_ABI_ERROR_CODE_MICROCODE_CRC 10U
#define RS_APU_ABI_ERROR_CODE_SEQUENCER 11U
#define RS_APU_ABI_ERROR_CODE_KWS_MODEL 12U
#define RS_APU_ABI_ERROR_CODE_KWS_CRC 13U
#define RS_APU_ABI_ERROR_CODE_KWS_ARITHMETIC 14U
#define RS_APU_ABI_ERROR_CODE_AXI_READ 15U
#define RS_APU_ABI_ERROR_CODE_AXI_WRITE 16U
#define RS_APU_ABI_ERROR_CODE_DMA_TIMEOUT 17U
#define RS_APU_ABI_ERROR_CODE_STREAM_UNDERRUN 18U
#define RS_APU_ABI_ERROR_CODE_STREAM_OVERRUN 19U
#define RS_APU_ABI_ERROR_CODE_ABORT 20U
#define RS_APU_ABI_ERROR_CODE_RESOURCE_RESET 21U
#define RS_APU_ABI_ERROR_CODE_OVERFLOW 22U
#define RS_APU_ABI_ERROR_STAGE_APB 0U
#define RS_APU_ABI_ERROR_STAGE_LOADER 1U
#define RS_APU_ABI_ERROR_STAGE_RING 2U
#define RS_APU_ABI_ERROR_STAGE_DMA_READ 3U
#define RS_APU_ABI_ERROR_STAGE_BITSTREAM 4U
#define RS_APU_ABI_ERROR_STAGE_ENTROPY 5U
#define RS_APU_ABI_ERROR_STAGE_RECONSTRUCTION 6U
#define RS_APU_ABI_ERROR_STAGE_RESAMPLER 7U
#define RS_APU_ABI_ERROR_STAGE_DMA_WRITE 8U
#define RS_APU_ABI_ERROR_STAGE_KWS_FRONTEND 9U
#define RS_APU_ABI_ERROR_STAGE_KWS_INFERENCE 10U
#define RS_APU_ABI_ERROR_STAGE_LIFECYCLE 11U
#define RS_APU_ABI_OWNER_STATUS_OWNER 0U
#define RS_APU_ABI_OWNER_STATUS_LOCK 8U
#define RS_APU_ABI_OWNER_STATUS_QUIESCE 9U
#define RS_APU_ABI_OWNER_STATUS_RESET 10U
#define RS_APU_ABI_PERF_CONTROL_ENABLE 0U
#define RS_APU_ABI_PERF_CONTROL_CLEAR 1U
#define RS_APU_ABI_PERF_CONTROL_SNAPSHOT 2U
#define RS_APU_ABI_PERF_STATUS_SNAPSHOT_VALID 0U
#define RS_APU_IP_ID_VALUE UINT32_C(0x41505530)
#define RS_APU_IP_VERSION_VALUE UINT32_C(0x00010000)
#define RS_APU_IP_VERSION_MAJOR_MASK UINT32_C(0xFFFF0000)
#define RS_APU_CAPABILITY0_IMPLEMENTED UINT32_C(0x00000000)
#define RS_APU_CAPABILITY1_IMPLEMENTED UINT32_C(0x00000000)
#define RS_APU_DIGEST_IMPLEMENTED UINT32_C(0x00000000)
#define RS_APU_IRQ_ALL UINT32_C(0x000007FF)
#define RS_APU_REG_IP_ID RS_APU_ABI_IP_ID
#define RS_APU_REG_IP_VERSION RS_APU_ABI_IP_VERSION
#define RS_APU_REG_CAPABILITY0 RS_APU_ABI_CAPABILITY0
#define RS_APU_REG_CAPABILITY1 RS_APU_ABI_CAPABILITY1
#define RS_APU_REG_ABI_DIGEST RS_APU_ABI_ABI_DIGEST
#define RS_APU_REG(offset) RS_SOC_REG32(RS_SOC_APB4_APU_BASE, (offset))
#endif
+2 -1
View File
@@ -14,7 +14,8 @@ typedef enum {
RS_RESOURCE_SPISD = 4,
RS_RESOURCE_EXT_H = 5,
RS_RESOURCE_JPEG = 6,
RS_RESOURCE_COUNT = 7,
RS_RESOURCE_APU = 7,
RS_RESOURCE_COUNT = 8,
} rs_resource_t;
typedef enum {
+21
View File
@@ -0,0 +1,21 @@
#include <stddef.h>
#include <retrosoc/hal/apu.h>
rs_status_t rs_apu_probe(rs_apu_info_t *info) {
if (info == NULL) {
return RS_EINVAL;
}
info->ip_id = RS_APU_REG(RS_APU_REG_IP_ID);
info->version = RS_APU_REG(RS_APU_REG_IP_VERSION);
info->capability0 = RS_APU_REG(RS_APU_REG_CAPABILITY0);
info->capability1 = RS_APU_REG(RS_APU_REG_CAPABILITY1);
info->abi_digest = RS_APU_REG(RS_APU_REG_ABI_DIGEST);
if ((info->ip_id != RS_APU_IP_ID_VALUE) ||
((info->version & RS_APU_IP_VERSION_MAJOR_MASK) != RS_APU_IP_VERSION_VALUE)) {
return RS_ENOTSUP;
}
return RS_OK;
}
+2
View File
@@ -127,6 +127,8 @@ static void rs_print_mmio_map(void) {
(void *)(uintptr_t)RS_SOC_APB4_HP_MAILBOX_BASE);
printf(" 1 x JPEG @%p\n",
(void *)(uintptr_t)RS_SOC_APB4_JPEG_BASE);
printf(" 1 x APU @%p\n",
(void *)(uintptr_t)RS_SOC_APB4_APU_BASE);
printf(" 1 x CLINT @%p\n",
(void *)(uintptr_t)RS_SOC_APB4_CLINT_BASE);
printf(" 1 x ARCHINFO @%p\n",
+6 -4
View File
@@ -26,10 +26,12 @@ The design was frozen on 2026-09-02 from these repository sources of truth:
programmable-LUT, and lifecycle patterns; and
- `dependencies/dependencies.lock.json` for managed inputs.
This specification defines a target, not an implemented feature. The current
executable address map keeps `APB4_APU` reserved and disabled. No claim is made
that APU RTL, microcode, assembler, codec conformance, KWS model, Linux driver,
timing closure, power closure, CDC/RDC signoff, or silicon qualification exists.
APU-P1 implements the APB4 register shell, Resource Controller index 7,
LP IRQ31/HP PLIC source10 ownership routing, and HAL discovery. The shell
advertises zero datapath capabilities and rejects every deferred datapath
command. No claim is made that APU DMA, streams, microcode, sequencer, codec
engines, KWS, codec conformance, Linux driver, timing closure, power closure,
CDC/RDC signoff, or silicon qualification exists.
## Commercial References
+6 -4
View File
@@ -7,10 +7,12 @@ APB4 peripherals. Their role in boot and lifecycle control is defined by
## PLIC
Source 0 is permanently reserved. Source 1 is UART1 and source 2 is the
HP-side mailbox doorbell; sources 3 through 31 are reserved and tied low. Each
source has a three-bit priority. Context 0 drives HP machine external interrupt
and context 1 drives HP supervisor external interrupt.
Source 0 is permanently reserved. Source 1 is UART1, source 2 is the HP-side
mailbox doorbell, source 3 is EXT-H, and sources 4 through 10 are central DMA,
USB2, SDIO0, SDIO1, SPI-SD, JPEG, and APU respectively. Sources 11 through 31
are reserved and tied low. Resource-owned sources are suppressed unless HP is
the exclusive owner. Each source has a three-bit priority. Context 0 drives HP
machine external interrupt and context 1 drives HP supervisor external interrupt.
| Address offset | Register | Access |
| --- | --- | --- |
+8 -5
View File
@@ -3,9 +3,9 @@
## Scope
The Resource Controller at `0x2000_A000` is the root-management ownership and
interrupt-routing authority for central DMA, USB2, SDIO0, SDIO1, SPI-SD, and
EXT-H. Hazard3 has read/write access; HP MMIO may inspect status but writes are
rejected by the root-control firewall.
interrupt-routing authority for central DMA, USB2, SDIO0, SDIO1, SPI-SD,
EXT-H, JPEG, and APU. Hazard3 has read/write access; HP MMIO may inspect status
but writes are rejected by the root-control firewall.
It is handwritten RTL and has a matching handwritten
`<retrosoc/hal/resource.h>` API; no register generator is used.
@@ -19,6 +19,8 @@ Resource indices are fixed:
| 3 | SDIO1 | 7 |
| 4 | SPI-SD | 8 |
| 5 | EXT-H | 3 |
| 6 | JPEG | 9 |
| 7 | APU | 10 |
Owner `0` routes the resource interrupt to the existing LP vector. Owner `1`
removes it from LP and routes it to the listed HP PLIC source. Reset masks both
@@ -74,6 +76,7 @@ LP/HP IRQ routing are implemented and directed-tested. `CONTROL.QUIESCE`
blocks the corresponding data-crossbar master and waits per-master outstanding
zero; shared I/O gateways are conservatively blocked as a pair. `CONTROL.RESET`
also blocks new data and masks IRQ but is not yet connected to every peripheral
engine's internal reset state machine. It must not be
described as independent peripheral power isolation or reset containment until
engine's internal reset state machine. The APU-P1 shell is an exception: its
index-7 quiesce acknowledgement and reset are connected locally in PCLK. It
must not be described as independent peripheral power isolation or reset containment until
those downstream acknowledgements and fault-injection tests exist.
+4 -3
View File
@@ -138,9 +138,10 @@ Its IRQ is delivered to LP IRQ 28 or HP PLIC source 3 according to owner,
never both. Software discovers it through `<retrosoc/hal/extension.h>`.
The Resource Controller at `0x2000_A000` is the central owner and IRQ authority
for DMA, USB2, SDIO0/1, SPI-SD, and EXT-H. Handoff requires idle, owner lock is
sticky, and rejected handoffs raise LP IRQ 29. It also carries the AON cache
request/clean acknowledgement used before HP drain. See
for DMA, USB2, SDIO0/1, SPI-SD, EXT-H, JPEG, and APU. Handoff requires idle,
owner lock is sticky, and rejected handoffs raise LP IRQ 29. APU index 7 routes
exclusively to LP IRQ31 or HP PLIC source10. The controller also carries the
AON cache request/clean acknowledgement used before HP drain. See
[`ip/resource-controller.md`](ip/resource-controller.md).
The root-only Fabric Monitor at `0x2000_B000` records per-master and
+6 -7
View File
@@ -119,13 +119,12 @@ ownership. Its implemented limits, handwritten ABI, measured performance, and
commercial release gates are documented in
[Baseline JPEG Codec](../docs/ip/jpeg.md).
The planned Mini Audio Processing Unit has a frozen coreless architecture at
the reserved `APB4_APU` window. LP loads one bounded microcode bundle containing
WAV, MP3, and FLAC entry points; a hardware sequencer drives fixed bitstream,
entropy, transform, reconstruction, resampler, DMA, and I2S stream engines.
Continuous KWS uses a separate fixed INT8 engine. The feature is not implemented
or enabled by the current topology; its ABI, phases, verification, and evidence
gates are defined in [Mini Audio Processing Unit](../docs/ip/apu.md).
The Mini Audio Processing Unit has a frozen coreless architecture. APU-P1
implements its fail-closed APB4 shell at `APB4_APU`, Resource Controller index
7, and exclusive LP IRQ31/HP PLIC source10 routing. The shell advertises no
datapath capabilities: private DMA, streams, microcode, codec engines, and KWS
remain deferred to their frozen phases. The complete ABI, phase order, and
evidence gates are defined in [Mini Audio Processing Unit](../docs/ip/apu.md).
SystemCtrl uses `sysctrl_if.sv`, `sysctrl_define.svh`, `sysctrl_reg.sv`, and
`sysctrl_core.sv` behind the stable `apb4_sysctrl` integration wrapper. Its
+28
View File
@@ -0,0 +1,28 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module apb4_apu (
// verilog_format: off -- preserve the APB and lifecycle boundary columns
input logic clk_i,
input logic rst_n_i,
input logic [1:0] owner_i,
input logic owner_lock_i,
input logic quiesce_i,
input logic resource_reset_i,
apb4_if.slave apb4,
output logic idle_o,
output logic irq_o
// verilog_format: on
);
apu_reg u_apu_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.owner_i (owner_i),
.owner_lock_i (owner_lock_i),
.quiesce_i (quiesce_i),
.resource_reset_i(resource_reset_i),
.apb4 (apb4),
.idle_o (idle_o),
.irq_o (irq_o)
);
endmodule
+207
View File
@@ -0,0 +1,207 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`ifndef RETROSOC_APU_DEFINE_SVH
`define RETROSOC_APU_DEFINE_SVH
// verilog_format: off -- keep the handwritten hardware/software ABI column aligned
`define APB4_APU__IP_ID 12'h000
`define APB4_APU__IP_VERSION 12'h004
`define APB4_APU__CAPABILITY0 12'h008
`define APB4_APU__CAPABILITY1 12'h00c
`define APB4_APU__COMMAND 12'h010
`define APB4_APU__STATUS 12'h014
`define APB4_APU__IRQ_STATE 12'h018
`define APB4_APU__IRQ_ENABLE 12'h01c
`define APB4_APU__IRQ_TEST 12'h020
`define APB4_APU__ERROR_STATUS 12'h024
`define APB4_APU__ERROR_ADDRESS 12'h028
`define APB4_APU__ERROR_DETAIL 12'h02c
`define APB4_APU__SEQUENCER_TIMEOUT 12'h030
`define APB4_APU__STREAM_ROUTE 12'h034
`define APB4_APU__STREAM_STATUS 12'h038
`define APB4_APU__OWNER_STATUS 12'h03c
`define APB4_APU__READ_BASE 12'h040
`define APB4_APU__READ_LIMIT 12'h044
`define APB4_APU__WRITE_BASE 12'h048
`define APB4_APU__WRITE_LIMIT 12'h04c
`define APB4_APU__DMA_TIMEOUT 12'h050
`define APB4_APU__ABI_DIGEST 12'h054
`define APB4_APU__SEQUENCER_STATUS 12'h058
`define APB4_APU__SEQUENCER_RETIRED 12'h05c
`define APB4_APU__MC_IMAGE_ADDRESS 12'h080
`define APB4_APU__MC_IMAGE_SIZE 12'h084
`define APB4_APU__MC_EXPECTED_CRC 12'h088
`define APB4_APU__MC_STATUS 12'h08c
`define APB4_APU__MC_ABI 12'h090
`define APB4_APU__MC_BUILD_ID_LO 12'h094
`define APB4_APU__MC_BUILD_ID_HI 12'h098
`define APB4_APU__MC_LOCK 12'h09c
`define APB4_APU__MC_ACTUAL_CRC 12'h0a0
`define APB4_APU__MC_LOAD_COUNT 12'h0a4
`define APB4_APU__JOB_CONTROL 12'h100
`define APB4_APU__JOB_INPUT_ADDRESS 12'h104
`define APB4_APU__JOB_INPUT_LENGTH 12'h108
`define APB4_APU__JOB_OUTPUT_ADDRESS 12'h10c
`define APB4_APU__JOB_OUTPUT_CAPACITY 12'h110
`define APB4_APU__JOB_INPUT_CONFIG 12'h114
`define APB4_APU__JOB_OUTPUT_CONFIG 12'h118
`define APB4_APU__JOB_FLAGS 12'h11c
`define APB4_APU__JOB_STATUS 12'h120
`define APB4_APU__JOB_INPUT_USED 12'h124
`define APB4_APU__JOB_OUTPUT_BYTES 12'h128
`define APB4_APU__JOB_FRAMES 12'h12c
`define APB4_APU__JOB_SOURCE_INFO 12'h130
`define APB4_APU__JOB_CYCLES 12'h134
`define APB4_APU__JOB_DETAIL 12'h138
`define APB4_APU__RING_BASE 12'h180
`define APB4_APU__RING_SIZE 12'h184
`define APB4_APU__RING_HEAD 12'h188
`define APB4_APU__RING_TAIL 12'h18c
`define APB4_APU__RING_CONTROL 12'h190
`define APB4_APU__RING_STATUS 12'h194
`define APB4_APU__RING_COMPLETED 12'h198
`define APB4_APU__RING_COALESCE 12'h19c
`define APB4_APU__RING_DOORBELL 12'h1a0
`define APB4_APU__KWS_MODEL_ADDRESS 12'h200
`define APB4_APU__KWS_MODEL_SIZE 12'h204
`define APB4_APU__KWS_MODEL_EXPECTED_CRC 12'h208
`define APB4_APU__KWS_CONTROL 12'h20c
`define APB4_APU__KWS_CONFIG 12'h210
`define APB4_APU__KWS_STATUS 12'h214
`define APB4_APU__KWS_RESULT 12'h218
`define APB4_APU__KWS_TIMESTAMP_LO 12'h21c
`define APB4_APU__KWS_TIMESTAMP_HI 12'h220
`define APB4_APU__KWS_FRAME_COUNT 12'h224
`define APB4_APU__KWS_INFERENCE_COUNT 12'h228
`define APB4_APU__KWS_HIT_COUNT 12'h22c
`define APB4_APU__KWS_OVERRUN_COUNT 12'h230
`define APB4_APU__KWS_MODEL_STATUS 12'h234
`define APB4_APU__KWS_MODEL_ACTUAL_CRC 12'h238
`define APB4_APU__PERF_CONTROL 12'h300
`define APB4_APU__PERF_STATUS 12'h304
`define APB4_APU__PERF_ACTIVE_CYCLES_LO 12'h308
`define APB4_APU__PERF_ACTIVE_CYCLES_HI 12'h30c
`define APB4_APU__PERF_INPUT_BYTES_LO 12'h310
`define APB4_APU__PERF_INPUT_BYTES_HI 12'h314
`define APB4_APU__PERF_OUTPUT_BYTES_LO 12'h318
`define APB4_APU__PERF_OUTPUT_BYTES_HI 12'h31c
`define APB4_APU__PERF_DECODED_FRAMES_LO 12'h320
`define APB4_APU__PERF_DECODED_FRAMES_HI 12'h324
`define APB4_APU__PERF_DMA_READ_STALLS_LO 12'h328
`define APB4_APU__PERF_DMA_READ_STALLS_HI 12'h32c
`define APB4_APU__PERF_DMA_WRITE_STALLS_LO 12'h330
`define APB4_APU__PERF_DMA_WRITE_STALLS_HI 12'h334
`define APB4_APU__PERF_STREAM_STALLS_LO 12'h338
`define APB4_APU__PERF_STREAM_STALLS_HI 12'h33c
`define APB4_APU__PERF_SEQUENCER_INSTR_LO 12'h340
`define APB4_APU__PERF_SEQUENCER_INSTR_HI 12'h344
`define APB4_APU__PERF_KWS_CYCLES_LO 12'h348
`define APB4_APU__PERF_KWS_CYCLES_HI 12'h34c
`define APB4_APU__PERF_FAULTS_LO 12'h350
`define APB4_APU__PERF_FAULTS_HI 12'h354
`define APB4_APU__CAPABILITY0_WAV 0
`define APB4_APU__CAPABILITY0_MP3 1
`define APB4_APU__CAPABILITY0_FLAC 2
`define APB4_APU__CAPABILITY0_PRIVATE_DMA 3
`define APB4_APU__CAPABILITY0_RING 4
`define APB4_APU__CAPABILITY0_STREAMS 5
`define APB4_APU__CAPABILITY0_KWS 6
`define APB4_APU__CAPABILITY0_SEQUENCER 7
`define APB4_APU__CAPABILITY0_RESAMPLER 8
`define APB4_APU__CAPABILITY1_CONTROL_KIB 0
`define APB4_APU__CAPABILITY1_DATA_KIB 8
`define APB4_APU__CAPABILITY1_MAX_CHANNELS 16
`define APB4_APU__CAPABILITY1_MAX_RATE_KHZ 18
`define APB4_APU__COMMAND_START_DIRECT 0
`define APB4_APU__COMMAND_ABORT 1
`define APB4_APU__COMMAND_SOFT_RESET 2
`define APB4_APU__COMMAND_RING_KICK 3
`define APB4_APU__COMMAND_MICROCODE_LOAD 4
`define APB4_APU__COMMAND_MODEL_LOAD 5
`define APB4_APU__COMMAND_CLEAR_COUNTERS 6
`define APB4_APU__STATUS_MICROCODE_VALID 0
`define APB4_APU__STATUS_MODEL_VALID 1
`define APB4_APU__STATUS_BUSY 2
`define APB4_APU__STATUS_RING 3
`define APB4_APU__STATUS_DECODE 4
`define APB4_APU__STATUS_KWS_LISTENING 5
`define APB4_APU__STATUS_QUIESCED 6
`define APB4_APU__STATUS_ABORTING 7
`define APB4_APU__STATUS_IDLE 8
`define APB4_APU__STATUS_SEQUENCER_TRAPPED 9
`define APB4_APU__IRQ_DIRECT_DONE 0
`define APB4_APU__IRQ_RING_EVENT 1
`define APB4_APU__IRQ_KWS_HIT 2
`define APB4_APU__IRQ_MICROCODE_LOAD_DONE 3
`define APB4_APU__IRQ_MODEL_LOAD_DONE 4
`define APB4_APU__IRQ_ABORT_DONE 5
`define APB4_APU__IRQ_INPUT_WATERMARK 6
`define APB4_APU__IRQ_OUTPUT_WATERMARK 7
`define APB4_APU__IRQ_FIRST_ERROR 8
`define APB4_APU__IRQ_STREAM_XRUN 9
`define APB4_APU__IRQ_SEQUENCER_TRAP 10
`define APB4_APU__ERROR_VALID 0
`define APB4_APU__ERROR_CODE 1
`define APB4_APU__ERROR_STAGE 7
`define APB4_APU__ERROR_AXI_RESPONSE 11
`define APB4_APU__ERROR_DESCRIPTOR_INDEX 13
`define APB4_APU__ERROR_CODE_NONE 0
`define APB4_APU__ERROR_CODE_INVALID_CONFIG 1
`define APB4_APU__ERROR_CODE_INVALID_RING 2
`define APB4_APU__ERROR_CODE_UNSUPPORTED 3
`define APB4_APU__ERROR_CODE_MALFORMED 4
`define APB4_APU__ERROR_CODE_TRUNCATED 5
`define APB4_APU__ERROR_CODE_CODEC_CRC 6
`define APB4_APU__ERROR_CODE_DECODE 7
`define APB4_APU__ERROR_CODE_RECONSTRUCTION 8
`define APB4_APU__ERROR_CODE_MICROCODE 9
`define APB4_APU__ERROR_CODE_MICROCODE_CRC 10
`define APB4_APU__ERROR_CODE_SEQUENCER 11
`define APB4_APU__ERROR_CODE_KWS_MODEL 12
`define APB4_APU__ERROR_CODE_KWS_CRC 13
`define APB4_APU__ERROR_CODE_KWS_ARITHMETIC 14
`define APB4_APU__ERROR_CODE_AXI_READ 15
`define APB4_APU__ERROR_CODE_AXI_WRITE 16
`define APB4_APU__ERROR_CODE_DMA_TIMEOUT 17
`define APB4_APU__ERROR_CODE_STREAM_UNDERRUN 18
`define APB4_APU__ERROR_CODE_STREAM_OVERRUN 19
`define APB4_APU__ERROR_CODE_ABORT 20
`define APB4_APU__ERROR_CODE_RESOURCE_RESET 21
`define APB4_APU__ERROR_CODE_OVERFLOW 22
`define APB4_APU__ERROR_STAGE_APB 0
`define APB4_APU__ERROR_STAGE_LOADER 1
`define APB4_APU__ERROR_STAGE_RING 2
`define APB4_APU__ERROR_STAGE_DMA_READ 3
`define APB4_APU__ERROR_STAGE_BITSTREAM 4
`define APB4_APU__ERROR_STAGE_ENTROPY 5
`define APB4_APU__ERROR_STAGE_RECONSTRUCTION 6
`define APB4_APU__ERROR_STAGE_RESAMPLER 7
`define APB4_APU__ERROR_STAGE_DMA_WRITE 8
`define APB4_APU__ERROR_STAGE_KWS_FRONTEND 9
`define APB4_APU__ERROR_STAGE_KWS_INFERENCE 10
`define APB4_APU__ERROR_STAGE_LIFECYCLE 11
`define APB4_APU__OWNER_STATUS_OWNER 0
`define APB4_APU__OWNER_STATUS_LOCK 8
`define APB4_APU__OWNER_STATUS_QUIESCE 9
`define APB4_APU__OWNER_STATUS_RESET 10
`define APB4_APU__PERF_CONTROL_ENABLE 0
`define APB4_APU__PERF_CONTROL_CLEAR 1
`define APB4_APU__PERF_CONTROL_SNAPSHOT 2
`define APB4_APU__PERF_STATUS_SNAPSHOT_VALID 0
// verilog_format: on
`endif
+561
View File
@@ -0,0 +1,561 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "apu_define.svh"
module apu_reg (
// verilog_format: off -- preserve the APB and lifecycle boundary columns
input logic clk_i,
input logic rst_n_i,
input logic [1:0] owner_i,
input logic owner_lock_i,
input logic quiesce_i,
input logic resource_reset_i,
apb4_if.slave apb4,
output logic idle_o,
output logic irq_o
// verilog_format: on
);
localparam logic [31:0] IpId = 32'h4150_5530;
localparam logic [31:0] IpVersion = 32'h0001_0000;
localparam logic [31:0] Capability0 = 32'd0;
localparam logic [31:0] Capability1 = 32'd0;
localparam logic [31:0] AbiDigest = 32'd0;
localparam logic [10:0] IrqMask = 11'h7ff;
localparam logic [31:0] TimeoutReset = 32'h0000_ffff;
localparam logic [31:0] RingCoalesceReset = 32'h0001_0001;
localparam logic [31:0] KwsConfigReset = 32'h0000_0380;
localparam logic [3:0][31:0] AclReset = {32'd0, 32'hffff_ffff, 32'd0, 32'hffff_ffff};
localparam logic [4:0][31:0] RingReset = {RingCoalesceReset, 32'd0, 32'd0, 32'd0, 32'd0};
logic s_apb4_ready_d, s_apb4_ready_q;
logic [31:0] s_apb4_rdata_q;
logic s_apb4_resp_err_d, s_apb4_resp_err_q;
logic s_req_accept;
logic s_write;
logic [11:0] s_offset;
logic [31:0] s_strobed_write;
logic [31:0] s_merged_write;
logic s_read_err;
logic s_write_err;
logic s_write_unsupported;
logic [31:0] s_read_data;
logic s_soft_reset;
logic s_cnt_clear;
logic [10:0] s_irq_clear;
logic [10:0] s_irq_set;
logic [10:0] s_irq_state_d, s_irq_state_q;
logic [10:0] s_irq_en_d, s_irq_en_q;
logic [31:0] s_err_stat_d, s_err_stat_q;
logic [31:0] s_err_addr_d, s_err_addr_q;
logic [31:0] s_err_detail_d, s_err_detail_q;
logic [1:0][31:0] s_timeout_d, s_timeout_q;
logic [3:0] s_stream_route_d, s_stream_route_q;
logic [3:0][31:0] s_acl_d, s_acl_q;
logic [2:0][31:0] s_mc_cfg_d, s_mc_cfg_q;
logic [7:0][31:0] s_job_cfg_d, s_job_cfg_q;
logic [4:0][31:0] s_ring_cfg_d, s_ring_cfg_q;
logic [2:0][31:0] s_kws_model_cfg_d, s_kws_model_cfg_q;
logic [15:0] s_kws_cfg_d, s_kws_cfg_q;
logic s_perf_en_d, s_perf_en_q;
logic s_perf_snapshot_valid_d, s_perf_snapshot_valid_q;
function automatic logic [31:0] apply_wstrb(
input logic [31:0] previous_i, input logic [31:0] value_i, input logic [3:0] strobe_i);
logic [31:0] s_value;
begin
s_value = previous_i;
for (int unsigned byte_index = 0; byte_index < 4; byte_index++) begin
if (strobe_i[byte_index]) begin
s_value[(byte_index*8)+:8] = value_i[(byte_index*8)+:8];
end
end
return s_value;
end
endfunction
function automatic logic is_power_of_two(input logic [31:0] value_i);
return (value_i != 32'd0) && ((value_i & (value_i - 1'b1)) == 32'd0);
endfunction
assign s_req_accept = apb4.psel && apb4.penable && !s_apb4_ready_q;
assign s_write = s_req_accept && apb4.pwrite;
assign s_offset = apb4.paddr[11:0];
assign s_strobed_write = apply_wstrb(32'd0, apb4.pwdata, apb4.pstrb);
assign s_apb4_ready_d = s_req_accept;
assign s_apb4_resp_err_d = s_req_accept && (apb4.pwrite ? s_write_err : s_read_err);
assign apb4.pready = s_apb4_ready_q;
assign apb4.prdata = s_apb4_rdata_q;
assign apb4.pslverr = s_apb4_resp_err_q;
assign idle_o = 1'b1;
assign irq_o = (s_irq_state_q & s_irq_en_q) != 11'd0;
always_comb begin
s_read_data = 32'd0;
s_read_err = s_offset[1:0] != 2'b00;
if (!s_read_err) begin
unique case (s_offset)
`APB4_APU__IP_ID: s_read_data = IpId;
`APB4_APU__IP_VERSION: s_read_data = IpVersion;
`APB4_APU__CAPABILITY0: s_read_data = Capability0;
`APB4_APU__CAPABILITY1: s_read_data = Capability1;
`APB4_APU__STATUS: s_read_data = {22'd0, 1'b0, 1'b1, 1'b0, quiesce_i, 6'd0};
`APB4_APU__IRQ_STATE: s_read_data = {21'd0, s_irq_state_q};
`APB4_APU__IRQ_ENABLE: s_read_data = {21'd0, s_irq_en_q};
`APB4_APU__ERROR_STATUS: s_read_data = s_err_stat_q;
`APB4_APU__ERROR_ADDRESS: s_read_data = s_err_addr_q;
`APB4_APU__ERROR_DETAIL: s_read_data = s_err_detail_q;
`APB4_APU__SEQUENCER_TIMEOUT: s_read_data = s_timeout_q[0];
`APB4_APU__STREAM_ROUTE: s_read_data = {28'd0, s_stream_route_q};
`APB4_APU__STREAM_STATUS: s_read_data = 32'd0;
`APB4_APU__OWNER_STATUS:
s_read_data = {21'd0, resource_reset_i, quiesce_i, owner_lock_i, 6'd0, owner_i};
`APB4_APU__READ_BASE: s_read_data = s_acl_q[0];
`APB4_APU__READ_LIMIT: s_read_data = s_acl_q[1];
`APB4_APU__WRITE_BASE: s_read_data = s_acl_q[2];
`APB4_APU__WRITE_LIMIT: s_read_data = s_acl_q[3];
`APB4_APU__DMA_TIMEOUT: s_read_data = s_timeout_q[1];
`APB4_APU__ABI_DIGEST: s_read_data = AbiDigest;
`APB4_APU__SEQUENCER_STATUS, `APB4_APU__SEQUENCER_RETIRED,
`APB4_APU__MC_STATUS, `APB4_APU__MC_ABI, `APB4_APU__MC_BUILD_ID_LO,
`APB4_APU__MC_BUILD_ID_HI, `APB4_APU__MC_LOCK, `APB4_APU__MC_ACTUAL_CRC,
`APB4_APU__MC_LOAD_COUNT, `APB4_APU__JOB_STATUS, `APB4_APU__JOB_INPUT_USED,
`APB4_APU__JOB_OUTPUT_BYTES, `APB4_APU__JOB_FRAMES,
`APB4_APU__JOB_SOURCE_INFO, `APB4_APU__JOB_CYCLES, `APB4_APU__JOB_DETAIL,
`APB4_APU__RING_HEAD, `APB4_APU__RING_STATUS, `APB4_APU__RING_COMPLETED,
`APB4_APU__KWS_STATUS, `APB4_APU__KWS_RESULT, `APB4_APU__KWS_TIMESTAMP_LO,
`APB4_APU__KWS_TIMESTAMP_HI, `APB4_APU__KWS_FRAME_COUNT,
`APB4_APU__KWS_INFERENCE_COUNT, `APB4_APU__KWS_HIT_COUNT,
`APB4_APU__KWS_OVERRUN_COUNT, `APB4_APU__KWS_MODEL_STATUS,
`APB4_APU__KWS_MODEL_ACTUAL_CRC:
s_read_data = 32'd0;
`APB4_APU__MC_IMAGE_ADDRESS: s_read_data = s_mc_cfg_q[0];
`APB4_APU__MC_IMAGE_SIZE: s_read_data = s_mc_cfg_q[1];
`APB4_APU__MC_EXPECTED_CRC: s_read_data = s_mc_cfg_q[2];
`APB4_APU__JOB_CONTROL: s_read_data = s_job_cfg_q[0];
`APB4_APU__JOB_INPUT_ADDRESS: s_read_data = s_job_cfg_q[1];
`APB4_APU__JOB_INPUT_LENGTH: s_read_data = s_job_cfg_q[2];
`APB4_APU__JOB_OUTPUT_ADDRESS: s_read_data = s_job_cfg_q[3];
`APB4_APU__JOB_OUTPUT_CAPACITY: s_read_data = s_job_cfg_q[4];
`APB4_APU__JOB_INPUT_CONFIG: s_read_data = s_job_cfg_q[5];
`APB4_APU__JOB_OUTPUT_CONFIG: s_read_data = s_job_cfg_q[6];
`APB4_APU__JOB_FLAGS: s_read_data = s_job_cfg_q[7];
`APB4_APU__RING_BASE: s_read_data = s_ring_cfg_q[0];
`APB4_APU__RING_SIZE: s_read_data = s_ring_cfg_q[1];
`APB4_APU__RING_TAIL: s_read_data = s_ring_cfg_q[2];
`APB4_APU__RING_CONTROL: s_read_data = s_ring_cfg_q[3];
`APB4_APU__RING_COALESCE: s_read_data = s_ring_cfg_q[4];
`APB4_APU__KWS_MODEL_ADDRESS: s_read_data = s_kws_model_cfg_q[0];
`APB4_APU__KWS_MODEL_SIZE: s_read_data = s_kws_model_cfg_q[1];
`APB4_APU__KWS_MODEL_EXPECTED_CRC: s_read_data = s_kws_model_cfg_q[2];
`APB4_APU__KWS_CONTROL: s_read_data = 32'd0;
`APB4_APU__KWS_CONFIG: s_read_data = {16'd0, s_kws_cfg_q};
`APB4_APU__PERF_CONTROL: s_read_data = {31'd0, s_perf_en_q};
`APB4_APU__PERF_STATUS: s_read_data = {31'd0, s_perf_snapshot_valid_q};
`APB4_APU__PERF_ACTIVE_CYCLES_LO, `APB4_APU__PERF_ACTIVE_CYCLES_HI,
`APB4_APU__PERF_INPUT_BYTES_LO, `APB4_APU__PERF_INPUT_BYTES_HI,
`APB4_APU__PERF_OUTPUT_BYTES_LO, `APB4_APU__PERF_OUTPUT_BYTES_HI,
`APB4_APU__PERF_DECODED_FRAMES_LO, `APB4_APU__PERF_DECODED_FRAMES_HI,
`APB4_APU__PERF_DMA_READ_STALLS_LO, `APB4_APU__PERF_DMA_READ_STALLS_HI,
`APB4_APU__PERF_DMA_WRITE_STALLS_LO, `APB4_APU__PERF_DMA_WRITE_STALLS_HI,
`APB4_APU__PERF_STREAM_STALLS_LO, `APB4_APU__PERF_STREAM_STALLS_HI,
`APB4_APU__PERF_SEQUENCER_INSTR_LO, `APB4_APU__PERF_SEQUENCER_INSTR_HI,
`APB4_APU__PERF_KWS_CYCLES_LO, `APB4_APU__PERF_KWS_CYCLES_HI,
`APB4_APU__PERF_FAULTS_LO, `APB4_APU__PERF_FAULTS_HI:
s_read_data = 32'd0;
`APB4_APU__COMMAND, `APB4_APU__IRQ_TEST, `APB4_APU__RING_DOORBELL: begin
s_read_data = 32'd0;
s_read_err = 1'b1;
end
default: begin
s_read_data = 32'd0;
s_read_err = 1'b1;
end
endcase
end
end
always_comb begin
s_write_err = s_offset[1:0] != 2'b00;
s_write_unsupported = 1'b0;
s_merged_write = s_strobed_write;
if (!s_write_err) begin
unique case (s_offset)
`APB4_APU__COMMAND: begin
s_write_unsupported = (apb4.pwdata & 32'h0000_003b) != 32'd0;
s_write_err = (apb4.pstrb != 4'hf) ||
((apb4.pwdata & 32'hffff_ff80) != 32'd0) ||
s_write_unsupported;
end
`APB4_APU__IRQ_STATE: s_write_err = (s_strobed_write & ~32'(IrqMask)) != 32'd0;
`APB4_APU__IRQ_ENABLE: begin
s_merged_write = apply_wstrb({21'd0, s_irq_en_q}, apb4.pwdata, apb4.pstrb);
s_write_err = (s_merged_write & ~32'(IrqMask)) != 32'd0;
end
`APB4_APU__IRQ_TEST:
s_write_err = (apb4.pstrb != 4'hf) || ((apb4.pwdata & ~32'(IrqMask)) != 32'd0);
`APB4_APU__ERROR_STATUS: s_write_err = (s_strobed_write & 32'hffff_fffe) != 32'd0;
`APB4_APU__SEQUENCER_TIMEOUT: begin
s_merged_write = apply_wstrb(s_timeout_q[0], apb4.pwdata, apb4.pstrb);
s_write_err = s_merged_write == 32'd0;
end
`APB4_APU__STREAM_ROUTE: begin
s_merged_write = apply_wstrb({28'd0, s_stream_route_q}, apb4.pwdata, apb4.pstrb);
s_write_unsupported = s_merged_write != 32'd0;
s_write_err = s_write_unsupported;
end
`APB4_APU__READ_BASE, `APB4_APU__READ_LIMIT, `APB4_APU__WRITE_BASE,
`APB4_APU__WRITE_LIMIT, `APB4_APU__MC_EXPECTED_CRC,
`APB4_APU__KWS_MODEL_EXPECTED_CRC:
s_write_err = apb4.pstrb != 4'hf;
`APB4_APU__DMA_TIMEOUT: begin
s_merged_write = apply_wstrb(s_timeout_q[1], apb4.pwdata, apb4.pstrb);
s_write_err = s_merged_write == 32'd0;
end
`APB4_APU__MC_IMAGE_ADDRESS, `APB4_APU__KWS_MODEL_ADDRESS:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[5:0] != 6'd0);
`APB4_APU__MC_IMAGE_SIZE, `APB4_APU__KWS_MODEL_SIZE:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata == 32'd0);
`APB4_APU__JOB_CONTROL: begin
s_merged_write = apply_wstrb(s_job_cfg_q[0], apb4.pwdata, apb4.pstrb);
s_write_err = (s_merged_write[31:12] != 20'd0) ||
(s_merged_write[3:0] > 4'd1) ||
(s_merged_write[7:4] > 4'd2) || (s_merged_write[9:8] > 2'd1);
end
`APB4_APU__JOB_INPUT_ADDRESS, `APB4_APU__JOB_INPUT_LENGTH,
`APB4_APU__JOB_OUTPUT_ADDRESS, `APB4_APU__JOB_OUTPUT_CAPACITY:
s_write_err = apb4.pstrb != 4'hf;
`APB4_APU__JOB_INPUT_CONFIG: begin
s_merged_write = apply_wstrb(s_job_cfg_q[5], apb4.pwdata, apb4.pstrb);
s_write_err = s_merged_write[31:26] != 6'd0;
end
`APB4_APU__JOB_OUTPUT_CONFIG: begin
s_merged_write = apply_wstrb(s_job_cfg_q[6], apb4.pwdata, apb4.pstrb);
s_write_err = (s_merged_write[31:21] != 11'd0) || (s_merged_write[20:19] > 2'd1);
end
`APB4_APU__JOB_FLAGS: begin
s_merged_write = apply_wstrb(s_job_cfg_q[7], apb4.pwdata, apb4.pstrb);
s_write_err = s_merged_write[31:1] != 31'd0;
end
`APB4_APU__RING_BASE: s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[6:0] != 7'd0);
`APB4_APU__RING_SIZE:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata < 32'd2) ||
(apb4.pwdata > 32'd256) || !is_power_of_two(apb4.pwdata);
`APB4_APU__RING_TAIL: s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[31:8] != 24'd0);
`APB4_APU__RING_CONTROL: s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[31:2] != 30'd0);
`APB4_APU__RING_COALESCE:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[15:8] != 8'd0) ||
(apb4.pwdata[7:0] == 8'd0) || (apb4.pwdata[31:16] == 16'd0);
`APB4_APU__RING_DOORBELL: begin
s_write_unsupported = 1'b1;
s_write_err = 1'b1;
end
`APB4_APU__KWS_CONTROL: begin
s_write_unsupported = apb4.pwdata[1:0] != 2'd0;
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[31:3] != 29'd0) || s_write_unsupported;
end
`APB4_APU__KWS_CONFIG: begin
s_merged_write = apply_wstrb({16'd0, s_kws_cfg_q}, apb4.pwdata, apb4.pstrb);
s_write_err = (s_merged_write[31:16] != 16'd0) || (s_merged_write[15:8] == 8'd0);
end
`APB4_APU__PERF_CONTROL: begin
s_merged_write = apply_wstrb({31'd0, s_perf_en_q}, apb4.pwdata, apb4.pstrb);
s_write_err = s_merged_write[31:3] != 29'd0;
end
`APB4_APU__IP_ID, `APB4_APU__IP_VERSION, `APB4_APU__CAPABILITY0,
`APB4_APU__CAPABILITY1, `APB4_APU__STATUS, `APB4_APU__STREAM_STATUS,
`APB4_APU__OWNER_STATUS, `APB4_APU__ABI_DIGEST,
`APB4_APU__SEQUENCER_STATUS, `APB4_APU__SEQUENCER_RETIRED,
`APB4_APU__MC_STATUS, `APB4_APU__MC_ABI, `APB4_APU__MC_BUILD_ID_LO,
`APB4_APU__MC_BUILD_ID_HI, `APB4_APU__MC_LOCK, `APB4_APU__MC_ACTUAL_CRC,
`APB4_APU__MC_LOAD_COUNT, `APB4_APU__JOB_STATUS, `APB4_APU__JOB_INPUT_USED,
`APB4_APU__JOB_OUTPUT_BYTES, `APB4_APU__JOB_FRAMES,
`APB4_APU__JOB_SOURCE_INFO, `APB4_APU__JOB_CYCLES, `APB4_APU__JOB_DETAIL,
`APB4_APU__RING_HEAD, `APB4_APU__RING_STATUS, `APB4_APU__RING_COMPLETED,
`APB4_APU__KWS_STATUS, `APB4_APU__KWS_RESULT, `APB4_APU__KWS_TIMESTAMP_LO,
`APB4_APU__KWS_TIMESTAMP_HI, `APB4_APU__KWS_FRAME_COUNT,
`APB4_APU__KWS_INFERENCE_COUNT, `APB4_APU__KWS_HIT_COUNT,
`APB4_APU__KWS_OVERRUN_COUNT, `APB4_APU__KWS_MODEL_STATUS,
`APB4_APU__KWS_MODEL_ACTUAL_CRC, `APB4_APU__PERF_STATUS,
`APB4_APU__PERF_ACTIVE_CYCLES_LO, `APB4_APU__PERF_ACTIVE_CYCLES_HI,
`APB4_APU__PERF_INPUT_BYTES_LO, `APB4_APU__PERF_INPUT_BYTES_HI,
`APB4_APU__PERF_OUTPUT_BYTES_LO, `APB4_APU__PERF_OUTPUT_BYTES_HI,
`APB4_APU__PERF_DECODED_FRAMES_LO, `APB4_APU__PERF_DECODED_FRAMES_HI,
`APB4_APU__PERF_DMA_READ_STALLS_LO, `APB4_APU__PERF_DMA_READ_STALLS_HI,
`APB4_APU__PERF_DMA_WRITE_STALLS_LO, `APB4_APU__PERF_DMA_WRITE_STALLS_HI,
`APB4_APU__PERF_STREAM_STALLS_LO, `APB4_APU__PERF_STREAM_STALLS_HI,
`APB4_APU__PERF_SEQUENCER_INSTR_LO, `APB4_APU__PERF_SEQUENCER_INSTR_HI,
`APB4_APU__PERF_KWS_CYCLES_LO, `APB4_APU__PERF_KWS_CYCLES_HI,
`APB4_APU__PERF_FAULTS_LO, `APB4_APU__PERF_FAULTS_HI:
s_write_err = 1'b1;
default: s_write_err = 1'b1;
endcase
end
end
always_comb begin
s_irq_state_d = s_irq_state_q;
s_irq_en_d = s_irq_en_q;
s_err_stat_d = s_err_stat_q;
s_err_addr_d = s_err_addr_q;
s_err_detail_d = s_err_detail_q;
s_timeout_d = s_timeout_q;
s_stream_route_d = s_stream_route_q;
s_acl_d = s_acl_q;
s_mc_cfg_d = s_mc_cfg_q;
s_job_cfg_d = s_job_cfg_q;
s_ring_cfg_d = s_ring_cfg_q;
s_kws_model_cfg_d = s_kws_model_cfg_q;
s_kws_cfg_d = s_kws_cfg_q;
s_perf_en_d = s_perf_en_q;
s_perf_snapshot_valid_d = s_perf_snapshot_valid_q;
s_soft_reset = 1'b0;
s_cnt_clear = 1'b0;
s_irq_clear = 11'd0;
s_irq_set = 11'd0;
if (s_write && !s_write_err) begin
unique case (s_offset)
`APB4_APU__COMMAND: begin
s_soft_reset = apb4.pwdata[`APB4_APU__COMMAND_SOFT_RESET];
s_cnt_clear = apb4.pwdata[`APB4_APU__COMMAND_CLEAR_COUNTERS];
end
`APB4_APU__IRQ_STATE: s_irq_clear = s_strobed_write[10:0];
`APB4_APU__IRQ_ENABLE: s_irq_en_d = s_merged_write[10:0];
`APB4_APU__IRQ_TEST: s_irq_set = apb4.pwdata[10:0];
`APB4_APU__ERROR_STATUS: begin
if (s_strobed_write[0]) begin
s_err_stat_d = 32'd0;
s_err_addr_d = 32'd0;
s_err_detail_d = 32'd0;
end
end
`APB4_APU__SEQUENCER_TIMEOUT: s_timeout_d[0] = s_merged_write;
`APB4_APU__STREAM_ROUTE: s_stream_route_d = s_merged_write[3:0];
`APB4_APU__READ_BASE: s_acl_d[0] = apb4.pwdata;
`APB4_APU__READ_LIMIT: s_acl_d[1] = apb4.pwdata;
`APB4_APU__WRITE_BASE: s_acl_d[2] = apb4.pwdata;
`APB4_APU__WRITE_LIMIT: s_acl_d[3] = apb4.pwdata;
`APB4_APU__DMA_TIMEOUT: s_timeout_d[1] = s_merged_write;
`APB4_APU__MC_IMAGE_ADDRESS: s_mc_cfg_d[0] = apb4.pwdata;
`APB4_APU__MC_IMAGE_SIZE: s_mc_cfg_d[1] = apb4.pwdata;
`APB4_APU__MC_EXPECTED_CRC: s_mc_cfg_d[2] = apb4.pwdata;
`APB4_APU__JOB_CONTROL: s_job_cfg_d[0] = s_merged_write;
`APB4_APU__JOB_INPUT_ADDRESS: s_job_cfg_d[1] = apb4.pwdata;
`APB4_APU__JOB_INPUT_LENGTH: s_job_cfg_d[2] = apb4.pwdata;
`APB4_APU__JOB_OUTPUT_ADDRESS: s_job_cfg_d[3] = apb4.pwdata;
`APB4_APU__JOB_OUTPUT_CAPACITY: s_job_cfg_d[4] = apb4.pwdata;
`APB4_APU__JOB_INPUT_CONFIG: s_job_cfg_d[5] = s_merged_write;
`APB4_APU__JOB_OUTPUT_CONFIG: s_job_cfg_d[6] = s_merged_write;
`APB4_APU__JOB_FLAGS: s_job_cfg_d[7] = s_merged_write;
`APB4_APU__RING_BASE: s_ring_cfg_d[0] = apb4.pwdata;
`APB4_APU__RING_SIZE: s_ring_cfg_d[1] = apb4.pwdata;
`APB4_APU__RING_TAIL: s_ring_cfg_d[2] = apb4.pwdata;
`APB4_APU__RING_CONTROL: s_ring_cfg_d[3] = apb4.pwdata;
`APB4_APU__RING_COALESCE: s_ring_cfg_d[4] = apb4.pwdata;
`APB4_APU__KWS_MODEL_ADDRESS: s_kws_model_cfg_d[0] = apb4.pwdata;
`APB4_APU__KWS_MODEL_SIZE: s_kws_model_cfg_d[1] = apb4.pwdata;
`APB4_APU__KWS_MODEL_EXPECTED_CRC: s_kws_model_cfg_d[2] = apb4.pwdata;
`APB4_APU__KWS_CONFIG: s_kws_cfg_d = s_merged_write[15:0];
`APB4_APU__PERF_CONTROL: begin
s_perf_en_d = s_merged_write[`APB4_APU__PERF_CONTROL_ENABLE];
if (s_merged_write[`APB4_APU__PERF_CONTROL_CLEAR]) begin
s_cnt_clear = 1'b1;
end
if (s_merged_write[`APB4_APU__PERF_CONTROL_SNAPSHOT]) begin
s_perf_snapshot_valid_d = 1'b1;
end
end
default: begin
end
endcase
end
if (s_cnt_clear) begin
s_perf_snapshot_valid_d = 1'b0;
end
if (s_req_accept && (apb4.pwrite ? s_write_err : s_read_err)) begin
s_irq_set[`APB4_APU__IRQ_FIRST_ERROR] = 1'b1;
if (!s_err_stat_q[`APB4_APU__ERROR_VALID]) begin
s_err_stat_d = 32'd1 |
(32'((apb4.pwrite && s_write_unsupported) ?
`APB4_APU__ERROR_CODE_UNSUPPORTED :
`APB4_APU__ERROR_CODE_INVALID_CONFIG)
<< `APB4_APU__ERROR_CODE) |
(32'(`APB4_APU__ERROR_STAGE_APB) << `APB4_APU__ERROR_STAGE);
s_err_addr_d = apb4.paddr;
s_err_detail_d = apb4.pwrite ? apb4.pwdata : {20'd0, s_offset};
end
end
s_irq_state_d = (s_irq_state_d & ~s_irq_clear) | s_irq_set;
if (s_soft_reset || resource_reset_i) begin
s_irq_state_d = 11'd0;
s_irq_en_d = 11'd0;
s_err_stat_d = 32'd0;
s_err_addr_d = 32'd0;
s_err_detail_d = 32'd0;
s_timeout_d[0] = TimeoutReset;
s_timeout_d[1] = TimeoutReset;
s_stream_route_d = 4'd0;
s_mc_cfg_d = '0;
s_job_cfg_d = '0;
s_ring_cfg_d = RingReset;
s_kws_model_cfg_d = '0;
s_kws_cfg_d = KwsConfigReset[15:0];
s_perf_en_d = 1'b0;
s_perf_snapshot_valid_d = 1'b0;
end
end
dffr #(
.DATA_WIDTH(1)
) u_ready_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_apb4_ready_d),
.dat_o (s_apb4_ready_q)
);
dffr #(
.DATA_WIDTH(1)
) u_resp_err_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_apb4_resp_err_d),
.dat_o (s_apb4_resp_err_q)
);
dffer #(
.DATA_WIDTH(32)
) u_rdata_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_req_accept && !apb4.pwrite),
.dat_i (s_read_data),
.dat_o (s_apb4_rdata_q)
);
dffr #(
.DATA_WIDTH(11)
) u_irq_state_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_irq_state_d),
.dat_o (s_irq_state_q)
);
dffr #(
.DATA_WIDTH(11)
) u_irq_enable_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_irq_en_d),
.dat_o (s_irq_en_q)
);
dffr #(
.DATA_WIDTH(32)
) u_error_status_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_err_stat_d),
.dat_o (s_err_stat_q)
);
dffr #(
.DATA_WIDTH(32)
) u_error_address_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_err_addr_d),
.dat_o (s_err_addr_q)
);
dffr #(
.DATA_WIDTH(32)
) u_error_detail_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_err_detail_d),
.dat_o (s_err_detail_q)
);
dffrc #(
.DATA_WIDTH(2 * 32),
.RESET_VAL ({TimeoutReset, TimeoutReset})
) u_timeout_dffrc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_timeout_d),
.dat_o (s_timeout_q)
);
dffr #(
.DATA_WIDTH(4)
) u_stream_route_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_stream_route_d),
.dat_o (s_stream_route_q)
);
dffrc #(
.DATA_WIDTH(4 * 32),
.RESET_VAL (AclReset)
) u_acl_dffrc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_acl_d),
.dat_o (s_acl_q)
);
dffr #(
.DATA_WIDTH(3 * 32)
) u_mc_cfg_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_mc_cfg_d),
.dat_o (s_mc_cfg_q)
);
dffr #(
.DATA_WIDTH(8 * 32)
) u_job_cfg_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_job_cfg_d),
.dat_o (s_job_cfg_q)
);
dffrc #(
.DATA_WIDTH(5 * 32),
.RESET_VAL (RingReset)
) u_ring_cfg_dffrc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_ring_cfg_d),
.dat_o (s_ring_cfg_q)
);
dffr #(
.DATA_WIDTH(3 * 32)
) u_kws_model_cfg_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_kws_model_cfg_d),
.dat_o (s_kws_model_cfg_q)
);
dffrc #(
.DATA_WIDTH(16),
.RESET_VAL (KwsConfigReset[15:0])
) u_kws_cfg_dffrc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_kws_cfg_d),
.dat_o (s_kws_cfg_q)
);
dffr #(
.DATA_WIDTH(1)
) u_perf_enable_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_perf_en_d),
.dat_o (s_perf_en_q)
);
dffr #(
.DATA_WIDTH(1)
) u_perf_snapshot_valid_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_perf_snapshot_valid_d),
.dat_o (s_perf_snapshot_valid_q)
);
endmodule
+3 -3
View File
@@ -421,9 +421,9 @@
"symbol": "APB4_APU",
"base": "0x10013000",
"size": "0x00001000",
"route": "reserved",
"kind": "reserved",
"public": false,
"route": "apb4_periph",
"kind": "active",
"public": true,
"user_access": "none"
},
{
+2
View File
@@ -125,6 +125,8 @@
/ip/multimedia/dvp_core.sv
/ip/multimedia/dvp_reg.sv
/ip/multimedia/axi4s_dvp.sv
/ip/multimedia/apu_reg.sv
/ip/multimedia/apb4_apu.sv
/ip/multimedia/jpeg_pkg.sv
/ip/multimedia/jpeg_transform.sv
/ip/multimedia/jpeg_quantizer.sv
+4 -3
View File
@@ -22,8 +22,8 @@ must appear exactly once. Disabled targets keep their slot and interface
declaration but cannot own an address region. This list stays separate from
`apb4_system_targets`, which owns the `0x2000_0000` `apb4_system` island.
Slot 15 is the active SDIO0 management window; SDIO1 is appended at slot 18,
the management-only crypto controller at slot 19, and USB2 at slot 20, so the
existing slots 0..17 remain stable.
the management-only crypto controller at slot 19, USB2 at slot 20, JPEG at
slot 26, and the APU shell at slot 27, so the existing slots remain stable.
Each `gpio_alt_functions` entry defines both alternate modes for one GPIO pin.
`inputs` are driven from the selected GPIO input, and `do` and `oe` define the
@@ -54,7 +54,8 @@ Existing allocated core IRQ bits retain their compatibility mapping; additions
must use currently unallocated bits and preserve the existing entries. SDIO0
and SDIO1 use APB4 group bits 16 and 17 and core bits 10 and 21. Crypto uses
APB4 group bit 18 and core bit 23. USB2 uses APB4 group bit 19 and core bit 24.
All four remain management-only in the
JPEG uses group bit 22 and core bit 30; APU uses group bit 23 and core bit 31.
All resource-owned sources remain management-only in the
generated user IRQ mask. Removing a source leaves its
core IRQ bit unallocated and driven low. Firmware does not
expose a generic external interrupt API until the SoC includes a claim/complete
@@ -48,6 +48,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
("watchdog_early_warning", "apb4_system", 3, 14, "u_wdg_if.irq_o"),
("rng", "apb4_system", 4, 16, "s_rng_irq"),
("resource_fault", "apb4_system", 7, 29, "s_resource_fault_irq"),
("apu", "apb4_periph", 23, 31, "resource_irq_lp_i[6]"),
("ws2812", "apb4_periph", 10, 17, "ws2812.irq_o"),
("gpio", "apb4_periph", 11, 18, "gpio.irq_o"),
("i2c1", "apb4_periph", 12, 19, "i2c1.irq_o"),
+17 -1
View File
@@ -5,7 +5,7 @@
"irq_groups": [
{
"name": "apb4_periph",
"width": 23,
"width": 24,
"top_signal": "s_apb4_periph_irq"
},
{
@@ -276,6 +276,15 @@
"core_bit": 29,
"signal": "s_resource_fault_irq",
"user_visible": false
},
{
"name": "apu",
"description": "APU completion and error interrupt",
"group": "apb4_periph",
"group_bit": 23,
"core_bit": 31,
"signal": "resource_irq_lp_i[6]",
"user_visible": false
}
],
"wake_sources": [
@@ -600,6 +609,13 @@
"timed_interface": "u_jpeg_apb4_if",
"pure_interface": "u_jpeg_apb4_pure_if",
"region": "APB4_JPEG"
},
{
"slot": 27,
"name": "apu",
"timed_interface": "u_apu_apb4_if",
"pure_interface": "u_apu_apb4_pure_if",
"region": "APB4_APU"
}
],
"apb4_system_targets": [
+1
View File
@@ -101,6 +101,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
$(ROOT_PATH)/crt/src/hal/dma_math.c \
$(ROOT_PATH)/crt/src/hal/dma.c \
$(ROOT_PATH)/crt/src/hal/crypto.c \
$(ROOT_PATH)/crt/src/hal/apu.c \
$(ROOT_PATH)/crt/src/hal/jpeg_math.c \
$(ROOT_PATH)/crt/src/hal/jpeg.c \
$(ROOT_PATH)/crt/src/hal/dvp.c \
+33 -14
View File
@@ -23,8 +23,12 @@ module apb4_periph (
input logic debug_halted_i,
input logic timebase_tick_i,
input logic ext_h_hp_irq_i,
input logic [5:0] resource_irq_lp_i,
input logic [5:0] resource_irq_hp_i,
input logic [6:0] resource_irq_lp_i,
input logic [6:0] resource_irq_hp_i,
input logic [1:0] apu_owner_i,
input logic apu_owner_lock_i,
input logic apu_quiesce_i,
input logic apu_reset_i,
input logic jpeg_quiesce_i,
input logic jpeg_reset_i,
axi4_if.slave cfg_axi4,
@@ -67,8 +71,9 @@ module apb4_periph (
output logic hp_software_irq_o,
output logic hp_machine_external_irq_o,
output logic hp_supervisor_external_irq_o,
output logic apu_idle_o,
output logic jpeg_idle_o,
output logic [5:0] resource_irq_raw_o,
output logic [6:0] resource_irq_raw_o,
output logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] irq_o
// verilog_format: on
);
@@ -151,6 +156,7 @@ axi4_stream_if #(
logic s_dma_crypto_in_proc;
logic s_dma_crypto_out_proc;
logic s_crypto_irq;
logic s_apu_irq_raw;
logic s_jpeg_irq_raw;
logic s_usb2_irq;
logic s_tim0_irq, s_tim1_irq;
@@ -210,7 +216,7 @@ 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];
assign resource_irq_raw_o = {
s_jpeg_irq_raw, spisd.irq_o, sdio1.irq_o, sdio0.irq_o, s_usb2_irq, s_dma_irq
s_apu_irq_raw, s_jpeg_irq_raw, spisd.irq_o, sdio1.irq_o, sdio0.irq_o, s_usb2_irq, s_dma_irq
};
apb4_async_bridge u_psram_cfg_mem_cdc (
@@ -281,16 +287,17 @@ axi4_stream_if #(
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;
s_hp_plic_source[4] = resource_irq_hp_i[0];
s_hp_plic_source[5] = resource_irq_hp_i[1];
s_hp_plic_source[6] = resource_irq_hp_i[2];
s_hp_plic_source[7] = resource_irq_hp_i[3];
s_hp_plic_source[8] = resource_irq_hp_i[4];
s_hp_plic_source[9] = resource_irq_hp_i[5];
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;
s_hp_plic_source[4] = resource_irq_hp_i[0];
s_hp_plic_source[5] = resource_irq_hp_i[1];
s_hp_plic_source[6] = resource_irq_hp_i[2];
s_hp_plic_source[7] = resource_irq_hp_i[3];
s_hp_plic_source[8] = resource_irq_hp_i[4];
s_hp_plic_source[9] = resource_irq_hp_i[5];
s_hp_plic_source[10] = resource_irq_hp_i[6];
end
`include "apb4_periph_irq_bindings.svh"
@@ -469,6 +476,18 @@ axi4_stream_if #(
.irq_o (s_jpeg_irq_raw)
);
apb4_apu u_apb4_apu (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.owner_i (apu_owner_i),
.owner_lock_i (apu_owner_lock_i),
.quiesce_i (apu_quiesce_i),
.resource_reset_i(apu_reset_i),
.apb4 (u_apu_apb4_if),
.idle_o (apu_idle_o),
.irq_o (s_apu_irq_raw)
);
apb4_sysctrl u_apb4_sysctrl (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
+30 -26
View File
@@ -23,9 +23,9 @@ module apb4_system (
input logic rst_aud_n_i,
input logic debug_halted_i,
input logic ext_h_data_idle_i,
input logic [6:0] resource_idle_i,
input logic [6:0] resource_block_ack_i,
input logic [5:0] resource_irq_i,
input logic [7:0] resource_idle_i,
input logic [7:0] resource_block_ack_i,
input logic [6:0] resource_irq_i,
input logic cache_request_i,
axi4_if.slave axi4,
axi4_if.master ext_h_axi4,
@@ -45,11 +45,12 @@ module apb4_system (
output logic ext_h_irq_raw_o,
output logic [1:0] ext_h_owner_o,
output logic cache_clean_o,
output logic [6:0][1:0] resource_owner_o,
output logic [6:0] resource_quiesce_o,
output logic [6:0] resource_reset_o,
output logic [5:0] resource_irq_lp_o,
output logic [5:0] resource_irq_hp_o,
output logic [7:0][1:0] resource_owner_o,
output logic [7:0] resource_owner_lock_o,
output logic [7:0] resource_quiesce_o,
output logic [7:0] resource_reset_o,
output logic [6:0] resource_irq_lp_o,
output logic [6:0] resource_irq_hp_o,
output logic [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] irq_o
// verilog_format: on
);
@@ -97,12 +98,13 @@ module apb4_system (
logic s_ext_h_irq;
logic s_ext_h_irq_raw;
logic [ 1:0] unused_ext_h_owner;
logic [ 6:0] s_resource_irq;
logic [ 6:0] s_resource_irq_lp;
logic [ 6:0] s_resource_irq_hp;
logic [ 6:0][1:0] s_resource_owner;
logic [ 6:0] s_resource_quiesce;
logic [ 6:0] s_resource_reset;
logic [ 7:0] s_resource_irq;
logic [ 7:0] s_resource_irq_lp;
logic [ 7:0] s_resource_irq_hp;
logic [ 7:0][1:0] s_resource_owner;
logic [ 7:0] s_resource_owner_lock;
logic [ 7:0] s_resource_quiesce;
logic [ 7:0] s_resource_reset;
logic s_resource_fault_irq;
logic s_cache_clean;
logic s_unused_resource;
@@ -110,16 +112,17 @@ module apb4_system (
logic s_unused_product_input;
`endif
assign s_resource_irq = {resource_irq_i[5], s_ext_h_irq_raw, resource_irq_i[4:0]};
assign s_ext_h_irq = s_resource_irq_lp[5];
assign ext_h_irq_raw_o = s_ext_h_irq_raw;
assign ext_h_owner_o = s_resource_owner[5];
assign cache_clean_o = s_cache_clean;
assign resource_owner_o = s_resource_owner;
assign resource_quiesce_o = s_resource_quiesce;
assign resource_reset_o = s_resource_reset;
assign resource_irq_lp_o = {s_resource_irq_lp[6], s_resource_irq_lp[4:0]};
assign resource_irq_hp_o = {s_resource_irq_hp[6], s_resource_irq_hp[4:0]};
assign s_resource_irq = {resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]};
assign s_ext_h_irq = s_resource_irq_lp[5];
assign ext_h_irq_raw_o = s_ext_h_irq_raw;
assign ext_h_owner_o = s_resource_owner[5];
assign cache_clean_o = s_cache_clean;
assign resource_owner_o = s_resource_owner;
assign resource_owner_lock_o = s_resource_owner_lock;
assign resource_quiesce_o = s_resource_quiesce;
assign resource_reset_o = s_resource_reset;
assign resource_irq_lp_o = {s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]};
assign resource_irq_hp_o = {s_resource_irq_hp[7:6], s_resource_irq_hp[4:0]};
`ifdef PDK_IHP130
localparam logic [31:0] ARCHINFO_TECHNOLOGY = 32'h0201_0082;
@@ -231,7 +234,7 @@ module apb4_system (
apb4_crc u_apb4_crc (.apb4(u_crc_apb4_if));
resource_controller #(
.ResourceCount(7)
.ResourceCount(8)
) u_resource_controller (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
@@ -241,6 +244,7 @@ module apb4_system (
.cache_request_i(cache_request_i),
.cache_clean_o (s_cache_clean),
.owner_o (s_resource_owner),
.owner_lock_o (s_resource_owner_lock),
.quiesce_o (s_resource_quiesce),
.reset_o (s_resource_reset),
.irq_lp_o (s_resource_irq_lp),
@@ -297,6 +301,6 @@ axi42apb4_system u_axi42apb4_system (
.ext_h_timeout_o (ext_h_timeout_o)
);
assign s_unused_resource = ^unused_ext_h_owner;
assign s_unused_resource = ^{unused_ext_h_owner, s_resource_irq_hp[5]};
endmodule
+8 -1
View File
@@ -433,6 +433,13 @@ module axi4_interconnect #(
automatic logic [32:0] wrap_base = {1'b0, addr} & ~(burst_bytes - 1'b1);
automatic
logic
apu_lp_only =
`SOC_ADDR_IS_APB4_APU(addr)
&& (((addr[11:0] >= 12'h040) && (addr[11:0] <= 12'h04c)) ||
((addr[11:0] >= 12'h080) && (addr[11:0] <= 12'h088)) ||
((addr[11:0] >= 12'h200) && (addr[11:0] <= 12'h208)));
automatic
logic
burst_legal =
(burst == `AXI4_BURST_TYPE_FIXED) ||
(burst == `AXI4_BURST_TYPE_INCR) ||
@@ -465,7 +472,7 @@ module axi4_interconnect #(
`SOC_ADDR_IS_APB4_EXT_H(addr)
&& !
`SOC_ADDR_IS_APB4_RESOURCE_CTRL(addr)
);
&& !apu_lp_only);
`else
s_access_allowed[master] = (master != 1) || ((read_req &&
`SOC_USER_ADDR_READABLE(addr)
+3 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: MulanPSL-2.0
module resource_controller #(
parameter int unsigned ResourceCount = 6
parameter int unsigned ResourceCount = 8
) (
// verilog_format: off -- preserve the resource ownership boundary columns
input logic clk_i,
@@ -13,6 +13,7 @@ module resource_controller #(
input logic cache_request_i,
output logic cache_clean_o,
output logic [ResourceCount-1:0][1:0] owner_o,
output logic [ResourceCount-1:0] owner_lock_o,
output logic [ResourceCount-1:0] quiesce_o,
output logic [ResourceCount-1:0] reset_o,
output logic [ResourceCount-1:0] irq_lp_o,
@@ -69,6 +70,7 @@ module resource_controller #(
assign apb4.pslverr = s_resp_err_q;
assign apb4.prdata = s_rdata_q;
assign owner_o = s_owner_q;
assign owner_lock_o = s_owner_lock_q;
assign quiesce_o = s_quiesce_q;
assign reset_o = s_reset_q;
assign cache_clean_o = s_cache_clean_q;
+57 -43
View File
@@ -232,18 +232,21 @@ module retrosoc (
logic [31:0] s_ext_h_timeout;
logic s_ext_h_irq_raw;
logic [ 1:0] s_ext_h_owner;
logic [ 6:0][1:0] s_resource_owner;
logic [ 6:0] s_resource_quiesce;
logic [ 6:0] s_resource_reset;
logic [ 7:0][1:0] s_resource_owner;
logic [ 7:0] s_resource_owner_lock;
logic [ 7:0] s_resource_quiesce;
logic [ 7:0] s_resource_reset;
logic [ 6:0] s_resource_idle_hp;
logic [ 6:0] s_resource_idle_pclk;
logic [ 6:0] s_resource_block_ack_hp;
logic [ 6:0] s_resource_block_ack_pclk;
logic [ 5:0] s_resource_irq_raw;
logic [ 5:0] s_resource_irq_lp;
logic [ 5:0] s_resource_irq_hp;
logic [ 6:0] s_resource_irq_raw;
logic [ 6:0] s_resource_irq_lp;
logic [ 6:0] s_resource_irq_hp;
logic s_apu_idle;
logic s_jpeg_idle;
logic [ 6:0] s_resource_idle_combined;
logic [ 7:0] s_resource_idle_combined;
logic [ 7:0] s_resource_block_ack_combined;
logic [31:0] s_fault_addr_mux;
logic [ 3:0] s_fault_wstrb_mux;
logic s_fault_reserved_mux;
@@ -555,7 +558,7 @@ core_wrapper u_core_wrapper (
.block_new_i (s_hp_block_hp),
.recovery_i (s_hp_recovery_hp),
.flush_i (s_hp_flush_hp),
.resource_block_i (s_resource_quiesce | s_resource_reset),
.resource_block_i (s_resource_quiesce[6:0] | s_resource_reset[6:0]),
.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),
@@ -797,6 +800,10 @@ core_wrapper u_core_wrapper (
.ext_h_hp_irq_i ((s_ext_h_owner == 2'd1) ? s_ext_h_irq_raw : 1'b0),
.resource_irq_lp_i (s_resource_irq_lp),
.resource_irq_hp_i (s_resource_irq_hp),
.apu_owner_i (s_resource_owner[7]),
.apu_owner_lock_i (s_resource_owner_lock[7]),
.apu_quiesce_i (s_resource_quiesce[7]),
.apu_reset_i (s_resource_reset[7]),
.jpeg_quiesce_i (s_resource_quiesce[6]),
.jpeg_reset_i (s_resource_reset[6]),
.cfg_axi4 (u_cfg_pclk_axi4_if),
@@ -840,6 +847,7 @@ core_wrapper u_core_wrapper (
.hp_machine_external_irq_o (s_hp_machine_external_irq),
.hp_supervisor_external_irq_o(s_hp_supervisor_external_irq),
.resource_irq_raw_o (s_resource_irq_raw),
.apu_idle_o (s_apu_idle),
.jpeg_idle_o (s_jpeg_idle),
.irq_o (s_apb4_periph_irq)
);
@@ -853,49 +861,54 @@ 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_data_idle_i (s_ext_h_data_idle),
.resource_idle_i (s_resource_idle_combined),
.resource_block_ack_i(s_resource_block_ack_pclk),
.resource_irq_i (s_resource_irq_raw),
.cache_request_i (s_hp_cache_req_pclk),
.ext_h_axi4 (u_ext_h_wide_axi4_if),
.fabric_monitor (u_fabric_monitor_pclk_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),
.cache_clean_o (s_hp_cache_clean_pclk),
.resource_owner_o (s_resource_owner),
.resource_quiesce_o (s_resource_quiesce),
.resource_reset_o (s_resource_reset),
.resource_irq_lp_o (s_resource_irq_lp),
.resource_irq_hp_o (s_resource_irq_hp),
.irq_o (s_apb4_system_irq)
.clk_i (clk_pclk_i),
.rst_n_i (rst_pclk_n_i),
.clk_aud_i (clk_aud_i),
.rst_aud_n_i (rst_aud_n_i),
.debug_halted_i (s_mgmt_debug_halted),
.ext_h_data_idle_i (s_ext_h_data_idle),
.resource_idle_i (s_resource_idle_combined),
.resource_block_ack_i (s_resource_block_ack_combined),
.resource_irq_i (s_resource_irq_raw),
.cache_request_i (s_hp_cache_req_pclk),
.ext_h_axi4 (u_ext_h_wide_axi4_if),
.fabric_monitor (u_fabric_monitor_pclk_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),
.cache_clean_o (s_hp_cache_clean_pclk),
.resource_owner_o (s_resource_owner),
.resource_owner_lock_o(s_resource_owner_lock),
.resource_quiesce_o (s_resource_quiesce),
.resource_reset_o (s_resource_reset),
.resource_irq_lp_o (s_resource_irq_lp),
.resource_irq_hp_o (s_resource_irq_hp),
.irq_o (s_apb4_system_irq)
);
assign s_resource_idle_combined = {
s_apu_idle,
s_jpeg_idle && s_resource_idle_pclk[6],
s_ext_h_data_idle && s_resource_idle_pclk[5],
s_resource_idle_pclk[4:0]
};
assign s_resource_block_ack_combined = {
s_apu_idle && (s_resource_quiesce[7] || s_resource_reset[7]), s_resource_block_ack_pclk
};
logic [35:0] s_unused_domain_inputs;
logic [36:0] s_unused_domain_inputs;
assign s_unused_domain_inputs = {
clk_pclk_i,
rst_pclk_n_i,
@@ -910,6 +923,7 @@ core_wrapper u_core_wrapper (
s_hp_lifecycle_draining,
s_hp_lifecycle_fault,
^s_resource_owner,
^s_resource_owner_lock,
^s_resource_quiesce,
^s_resource_reset,
^unused_cdc_clear_busy,
+3
View File
@@ -133,7 +133,10 @@
"sdram_reg.sv"
],
"rtl/ip/multimedia": [
"apb4_apu.sv",
"apb4_jpeg.sv",
"apu_define.svh",
"apu_reg.sv",
"axi4s_dvp.sv",
"dvp_core.sv",
"dvp_define.svh",
+1
View File
@@ -33,6 +33,7 @@ TEST_SOURCES = (
"crt/src/hal/i2s_math.c",
"crt/src/hal/dma_math.c",
"crt/src/hal/jpeg_math.c",
"crt/src/hal/apu.c",
"crt/src/hal/sysctrl.c",
"crt/src/hal/clock.c",
"crt/src/hal/resource.c",
+3
View File
@@ -16,6 +16,9 @@ tooling.
APB4 simulations; `test_crypto_register_parity.py` checks the handwritten
RTL/C register ABI and `test_dma.py` covers DMA bursts, TCD fetch, CRC,
tail-byte writes, and crypto endpoints.
- `test_apu.py` checks the complete fail-closed APU-P1 APB4 register matrix and
integrated LP/HP IRQ ownership topology; `test_apu_register_parity.py` keeps
its handwritten RTL/C ABI and matrix coverage synchronized.
- `test_user_ip_register_parity.py` keeps the integrated slot 1 timer and slot
2 GPIO register offsets synchronized with their application-owned C
definitions and checks their extension-manifest slot assignments.
+6
View File
@@ -6,6 +6,7 @@
#include <retrosoc/core/status.h>
#include <retrosoc/core/wait.h>
#include <retrosoc/hal/apu.h>
#include <retrosoc/hal/gpio.h>
#include <retrosoc/hal/clock.h>
#include <retrosoc/hal/extension.h>
@@ -864,6 +865,10 @@ static int test_resource_validation(void) {
return 0;
}
static int test_apu_validation(void) {
return (rs_apu_probe(NULL) == RS_EINVAL) ? 0 : 1;
}
static int test_jpeg_validation(void) {
static _Alignas(RS_JPEG_DESCRIPTOR_ALIGNMENT) rs_jpeg_descriptor_t ring[2];
rs_jpeg_descriptor_t descriptor;
@@ -1016,6 +1021,7 @@ int main(void) {
test_user_ip_validation(),
test_extension_validation(),
test_resource_validation(),
test_apu_validation(),
test_jpeg_validation(),
test_ps2_decoders(),
test_wav_parser(),
+2 -2
View File
@@ -16,7 +16,7 @@ module apb4_topology_tb;
begin
s_decode_addr = address;
#1;
if (s_psel_comb !== (20'd1 << slot)) begin
if (s_psel_comb !== (28'd1 << slot)) begin
$fatal(1, "unexpected APB4 target slot for %h: got %b", address, s_psel_comb);
end
end
@@ -44,7 +44,7 @@ module apb4_topology_tb;
expect_select(`SOC_ADDR_APB4_SDIO1_BASE, 18);
expect_select(`SOC_ADDR_APB4_CRYPTO_BASE, 19);
expect_disabled(`SOC_ADDR_APB4_GA_BASE);
expect_disabled(`SOC_ADDR_APB4_APU_BASE);
expect_select(`SOC_ADDR_APB4_APU_BASE, 27);
$display("SoC topology APB4 routing test passed");
$finish;
end
+271
View File
@@ -0,0 +1,271 @@
`timescale 1ns / 1ps
`include "apu_define.svh"
`include "soc_irq_config.svh"
module apu_irq_topology_tb;
localparam logic [31:0] ApuBase = 32'h1001_3000;
localparam logic [11:0] Resource7Owner = 12'h1e0;
localparam logic [11:0] Resource7Control = 12'h1e4;
localparam logic [11:0] Resource7Fault = 12'h1ec;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic s_apu_idle;
logic s_apu_irq_raw;
logic [ 7:0] s_resource_idle;
logic [ 7:0] s_resource_block_ack;
logic [ 7:0] s_resource_irq_raw;
logic [ 7:0][1:0] s_resource_owner;
logic [ 7:0] s_resource_owner_lock;
logic [ 7:0] s_resource_quiesce;
logic [ 7:0] s_resource_reset;
logic [ 7:0] s_resource_irq_lp;
logic [ 7:0] s_resource_irq_hp;
logic [ 6:0] s_resource_irq_lp_compact;
logic [ 6:0] s_resource_irq_hp_compact;
logic s_resource_fault_irq;
logic s_cache_clean;
logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] s_apb4_periph_irq;
logic [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] s_apb4_system_irq;
logic [ `SOC_IRQ_VECTOR_WIDTH-1:0] s_irq;
logic [ 31:0] s_hp_plic_source;
logic [ 1:0] s_hp_plic_context_irq;
logic [ 31:0] s_value;
apb4_if u_apu_apb4_if (
.pclk (clk_i),
.presetn(rst_n_i)
);
apb4_if u_resource_apb4_if (
.pclk (clk_i),
.presetn(rst_n_i)
);
apb4_if u_plic_apb4_if (
.pclk (clk_i),
.presetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
assign s_resource_idle = {s_apu_idle, 7'h7f};
assign s_resource_block_ack = {
s_apu_idle && (s_resource_quiesce[7] || s_resource_reset[7]), 7'd0
};
assign s_resource_irq_raw = {s_apu_irq_raw, 7'd0};
assign s_resource_irq_lp_compact = {s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]};
assign s_resource_irq_hp_compact = {s_resource_irq_hp[7:6], s_resource_irq_hp[4:0]};
assign s_apb4_periph_irq = {s_resource_irq_lp_compact[6], 23'd0};
assign s_apb4_system_irq = '0;
assign s_hp_plic_source = {21'd0, s_resource_irq_hp_compact[6], 10'd0};
`include "soc_irq_wiring.svh"
apb4_apu u_apu (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.owner_i (s_resource_owner[7]),
.owner_lock_i (s_resource_owner_lock[7]),
.quiesce_i (s_resource_quiesce[7]),
.resource_reset_i(s_resource_reset[7]),
.apb4 (u_apu_apb4_if),
.idle_o (s_apu_idle),
.irq_o (s_apu_irq_raw)
);
resource_controller #(
.ResourceCount(8)
) u_resource_controller (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.idle_i (s_resource_idle),
.block_ack_i (s_resource_block_ack),
.irq_i (s_resource_irq_raw),
.cache_request_i(1'b0),
.cache_clean_o (s_cache_clean),
.owner_o (s_resource_owner),
.owner_lock_o (s_resource_owner_lock),
.quiesce_o (s_resource_quiesce),
.reset_o (s_resource_reset),
.irq_lp_o (s_resource_irq_lp),
.irq_hp_o (s_resource_irq_hp),
.fault_irq_o (s_resource_fault_irq),
.apb4 (u_resource_apb4_if)
);
apb4_plic u_hp_plic (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.source_i (s_hp_plic_source),
.apb4 (u_plic_apb4_if),
.context_irq_o(s_hp_plic_context_irq)
);
task automatic drive_apb_idle;
begin
u_apu_apb4_if.paddr = 32'd0;
u_apu_apb4_if.pprot = 3'd0;
u_apu_apb4_if.psel = 1'b0;
u_apu_apb4_if.penable = 1'b0;
u_apu_apb4_if.pwrite = 1'b0;
u_apu_apb4_if.pwdata = 32'd0;
u_apu_apb4_if.pstrb = 4'd0;
u_resource_apb4_if.paddr = 32'd0;
u_resource_apb4_if.pprot = 3'd0;
u_resource_apb4_if.psel = 1'b0;
u_resource_apb4_if.penable = 1'b0;
u_resource_apb4_if.pwrite = 1'b0;
u_resource_apb4_if.pwdata = 32'd0;
u_resource_apb4_if.pstrb = 4'd0;
u_plic_apb4_if.paddr = 32'd0;
u_plic_apb4_if.pprot = 3'd0;
u_plic_apb4_if.psel = 1'b0;
u_plic_apb4_if.penable = 1'b0;
u_plic_apb4_if.pwrite = 1'b0;
u_plic_apb4_if.pwdata = 32'd0;
u_plic_apb4_if.pstrb = 4'd0;
end
endtask
task automatic apu_write(input logic [11:0] offset_i, input logic [31:0] data_i);
begin
@(negedge clk_i);
u_apu_apb4_if.paddr = ApuBase + offset_i;
u_apu_apb4_if.pwdata = data_i;
u_apu_apb4_if.pstrb = 4'hf;
u_apu_apb4_if.pwrite = 1'b1;
u_apu_apb4_if.psel = 1'b1;
u_apu_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_apu_apb4_if.penable = 1'b1;
while (!u_apu_apb4_if.pready) @(negedge clk_i);
if (u_apu_apb4_if.pslverr) $fatal(1, "APU topology write failed at %h", offset_i);
@(negedge clk_i);
u_apu_apb4_if.psel = 1'b0;
u_apu_apb4_if.penable = 1'b0;
u_apu_apb4_if.pwrite = 1'b0;
u_apu_apb4_if.pstrb = 4'd0;
end
endtask
task automatic resource_write(input logic [11:0] offset_i, input logic [31:0] data_i,
input logic expected_err_i);
begin
@(negedge clk_i);
u_resource_apb4_if.paddr = {20'd0, offset_i};
u_resource_apb4_if.pwdata = data_i;
u_resource_apb4_if.pstrb = 4'hf;
u_resource_apb4_if.pwrite = 1'b1;
u_resource_apb4_if.psel = 1'b1;
u_resource_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_resource_apb4_if.penable = 1'b1;
while (!u_resource_apb4_if.pready) @(negedge clk_i);
if (u_resource_apb4_if.pslverr != expected_err_i) begin
$fatal(1, "Resource topology write response mismatch at %h", offset_i);
end
@(negedge clk_i);
u_resource_apb4_if.psel = 1'b0;
u_resource_apb4_if.penable = 1'b0;
u_resource_apb4_if.pwrite = 1'b0;
u_resource_apb4_if.pstrb = 4'd0;
end
endtask
task automatic plic_write(input logic [25:0] offset_i, input logic [31:0] data_i);
begin
@(negedge clk_i);
u_plic_apb4_if.paddr = {6'd0, offset_i};
u_plic_apb4_if.pwdata = data_i;
u_plic_apb4_if.pstrb = 4'hf;
u_plic_apb4_if.pwrite = 1'b1;
u_plic_apb4_if.psel = 1'b1;
u_plic_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_plic_apb4_if.penable = 1'b1;
while (!u_plic_apb4_if.pready) @(negedge clk_i);
if (u_plic_apb4_if.pslverr) $fatal(1, "PLIC topology write failed at %h", offset_i);
@(negedge clk_i);
u_plic_apb4_if.psel = 1'b0;
u_plic_apb4_if.penable = 1'b0;
u_plic_apb4_if.pwrite = 1'b0;
u_plic_apb4_if.pstrb = 4'd0;
end
endtask
task automatic plic_read(input logic [25:0] offset_i, output logic [31:0] data_o);
begin
@(negedge clk_i);
u_plic_apb4_if.paddr = {6'd0, offset_i};
u_plic_apb4_if.pstrb = 4'd0;
u_plic_apb4_if.pwrite = 1'b0;
u_plic_apb4_if.psel = 1'b1;
u_plic_apb4_if.penable = 1'b0;
@(negedge clk_i);
u_plic_apb4_if.penable = 1'b1;
while (!u_plic_apb4_if.pready) @(negedge clk_i);
if (u_plic_apb4_if.pslverr) $fatal(1, "PLIC topology read failed at %h", offset_i);
data_o = u_plic_apb4_if.prdata;
@(negedge clk_i);
u_plic_apb4_if.psel = 1'b0;
u_plic_apb4_if.penable = 1'b0;
end
endtask
initial begin
drive_apb_idle();
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
plic_write(26'h000028, 32'd3);
plic_write(26'h002000, 32'h0000_0400);
plic_write(26'h200000, 32'd0);
apu_write(`APB4_APU__IRQ_ENABLE, 32'h0000_0001);
apu_write(`APB4_APU__IRQ_TEST, 32'h0000_0001);
repeat (2) @(posedge clk_i);
#1;
if ((s_resource_owner[7] != 2'd0) || !s_resource_irq_lp[7] || s_resource_irq_hp[7] ||
!s_apb4_periph_irq[23] || !s_irq[31] || s_hp_plic_source[10] ||
s_hp_plic_context_irq[0]) begin
$fatal(1, "APU event was not delivered exclusively to LP IRQ31");
end
resource_write(Resource7Control, 32'h0000_0001, 1'b0);
resource_write(Resource7Owner, 32'h0000_0101, 1'b0);
repeat (2) @(posedge clk_i);
#1;
if ((s_resource_owner[7] != 2'd1) || !s_resource_owner_lock[7] ||
s_resource_irq_lp[7] || !s_resource_irq_hp[7] || s_apb4_periph_irq[23] ||
s_irq[31] || !s_hp_plic_source[10] || !s_hp_plic_context_irq[0]) begin
$fatal(1, "APU event was not delivered exclusively to HP PLIC source 10");
end
plic_read(26'h200004, s_value);
if (s_value != 32'd10) $fatal(1, "HP PLIC did not claim APU source 10");
resource_write(Resource7Owner, 32'd0, 1'b1);
if ((s_resource_owner[7] != 2'd1) || !s_resource_owner_lock[7] || !s_resource_fault_irq) begin
$fatal(1, "APU owner lock did not preserve HP ownership");
end
resource_write(Resource7Fault, 32'h0000_0001, 1'b0);
if (s_resource_fault_irq) $fatal(1, "APU resource fault did not clear");
resource_write(Resource7Control, 32'h0000_0003, 1'b0);
repeat (2) @(posedge clk_i);
#1;
if (s_resource_irq_lp[7] || s_resource_irq_hp[7] || s_apb4_periph_irq[23] || s_irq[31] ||
s_hp_plic_source[10]) begin
$fatal(1, "APU resource reset did not mask both interrupt routes");
end
if (s_resource_fault_irq || s_cache_clean) begin
$fatal(1, "APU topology test left an unrelated controller output asserted");
end
$display("APU-P1 integrated IRQ ownership topology passed");
$finish;
end
initial begin
repeat (1000) @(posedge clk_i);
$fatal(1, "APU-P1 IRQ ownership topology timed out");
end
endmodule
+542
View File
@@ -0,0 +1,542 @@
`timescale 1ns / 1ps
`include "apu_define.svh"
module apu_reg_tb;
localparam logic [31:0] ApuBase = 32'h1001_3000;
localparam int unsigned RegisterCount = 95;
localparam logic [1:0] AccessRo = 2'd0;
localparam logic [1:0] AccessWo = 2'd1;
localparam logic [1:0] AccessRw = 2'd2;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [ 1:0] owner_i = 2'd0;
logic owner_lock_i = 1'b0;
logic quiesce_i = 1'b0;
logic resource_reset_i = 1'b0;
logic idle_o;
logic irq_o;
logic [31:0] s_value;
logic [11:0] s_reg_offset [RegisterCount];
logic [ 1:0] s_reg_access [RegisterCount];
logic [31:0] s_reg_reset [RegisterCount];
logic s_reg_full_strobe [RegisterCount];
int unsigned s_reg_count;
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
apb4_apu u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.owner_i (owner_i),
.owner_lock_i (owner_lock_i),
.quiesce_i (quiesce_i),
.resource_reset_i(resource_reset_i),
.apb4 (apb4),
.idle_o (idle_o),
.irq_o (irq_o)
);
function automatic logic [31:0] legal_write_value(input logic [11:0] offset_i);
case (offset_i)
`APB4_APU__IRQ_STATE: legal_write_value = 32'h0000_07ff;
`APB4_APU__IRQ_ENABLE: legal_write_value = 32'h0000_0005;
`APB4_APU__ERROR_STATUS: legal_write_value = 32'h0000_0001;
`APB4_APU__SEQUENCER_TIMEOUT: legal_write_value = 32'h1234_5678;
`APB4_APU__STREAM_ROUTE: legal_write_value = 32'd0;
`APB4_APU__READ_BASE: legal_write_value = 32'h3000_0000;
`APB4_APU__READ_LIMIT: legal_write_value = 32'h3000_ffff;
`APB4_APU__WRITE_BASE: legal_write_value = 32'h3001_0000;
`APB4_APU__WRITE_LIMIT: legal_write_value = 32'h3001_ffff;
`APB4_APU__DMA_TIMEOUT: legal_write_value = 32'h8765_4321;
`APB4_APU__MC_IMAGE_ADDRESS: legal_write_value = 32'h3002_0000;
`APB4_APU__MC_IMAGE_SIZE: legal_write_value = 32'h0000_0040;
`APB4_APU__MC_EXPECTED_CRC: legal_write_value = 32'ha5a5_5a5a;
`APB4_APU__JOB_CONTROL: legal_write_value = 32'h0000_0121;
`APB4_APU__JOB_INPUT_ADDRESS: legal_write_value = 32'h3003_0000;
`APB4_APU__JOB_INPUT_LENGTH: legal_write_value = 32'h0000_0100;
`APB4_APU__JOB_OUTPUT_ADDRESS: legal_write_value = 32'h3003_1000;
`APB4_APU__JOB_OUTPUT_CAPACITY: legal_write_value = 32'h0000_1000;
`APB4_APU__JOB_INPUT_CONFIG: legal_write_value = 32'h0012_3456;
`APB4_APU__JOB_OUTPUT_CONFIG: legal_write_value = 32'h0001_2345;
`APB4_APU__JOB_FLAGS: legal_write_value = 32'h0000_0001;
`APB4_APU__RING_BASE: legal_write_value = 32'h3004_0000;
`APB4_APU__RING_SIZE: legal_write_value = 32'h0000_0008;
`APB4_APU__RING_TAIL: legal_write_value = 32'h0000_0003;
`APB4_APU__RING_CONTROL: legal_write_value = 32'h0000_0001;
`APB4_APU__RING_COALESCE: legal_write_value = 32'h0004_0002;
`APB4_APU__KWS_MODEL_ADDRESS: legal_write_value = 32'h3005_0000;
`APB4_APU__KWS_MODEL_SIZE: legal_write_value = 32'h0000_0100;
`APB4_APU__KWS_MODEL_EXPECTED_CRC: legal_write_value = 32'h5a5a_a5a5;
`APB4_APU__KWS_CONTROL: legal_write_value = 32'h0000_0004;
`APB4_APU__KWS_CONFIG: legal_write_value = 32'h0000_0590;
`APB4_APU__PERF_CONTROL: legal_write_value = 32'h0000_0001;
default: legal_write_value = 32'd0;
endcase
endfunction
function automatic logic [31:0] legal_readback_value(input logic [11:0] offset_i);
case (offset_i)
`APB4_APU__IRQ_STATE, `APB4_APU__ERROR_STATUS, `APB4_APU__STREAM_ROUTE,
`APB4_APU__KWS_CONTROL:
legal_readback_value = 32'd0;
default: legal_readback_value = legal_write_value(offset_i);
endcase
endfunction
function automatic logic [31:0] reset_or_preserved_value(input logic [11:0] offset_i,
input logic [31:0] reset_i);
case (offset_i)
`APB4_APU__READ_BASE, `APB4_APU__READ_LIMIT, `APB4_APU__WRITE_BASE, `APB4_APU__WRITE_LIMIT:
reset_or_preserved_value = legal_write_value(offset_i);
default: reset_or_preserved_value = reset_i;
endcase
endfunction
task automatic add_register(input logic [11:0] offset_i, input logic [1:0] access_i,
input logic [31:0] reset_i, input logic full_strobe_i);
begin
if (s_reg_count >= RegisterCount) $fatal(1, "APU register table overflow");
s_reg_offset[s_reg_count] = offset_i;
s_reg_access[s_reg_count] = access_i;
s_reg_reset[s_reg_count] = reset_i;
s_reg_full_strobe[s_reg_count] = full_strobe_i;
s_reg_count++;
end
endtask
task automatic initialize_register_table;
begin
s_reg_count = 0;
add_register(`APB4_APU__IP_ID, AccessRo, 32'h4150_5530, 1'b0);
add_register(`APB4_APU__IP_VERSION, AccessRo, 32'h0001_0000, 1'b0);
add_register(`APB4_APU__CAPABILITY0, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__CAPABILITY1, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__COMMAND, AccessWo, 32'd0, 1'b1);
add_register(`APB4_APU__STATUS, AccessRo, 32'h0000_0100, 1'b0);
add_register(`APB4_APU__IRQ_STATE, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__IRQ_ENABLE, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__IRQ_TEST, AccessWo, 32'd0, 1'b1);
add_register(`APB4_APU__ERROR_STATUS, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__ERROR_ADDRESS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__ERROR_DETAIL, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__SEQUENCER_TIMEOUT, AccessRw, 32'h0000_ffff, 1'b0);
add_register(`APB4_APU__STREAM_ROUTE, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__STREAM_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__OWNER_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__READ_BASE, AccessRw, 32'hffff_ffff, 1'b1);
add_register(`APB4_APU__READ_LIMIT, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__WRITE_BASE, AccessRw, 32'hffff_ffff, 1'b1);
add_register(`APB4_APU__WRITE_LIMIT, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__DMA_TIMEOUT, AccessRw, 32'h0000_ffff, 1'b0);
add_register(`APB4_APU__ABI_DIGEST, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__SEQUENCER_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__SEQUENCER_RETIRED, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_IMAGE_ADDRESS, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__MC_IMAGE_SIZE, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__MC_EXPECTED_CRC, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__MC_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_ABI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_BUILD_ID_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_BUILD_ID_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_LOCK, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_ACTUAL_CRC, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__MC_LOAD_COUNT, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_CONTROL, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_INPUT_ADDRESS, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__JOB_INPUT_LENGTH, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__JOB_OUTPUT_ADDRESS, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__JOB_OUTPUT_CAPACITY, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__JOB_INPUT_CONFIG, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_OUTPUT_CONFIG, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_FLAGS, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_INPUT_USED, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_OUTPUT_BYTES, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_FRAMES, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_SOURCE_INFO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_CYCLES, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__JOB_DETAIL, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__RING_BASE, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__RING_SIZE, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__RING_HEAD, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__RING_TAIL, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__RING_CONTROL, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__RING_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__RING_COMPLETED, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__RING_COALESCE, AccessRw, 32'h0001_0001, 1'b1);
add_register(`APB4_APU__RING_DOORBELL, AccessWo, 32'd0, 1'b1);
add_register(`APB4_APU__KWS_MODEL_ADDRESS, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__KWS_MODEL_SIZE, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__KWS_MODEL_EXPECTED_CRC, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__KWS_CONTROL, AccessRw, 32'd0, 1'b1);
add_register(`APB4_APU__KWS_CONFIG, AccessRw, 32'h0000_0380, 1'b0);
add_register(`APB4_APU__KWS_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_RESULT, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_TIMESTAMP_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_TIMESTAMP_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_FRAME_COUNT, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_INFERENCE_COUNT, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_HIT_COUNT, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_OVERRUN_COUNT, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_MODEL_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__KWS_MODEL_ACTUAL_CRC, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_CONTROL, AccessRw, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_STATUS, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_ACTIVE_CYCLES_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_ACTIVE_CYCLES_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_INPUT_BYTES_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_INPUT_BYTES_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_OUTPUT_BYTES_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_OUTPUT_BYTES_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_DECODED_FRAMES_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_DECODED_FRAMES_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_DMA_READ_STALLS_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_DMA_READ_STALLS_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_DMA_WRITE_STALLS_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_DMA_WRITE_STALLS_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_STREAM_STALLS_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_STREAM_STALLS_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_SEQUENCER_INSTR_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_SEQUENCER_INSTR_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_KWS_CYCLES_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_KWS_CYCLES_HI, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_FAULTS_LO, AccessRo, 32'd0, 1'b0);
add_register(`APB4_APU__PERF_FAULTS_HI, AccessRo, 32'd0, 1'b0);
if (s_reg_count != RegisterCount) begin
$fatal(1, "APU register table has %0d entries, expected %0d", s_reg_count, RegisterCount);
end
end
endtask
task automatic drive_apb_idle;
begin
apb4.paddr = 32'd0;
apb4.pprot = 3'd0;
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.pwdata = 32'd0;
apb4.pstrb = 4'd0;
end
endtask
task automatic hard_reset;
begin
@(negedge clk_i);
drive_apb_idle();
owner_i = 2'd0;
owner_lock_i = 1'b0;
quiesce_i = 1'b0;
resource_reset_i = 1'b0;
rst_n_i = 1'b0;
repeat (2) @(posedge clk_i);
@(negedge clk_i);
rst_n_i = 1'b1;
end
endtask
task automatic apb_write(input logic [11:0] offset_i, input logic [31:0] data_i,
input logic [3:0] strobe_i, input logic expected_err_i);
int unsigned s_wait_cycles;
logic s_response_err;
begin
@(negedge clk_i);
apb4.paddr = ApuBase + offset_i;
apb4.pwdata = data_i;
apb4.pstrb = strobe_i;
apb4.pwrite = 1'b1;
apb4.psel = 1'b1;
apb4.penable = 1'b0;
#1;
if (apb4.pready) $fatal(1, "APU PREADY asserted during write setup at %h", offset_i);
@(negedge clk_i);
apb4.penable = 1'b1;
s_wait_cycles = 0;
#1;
while (!apb4.pready) begin
s_wait_cycles++;
if (s_wait_cycles > 4) $fatal(1, "APU write wait timeout at %h", offset_i);
@(negedge clk_i);
#1;
end
if (s_wait_cycles != 1) begin
$fatal(1, "APU write wait count mismatch at %h: %0d", offset_i, s_wait_cycles);
end
if (apb4.pslverr != expected_err_i) $fatal(1, "APU write response mismatch at %h", offset_i);
s_response_err = apb4.pslverr;
#2;
if (!apb4.pready || (apb4.pslverr != s_response_err)) begin
$fatal(1, "APU write response was not retained through completion at %h", offset_i);
end
@(negedge clk_i);
drive_apb_idle();
end
endtask
task automatic apb_read(input logic [11:0] offset_i, output logic [31:0] data_o,
input logic expected_err_i);
int unsigned s_wait_cycles;
logic [31:0] s_response_data;
logic s_response_err;
begin
@(negedge clk_i);
apb4.paddr = ApuBase + offset_i;
apb4.pstrb = 4'd0;
apb4.pwrite = 1'b0;
apb4.psel = 1'b1;
apb4.penable = 1'b0;
#1;
if (apb4.pready) $fatal(1, "APU PREADY asserted during read setup at %h", offset_i);
@(negedge clk_i);
apb4.penable = 1'b1;
s_wait_cycles = 0;
#1;
while (!apb4.pready) begin
s_wait_cycles++;
if (s_wait_cycles > 4) $fatal(1, "APU read wait timeout at %h", offset_i);
@(negedge clk_i);
#1;
end
if (s_wait_cycles != 1) begin
$fatal(1, "APU read wait count mismatch at %h: %0d", offset_i, s_wait_cycles);
end
if (apb4.pslverr != expected_err_i) $fatal(1, "APU read response mismatch at %h", offset_i);
s_response_data = apb4.prdata;
s_response_err = apb4.pslverr;
#2;
if (!apb4.pready || (apb4.prdata != s_response_data) ||
(apb4.pslverr != s_response_err)) begin
$fatal(1, "APU read response was not retained through completion at %h", offset_i);
end
data_o = s_response_data;
@(negedge clk_i);
drive_apb_idle();
end
endtask
task automatic expect_read(input logic [11:0] offset_i, input logic [31:0] expected_i);
begin
apb_read(offset_i, s_value, 1'b0);
if (s_value != expected_i) begin
$fatal(1, "APU read mismatch at %h: got %h expected %h", offset_i, s_value, expected_i);
end
end
endtask
task automatic program_rw_registers;
begin
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
if (s_reg_access[register_index] == AccessRw) begin
apb_write(s_reg_offset[register_index], legal_write_value(s_reg_offset[register_index]),
4'hf, 1'b0);
end
end
end
endtask
task automatic check_reset_state(input logic preserve_acl_i);
logic [31:0] s_expected;
begin
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
if (s_reg_access[register_index] != AccessWo) begin
s_expected = preserve_acl_i ?
reset_or_preserved_value(s_reg_offset[register_index], s_reg_reset[register_index]) :
s_reg_reset[register_index];
expect_read(s_reg_offset[register_index], s_expected);
end
end
end
endtask
task automatic check_rejected_write(input logic [11:0] offset_i,
input logic [31:0] rejected_value_i,
input logic [5:0] error_code_i);
logic [31:0] s_before;
begin
hard_reset();
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h1234_5678, 4'hf, 1'b0);
if ((offset_i != `APB4_APU__COMMAND) && (offset_i != `APB4_APU__IRQ_TEST) &&
(offset_i != `APB4_APU__RING_DOORBELL)) begin
apb_read(offset_i, s_before, 1'b0);
end else begin
s_before = 32'd0;
end
apb_write(offset_i, rejected_value_i, 4'hf, 1'b1);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h1234_5678);
expect_read(`APB4_APU__ERROR_STATUS, 32'd1 | (32'(error_code_i) << 1));
expect_read(`APB4_APU__ERROR_ADDRESS, ApuBase + offset_i);
if ((offset_i != `APB4_APU__COMMAND) && (offset_i != `APB4_APU__IRQ_TEST) &&
(offset_i != `APB4_APU__RING_DOORBELL) && (offset_i != `APB4_APU__IRQ_STATE) &&
(offset_i != `APB4_APU__ERROR_STATUS) && (offset_i != `APB4_APU__ERROR_ADDRESS) &&
(offset_i != `APB4_APU__ERROR_DETAIL)) begin
expect_read(offset_i, s_before);
end
end
endtask
initial begin
initialize_register_table();
drive_apb_idle();
hard_reset();
if (!idle_o || irq_o) $fatal(1, "APU reset lifecycle outputs mismatch");
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
hard_reset();
if (s_reg_access[register_index] == AccessWo) begin
apb_read(s_reg_offset[register_index], s_value, 1'b1);
end else begin
expect_read(s_reg_offset[register_index], s_reg_reset[register_index]);
end
end
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
hard_reset();
case (s_reg_access[register_index])
AccessRo: begin
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h1234_5678, 4'hf, 1'b0);
apb_write(s_reg_offset[register_index], 32'd0, 4'hf, 1'b1);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h1234_5678);
if ((s_reg_offset[register_index] != `APB4_APU__ERROR_ADDRESS) &&
(s_reg_offset[register_index] != `APB4_APU__ERROR_DETAIL)) begin
expect_read(s_reg_offset[register_index], s_reg_reset[register_index]);
end
end
AccessWo: begin
apb_read(s_reg_offset[register_index], s_value, 1'b1);
hard_reset();
if (s_reg_offset[register_index] == `APB4_APU__COMMAND) begin
apb_write(s_reg_offset[register_index], 32'h0000_0004, 4'hf, 1'b0);
end else if (s_reg_offset[register_index] == `APB4_APU__IRQ_TEST) begin
apb_write(s_reg_offset[register_index], 32'd0, 4'hf, 1'b0);
end else begin
apb_write(s_reg_offset[register_index], 32'h0000_0001, 4'hf, 1'b1);
end
end
AccessRw: begin
apb_write(s_reg_offset[register_index], legal_write_value(s_reg_offset[register_index]),
4'hf, 1'b0);
expect_read(s_reg_offset[register_index], legal_readback_value(
s_reg_offset[register_index]));
end
default: $fatal(1, "APU register table has invalid access class");
endcase
end
hard_reset();
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h0000_00aa, 4'h1, 1'b0);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h0000_ffaa);
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h0000_bb00, 4'h2, 1'b0);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h0000_bbaa);
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h00cc_0000, 4'h4, 1'b0);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h00cc_bbaa);
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'hdd00_0000, 4'h8, 1'b0);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'hddcc_bbaa);
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
if (s_reg_full_strobe[register_index]) begin
hard_reset();
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h1234_5678, 4'hf, 1'b0);
apb_write(s_reg_offset[register_index], legal_write_value(s_reg_offset[register_index]),
4'h7, 1'b1);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h1234_5678);
if (s_reg_access[register_index] == AccessRw) begin
expect_read(s_reg_offset[register_index], s_reg_reset[register_index]);
end
end
end
check_rejected_write(`APB4_APU__COMMAND, 32'h0000_0080, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
for (int bit_index = 0; bit_index < 6; bit_index++) begin
if ((bit_index != `APB4_APU__COMMAND_SOFT_RESET) &&
(bit_index != `APB4_APU__COMMAND_CLEAR_COUNTERS)) begin
check_rejected_write(`APB4_APU__COMMAND, 32'd1 << bit_index,
`APB4_APU__ERROR_CODE_UNSUPPORTED);
end
end
check_rejected_write(`APB4_APU__IRQ_STATE, 32'h0000_0800, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__IRQ_ENABLE, 32'h0000_0800,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__IRQ_TEST, 32'h0000_0800, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__ERROR_STATUS, 32'h0000_0002,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'd0, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__STREAM_ROUTE, 32'h0000_0001, `APB4_APU__ERROR_CODE_UNSUPPORTED);
check_rejected_write(`APB4_APU__STREAM_ROUTE, 32'h0000_0004, `APB4_APU__ERROR_CODE_UNSUPPORTED);
check_rejected_write(`APB4_APU__DMA_TIMEOUT, 32'd0, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__MC_IMAGE_ADDRESS, 32'h3002_0001,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__MC_IMAGE_SIZE, 32'd0, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__JOB_CONTROL, 32'h8000_0000,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__JOB_INPUT_CONFIG, 32'h8000_0000,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__JOB_OUTPUT_CONFIG, 32'h8000_0000,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__JOB_FLAGS, 32'h0000_0002, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__RING_BASE, 32'h3004_0001, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__RING_SIZE, 32'h0000_0003, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__RING_TAIL, 32'h0000_0100, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__RING_CONTROL, 32'h0000_0004,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__RING_COALESCE, 32'd0, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__RING_DOORBELL, 32'h0000_0001,
`APB4_APU__ERROR_CODE_UNSUPPORTED);
check_rejected_write(`APB4_APU__KWS_MODEL_ADDRESS, 32'h3005_0001,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__KWS_MODEL_SIZE, 32'd0, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__KWS_CONTROL, 32'h0000_0001, `APB4_APU__ERROR_CODE_UNSUPPORTED);
check_rejected_write(`APB4_APU__KWS_CONTROL, 32'h0000_0002, `APB4_APU__ERROR_CODE_UNSUPPORTED);
check_rejected_write(`APB4_APU__KWS_CONTROL, 32'h0000_0008,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__KWS_CONFIG, 32'h0000_0080,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__PERF_CONTROL, 32'h0000_0008,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
hard_reset();
apb_write(`APB4_APU__IRQ_TEST, 32'h0000_0001, 4'hf, 1'b0);
force u_dut.u_apu_reg.s_irq_set = 11'h001;
apb_write(`APB4_APU__IRQ_STATE, 32'h0000_0001, 4'h1, 1'b0);
release u_dut.u_apu_reg.s_irq_set;
expect_read(`APB4_APU__IRQ_STATE, 32'h0000_0001);
apb_write(`APB4_APU__IRQ_STATE, 32'h0000_0001, 4'h1, 1'b0);
expect_read(`APB4_APU__IRQ_STATE, 32'd0);
hard_reset();
program_rw_registers();
apb_write(`APB4_APU__COMMAND, 32'h0000_0004, 4'hf, 1'b0);
check_reset_state(1'b1);
hard_reset();
program_rw_registers();
@(negedge clk_i);
resource_reset_i = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
resource_reset_i = 1'b0;
check_reset_state(1'b1);
hard_reset();
owner_i = 2'd1;
owner_lock_i = 1'b1;
quiesce_i = 1'b1;
expect_read(`APB4_APU__OWNER_STATUS, 32'h0000_0301);
apb_read(12'h060, s_value, 1'b1);
apb_read(12'h001, s_value, 1'b1);
$display("APU-P1 complete APB register matrix passed");
$finish;
end
initial begin
repeat (20000) @(posedge clk_i);
$fatal(1, "APU-P1 APB register matrix timed out");
end
endmodule
+40
View File
@@ -180,6 +180,41 @@ module axi4_interconnect_tb;
end
endtask
task automatic issue_hp_apu_write(input logic [31:0] address, input logic [1:0] expected_response,
input logic expected_access_fault);
begin
@(negedge clk_i);
masters[6].awaddr = address;
masters[6].awlen = 8'd0;
masters[6].awvalid = 1'b1;
do @(posedge clk_i); while (!masters[6].awready);
@(negedge clk_i);
masters[6].awvalid = 1'b0;
masters[6].wdata = 32'h1234_5678;
masters[6].wstrb = 4'hf;
masters[6].wlast = 1'b1;
masters[6].wvalid = 1'b1;
do @(posedge clk_i); while (!masters[6].wready);
@(negedge clk_i);
masters[6].wvalid = 1'b0;
masters[6].bready = 1'b1;
while (!masters[6].bvalid) @(negedge clk_i);
#1;
if ((masters[6].bresp != expected_response) ||
(fault_valid_o != expected_access_fault) ||
(expected_access_fault &&
(!fault_access_o || (fault_addr_o != address) || (fault_master_o != 3'd6) ||
(fault_code_o != `RIB_RESP_PROTERR)))) begin
$fatal(
1,
"HP APU access policy mismatch at %h: resp=%0d fault=%0d access=%0d master=%0d code=%0d",
address, masters[6].bresp, fault_valid_o, fault_access_o, fault_master_o, fault_code_o);
end
@(negedge clk_i);
masters[6].bready = 1'b0;
end
endtask
task automatic issue_management_with_idle_sdio;
integer cycles;
begin
@@ -347,7 +382,12 @@ module axi4_interconnect_tb;
issue_management_with_idle_sdio();
issue_mgmt_error_read(32'hA000_0000, 8'd0, `AXI4_RESP_DECODE_ERROR, `RIB_RESP_DECERR);
issue_mgmt_error_read(32'h3000_0000, 8'd16, `AXI4_RESP_SLAVE_ERROR, `RIB_RESP_BURSTERR);
`ifdef MINI_PRODUCT
issue_hp_apu_write(32'h1001_301C, `AXI4_RESP_OKAY, 1'b0);
issue_hp_apu_write(32'h1001_3040, `AXI4_RESP_SLAVE_ERROR, 1'b1);
`else
issue_denied_user_write(32'h1000_B000);
`endif
issue_contending_sdio_faults();
issue_hp_accesses();
+21 -9
View File
@@ -3,16 +3,17 @@
module resource_controller_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [ 5:0] idle_i = '0;
logic [ 5:0] block_ack_i = '0;
logic [ 5:0] irq_i = '0;
logic [ 7:0] idle_i = '0;
logic [ 7:0] block_ack_i = '0;
logic [ 7:0] irq_i = '0;
logic cache_request_i = 1'b0;
logic cache_clean_o;
logic [ 5:0][1:0] owner_o;
logic [ 5:0] quiesce_o;
logic [ 5:0] reset_o;
logic [ 5:0] irq_lp_o;
logic [ 5:0] irq_hp_o;
logic [ 7:0][1:0] owner_o;
logic [ 7:0] owner_lock_o;
logic [ 7:0] quiesce_o;
logic [ 7:0] reset_o;
logic [ 7:0] irq_lp_o;
logic [ 7:0] irq_hp_o;
logic fault_irq_o;
logic [31:0] read_data;
@@ -32,6 +33,7 @@ module resource_controller_tb;
.cache_request_i(cache_request_i),
.cache_clean_o (cache_clean_o),
.owner_o (owner_o),
.owner_lock_o (owner_lock_o),
.quiesce_o (quiesce_o),
.reset_o (reset_o),
.irq_lp_o (irq_lp_o),
@@ -90,7 +92,7 @@ module resource_controller_tb;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
idle_i = 6'h3F;
idle_i = 8'hFF;
apb_read(12'h000, read_data);
if (read_data != 32'h5253_4354) $fatal(1, "resource controller ID mismatch");
@@ -135,6 +137,16 @@ module resource_controller_tb;
$fatal(1, "resource lifecycle controls did not update");
end
irq_i[7] = 1'b1;
#1;
if (!irq_lp_o[7] || irq_hp_o[7]) $fatal(1, "APU reset owner routing mismatch");
block_ack_i[7] = 1'b1;
apb_write(12'h1E4, 32'h0000_0001, 1'b0);
apb_write(12'h1E0, 32'h0000_0101, 1'b0);
if ((owner_o[7] != 2'd1) || !owner_lock_o[7] || irq_lp_o[7] || !irq_hp_o[7]) begin
$fatal(1, "APU resource index 7 ownership or IRQ routing mismatch");
end
$display("Resource Controller ownership, IRQ, and cache handshake test passed");
$finish;
end
+2 -1
View File
@@ -43,6 +43,7 @@ module soc_irq_topology_tb;
20: expect_irq(32'd1 << 25);
21: expect_irq(32'd1 << 26);
22: expect_irq(32'd1 << 30);
23: expect_irq(32'd1 << 31);
default: expect_irq(32'd1 << (bit_index + 7));
endcase
end
@@ -70,7 +71,7 @@ module soc_irq_topology_tb;
$fatal(1, "SDIO core IRQ bits are not low when sources are low: IRQ10=%b IRQ21=%b",
s_irq[10], s_irq[21]);
end
if ((s_irq[31] !== 1'b0) || (s_irq[19:18] !== '0)) begin
if (s_irq[19:18] !== '0) begin
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq);
end
+137
View File
@@ -0,0 +1,137 @@
"""Directed verification for the APU-P1 APB4 register shell."""
from __future__ import annotations
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
TOPOLOGY = ROOT / "rtl/mini/integration/soc_topology.json"
TOPOLOGY_GENERATOR = ROOT / "rtl/mini/integration/generate_soc_topology.py"
MEMORY_MAP = ROOT / "rtl/mini/address_map/memory_map.json"
def test_apu_p1_apb_register_shell(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
sv2v = shutil.which("sv2v")
if iverilog is None or vvp is None or sv2v is None:
return
common = ROOT / "rtl/managed/clusterip/common/rtl"
multimedia = ROOT / "rtl/ip/multimedia"
source_list = tmp_path / "apu_reg.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{multimedia}",
str(common / "interface/apb4_if.sv"),
str(common / "utils/register.sv"),
str(multimedia / "apu_reg.sv"),
str(multimedia / "apb4_apu.sv"),
str(ROOT / "tests/rtl/apu_reg_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apu_reg_tb.v"
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
"-f",
str(source_list),
"--output",
str(converted),
],
check=True,
)
simulation = tmp_path / "apu_reg_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "apu_reg_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "APU-P1 complete APB register matrix passed" in result.stdout
def test_apu_p1_integrated_irq_ownership_topology(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
sv2v = shutil.which("sv2v")
if iverilog is None or vvp is None or sv2v is None:
return
common = ROOT / "rtl/managed/clusterip/common/rtl"
multimedia = ROOT / "rtl/ip/multimedia"
peripheral = ROOT / "rtl/ip/peripheral"
topology_output = tmp_path / "topology"
subprocess.run(
[
sys.executable,
str(TOPOLOGY_GENERATOR),
"--map",
str(TOPOLOGY),
"--memory-map",
str(MEMORY_MAP),
"--output-dir",
str(topology_output),
],
check=True,
)
source_list = tmp_path / "apu_irq_topology.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{topology_output / 'rtl'}",
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{multimedia}",
str(common / "interface/apb4_if.sv"),
str(common / "utils/register.sv"),
str(multimedia / "apu_reg.sv"),
str(multimedia / "apb4_apu.sv"),
str(ROOT / "rtl/mini/top/resource_controller.sv"),
str(peripheral / "apb4_plic.sv"),
str(ROOT / "tests/rtl/apu_irq_topology_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apu_irq_topology_tb.v"
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
"-f",
str(source_list),
"--output",
str(converted),
],
check=True,
)
simulation = tmp_path / "apu_irq_topology_tb"
subprocess.run(
[
iverilog,
"-g2012",
"-s",
"apu_irq_topology_tb",
"-o",
str(simulation),
str(converted),
],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "APU-P1 integrated IRQ ownership topology passed" in result.stdout
+66
View File
@@ -0,0 +1,66 @@
"""Keep the handwritten APU-P1 RTL and SDK register ABI synchronized."""
from __future__ import annotations
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
RTL_DEFINE = ROOT / "rtl/ip/multimedia/apu_define.svh"
C_HEADER = ROOT / "crt/include/retrosoc/hal/apu_regs.h"
REGISTER_TESTBENCH = ROOT / "tests/rtl/apu_reg_tb.sv"
def _rtl_values() -> dict[str, int]:
values: dict[str, int] = {}
pattern = re.compile(
r"^`define\s+APB4_APU__(\w+)\s+((?:\d+)'[hHdDbB][0-9a-fA-F_]+|\d+)\s*$"
)
for line in RTL_DEFINE.read_text(encoding="utf-8").splitlines():
match = pattern.match(line)
if match is None:
continue
name, literal = match.groups()
if "'" in literal:
_, value = literal.split("'", maxsplit=1)
radix = {"h": 16, "d": 10, "b": 2}[value[0].lower()]
values[name] = int(value[1:].replace("_", ""), radix)
else:
values[name] = int(literal, 10)
return values
def _c_values() -> dict[str, int]:
values: dict[str, int] = {}
pattern = re.compile(
r"^#define\s+RS_APU_ABI_(\w+)\s+"
r"(?:UINT32_C\((0[xX][0-9a-fA-F]+)\)|(\d+)[uU]?)\s*$"
)
for line in C_HEADER.read_text(encoding="utf-8").splitlines():
match = pattern.match(line)
if match is None:
continue
name, hexadecimal, decimal = match.groups()
values[name] = int(hexadecimal, 16) if hexadecimal is not None else int(decimal, 10)
return values
def test_apu_register_constants_match_expected_abi() -> None:
assert _c_values() == _rtl_values()
def test_apu_register_matrix_covers_each_offset_once() -> None:
offset_pattern = re.compile(
r"^`define\s+APB4_APU__(\w+)\s+12'[hH][0-9a-fA-F_]+\s*$"
)
table_pattern = re.compile(r"add_register\(`APB4_APU__(\w+),")
expected = [
match.group(1)
for line in RTL_DEFINE.read_text(encoding="utf-8").splitlines()
if (match := offset_pattern.match(line)) is not None
]
covered = table_pattern.findall(REGISTER_TESTBENCH.read_text(encoding="utf-8"))
assert len(covered) == len(set(covered))
assert set(covered) == set(expected)
+5 -1
View File
@@ -8,6 +8,8 @@ import subprocess
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
@@ -173,8 +175,9 @@ def test_axi4_word_bridge_supports_bursts_backpressure_and_errors(tmp_path: Path
assert "AXI4 word bridge test passed" in result.stdout
@pytest.mark.parametrize("product_mode", [False, True])
def test_axi4_interconnect_classifies_decode_protocol_and_access_errors(
tmp_path: Path,
tmp_path: Path, product_mode: bool
) -> None:
verilator = shutil.which("verilator")
if verilator is None:
@@ -205,6 +208,7 @@ def test_axi4_interconnect_classifies_decode_protocol_and_access_errors(
"-Wno-fatal",
"--top-module",
"axi4_interconnect_tb",
*(["-DMINI_PRODUCT"] if product_mode else []),
"-I" + str(memory_map / "rtl"),
"-I" + str(ROOT / "rtl/mini/top"),
"-I" + str(ROOT / "rtl/managed/clusterip/common/rtl"),
+3 -1
View File
@@ -125,7 +125,7 @@ def test_booter_prints_every_public_active_mmio_region() -> None:
assert "DMA(8CH)" in mmio_function
assert "DMA(6CH)" not in mmio_function
assert "RS_SOC_APB4_GA_BASE" not in mmio_function
assert "RS_SOC_APB4_APU_BASE" not in mmio_function
assert "RS_SOC_APB4_APU_BASE" in mmio_function
def test_sram_capacity_selects_one_consistent_hardware_software_window(tmp_path: Path) -> None:
@@ -173,9 +173,11 @@ def test_user_ip_is_always_emitted_for_the_fixed_platform(tmp_path: Path) -> Non
assert "`define SOC_ADDR_APB4_SDIO0_BASE 32'h1000F000" in rtl
assert "`define SOC_ADDR_APB4_SDIO1_BASE 32'h10015000" in rtl
assert "`define SOC_ADDR_APB4_USB2_BASE 32'h10016000" in rtl
assert "`define SOC_ADDR_APB4_APU_BASE 32'h10013000" in rtl
assert "`define SOC_ADDR_APB4_CRYPTO_BASE 32'h1000C000" in rtl
assert "#define RS_SOC_APB4_CRYPTO_BASE UINT32_C(0x1000C000)" in header
assert "#define RS_SOC_APB4_USB2_BASE UINT32_C(0x10016000)" in header
assert "#define RS_SOC_APB4_APU_BASE UINT32_C(0x10013000)" in header
def test_bootstrap_assembly_uses_the_generated_gpio_admin_base() -> None:
+25 -3
View File
@@ -77,7 +77,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
data_policy = (tmp_path / "rtl/soc_data_policy.svh").read_text(encoding="utf-8")
filelist = (tmp_path / "soc_topology.fl").read_text(encoding="utf-8")
assert interfaces.count("apb4_if u_") == 25
assert interfaces.count("apb4_if u_") == 26
assert "nmi_if" not in interfaces
assert "soc_nmi" not in interfaces
assert "assign s_psel_comb[17] = `SOC_ADDR_IS_APB4_I2C1(s_decode_addr);" in routes
@@ -93,6 +93,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "assign s_psel_comb[24] = `SOC_ADDR_IS_HP_ACLINT(s_decode_addr);" in routes
assert "assign s_psel_comb[25] = `SOC_ADDR_IS_HP_PLIC(s_decode_addr);" in routes
assert "assign s_psel_comb[26] = `SOC_ADDR_IS_APB4_JPEG(s_decode_addr);" in routes
assert "assign s_psel_comb[27] = `SOC_ADDR_IS_APB4_APU(s_decode_addr);" in routes
assert gpio.count("// GPIO") == 64
assert "u_uart1_if" not in gpio
assert "assign u_uart0_if.cts_n_i = u_gpio_if.di_i[0];" in gpio
@@ -141,7 +142,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert ".usb2_axi4(u_usb2_axi4_if)" in apb_periph_fabric
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
assert "`define SOC_USER_IRQ_MASK 32'h004EFBFC" in irq_config
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 23" in irq_config
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 24" in irq_config
assert "`define SOC_IRQ_APB4_SYSTEM_WIDTH 8" in irq_config
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
@@ -155,6 +156,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "assign irq_o[18] = s_crypto_irq;" in rib_irq
assert "assign irq_o[19] = resource_irq_lp_i[1];" in rib_irq
assert "assign irq_o[22] = resource_irq_lp_i[5];" in rib_irq
assert "assign irq_o[23] = resource_irq_lp_i[6];" in rib_irq
assert "assign irq_o[0] = pwm.irq_o;" in apb_irq
assert "assign irq_o[4] = s_rng_irq;" in apb_irq
assert "assign irq_o[5] = s_ext_l_irq;" in apb_irq
@@ -172,6 +174,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "s_irq[28] = s_apb4_system_irq[6];" in irq_wiring
assert "s_irq[29] = s_apb4_system_irq[7];" in irq_wiring
assert "s_irq[30] = s_apb4_periph_irq[22];" in irq_wiring
assert "s_irq[31] = s_apb4_periph_irq[23];" in irq_wiring
assert "irq_i[10] == apb4_periph_irq_i[16]" in irq_sva
assert "irq_i[15] == apb4_periph_irq_i[13]" in irq_sva
assert "irq_i[20] == apb4_periph_irq_i[14]" in irq_sva
@@ -180,7 +183,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert "irq_i[23] == apb4_periph_irq_i[18]" in irq_sva
assert "irq_i[24] == apb4_periph_irq_i[19]" in irq_sva
assert "irq_i[30] == apb4_periph_irq_i[22]" in irq_sva
assert "irq_i[31] == 1'b0" in irq_sva
assert "irq_i[31] == apb4_periph_irq_i[23]" in irq_sva
assert "bind retrosoc soc_irq_topology_sva" in irq_sva
assert ".clk_i(clk_lp_i)" in irq_sva
assert ".rst_n_i(rst_lp_n_i)" in irq_sva
@@ -236,9 +239,28 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
("extension_h", "apb4_system", 6, 28, "s_ext_h_irq"),
("jpeg", "apb4_periph", 22, 30, "resource_irq_lp_i[5]"),
("resource_fault", "apb4_system", 7, 29, "s_resource_fault_irq"),
("apu", "apb4_periph", 23, 31, "resource_irq_lp_i[6]"),
]
def test_apu_p1_fixed_resource_and_hp_irq_allocations() -> None:
periph = (ROOT / "rtl/mini/top/apb4_periph.sv").read_text(encoding="utf-8")
system = (ROOT / "rtl/mini/top/apb4_system.sv").read_text(encoding="utf-8")
top = (ROOT / "rtl/mini/top/retrosoc.sv").read_text(encoding="utf-8")
resource_header = (ROOT / "crt/include/retrosoc/hal/resource.h").read_text(
encoding="utf-8"
)
assert "s_hp_plic_source[10] = resource_irq_hp_i[6];" in periph
assert "s_apu_irq_raw, s_jpeg_irq_raw" in periph
assert ".ResourceCount(8)" in system
assert ".apu_owner_i (s_resource_owner[7])" in top
assert ".apu_quiesce_i (s_resource_quiesce[7])" in top
assert ".apu_reset_i (s_resource_reset[7])" in top
assert "RS_RESOURCE_APU = 7" in resource_header
assert "RS_RESOURCE_COUNT = 8" in resource_header
def test_topology_always_adds_the_user_apb_target(tmp_path: Path) -> None:
generate(tmp_path)