feat: enhance APU and AXI4 functionality with new tests and updates

- Updated axi4_async_bridge_tb.sv to include unilateral reset handling in the test.
- Enhanced axi4_target_guard_tb.sv with a new task for read beat normalization and additional read tests.
- Introduced hp_axi4_mux3_rr_tb.sv to test round-robin arbitration for multiple AXI4 interfaces.
- Expanded test_apu.py to include tests for APU stream router, DMA, ring scheduler, and integrated DMA/ring/backend functionality.
- Added new test cases for APU-P2 Gateway A round-robin fairness.
- Updated test_clock_reset_domains.py to include APU data crossing.
- Enhanced test_script_tools.py to scope formal filelists for APU and Gateway A.
This commit is contained in:
maksyuki committed 2026-09-03 13:56:04 +08:00
1 parent a464cc26dc
commit 5c65fcca27
48 files changed
+7485 -469

No files matched your search

+3 -3
View File
@@ -343,7 +343,7 @@ include physical/ecc/Makefile
hp-performance-check \
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-dvp formal-i2s formal-onchip-ram formal-opipsram formal-dma formal-sdio formal-clean formal-doctor \
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-dvp formal-i2s formal-onchip-ram formal-opipsram formal-dma formal-apu formal-gateway-a formal-sdio formal-clean formal-doctor \
rtl-style-check-all rtl-readiness-check rtl-readiness-check-all vexii-generate
.NOTPARALLEL: setup
@@ -387,7 +387,7 @@ help:
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
' formal | formal-bus | formal-rib-adapter | formal-rib2apb run SBY protocol proofs' \
'formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-i2c | formal-timer | formal-clint | formal-dvp | formal-i2s | formal-onchip-ram | formal-opipsram | formal-dma | formal-sdio run peripheral proofs' \
'formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-i2c | formal-timer | formal-clint | formal-dvp | formal-i2s | formal-onchip-ram | formal-opipsram | formal-dma | formal-apu | formal-gateway-a | formal-sdio run peripheral proofs' \
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
' benchmark-report run the memory/DMA profile and write meta/performance.json' \
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
@@ -684,4 +684,4 @@ regress-nightly:
python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly
sim-asm: asm
$(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim
$(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim
+3 -3
View File
@@ -26,7 +26,7 @@ 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) {
static bool rs_ci_smoke_apu(void) {
rs_apu_info_t info;
return (rs_apu_probe(&info) == RS_OK) && (info.capability0 == RS_APU_CAPABILITY0_IMPLEMENTED) &&
@@ -385,10 +385,10 @@ int main(void) {
rs_test_finish(RS_TEST_FAILED, 1U);
}
printf("ci_smoke: archinfo passed\n");
if (!rs_ci_smoke_apu_p1()) {
if (!rs_ci_smoke_apu()) {
rs_test_finish(RS_TEST_FAILED, 14U);
}
printf("ci_smoke: APU-P1 discovery passed\n");
printf("ci_smoke: APU-P2 discovery passed\n");
if (!rs_ci_smoke_fabric_monitor_start()) {
rs_test_finish(RS_TEST_FAILED, 13U);
}
+54
View File
@@ -1,6 +1,7 @@
#ifndef RETROSOC_HAL_APU_H
#define RETROSOC_HAL_APU_H
#include <stddef.h>
#include <stdint.h>
#include <retrosoc/core/status.h>
@@ -14,6 +15,59 @@ typedef struct {
uint32_t abi_digest;
} rs_apu_info_t;
typedef struct {
uint32_t control;
uint32_t result_status;
uint32_t input_address;
uint32_t input_length;
uint32_t output_address;
uint32_t output_capacity;
uint32_t input_config;
uint32_t output_config;
uint32_t job_flags;
uint32_t kws_config;
uint32_t result_input_used;
uint32_t result_output_bytes;
uint32_t result_frames;
uint32_t result_source_info;
uint32_t result_cycles;
uint32_t result_detail;
uint32_t cookie[2];
uint32_t start_timestamp[2];
uint32_t finish_timestamp[2];
uint32_t kws_result;
uint32_t microcode_build_id;
uint32_t reserved[8];
} rs_apu_descriptor_t;
_Static_assert(sizeof(rs_apu_descriptor_t) == RS_APU_ABI_DESCRIPTOR_BYTES,
"APU descriptor ABI must be 128 bytes");
#define RS_APU_DESCRIPTOR_OFFSET_ASSERT(member, word) \
_Static_assert(offsetof(rs_apu_descriptor_t, member) == ((word) * sizeof(uint32_t)), \
"APU descriptor member offset mismatch")
RS_APU_DESCRIPTOR_OFFSET_ASSERT(control, RS_APU_ABI_DESCRIPTOR_CONTROL);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_status, RS_APU_ABI_DESCRIPTOR_RESULT_STATUS);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(input_address, RS_APU_ABI_DESCRIPTOR_INPUT_ADDRESS);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(input_length, RS_APU_ABI_DESCRIPTOR_INPUT_LENGTH);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(output_address, RS_APU_ABI_DESCRIPTOR_OUTPUT_ADDRESS);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(output_capacity, RS_APU_ABI_DESCRIPTOR_OUTPUT_CAPACITY);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(input_config, RS_APU_ABI_DESCRIPTOR_INPUT_CONFIG);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(output_config, RS_APU_ABI_DESCRIPTOR_OUTPUT_CONFIG);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(job_flags, RS_APU_ABI_DESCRIPTOR_JOB_FLAGS);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(kws_config, RS_APU_ABI_DESCRIPTOR_KWS_CONFIG);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_input_used, RS_APU_ABI_DESCRIPTOR_RESULT_INPUT_USED);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_output_bytes, RS_APU_ABI_DESCRIPTOR_RESULT_OUTPUT_BYTES);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_frames, RS_APU_ABI_DESCRIPTOR_RESULT_FRAMES);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_source_info, RS_APU_ABI_DESCRIPTOR_RESULT_SOURCE_INFO);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_cycles, RS_APU_ABI_DESCRIPTOR_RESULT_CYCLES);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(result_detail, RS_APU_ABI_DESCRIPTOR_RESULT_DETAIL);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(cookie, RS_APU_ABI_DESCRIPTOR_COOKIE_LO);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(start_timestamp, RS_APU_ABI_DESCRIPTOR_START_TIMESTAMP_LO);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(finish_timestamp, RS_APU_ABI_DESCRIPTOR_FINISH_TIMESTAMP_LO);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(kws_result, RS_APU_ABI_DESCRIPTOR_KWS_RESULT);
RS_APU_DESCRIPTOR_OFFSET_ASSERT(microcode_build_id, RS_APU_ABI_DESCRIPTOR_MICROCODE_BUILD_ID);
#undef RS_APU_DESCRIPTOR_OFFSET_ASSERT
rs_status_t rs_apu_probe(rs_apu_info_t *info);
#endif
+271 -197
View File
@@ -6,205 +6,279 @@
#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_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_STREAM_WATERMARK UINT32_C(0x060)
#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_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_STREAM_STATUS_TX_ACTIVE 0U
#define RS_APU_ABI_STREAM_STATUS_RX_ACTIVE 1U
#define RS_APU_ABI_STREAM_STATUS_TX_EMPTY 2U
#define RS_APU_ABI_STREAM_STATUS_TX_FULL 3U
#define RS_APU_ABI_STREAM_STATUS_RX_EMPTY 4U
#define RS_APU_ABI_STREAM_STATUS_RX_FULL 5U
#define RS_APU_ABI_STREAM_STATUS_TX_UNDERRUN 6U
#define RS_APU_ABI_STREAM_STATUS_RX_OVERRUN 7U
#define RS_APU_ABI_STREAM_STATUS_TX_COUNT 8U
#define RS_APU_ABI_STREAM_STATUS_RX_COUNT 16U
#define RS_APU_ABI_STREAM_WATERMARK_RX_HIGH 0U
#define RS_APU_ABI_STREAM_WATERMARK_TX_LOW 8U
#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_JOB_STATUS_BUSY 0U
#define RS_APU_ABI_JOB_STATUS_DONE 1U
#define RS_APU_ABI_JOB_STATUS_ERROR 2U
#define RS_APU_ABI_JOB_STATUS_ABORTED 3U
#define RS_APU_ABI_JOB_STATUS_DIRECT_ACTIVE 4U
#define RS_APU_ABI_JOB_STATUS_INPUT_PENDING 5U
#define RS_APU_ABI_JOB_STATUS_OUTPUT_PENDING 6U
#define RS_APU_ABI_JOB_STATUS_WRITEBACK_PENDING 7U
#define RS_APU_ABI_JOB_STATUS_ERROR_CODE 8U
#define RS_APU_ABI_JOB_STATUS_STAGE 14U
#define RS_APU_ABI_JOB_STATUS_AXI_RESPONSE 18U
#define RS_APU_ABI_RING_STATUS_ACTIVE 0U
#define RS_APU_ABI_RING_STATUS_STALLED_UNOWNED 1U
#define RS_APU_ABI_RING_STATUS_EMPTY 2U
#define RS_APU_ABI_RING_STATUS_ERROR 3U
#define RS_APU_ABI_RING_STATUS_WRAPPED 4U
#define RS_APU_ABI_RING_STATUS_COALESCE_PENDING 5U
#define RS_APU_ABI_RING_STATUS_WRITEBACK_PENDING 6U
#define RS_APU_ABI_RING_STATUS_STOPPED_ON_ERROR 7U
#define RS_APU_ABI_RING_STATUS_PENDING_COUNT 8U
#define RS_APU_ABI_RING_STATUS_LAST_INDEX 16U
#define RS_APU_ABI_DESCRIPTOR_WORDS 32U
#define RS_APU_ABI_DESCRIPTOR_BYTES 128U
#define RS_APU_ABI_DESCRIPTOR_ALIGNMENT 128U
#define RS_APU_ABI_DESCRIPTOR_CONTROL 0U
#define RS_APU_ABI_DESCRIPTOR_RESULT_STATUS 1U
#define RS_APU_ABI_DESCRIPTOR_INPUT_ADDRESS 2U
#define RS_APU_ABI_DESCRIPTOR_INPUT_LENGTH 3U
#define RS_APU_ABI_DESCRIPTOR_OUTPUT_ADDRESS 4U
#define RS_APU_ABI_DESCRIPTOR_OUTPUT_CAPACITY 5U
#define RS_APU_ABI_DESCRIPTOR_INPUT_CONFIG 6U
#define RS_APU_ABI_DESCRIPTOR_OUTPUT_CONFIG 7U
#define RS_APU_ABI_DESCRIPTOR_JOB_FLAGS 8U
#define RS_APU_ABI_DESCRIPTOR_KWS_CONFIG 9U
#define RS_APU_ABI_DESCRIPTOR_RESULT_INPUT_USED 10U
#define RS_APU_ABI_DESCRIPTOR_RESULT_OUTPUT_BYTES 11U
#define RS_APU_ABI_DESCRIPTOR_RESULT_FRAMES 12U
#define RS_APU_ABI_DESCRIPTOR_RESULT_SOURCE_INFO 13U
#define RS_APU_ABI_DESCRIPTOR_RESULT_CYCLES 14U
#define RS_APU_ABI_DESCRIPTOR_RESULT_DETAIL 15U
#define RS_APU_ABI_DESCRIPTOR_COOKIE_LO 16U
#define RS_APU_ABI_DESCRIPTOR_COOKIE_HI 17U
#define RS_APU_ABI_DESCRIPTOR_START_TIMESTAMP_LO 18U
#define RS_APU_ABI_DESCRIPTOR_START_TIMESTAMP_HI 19U
#define RS_APU_ABI_DESCRIPTOR_FINISH_TIMESTAMP_LO 20U
#define RS_APU_ABI_DESCRIPTOR_FINISH_TIMESTAMP_HI 21U
#define RS_APU_ABI_DESCRIPTOR_KWS_RESULT 22U
#define RS_APU_ABI_DESCRIPTOR_MICROCODE_BUILD_ID 23U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_OPERATION 0U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_INPUT_FORMAT 4U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_OUTPUT_MODE 8U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_DOWNMIX 10U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_RESAMPLE 11U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_IOC 30U
#define RS_APU_ABI_DESCRIPTOR_CONTROL_OWN 31U
#define RS_APU_ABI_DESCRIPTOR_STATUS_DONE 0U
#define RS_APU_ABI_DESCRIPTOR_STATUS_ERROR 1U
#define RS_APU_ABI_DESCRIPTOR_STATUS_ABORTED 2U
#define RS_APU_ABI_DESCRIPTOR_STATUS_ERROR_CODE 3U
#define RS_APU_ABI_DESCRIPTOR_STATUS_STAGE 9U
#define RS_APU_ABI_DESCRIPTOR_STATUS_AXI_RESPONSE 13U
#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_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(0x00000018)
#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))
#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
+5 -4
View File
@@ -26,10 +26,11 @@ 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.
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
APU-P2 implements the private AXI4 DMA, descriptor ring scheduler, fair Gateway
A arbitration, and the production audio stream router with two 64-word Common
FIFOs. The shell reports only private-DMA and ring capabilities; public direct
start, ring doorbell, and APU stream routes remain fail-closed until their
later-phase engines exist. No claim is made that microcode, sequencer, codec
engines, KWS, codec conformance, Linux driver, timing closure, power closure,
CDC/RDC signoff, or silicon qualification exists.
+7 -6
View File
@@ -119,12 +119,13 @@ ownership. Its implemented limits, handwritten ABI, measured performance, and
commercial release gates are documented in
[Baseline JPEG Codec](../docs/ip/jpeg.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).
The Mini Audio Processing Unit has a frozen coreless architecture. APU-P2 adds
the private AXI4 DMA, descriptor scheduler, fair Gateway A arbitration, and
production stream router/FIFOs to the fail-closed APB4 shell at `APB4_APU`.
Resource Controller index 7 and exclusive LP IRQ31/HP PLIC source10 routing
remain fixed. Public jobs and APU stream routes remain disabled until their
later-phase engines exist. 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
+370 -18
View File
@@ -1,28 +1,380 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// SPDX-License-Identifier: MulanPSL-2.0
`include "apu_define.svh"
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: off -- preserve APB, lifecycle, DMA, and stream 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,
input logic [7:0] bridge_epoch_i,
input logic i2s_tx_underrun_i,
input logic i2s_rx_overrun_i,
apb4_if.slave apb4,
axi4_if.master axi4,
axi4_stream_if.sink dma_tx_axis,
axi4_stream_if.source dma_rx_axis,
axi4_stream_if.source i2s_tx_axis,
axi4_stream_if.sink i2s_rx_axis,
output logic idle_o,
output logic irq_o
// verilog_format: on
);
logic s_soft_reset, s_abort, s_cnt_clear, s_xrun_clear, s_perf_enable;
logic [ 3:0] s_stream_route;
logic [15:0] s_stream_watermark;
logic [31:0] s_read_base, s_read_limit, s_write_base, s_write_limit;
logic [31:0] s_dma_timeout, s_ring_base, s_ring_coalesce;
logic [8:0] s_ring_size;
logic [7:0] s_ring_tail, s_ring_head;
logic [1:0] s_ring_control;
logic [31:0] s_stream_stat, s_job_stat, s_ring_stat, s_ring_completed;
logic [10:0] s_irq_set;
logic s_input_watermark_evt, s_output_watermark_evt, s_xrun_evt;
logic s_ring_event, s_ring_err, s_abort_done;
logic [ 5:0] s_ring_err_code;
logic [ 3:0] s_ring_err_stage;
logic [ 1:0] s_ring_err_resp;
logic [ 7:0] s_ring_err_index;
logic [31:0] s_ring_err_addr;
logic s_fault_valid;
logic [ 5:0] s_fault_code;
logic [ 3:0] s_fault_stage;
logic [ 1:0] s_fault_resp;
logic [ 7:0] s_fault_index;
logic [31:0] s_fault_addr;
logic s_dma_req_valid, s_dma_req_ready, s_dma_req_write;
logic [31:0] s_dma_req_addr, s_dma_req_bytes;
logic s_dma_busy, s_dma_done, s_dma_err, s_dma_aborted, s_dma_aborting;
logic s_dma_abort;
logic [ 5:0] s_dma_err_code;
logic [ 3:0] s_dma_err_stage;
logic [ 1:0] s_dma_err_resp;
logic [31:0] s_dma_err_addr;
logic s_dma_input_pending, s_dma_output_pending;
logic [63:0] s_dma_read_bytes, s_dma_write_bytes;
logic [63:0] s_dma_read_stalls, s_dma_write_stalls;
logic s_scheduler_idle, s_scheduler_aborting, s_stream_idle;
logic s_dma_admission_block;
logic s_transport_idle, s_resource_reset_request, s_resource_reset_apply_q;
logic s_resource_reset_pending_q, s_resource_reset_seen_q;
logic s_tx_route_apu, s_rx_route_apu;
logic s_reg_idle_unused, s_backend_job_valid_unused, s_backend_resp_ready_unused;
logic [1023:0] s_backend_descriptor_unused;
logic [ 7:0] s_backend_index_unused;
logic [63:0] s_active_cycles_q, s_stream_stalls_q, s_faults_q;
axi4_stream_if #(
.DATA_WIDTH(32)
) u_dma_read_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_dma_write_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_apu_tx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_apu_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
assign u_apu_tx_axis.tdata = 32'd0;
assign u_apu_tx_axis.tkeep = 4'hf;
assign u_apu_tx_axis.tstrb = 4'hf;
assign u_apu_tx_axis.tlast = 1'b0;
assign u_apu_tx_axis.tid = '0;
assign u_apu_tx_axis.tdest = '0;
assign u_apu_tx_axis.tuser = '0;
assign u_apu_tx_axis.tvalid = 1'b0;
assign u_apu_rx_axis.tready = 1'b0;
assign s_irq_set = {
1'b0,
s_xrun_evt,
s_fault_valid,
s_output_watermark_evt,
s_input_watermark_evt,
s_abort_done,
3'b000,
s_ring_event,
1'b0
};
assign s_tx_route_apu = s_stream_route[1:0] == 2'd1;
assign s_rx_route_apu = s_stream_route[3:2] == 2'd1;
assign s_transport_idle = s_scheduler_idle && !s_dma_busy && s_stream_idle;
assign idle_o = s_transport_idle;
assign s_resource_reset_request = s_resource_reset_pending_q ||
(resource_reset_i && !s_resource_reset_seen_q);
assign s_dma_abort = (s_abort || s_resource_reset_request) &&
!s_ring_stat[`APB4_APU__RING_STATUS_WRITEBACK_PENDING];
assign s_dma_admission_block = (quiesce_i || s_resource_reset_request) &&
!s_job_stat[`APB4_APU__JOB_STATUS_BUSY] &&
!s_ring_stat[`APB4_APU__RING_STATUS_WRITEBACK_PENDING];
always_comb begin
s_fault_valid = s_ring_err;
s_fault_code = s_ring_err_code;
s_fault_stage = s_ring_err_stage;
s_fault_resp = s_ring_err_resp;
s_fault_index = s_ring_err_index;
s_fault_addr = s_ring_err_addr;
if (!s_ring_err && s_rx_route_apu && i2s_rx_overrun_i) begin
s_fault_valid = 1'b1;
s_fault_code = `APB4_APU__ERROR_CODE_STREAM_OVERRUN;
s_fault_stage = `APB4_APU__ERROR_STAGE_KWS_FRONTEND;
s_fault_resp = 2'd0;
s_fault_index = 8'd0;
s_fault_addr = 32'd0;
end else if (!s_ring_err && s_tx_route_apu && i2s_tx_underrun_i) begin
s_fault_valid = 1'b1;
s_fault_code = `APB4_APU__ERROR_CODE_STREAM_UNDERRUN;
s_fault_stage = `APB4_APU__ERROR_STAGE_DMA_WRITE;
s_fault_resp = 2'd0;
s_fault_index = 8'd0;
s_fault_addr = 32'd0;
end
end
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),
.resource_reset_apply_i (s_resource_reset_apply_q),
.core_idle_i (idle_o),
.core_busy_i (!idle_o),
.core_aborting_i (s_dma_aborting || s_scheduler_aborting || s_resource_reset_request),
.stream_status_i (s_stream_stat),
.job_status_i (s_job_stat),
.job_input_used_i (32'd0),
.job_output_bytes_i (32'd0),
.job_frames_i (32'd0),
.job_source_info_i (32'd0),
.job_cycles_i (32'd0),
.job_detail_i (32'd0),
.ring_status_i (s_ring_stat),
.ring_head_i (s_ring_head),
.ring_completed_i (s_ring_completed),
.irq_set_i (s_irq_set),
.fault_valid_i (s_fault_valid),
.fault_code_i (s_fault_code),
.fault_stage_i (s_fault_stage),
.fault_resp_i (s_fault_resp),
.fault_index_i (s_fault_index),
.fault_addr_i (s_fault_addr),
.fault_detail_i (32'd0),
.perf_active_cycles_i (s_active_cycles_q),
.perf_input_bytes_i (s_dma_read_bytes),
.perf_output_bytes_i (s_dma_write_bytes),
.perf_dma_read_stalls_i (s_dma_read_stalls),
.perf_dma_write_stalls_i(s_dma_write_stalls),
.perf_stream_stalls_i (s_stream_stalls_q),
.perf_faults_i (s_faults_q),
.apb4 (apb4),
.soft_reset_o (s_soft_reset),
.abort_o (s_abort),
.counter_clear_o (s_cnt_clear),
.perf_enable_o (s_perf_enable),
.xrun_clear_o (s_xrun_clear),
.stream_route_o (s_stream_route),
.stream_watermark_o (s_stream_watermark),
.read_base_o (s_read_base),
.read_limit_o (s_read_limit),
.write_base_o (s_write_base),
.write_limit_o (s_write_limit),
.dma_timeout_o (s_dma_timeout),
.ring_base_o (s_ring_base),
.ring_size_o (s_ring_size),
.ring_tail_o (s_ring_tail),
.ring_control_o (s_ring_control),
.ring_coalesce_o (s_ring_coalesce),
.idle_o (s_reg_idle_unused),
.irq_o (irq_o)
);
apu_dma u_apu_dma (
.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)
.abort_i (s_dma_abort),
.quiesce_i (s_dma_admission_block),
.bridge_epoch_i (bridge_epoch_i),
.perf_enable_i (s_perf_enable),
.counter_clear_i (s_cnt_clear),
.request_valid_i (s_dma_req_valid),
.request_ready_o (s_dma_req_ready),
.request_write_i (s_dma_req_write),
.request_addr_i (s_dma_req_addr),
.request_bytes_i (s_dma_req_bytes),
.read_base_i (s_read_base),
.read_limit_i (s_read_limit),
.write_base_i (s_write_base),
.write_limit_i (s_write_limit),
.timeout_i (s_dma_timeout),
.read_axis (u_dma_read_axis),
.write_axis (u_dma_write_axis),
.busy_o (s_dma_busy),
.done_o (s_dma_done),
.error_o (s_dma_err),
.aborted_o (s_dma_aborted),
.aborting_o (s_dma_aborting),
.error_code_o (s_dma_err_code),
.error_stage_o (s_dma_err_stage),
.error_resp_o (s_dma_err_resp),
.error_addr_o (s_dma_err_addr),
.input_pending_o (s_dma_input_pending),
.output_pending_o(s_dma_output_pending),
.read_bytes_o (s_dma_read_bytes),
.write_bytes_o (s_dma_write_bytes),
.read_stalls_o (s_dma_read_stalls),
.write_stalls_o (s_dma_write_stalls),
.axi4 (axi4)
);
apu_ring_scheduler u_ring_scheduler (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.soft_reset_i (s_soft_reset || s_resource_reset_apply_q),
.counter_clear_i (s_cnt_clear),
.abort_i (s_abort || s_resource_reset_request),
.quiesce_i (quiesce_i || s_resource_reset_request),
.start_i (1'b0),
.ring_base_i (s_ring_base),
.ring_size_i (s_ring_size),
.ring_tail_i (s_ring_tail),
.ring_enable_i (s_ring_control[0]),
.stop_on_error_i (s_ring_control[1]),
.coalesce_count_i (s_ring_coalesce[7:0]),
.coalesce_timeout_i (s_ring_coalesce[31:16]),
.dma_request_valid_o (s_dma_req_valid),
.dma_request_ready_i (s_dma_req_ready),
.dma_request_write_o (s_dma_req_write),
.dma_request_addr_o (s_dma_req_addr),
.dma_request_bytes_o (s_dma_req_bytes),
.dma_read_axis (u_dma_read_axis),
.dma_write_axis (u_dma_write_axis),
.dma_done_i (s_dma_done),
.dma_error_i (s_dma_err),
.dma_error_code_i (s_dma_err_code),
.dma_error_stage_i (s_dma_err_stage),
.dma_error_resp_i (s_dma_err_resp),
.dma_error_addr_i (s_dma_err_addr),
.backend_job_valid_o (s_backend_job_valid_unused),
.backend_job_ready_i (1'b0),
.backend_descriptor_o (s_backend_descriptor_unused),
.backend_index_o (s_backend_index_unused),
.backend_result_valid_i(1'b0),
.backend_result_ready_o(s_backend_resp_ready_unused),
.backend_result_error_i(1'b0),
.backend_result_code_i (6'd0),
.backend_result_stage_i(4'd0),
.backend_result_resp_i (2'd0),
.backend_input_used_i (32'd0),
.backend_output_bytes_i(32'd0),
.backend_frames_i (32'd0),
.backend_source_info_i (32'd0),
.backend_cycles_i (32'd0),
.backend_detail_i (32'd0),
.job_status_o (s_job_stat),
.ring_status_o (s_ring_stat),
.ring_head_o (s_ring_head),
.ring_completed_o (s_ring_completed),
.ring_event_o (s_ring_event),
.error_event_o (s_ring_err),
.error_code_o (s_ring_err_code),
.error_stage_o (s_ring_err_stage),
.error_resp_o (s_ring_err_resp),
.error_index_o (s_ring_err_index),
.error_addr_o (s_ring_err_addr),
.abort_done_o (s_abort_done),
.aborting_o (s_scheduler_aborting),
.idle_o (s_scheduler_idle)
);
apu_stream_router u_stream_router (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.flush_i (s_soft_reset || s_resource_reset_apply_q),
.counter_clear_i (s_cnt_clear),
.xrun_clear_i (s_xrun_clear),
.tx_route_apu_i (s_tx_route_apu),
.rx_route_apu_i (s_rx_route_apu),
.tx_session_active_i (1'b0),
.rx_session_active_i (1'b0),
.rx_high_watermark_i (s_stream_watermark[7:0]),
.tx_low_watermark_i (s_stream_watermark[15:8]),
.tx_underrun_i (i2s_tx_underrun_i),
.rx_overrun_i (i2s_rx_overrun_i),
.dma_tx_axis (dma_tx_axis),
.dma_rx_axis (dma_rx_axis),
.i2s_tx_axis (i2s_tx_axis),
.i2s_rx_axis (i2s_rx_axis),
.apu_tx_axis (u_apu_tx_axis),
.apu_rx_axis (u_apu_rx_axis),
.status_o (s_stream_stat),
.input_watermark_evt_o (s_input_watermark_evt),
.output_watermark_evt_o(s_output_watermark_evt),
.stream_xrun_evt_o (s_xrun_evt),
.idle_o (s_stream_idle)
);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_resource_reset_pending_q <= 1'b0;
s_resource_reset_seen_q <= 1'b0;
s_resource_reset_apply_q <= 1'b0;
end else begin
s_resource_reset_apply_q <= 1'b0;
if (resource_reset_i && !s_resource_reset_seen_q) begin
s_resource_reset_pending_q <= 1'b1;
s_resource_reset_seen_q <= 1'b1;
end
if (s_resource_reset_request && s_transport_idle) begin
s_resource_reset_pending_q <= 1'b0;
s_resource_reset_apply_q <= 1'b1;
end
if (!resource_reset_i && !s_resource_reset_pending_q) begin
s_resource_reset_seen_q <= 1'b0;
end
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i || s_soft_reset || s_resource_reset_apply_q || s_cnt_clear) begin
s_active_cycles_q <= 64'd0;
s_stream_stalls_q <= 64'd0;
s_faults_q <= 64'd0;
end else begin
if (s_perf_enable && !idle_o && !(&s_active_cycles_q)) begin
s_active_cycles_q <= s_active_cycles_q + 1'b1;
end
if (s_perf_enable && ((i2s_tx_axis.tvalid && !i2s_tx_axis.tready) ||
(i2s_rx_axis.tvalid && !i2s_rx_axis.tready)) && !(&s_stream_stalls_q)) begin
s_stream_stalls_q <= s_stream_stalls_q + 1'b1;
end
if (s_perf_enable && s_fault_valid && !(&s_faults_q)) begin
s_faults_q <= s_faults_q + 1'b1;
end
end
end
logic s_unused_pending;
assign s_unused_pending = s_dma_input_pending ^ s_dma_output_pending ^ s_dma_aborted ^
s_reg_idle_unused ^ s_backend_job_valid_unused ^ s_backend_resp_ready_unused ^
^s_backend_descriptor_unused ^ ^s_backend_index_unused ^ ^s_ring_coalesce[15:8];
endmodule
+80
View File
@@ -29,6 +29,7 @@
`define APB4_APU__ABI_DIGEST 12'h054
`define APB4_APU__SEQUENCER_STATUS 12'h058
`define APB4_APU__SEQUENCER_RETIRED 12'h05c
`define APB4_APU__STREAM_WATERMARK 12'h060
`define APB4_APU__MC_IMAGE_ADDRESS 12'h080
`define APB4_APU__MC_IMAGE_SIZE 12'h084
@@ -139,6 +140,20 @@
`define APB4_APU__STATUS_IDLE 8
`define APB4_APU__STATUS_SEQUENCER_TRAPPED 9
`define APB4_APU__STREAM_STATUS_TX_ACTIVE 0
`define APB4_APU__STREAM_STATUS_RX_ACTIVE 1
`define APB4_APU__STREAM_STATUS_TX_EMPTY 2
`define APB4_APU__STREAM_STATUS_TX_FULL 3
`define APB4_APU__STREAM_STATUS_RX_EMPTY 4
`define APB4_APU__STREAM_STATUS_RX_FULL 5
`define APB4_APU__STREAM_STATUS_TX_UNDERRUN 6
`define APB4_APU__STREAM_STATUS_RX_OVERRUN 7
`define APB4_APU__STREAM_STATUS_TX_COUNT 8
`define APB4_APU__STREAM_STATUS_RX_COUNT 16
`define APB4_APU__STREAM_WATERMARK_RX_HIGH 0
`define APB4_APU__STREAM_WATERMARK_TX_LOW 8
`define APB4_APU__IRQ_DIRECT_DONE 0
`define APB4_APU__IRQ_RING_EVENT 1
`define APB4_APU__IRQ_KWS_HIT 2
@@ -198,6 +213,71 @@
`define APB4_APU__OWNER_STATUS_LOCK 8
`define APB4_APU__OWNER_STATUS_QUIESCE 9
`define APB4_APU__OWNER_STATUS_RESET 10
`define APB4_APU__JOB_STATUS_BUSY 0
`define APB4_APU__JOB_STATUS_DONE 1
`define APB4_APU__JOB_STATUS_ERROR 2
`define APB4_APU__JOB_STATUS_ABORTED 3
`define APB4_APU__JOB_STATUS_DIRECT_ACTIVE 4
`define APB4_APU__JOB_STATUS_INPUT_PENDING 5
`define APB4_APU__JOB_STATUS_OUTPUT_PENDING 6
`define APB4_APU__JOB_STATUS_WRITEBACK_PENDING 7
`define APB4_APU__JOB_STATUS_ERROR_CODE 8
`define APB4_APU__JOB_STATUS_STAGE 14
`define APB4_APU__JOB_STATUS_AXI_RESPONSE 18
`define APB4_APU__RING_STATUS_ACTIVE 0
`define APB4_APU__RING_STATUS_STALLED_UNOWNED 1
`define APB4_APU__RING_STATUS_EMPTY 2
`define APB4_APU__RING_STATUS_ERROR 3
`define APB4_APU__RING_STATUS_WRAPPED 4
`define APB4_APU__RING_STATUS_COALESCE_PENDING 5
`define APB4_APU__RING_STATUS_WRITEBACK_PENDING 6
`define APB4_APU__RING_STATUS_STOPPED_ON_ERROR 7
`define APB4_APU__RING_STATUS_PENDING_COUNT 8
`define APB4_APU__RING_STATUS_LAST_INDEX 16
`define APB4_APU__DESCRIPTOR_WORDS 32
`define APB4_APU__DESCRIPTOR_BYTES 128
`define APB4_APU__DESCRIPTOR_ALIGNMENT 128
`define APB4_APU__DESCRIPTOR_CONTROL 0
`define APB4_APU__DESCRIPTOR_RESULT_STATUS 1
`define APB4_APU__DESCRIPTOR_INPUT_ADDRESS 2
`define APB4_APU__DESCRIPTOR_INPUT_LENGTH 3
`define APB4_APU__DESCRIPTOR_OUTPUT_ADDRESS 4
`define APB4_APU__DESCRIPTOR_OUTPUT_CAPACITY 5
`define APB4_APU__DESCRIPTOR_INPUT_CONFIG 6
`define APB4_APU__DESCRIPTOR_OUTPUT_CONFIG 7
`define APB4_APU__DESCRIPTOR_JOB_FLAGS 8
`define APB4_APU__DESCRIPTOR_KWS_CONFIG 9
`define APB4_APU__DESCRIPTOR_RESULT_INPUT_USED 10
`define APB4_APU__DESCRIPTOR_RESULT_OUTPUT_BYTES 11
`define APB4_APU__DESCRIPTOR_RESULT_FRAMES 12
`define APB4_APU__DESCRIPTOR_RESULT_SOURCE_INFO 13
`define APB4_APU__DESCRIPTOR_RESULT_CYCLES 14
`define APB4_APU__DESCRIPTOR_RESULT_DETAIL 15
`define APB4_APU__DESCRIPTOR_COOKIE_LO 16
`define APB4_APU__DESCRIPTOR_COOKIE_HI 17
`define APB4_APU__DESCRIPTOR_START_TIMESTAMP_LO 18
`define APB4_APU__DESCRIPTOR_START_TIMESTAMP_HI 19
`define APB4_APU__DESCRIPTOR_FINISH_TIMESTAMP_LO 20
`define APB4_APU__DESCRIPTOR_FINISH_TIMESTAMP_HI 21
`define APB4_APU__DESCRIPTOR_KWS_RESULT 22
`define APB4_APU__DESCRIPTOR_MICROCODE_BUILD_ID 23
`define APB4_APU__DESCRIPTOR_CONTROL_OPERATION 0
`define APB4_APU__DESCRIPTOR_CONTROL_INPUT_FORMAT 4
`define APB4_APU__DESCRIPTOR_CONTROL_OUTPUT_MODE 8
`define APB4_APU__DESCRIPTOR_CONTROL_DOWNMIX 10
`define APB4_APU__DESCRIPTOR_CONTROL_RESAMPLE 11
`define APB4_APU__DESCRIPTOR_CONTROL_IOC 30
`define APB4_APU__DESCRIPTOR_CONTROL_OWN 31
`define APB4_APU__DESCRIPTOR_STATUS_DONE 0
`define APB4_APU__DESCRIPTOR_STATUS_ERROR 1
`define APB4_APU__DESCRIPTOR_STATUS_ABORTED 2
`define APB4_APU__DESCRIPTOR_STATUS_ERROR_CODE 3
`define APB4_APU__DESCRIPTOR_STATUS_STAGE 9
`define APB4_APU__DESCRIPTOR_STATUS_AXI_RESPONSE 13
`define APB4_APU__PERF_CONTROL_ENABLE 0
`define APB4_APU__PERF_CONTROL_CLEAR 1
`define APB4_APU__PERF_CONTROL_SNAPSHOT 2
+410
View File
@@ -0,0 +1,410 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
`include "apu_define.svh"
`include "axi4_define.svh"
module apu_dma (
// verilog_format: off -- preserve command, result, and bus columns
input logic clk_i,
input logic rst_n_i,
input logic abort_i,
input logic quiesce_i,
input logic [7:0] bridge_epoch_i,
input logic perf_enable_i,
input logic counter_clear_i,
input logic request_valid_i,
output logic request_ready_o,
input logic request_write_i,
input logic [31:0] request_addr_i,
input logic [31:0] request_bytes_i,
input logic [31:0] read_base_i,
input logic [31:0] read_limit_i,
input logic [31:0] write_base_i,
input logic [31:0] write_limit_i,
input logic [31:0] timeout_i,
axi4_stream_if.source read_axis,
axi4_stream_if.sink write_axis,
output logic busy_o,
output logic done_o,
output logic error_o,
output logic aborted_o,
output logic aborting_o,
output logic [5:0] error_code_o,
output logic [3:0] error_stage_o,
output logic [1:0] error_resp_o,
output logic [31:0] error_addr_o,
output logic input_pending_o,
output logic output_pending_o,
output logic [63:0] read_bytes_o,
output logic [63:0] write_bytes_o,
output logic [63:0] read_stalls_o,
output logic [63:0] write_stalls_o,
axi4_if.master axi4
// verilog_format: on
);
typedef enum logic [2:0] {
Idle,
ReadStart,
ReadData,
WriteStart,
WriteData,
WriteResponse
} state_e;
state_e s_state_q;
logic [31:0] s_addr_q;
logic [31:0] s_remaining_q;
logic [ 4:0] s_burst_beats_q;
logic [31:0] s_timeout_q;
logic s_drain_q;
logic s_err_q;
logic s_aborted_q;
logic [ 5:0] s_err_code_q;
logic [ 3:0] s_err_stage_q;
logic [ 1:0] s_err_resp_q;
logic [31:0] s_err_addr_q;
logic s_done_q;
logic [63:0] s_read_bytes_q;
logic [63:0] s_write_bytes_q;
logic [63:0] s_read_stalls_q;
logic [63:0] s_write_stalls_q;
logic [ 4:0] s_sel_beats;
logic [31:0] s_beat_bytes;
logic [ 3:0] s_expected_keep;
logic s_read_start_ready;
logic s_read_busy;
logic s_read_valid;
logic s_read_ready;
logic [31:0] s_read_data;
logic [ 1:0] s_read_resp;
logic s_read_last;
logic s_read_expected_last;
logic s_read_id_error;
logic s_read_done;
logic s_write_start_ready;
logic s_write_busy;
logic s_write_ready;
logic s_write_done;
logic [ 1:0] s_write_resp;
logic s_write_id_error;
logic s_progress;
logic s_timeout_expire;
logic s_read_fault;
logic s_write_fault;
logic s_payload_fault;
logic s_timeout_active;
logic s_bridge_flush;
logic s_read_missing_last;
logic s_req_range_valid;
logic [32:0] s_req_last;
logic [ 7:0] s_bridge_epoch_q;
function automatic logic [4:0] choose_burst(input logic [11:0] addr_i,
input logic [31:0] bytes_i);
logic [31:0] s_needed;
logic [31:0] s_boundary;
logic [31:0] s_sel;
begin
s_needed = (bytes_i + 32'd3) >> 2;
s_boundary = (32'd4096 - {20'd0, addr_i}) >> 2;
s_sel = s_needed;
if (s_sel > 32'd16) s_sel = 32'd16;
if (s_sel > s_boundary) s_sel = s_boundary;
if (s_sel == 32'd0) s_sel = 32'd1;
return s_sel[4:0];
end
endfunction
function automatic logic [3:0] byte_mask(input logic [31:0] bytes_i);
case (bytes_i)
32'd1: byte_mask = 4'b0001;
32'd2: byte_mask = 4'b0011;
32'd3: byte_mask = 4'b0111;
default: byte_mask = 4'b1111;
endcase
endfunction
function automatic logic [63:0] saturating_add(input logic [63:0] value_i,
input logic [31:0] increment_i);
logic [64:0] s_sum;
begin
s_sum = {1'b0, value_i} + {33'd0, increment_i};
return s_sum[64] ? 64'hffff_ffff_ffff_ffff : s_sum[63:0];
end
endfunction
assign s_sel_beats = choose_burst(s_addr_q[11:0], s_remaining_q);
assign s_beat_bytes = (s_remaining_q < 32'd4) ? s_remaining_q : 32'd4;
assign s_expected_keep = byte_mask(s_beat_bytes);
assign s_req_last = {1'b0, request_addr_i} + {1'b0, request_bytes_i} - 1'b1;
assign s_req_range_valid = (request_bytes_i != 32'd0) && !s_req_last[32] &&
(request_addr_i[1:0] == 2'd0) &&
(request_write_i ? ((request_addr_i >= write_base_i) &&
(s_req_last[31:0] <= write_limit_i)) :
((request_addr_i >= read_base_i) &&
(s_req_last[31:0] <= read_limit_i)));
assign request_ready_o = (s_state_q == Idle) && !quiesce_i && !abort_i && !s_bridge_flush;
assign busy_o = s_state_q != Idle;
assign done_o = s_done_q;
assign error_o = s_err_q;
assign aborted_o = s_aborted_q;
assign aborting_o = busy_o && s_drain_q && s_aborted_q;
assign error_code_o = s_err_code_q;
assign error_stage_o = s_err_stage_q;
assign error_resp_o = s_err_resp_q;
assign error_addr_o = s_err_addr_q;
assign input_pending_o = (s_state_q == ReadStart) || (s_state_q == ReadData);
assign output_pending_o = (s_state_q == WriteStart) || (s_state_q == WriteData) ||
(s_state_q == WriteResponse);
assign read_bytes_o = s_read_bytes_q;
assign write_bytes_o = s_write_bytes_q;
assign read_stalls_o = s_read_stalls_q;
assign write_stalls_o = s_write_stalls_q;
assign read_axis.tdata = s_read_data;
assign read_axis.tkeep = s_expected_keep;
assign read_axis.tstrb = s_expected_keep;
assign read_axis.tlast = s_remaining_q <= 32'd4;
assign read_axis.tid = '0;
assign read_axis.tdest = '0;
assign read_axis.tuser = '0;
assign read_axis.tvalid = (s_state_q == ReadData) && s_read_valid && !s_drain_q && !s_read_fault;
assign s_read_ready = (s_state_q == ReadData) && (s_drain_q || s_read_fault || read_axis.tready);
assign s_read_fault = s_read_valid &&
((s_read_resp != `AXI4_RESP_OKAY) || s_read_id_error ||
(s_read_last != s_read_expected_last));
assign s_read_missing_last = (s_state_q == ReadData) && s_read_valid && s_read_ready &&
s_read_expected_last && !s_read_last;
assign s_payload_fault = write_axis.tvalid &&
((write_axis.tkeep != s_expected_keep) || (write_axis.tstrb != s_expected_keep) ||
(write_axis.tlast != (s_remaining_q <= 32'd4)));
assign write_axis.tready = (s_state_q == WriteData) && s_write_ready && !s_drain_q &&
!s_payload_fault;
assign s_write_fault = s_write_done && ((s_write_resp != `AXI4_RESP_OKAY) || s_write_id_error);
assign s_progress = (axi4.awvalid && axi4.awready) || (axi4.wvalid && axi4.wready) ||
(axi4.bvalid && axi4.bready) || (axi4.arvalid && axi4.arready) ||
(axi4.rvalid && axi4.rready);
assign s_timeout_active = s_read_busy || s_write_busy;
assign s_timeout_expire = s_timeout_active && !s_progress && (s_timeout_q == 32'd1);
assign s_bridge_flush = bridge_epoch_i != s_bridge_epoch_q;
dma_axi4_master #(
.AddrWidth (32),
.DataWidth (32),
.MaxBurstBeats(16)
) u_axi4_master (
.clk_i(clk_i),
.rst_n_i(rst_n_i),
.clear_i(s_bridge_flush || s_read_missing_last),
.read_start_valid_i((s_state_q == ReadStart) && !s_drain_q && !abort_i && !s_timeout_expire),
.read_start_ready_o(s_read_start_ready),
.read_addr_i(s_addr_q),
.read_beats_i(s_sel_beats),
.read_fixed_i(1'b0),
.read_busy_o(s_read_busy),
.read_beat_valid_o(s_read_valid),
.read_beat_ready_i(s_read_ready),
.read_data_o(s_read_data),
.read_resp_o(s_read_resp),
.read_last_o(s_read_last),
.read_expected_last_o(s_read_expected_last),
.read_id_error_o(s_read_id_error),
.read_done_o(s_read_done),
.write_start_valid_i((s_state_q == WriteStart) && !s_drain_q && !abort_i &&
!s_timeout_expire),
.write_start_ready_o(s_write_start_ready),
.write_addr_i(s_addr_q),
.write_beats_i(s_sel_beats),
.write_fixed_i(1'b0),
.write_busy_o(s_write_busy),
.write_data_valid_i ((s_state_q == WriteData) &&
(s_drain_q || s_payload_fault || write_axis.tvalid)),
.write_data_ready_o(s_write_ready),
.write_data_i((s_drain_q || s_payload_fault) ? 32'd0 : write_axis.tdata),
.write_strb_i((s_drain_q || s_payload_fault) ? 4'd0 : write_axis.tkeep),
.write_done_o(s_write_done),
.write_resp_o(s_write_resp),
.write_id_error_o(s_write_id_error),
.axi4(axi4)
);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_state_q <= Idle;
s_addr_q <= 32'd0;
s_remaining_q <= 32'd0;
s_burst_beats_q <= 5'd0;
s_timeout_q <= 32'd0;
s_drain_q <= 1'b0;
s_err_q <= 1'b0;
s_aborted_q <= 1'b0;
s_err_code_q <= 6'd0;
s_err_stage_q <= 4'd0;
s_err_resp_q <= 2'd0;
s_err_addr_q <= 32'd0;
s_done_q <= 1'b0;
s_read_bytes_q <= 64'd0;
s_write_bytes_q <= 64'd0;
s_read_stalls_q <= 64'd0;
s_write_stalls_q <= 64'd0;
s_bridge_epoch_q <= 8'd0;
end else begin
s_done_q <= 1'b0;
s_bridge_epoch_q <= bridge_epoch_i;
if (counter_clear_i) begin
s_read_bytes_q <= 64'd0;
s_write_bytes_q <= 64'd0;
s_read_stalls_q <= 64'd0;
s_write_stalls_q <= 64'd0;
end
if (s_bridge_flush) begin
s_timeout_q <= 32'd0;
s_drain_q <= 1'b0;
if (s_state_q != Idle) begin
s_state_q <= Idle;
s_done_q <= 1'b1;
s_err_q <= 1'b1;
s_aborted_q <= s_aborted_q || abort_i;
s_err_code_q <= output_pending_o ? 6'd16 : 6'd15;
s_err_stage_q <= output_pending_o ? 4'd8 : 4'd3;
s_err_resp_q <= `AXI4_RESP_DECODE_ERROR;
s_err_addr_q <= s_addr_q;
end
end else if (request_valid_i && request_ready_o) begin
s_drain_q <= 1'b0;
s_err_q <= 1'b0;
s_aborted_q <= 1'b0;
s_err_code_q <= 6'd0;
s_err_stage_q <= 4'd0;
s_err_resp_q <= 2'd0;
s_err_addr_q <= 32'd0;
s_addr_q <= request_addr_i;
s_remaining_q <= request_bytes_i;
s_timeout_q <= timeout_i;
if (!s_req_range_valid) begin
s_err_q <= 1'b1;
s_err_code_q <= request_write_i ? 6'd16 : 6'd15;
s_err_stage_q <= request_write_i ? 4'd8 : 4'd3;
s_err_resp_q <= `AXI4_RESP_SLAVE_ERROR;
s_err_addr_q <= request_addr_i;
s_done_q <= 1'b1;
end else begin
s_state_q <= request_write_i ? WriteStart : ReadStart;
end
end else if (s_state_q != Idle) begin
if (s_progress) s_timeout_q <= timeout_i;
else if (s_timeout_active && (s_timeout_q != 32'd0)) s_timeout_q <= s_timeout_q - 1'b1;
if (perf_enable_i && !counter_clear_i && input_pending_o && !s_progress)
s_read_stalls_q <= saturating_add(s_read_stalls_q, 1);
if (perf_enable_i && !counter_clear_i && output_pending_o && !s_progress)
s_write_stalls_q <= saturating_add(s_write_stalls_q, 1);
if ((abort_i || s_timeout_expire) && !s_drain_q) begin
s_drain_q <= 1'b1;
s_timeout_q <= 32'd0;
s_err_q <= s_timeout_expire;
s_aborted_q <= abort_i;
s_err_code_q <= s_timeout_expire ? 6'd17 : 6'd20;
s_err_stage_q <= output_pending_o ? 4'd8 : 4'd3;
s_err_addr_q <= s_addr_q;
end
case (s_state_q)
ReadStart: begin
if (s_drain_q) begin
s_state_q <= Idle;
s_done_q <= 1'b1;
s_drain_q <= 1'b0;
s_timeout_q <= 32'd0;
end else if (s_read_start_ready && !abort_i && !s_timeout_expire) begin
s_state_q <= ReadData;
end
end
ReadData: begin
if (s_read_valid && s_read_ready) begin
if (s_read_fault) begin
s_err_q <= 1'b1;
s_err_code_q <= 6'd15;
s_err_stage_q <= 4'd3;
s_err_resp_q <= s_read_resp;
s_err_addr_q <= s_addr_q;
s_drain_q <= 1'b1;
end else if (perf_enable_i && !s_drain_q && !counter_clear_i) begin
s_read_bytes_q <= saturating_add(s_read_bytes_q, s_beat_bytes);
end
s_addr_q <= s_addr_q + s_beat_bytes;
s_remaining_q <= s_remaining_q - s_beat_bytes;
if (s_read_missing_last) begin
s_state_q <= Idle;
s_done_q <= 1'b1;
s_drain_q <= 1'b0;
s_timeout_q <= 32'd0;
end else if (s_read_last) begin
if (s_drain_q || s_read_fault || (s_remaining_q <= 32'd4)) begin
s_state_q <= Idle;
s_done_q <= 1'b1;
s_drain_q <= 1'b0;
s_timeout_q <= 32'd0;
end else begin
s_state_q <= ReadStart;
end
end
end
end
WriteStart: begin
if (s_drain_q) begin
s_state_q <= Idle;
s_done_q <= 1'b1;
s_drain_q <= 1'b0;
s_timeout_q <= 32'd0;
end else if (s_write_start_ready && !abort_i && !s_timeout_expire) begin
s_burst_beats_q <= s_sel_beats;
s_state_q <= WriteData;
end
end
WriteData: begin
if (s_write_ready && (s_drain_q || s_payload_fault || write_axis.tvalid)) begin
if (s_payload_fault && !s_err_q && !s_drain_q) begin
s_err_q <= 1'b1;
s_err_code_q <= 6'd16;
s_err_stage_q <= 4'd8;
s_err_resp_q <= `AXI4_RESP_SLAVE_ERROR;
s_err_addr_q <= s_addr_q;
s_drain_q <= 1'b1;
end else if (perf_enable_i && !s_drain_q && !counter_clear_i) begin
s_write_bytes_q <= saturating_add(s_write_bytes_q, s_beat_bytes);
end
s_addr_q <= s_addr_q + s_beat_bytes;
s_remaining_q <= s_remaining_q - s_beat_bytes;
s_burst_beats_q <= s_burst_beats_q - 1'b1;
if (s_burst_beats_q == 5'd1) s_state_q <= WriteResponse;
end
end
WriteResponse: begin
if (s_write_done) begin
if (s_write_fault) begin
s_err_q <= 1'b1;
s_err_code_q <= 6'd16;
s_err_stage_q <= 4'd8;
s_err_resp_q <= s_write_resp;
s_err_addr_q <= s_addr_q;
end
if (s_drain_q || s_write_fault || (s_remaining_q == 32'd0)) begin
s_state_q <= Idle;
s_done_q <= 1'b1;
s_drain_q <= 1'b0;
s_timeout_q <= 32'd0;
end else begin
s_state_q <= WriteStart;
end
end
end
default: s_state_q <= Idle;
endcase
end
end
end
logic s_unused_master_status;
assign s_unused_master_status = s_read_busy ^ s_read_done ^ s_write_busy;
endmodule
+202 -47
View File
@@ -11,14 +11,61 @@ module apu_reg (
input logic owner_lock_i,
input logic quiesce_i,
input logic resource_reset_i,
input logic resource_reset_apply_i,
input logic core_idle_i,
input logic core_busy_i,
input logic core_aborting_i,
input logic [31:0] stream_status_i,
input logic [31:0] job_status_i,
input logic [31:0] job_input_used_i,
input logic [31:0] job_output_bytes_i,
input logic [31:0] job_frames_i,
input logic [31:0] job_source_info_i,
input logic [31:0] job_cycles_i,
input logic [31:0] job_detail_i,
input logic [31:0] ring_status_i,
input logic [7:0] ring_head_i,
input logic [31:0] ring_completed_i,
input logic [10:0] irq_set_i,
input logic fault_valid_i,
input logic [5:0] fault_code_i,
input logic [3:0] fault_stage_i,
input logic [1:0] fault_resp_i,
input logic [7:0] fault_index_i,
input logic [31:0] fault_addr_i,
input logic [31:0] fault_detail_i,
input logic [63:0] perf_active_cycles_i,
input logic [63:0] perf_input_bytes_i,
input logic [63:0] perf_output_bytes_i,
input logic [63:0] perf_dma_read_stalls_i,
input logic [63:0] perf_dma_write_stalls_i,
input logic [63:0] perf_stream_stalls_i,
input logic [63:0] perf_faults_i,
apb4_if.slave apb4,
output logic soft_reset_o,
output logic abort_o,
output logic counter_clear_o,
output logic perf_enable_o,
output logic xrun_clear_o,
output logic [3:0] stream_route_o,
output logic [15:0] stream_watermark_o,
output logic [31:0] read_base_o,
output logic [31:0] read_limit_o,
output logic [31:0] write_base_o,
output logic [31:0] write_limit_o,
output logic [31:0] dma_timeout_o,
output logic [31:0] ring_base_o,
output logic [8:0] ring_size_o,
output logic [7:0] ring_tail_o,
output logic [1:0] ring_control_o,
output logic [31:0] ring_coalesce_o,
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] Capability0 = 32'h0000_0018;
localparam logic [31:0] Capability1 = 32'd0;
localparam logic [31:0] AbiDigest = 32'd0;
localparam logic [10:0] IrqMask = 11'h7ff;
@@ -41,6 +88,7 @@ module apu_reg (
logic s_write_unsupported;
logic [31:0] s_read_data;
logic s_soft_reset;
logic s_abort;
logic s_cnt_clear;
logic [10:0] s_irq_clear;
logic [10:0] s_irq_set;
@@ -58,8 +106,12 @@ module apu_reg (
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 [15:0] s_stream_watermark_d, s_stream_watermark_q;
logic s_perf_en_d, s_perf_en_q;
logic s_perf_snapshot_valid_d, s_perf_snapshot_valid_q;
logic [9:0][63:0] s_perf_snapshot_q;
logic s_err_clear;
logic s_unused_snapshot;
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);
@@ -79,17 +131,37 @@ module apu_reg (
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_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;
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 = core_idle_i;
assign irq_o = (s_irq_state_q & s_irq_en_q) != 11'd0;
assign soft_reset_o = s_soft_reset;
assign abort_o = s_abort;
assign counter_clear_o = s_cnt_clear;
assign perf_enable_o = s_perf_en_q;
assign xrun_clear_o = s_irq_clear[`APB4_APU__IRQ_STREAM_XRUN];
assign stream_route_o = s_stream_route_q;
assign stream_watermark_o = s_stream_watermark_q;
assign read_base_o = s_acl_q[0];
assign read_limit_o = s_acl_q[1];
assign write_base_o = s_acl_q[2];
assign write_limit_o = s_acl_q[3];
assign dma_timeout_o = s_timeout_q[1];
assign ring_base_o = s_ring_cfg_q[0];
assign ring_size_o = s_ring_cfg_q[1][8:0];
assign ring_tail_o = s_ring_cfg_q[2][7:0];
assign ring_control_o = s_ring_cfg_q[3][1:0];
assign ring_coalesce_o = s_ring_cfg_q[4];
assign s_err_clear = s_write && !s_write_err &&
(s_offset == `APB4_APU__ERROR_STATUS) && s_strobed_write[0];
assign s_unused_snapshot = ^s_perf_snapshot_q[3] ^ ^s_perf_snapshot_q[7] ^ ^s_perf_snapshot_q[8];
always_comb begin
s_read_data = 32'd0;
@@ -100,7 +172,18 @@ module apu_reg (
`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__STATUS:
s_read_data = {
22'd0,
1'b0,
!core_busy_i,
core_aborting_i,
quiesce_i,
2'd0,
ring_status_i[`APB4_APU__RING_STATUS_ACTIVE],
core_busy_i,
2'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;
@@ -108,7 +191,7 @@ module apu_reg (
`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__STREAM_STATUS: s_read_data = stream_status_i;
`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];
@@ -120,16 +203,14 @@ module apu_reg (
`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__MC_LOAD_COUNT,
`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__STREAM_WATERMARK: s_read_data = {16'd0, s_stream_watermark_q};
`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];
@@ -141,11 +222,21 @@ module apu_reg (
`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__JOB_STATUS: s_read_data = job_status_i;
`APB4_APU__JOB_INPUT_USED: s_read_data = job_input_used_i;
`APB4_APU__JOB_OUTPUT_BYTES: s_read_data = job_output_bytes_i;
`APB4_APU__JOB_FRAMES: s_read_data = job_frames_i;
`APB4_APU__JOB_SOURCE_INFO: s_read_data = job_source_info_i;
`APB4_APU__JOB_CYCLES: s_read_data = job_cycles_i;
`APB4_APU__JOB_DETAIL: s_read_data = job_detail_i;
`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__RING_HEAD: s_read_data = {24'd0, ring_head_i};
`APB4_APU__RING_STATUS: s_read_data = ring_status_i;
`APB4_APU__RING_COMPLETED: s_read_data = ring_completed_i;
`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];
@@ -153,17 +244,24 @@ module apu_reg (
`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_ACTIVE_CYCLES_LO: s_read_data = s_perf_snapshot_q[0][31:0];
`APB4_APU__PERF_ACTIVE_CYCLES_HI: s_read_data = s_perf_snapshot_q[0][63:32];
`APB4_APU__PERF_INPUT_BYTES_LO: s_read_data = s_perf_snapshot_q[1][31:0];
`APB4_APU__PERF_INPUT_BYTES_HI: s_read_data = s_perf_snapshot_q[1][63:32];
`APB4_APU__PERF_OUTPUT_BYTES_LO: s_read_data = s_perf_snapshot_q[2][31:0];
`APB4_APU__PERF_OUTPUT_BYTES_HI: s_read_data = s_perf_snapshot_q[2][63:32];
`APB4_APU__PERF_DECODED_FRAMES_LO, `APB4_APU__PERF_DECODED_FRAMES_HI: s_read_data = 32'd0;
`APB4_APU__PERF_DMA_READ_STALLS_LO: s_read_data = s_perf_snapshot_q[4][31:0];
`APB4_APU__PERF_DMA_READ_STALLS_HI: s_read_data = s_perf_snapshot_q[4][63:32];
`APB4_APU__PERF_DMA_WRITE_STALLS_LO: s_read_data = s_perf_snapshot_q[5][31:0];
`APB4_APU__PERF_DMA_WRITE_STALLS_HI: s_read_data = s_perf_snapshot_q[5][63:32];
`APB4_APU__PERF_STREAM_STALLS_LO: s_read_data = s_perf_snapshot_q[6][31:0];
`APB4_APU__PERF_STREAM_STALLS_HI: s_read_data = s_perf_snapshot_q[6][63:32];
`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:
`APB4_APU__PERF_KWS_CYCLES_LO, `APB4_APU__PERF_KWS_CYCLES_HI:
s_read_data = 32'd0;
`APB4_APU__PERF_FAULTS_LO: s_read_data = s_perf_snapshot_q[9][31:0];
`APB4_APU__PERF_FAULTS_HI: s_read_data = s_perf_snapshot_q[9][63:32];
`APB4_APU__COMMAND, `APB4_APU__IRQ_TEST, `APB4_APU__RING_DOORBELL: begin
s_read_data = 32'd0;
s_read_err = 1'b1;
@@ -183,9 +281,12 @@ module apu_reg (
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_unsupported = (apb4.pwdata & 32'h0000_0039) != 32'd0;
s_write_err = (apb4.pstrb != 4'hf) ||
((apb4.pwdata & 32'hffff_ff80) != 32'd0) ||
(apb4.pwdata[`APB4_APU__COMMAND_ABORT] && !core_busy_i) ||
((apb4.pwdata[`APB4_APU__COMMAND_SOFT_RESET] ||
apb4.pwdata[`APB4_APU__COMMAND_CLEAR_COUNTERS]) && !core_idle_i) ||
s_write_unsupported;
end
`APB4_APU__IRQ_STATE: s_write_err = (s_strobed_write & ~32'(IrqMask)) != 32'd0;
@@ -198,66 +299,81 @@ module apu_reg (
`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;
s_write_err = (s_merged_write == 32'd0) || !core_idle_i;
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;
s_write_err = s_write_unsupported || !core_idle_i;
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;
s_write_err = (apb4.pstrb != 4'hf) || !core_idle_i || (owner_i != 2'd0);
`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;
s_write_err = (s_merged_write == 32'd0) || !core_idle_i;
end
`APB4_APU__STREAM_WATERMARK: begin
s_merged_write = apply_wstrb({16'd0, s_stream_watermark_q}, apb4.pwdata, apb4.pstrb);
s_write_err = (s_merged_write[31:16] != 16'd0) ||
(s_merged_write[7:0] > 8'd64) || (s_merged_write[15:8] > 8'd64) ||
!core_idle_i;
end
`APB4_APU__MC_IMAGE_ADDRESS, `APB4_APU__KWS_MODEL_ADDRESS:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[5:0] != 6'd0);
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[5:0] != 6'd0) ||
!core_idle_i || (owner_i != 2'd0);
`APB4_APU__MC_IMAGE_SIZE, `APB4_APU__KWS_MODEL_SIZE:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata == 32'd0);
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata == 32'd0) ||
!core_idle_i || (owner_i != 2'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);
(s_merged_write[7:4] > 4'd2) || (s_merged_write[9:8] > 2'd1) ||
!core_idle_i;
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;
s_write_err = (apb4.pstrb != 4'hf) || !core_idle_i;
`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;
s_write_err = (s_merged_write[31:26] != 6'd0) || !core_idle_i;
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);
s_write_err = (s_merged_write[31:21] != 11'd0) ||
(s_merged_write[20:19] > 2'd1) || !core_idle_i;
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;
s_write_err = (s_merged_write[31:1] != 31'd0) || !core_idle_i;
end
`APB4_APU__RING_BASE: s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[6:0] != 7'd0);
`APB4_APU__RING_BASE:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[6:0] != 7'd0) || !core_idle_i;
`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.pwdata > 32'd256) || !is_power_of_two(apb4.pwdata) || !core_idle_i;
`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_CONTROL:
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[31:2] != 30'd0) || !core_idle_i;
`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.pwdata[7:0] == 8'd0) || (apb4.pwdata[31:16] == 16'd0) ||
!core_idle_i;
`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;
s_write_err = (apb4.pstrb != 4'hf) || (apb4.pwdata[31:3] != 29'd0) ||
s_write_unsupported || !core_idle_i;
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);
s_write_err = (s_merged_write[31:16] != 16'd0) ||
(s_merged_write[15:8] == 8'd0) || !core_idle_i;
end
`APB4_APU__PERF_CONTROL: begin
s_merged_write = apply_wstrb({31'd0, s_perf_en_q}, apb4.pwdata, apb4.pstrb);
@@ -308,22 +424,25 @@ module apu_reg (
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_stream_watermark_d = s_stream_watermark_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_abort = 1'b0;
s_cnt_clear = 1'b0;
s_irq_clear = 11'd0;
s_irq_set = 11'd0;
s_irq_set = irq_set_i;
if (s_write && !s_write_err) begin
unique case (s_offset)
`APB4_APU__COMMAND: begin
s_abort = apb4.pwdata[`APB4_APU__COMMAND_ABORT];
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__IRQ_TEST: s_irq_set = s_irq_set | apb4.pwdata[10:0];
`APB4_APU__ERROR_STATUS: begin
if (s_strobed_write[0]) begin
s_err_stat_d = 32'd0;
@@ -338,6 +457,7 @@ module apu_reg (
`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__STREAM_WATERMARK: s_stream_watermark_d = s_merged_write[15:0];
`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;
@@ -388,9 +508,17 @@ module apu_reg (
s_err_detail_d = apb4.pwrite ? apb4.pwdata : {20'd0, s_offset};
end
end
if (fault_valid_i && (!s_err_stat_q[`APB4_APU__ERROR_VALID] || s_err_clear)) begin
s_err_stat_d = 32'd1 | (32'(fault_code_i) << `APB4_APU__ERROR_CODE) |
(32'(fault_stage_i) << `APB4_APU__ERROR_STAGE) |
(32'(fault_resp_i) << `APB4_APU__ERROR_AXI_RESPONSE) |
(32'(fault_index_i) << `APB4_APU__ERROR_DESCRIPTOR_INDEX);
s_err_addr_d = fault_addr_i;
s_err_detail_d = fault_detail_i;
end
s_irq_state_d = (s_irq_state_d & ~s_irq_clear) | s_irq_set;
if (s_soft_reset || resource_reset_i) begin
if (s_soft_reset || resource_reset_apply_i) begin
s_irq_state_d = 11'd0;
s_irq_en_d = 11'd0;
s_err_stat_d = 32'd0;
@@ -404,6 +532,7 @@ module apu_reg (
s_ring_cfg_d = RingReset;
s_kws_model_cfg_d = '0;
s_kws_cfg_d = KwsConfigReset[15:0];
s_stream_watermark_d = 16'd0;
s_perf_en_d = 1'b0;
s_perf_snapshot_valid_d = 1'b0;
end
@@ -542,6 +671,14 @@ module apu_reg (
.dat_i (s_kws_cfg_d),
.dat_o (s_kws_cfg_q)
);
dffr #(
.DATA_WIDTH(16)
) u_stream_watermark_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_stream_watermark_d),
.dat_o (s_stream_watermark_q)
);
dffr #(
.DATA_WIDTH(1)
) u_perf_enable_dffr (
@@ -558,4 +695,22 @@ module apu_reg (
.dat_i (s_perf_snapshot_valid_d),
.dat_o (s_perf_snapshot_valid_q)
);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i || s_soft_reset || resource_reset_apply_i || s_cnt_clear) begin
s_perf_snapshot_q <= '0;
end else if (s_write && !s_write_err && (s_offset == `APB4_APU__PERF_CONTROL) &&
s_merged_write[`APB4_APU__PERF_CONTROL_SNAPSHOT]) begin
s_perf_snapshot_q[0] <= perf_active_cycles_i;
s_perf_snapshot_q[1] <= perf_input_bytes_i;
s_perf_snapshot_q[2] <= perf_output_bytes_i;
s_perf_snapshot_q[3] <= 64'd0;
s_perf_snapshot_q[4] <= perf_dma_read_stalls_i;
s_perf_snapshot_q[5] <= perf_dma_write_stalls_i;
s_perf_snapshot_q[6] <= perf_stream_stalls_i;
s_perf_snapshot_q[7] <= 64'd0;
s_perf_snapshot_q[8] <= 64'd0;
s_perf_snapshot_q[9] <= perf_faults_i;
end
end
endmodule
+731
View File
@@ -0,0 +1,731 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
`include "apu_define.svh"
module apu_ring_scheduler (
// verilog_format: off -- preserve ring, backend, and DMA service columns
input logic clk_i,
input logic rst_n_i,
input logic soft_reset_i,
input logic counter_clear_i,
input logic abort_i,
input logic quiesce_i,
input logic start_i,
input logic [31:0] ring_base_i,
input logic [8:0] ring_size_i,
input logic [7:0] ring_tail_i,
input logic ring_enable_i,
input logic stop_on_error_i,
input logic [7:0] coalesce_count_i,
input logic [15:0] coalesce_timeout_i,
output logic dma_request_valid_o,
input logic dma_request_ready_i,
output logic dma_request_write_o,
output logic [31:0] dma_request_addr_o,
output logic [31:0] dma_request_bytes_o,
axi4_stream_if.sink dma_read_axis,
axi4_stream_if.source dma_write_axis,
input logic dma_done_i,
input logic dma_error_i,
input logic [5:0] dma_error_code_i,
input logic [3:0] dma_error_stage_i,
input logic [1:0] dma_error_resp_i,
input logic [31:0] dma_error_addr_i,
output logic backend_job_valid_o,
input logic backend_job_ready_i,
output logic [1023:0] backend_descriptor_o,
output logic [7:0] backend_index_o,
input logic backend_result_valid_i,
output logic backend_result_ready_o,
input logic backend_result_error_i,
input logic [5:0] backend_result_code_i,
input logic [3:0] backend_result_stage_i,
input logic [1:0] backend_result_resp_i,
input logic [31:0] backend_input_used_i,
input logic [31:0] backend_output_bytes_i,
input logic [31:0] backend_frames_i,
input logic [31:0] backend_source_info_i,
input logic [31:0] backend_cycles_i,
input logic [31:0] backend_detail_i,
output logic [31:0] job_status_o,
output logic [31:0] ring_status_o,
output logic [7:0] ring_head_o,
output logic [31:0] ring_completed_o,
output logic ring_event_o,
output logic error_event_o,
output logic [5:0] error_code_o,
output logic [3:0] error_stage_o,
output logic [1:0] error_resp_o,
output logic [7:0] error_index_o,
output logic [31:0] error_addr_o,
output logic abort_done_o,
output logic aborting_o,
output logic idle_o
// verilog_format: on
);
typedef enum logic [3:0] {
Idle,
FetchRequest,
FetchData,
Evaluate,
BackendRequest,
BackendWait,
ResultWriteRequest,
ResultWriteData,
ResultWriteWait,
OwnerWriteRequest,
OwnerWriteData,
OwnerWriteWait,
Stalled
} state_e;
state_e s_state_q;
logic [31:0] s_descriptor_q [32];
logic [ 5:0] s_word_index_q;
logic [ 7:0] s_head_q;
logic [31:0] s_completed_q;
logic s_active_q;
logic s_ring_err_q;
logic s_wrapped_q;
logic s_stopped_q;
logic [ 7:0] s_pending_q;
logic [15:0] s_coalesce_timer_q;
logic [ 7:0] s_last_index_q;
logic s_job_err_q;
logic s_job_busy_q;
logic s_job_done_q;
logic s_job_aborted_q;
logic [ 5:0] s_job_code_q;
logic [ 3:0] s_job_stage_q;
logic [ 1:0] s_job_resp_q;
logic s_ring_event_q;
logic s_err_event_q;
logic s_abort_done_q;
logic [ 5:0] s_err_code_q;
logic [ 3:0] s_err_stage_q;
logic [ 1:0] s_err_resp_q;
logic [ 7:0] s_err_index_q;
logic [31:0] s_err_addr_q;
logic s_descriptor_valid;
logic s_descriptor_ioc;
logic [31:0] s_descriptor_addr;
logic [32:0] s_descriptor_addr_ext;
logic [32:0] s_ring_last;
logic s_ring_config_valid;
logic s_writeback_pending;
logic [ 7:0] s_next_head;
logic [ 8:0] s_incremented_head;
logic [ 7:0] s_post_pending;
logic s_abort_pending_q;
logic s_ring_en_q;
logic [63:0] s_timestamp_q;
function automatic logic [31:0] saturating_increment(input logic [31:0] value_i);
return (&value_i) ? value_i : value_i + 1'b1;
endfunction
function automatic logic is_power_of_two(input logic [8:0] value_i);
return (value_i != 9'd0) && ((value_i & (value_i - 1'b1)) == 9'd0);
endfunction
always_comb begin
s_descriptor_valid = s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN] &&
(s_descriptor_q[0][29:12] == 18'd0) &&
(s_descriptor_q[0][3:0] <= 4'd1) && (s_descriptor_q[0][7:4] <= 4'd2) &&
(s_descriptor_q[0][9:8] <= 2'd1) &&
(s_descriptor_q[2][1:0] == 2'd0) && (s_descriptor_q[3] != 32'd0) &&
(((s_descriptor_q[0][9:8] == 2'd0) && (s_descriptor_q[4][1:0] == 2'd0) &&
(s_descriptor_q[5] != 32'd0)) ||
((s_descriptor_q[0][9:8] == 2'd1) && (s_descriptor_q[4] == 32'd0) &&
(s_descriptor_q[5] == 32'd0))) &&
(s_descriptor_q[6][31:26] == 6'd0) && (s_descriptor_q[6][19] == 1'b0) &&
(s_descriptor_q[6][18:17] <= 2'd2) &&
((s_descriptor_q[6][25:20] == 6'd0) || (s_descriptor_q[6][25:20] == 6'd16) ||
(s_descriptor_q[6][25:20] == 6'd24)) &&
(s_descriptor_q[7][31:21] == 11'd0) && (s_descriptor_q[7][18:17] <= 2'd2) &&
(s_descriptor_q[7][20:19] <= 2'd1) && (s_descriptor_q[8][31:1] == 31'd0) &&
(((s_descriptor_q[0][3:0] == 4'd0) && (s_descriptor_q[9] == 32'd0)) ||
(s_descriptor_q[0][3:0] == 4'd1));
for (int word_index = 24; word_index < 32; word_index++) begin
s_descriptor_valid = s_descriptor_valid && (s_descriptor_q[word_index] == 32'd0);
end
end
assign s_descriptor_ioc = s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_IOC];
assign s_descriptor_addr_ext = {1'b0, ring_base_i} + ({25'd0, s_head_q} << 7);
assign s_descriptor_addr = s_descriptor_addr_ext[31:0];
assign s_ring_last = {1'b0, ring_base_i} + ({24'd0, ring_size_i} << 7) - 1'b1;
assign s_ring_config_valid = (ring_base_i[6:0] == 7'd0) &&
(ring_size_i >= 9'd2) && (ring_size_i <= 9'd256) && is_power_of_two(
ring_size_i
) && (s_ring_last <= 33'h0_ffff_ffff) && (s_descriptor_addr_ext <= 33'h0_ffff_ffff) &&
({1'b0, s_head_q} < ring_size_i) && ({1'b0, ring_tail_i} < ring_size_i);
assign s_incremented_head = {1'b0, s_head_q} + 1'b1;
assign s_next_head = (s_incremented_head >= ring_size_i) ? 8'd0 : s_incremented_head[7:0];
assign s_post_pending = (&s_pending_q) ? s_pending_q : s_pending_q + 1'b1;
assign s_writeback_pending = (s_state_q == ResultWriteRequest) ||
(s_state_q == ResultWriteData) || (s_state_q == ResultWriteWait) ||
(s_state_q == OwnerWriteRequest) || (s_state_q == OwnerWriteData) ||
(s_state_q == OwnerWriteWait);
assign dma_request_valid_o = (s_state_q == FetchRequest) ||
(s_state_q == ResultWriteRequest) || (s_state_q == OwnerWriteRequest);
assign dma_request_write_o = s_state_q != FetchRequest;
assign dma_request_addr_o = ((s_state_q == OwnerWriteRequest) ||
(s_state_q == OwnerWriteData) ||
(s_state_q == OwnerWriteWait)) ?
s_descriptor_addr :
(((s_state_q == ResultWriteRequest) || (s_state_q == ResultWriteData) ||
(s_state_q == ResultWriteWait)) ? s_descriptor_addr + 32'd4 : s_descriptor_addr);
assign dma_request_bytes_o = ((s_state_q == OwnerWriteRequest) ||
(s_state_q == OwnerWriteData) ||
(s_state_q == OwnerWriteWait)) ? 32'd4 :
(((s_state_q == ResultWriteRequest) || (s_state_q == ResultWriteData) ||
(s_state_q == ResultWriteWait)) ? 32'd124 : 32'd128);
assign dma_read_axis.tready = s_state_q == FetchData;
assign dma_write_axis.tdata = (s_state_q == OwnerWriteData) ?
s_descriptor_q[0] : s_descriptor_q[s_word_index_q[4:0]];
assign dma_write_axis.tkeep = 4'hf;
assign dma_write_axis.tstrb = 4'hf;
assign dma_write_axis.tlast = (s_state_q == OwnerWriteData) || (s_word_index_q == 6'd31);
assign dma_write_axis.tid = '0;
assign dma_write_axis.tdest = '0;
assign dma_write_axis.tuser = '0;
assign dma_write_axis.tvalid = (s_state_q == ResultWriteData) || (s_state_q == OwnerWriteData);
assign backend_job_valid_o = (s_state_q == BackendRequest) && !abort_i;
assign backend_descriptor_o = {
s_descriptor_q[31],
s_descriptor_q[30],
s_descriptor_q[29],
s_descriptor_q[28],
s_descriptor_q[27],
s_descriptor_q[26],
s_descriptor_q[25],
s_descriptor_q[24],
s_descriptor_q[23],
s_descriptor_q[22],
s_descriptor_q[21],
s_descriptor_q[20],
s_descriptor_q[19],
s_descriptor_q[18],
s_descriptor_q[17],
s_descriptor_q[16],
s_descriptor_q[15],
s_descriptor_q[14],
s_descriptor_q[13],
s_descriptor_q[12],
s_descriptor_q[11],
s_descriptor_q[10],
s_descriptor_q[9],
s_descriptor_q[8],
s_descriptor_q[7],
s_descriptor_q[6],
s_descriptor_q[5],
s_descriptor_q[4],
s_descriptor_q[3],
s_descriptor_q[2],
s_descriptor_q[1],
s_descriptor_q[0]
};
assign backend_index_o = s_head_q;
assign backend_result_ready_o = s_state_q == BackendWait;
assign ring_head_o = s_head_q;
assign ring_completed_o = s_completed_q;
assign ring_event_o = s_ring_event_q;
assign error_event_o = s_err_event_q;
assign abort_done_o = s_abort_done_q;
assign aborting_o = s_abort_pending_q || (s_job_busy_q && s_job_aborted_q);
assign error_code_o = s_err_code_q;
assign error_stage_o = s_err_stage_q;
assign error_resp_o = s_err_resp_q;
assign error_index_o = s_err_index_q;
assign error_addr_o = s_err_addr_q;
assign idle_o = s_state_q == Idle;
assign job_status_o = {
12'd0,
s_job_resp_q,
s_job_stage_q,
s_job_code_q,
s_writeback_pending,
1'b0,
(s_state_q == FetchRequest) || (s_state_q == FetchData),
1'b0,
s_job_aborted_q,
s_job_err_q,
s_job_done_q,
s_job_busy_q
};
assign ring_status_o = {
8'd0,
s_last_index_q,
s_pending_q,
s_stopped_q,
s_writeback_pending,
s_pending_q != 8'd0,
s_wrapped_q,
s_ring_err_q,
(s_head_q == ring_tail_i) && (s_state_q == Idle),
s_state_q == Stalled,
s_active_q
};
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_timestamp_q <= 64'd0;
end else begin
s_timestamp_q <= s_timestamp_q + 1'b1;
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i || soft_reset_i) begin
s_state_q <= Idle;
s_word_index_q <= 6'd0;
s_head_q <= 8'd0;
s_completed_q <= 32'd0;
s_active_q <= 1'b0;
s_ring_err_q <= 1'b0;
s_wrapped_q <= 1'b0;
s_stopped_q <= 1'b0;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
s_last_index_q <= 8'd0;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b0;
s_job_aborted_q <= 1'b0;
s_job_code_q <= 6'd0;
s_job_stage_q <= 4'd0;
s_job_resp_q <= 2'd0;
s_ring_event_q <= 1'b0;
s_err_event_q <= 1'b0;
s_abort_done_q <= 1'b0;
s_err_code_q <= 6'd0;
s_err_stage_q <= 4'd0;
s_err_resp_q <= 2'd0;
s_err_index_q <= 8'd0;
s_err_addr_q <= 32'd0;
s_abort_pending_q <= 1'b0;
s_ring_en_q <= 1'b0;
end else begin
s_ring_event_q <= 1'b0;
s_err_event_q <= 1'b0;
s_abort_done_q <= 1'b0;
s_ring_en_q <= ring_enable_i;
if (counter_clear_i) s_completed_q <= 32'd0;
if (ring_enable_i && !s_ring_en_q) begin
s_ring_err_q <= 1'b0;
s_wrapped_q <= 1'b0;
s_stopped_q <= 1'b0;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
s_last_index_q <= 8'd0;
end
if (!ring_enable_i) begin
s_active_q <= 1'b0;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
if (s_state_q == Stalled) s_state_q <= Idle;
end
if (start_i && ring_enable_i && !quiesce_i && !abort_i && !s_active_q) begin
s_wrapped_q <= 1'b0;
s_stopped_q <= 1'b0;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
s_last_index_q <= 8'd0;
s_state_q <= Idle;
if (s_ring_config_valid) begin
s_active_q <= 1'b1;
s_ring_err_q <= 1'b0;
end else begin
s_active_q <= 1'b0;
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= 6'd2;
s_err_stage_q <= 4'd2;
s_err_resp_q <= 2'd0;
s_err_index_q <= 8'd0;
s_err_addr_q <= ring_base_i;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_code_q <= 6'd2;
s_job_stage_q <= 4'd2;
s_job_resp_q <= 2'd0;
end
end
if (abort_i && (s_active_q || (s_state_q != Idle))) begin
s_abort_pending_q <= 1'b1;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
s_active_q <= 1'b0;
end
case (s_state_q)
Idle: begin
if (abort_i && s_active_q) begin
s_job_busy_q <= 1'b0;
s_abort_pending_q <= 1'b0;
s_abort_done_q <= 1'b1;
end else if (s_active_q && (s_head_q != ring_tail_i) && !quiesce_i) begin
s_word_index_q <= 6'd0;
s_state_q <= FetchRequest;
end
end
FetchRequest: begin
if (abort_i) begin
s_state_q <= Idle;
s_job_busy_q <= 1'b0;
s_abort_pending_q <= 1'b0;
s_abort_done_q <= 1'b1;
end else if (quiesce_i) begin
s_state_q <= Idle;
s_job_busy_q <= 1'b0;
end else if (dma_request_ready_i) begin
s_state_q <= FetchData;
end
end
FetchData: begin
if (dma_read_axis.tvalid && dma_read_axis.tready) begin
s_descriptor_q[s_word_index_q[4:0]] <= dma_read_axis.tdata;
s_word_index_q <= s_word_index_q + 1'b1;
end
if (dma_done_i) begin
if (dma_error_i) begin
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= dma_error_code_i;
s_err_stage_q <= dma_error_stage_i;
s_err_resp_q <= dma_error_resp_i;
s_err_index_q <= s_head_q;
s_err_addr_q <= dma_error_addr_i;
s_active_q <= 1'b0;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_code_q <= dma_error_code_i;
s_job_stage_q <= dma_error_stage_i;
s_job_resp_q <= dma_error_resp_i;
if (abort_i || s_abort_pending_q) s_abort_done_q <= 1'b1;
s_abort_pending_q <= 1'b0;
s_state_q <= Idle;
end else if (abort_i || s_abort_pending_q) begin
s_active_q <= 1'b0;
s_job_busy_q <= 1'b0;
s_abort_pending_q <= 1'b0;
s_abort_done_q <= 1'b1;
s_state_q <= Idle;
end else begin
s_state_q <= Evaluate;
end
end
end
Evaluate: begin
if (abort_i) begin
if (s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN]) begin
s_job_busy_q <= 1'b1;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b0;
s_job_aborted_q <= 1'b1;
s_job_code_q <= 6'd20;
s_job_stage_q <= 4'd11;
s_job_resp_q <= 2'd0;
s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN] <= 1'b0;
s_descriptor_q[1] <= 32'd1 << `APB4_APU__DESCRIPTOR_STATUS_ABORTED;
for (int result_word = 10; result_word < 16; result_word++) begin
s_descriptor_q[result_word] <= 32'd0;
end
s_descriptor_q[18] <= s_timestamp_q[31:0];
s_descriptor_q[19] <= s_timestamp_q[63:32];
s_descriptor_q[20] <= s_timestamp_q[31:0];
s_descriptor_q[21] <= s_timestamp_q[63:32];
s_descriptor_q[22] <= 32'd0;
s_descriptor_q[23] <= 32'd0;
s_word_index_q <= 6'd1;
s_state_q <= ResultWriteRequest;
end else begin
s_job_busy_q <= 1'b0;
s_abort_pending_q <= 1'b0;
s_abort_done_q <= 1'b1;
s_state_q <= Idle;
end
end else if (!s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN]) begin
s_state_q <= Stalled;
end else if (!s_descriptor_valid) begin
s_job_busy_q <= 1'b1;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_aborted_q <= 1'b0;
s_job_code_q <= 6'd2;
s_job_stage_q <= 4'd2;
s_job_resp_q <= 2'd0;
s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN] <= 1'b0;
s_descriptor_q[1] <= (32'd1 << `APB4_APU__DESCRIPTOR_STATUS_ERROR) |
(32'd2 << `APB4_APU__DESCRIPTOR_STATUS_ERROR_CODE) |
(32'd2 << `APB4_APU__DESCRIPTOR_STATUS_STAGE);
for (int result_word = 10; result_word < 16; result_word++) begin
s_descriptor_q[result_word] <= 32'd0;
end
s_descriptor_q[18] <= s_timestamp_q[31:0];
s_descriptor_q[19] <= s_timestamp_q[63:32];
s_descriptor_q[20] <= s_timestamp_q[31:0];
s_descriptor_q[21] <= s_timestamp_q[63:32];
s_descriptor_q[22] <= 32'd0;
s_descriptor_q[23] <= 32'd0;
s_word_index_q <= 6'd1;
s_state_q <= ResultWriteRequest;
end else begin
s_job_busy_q <= 1'b1;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b0;
s_job_aborted_q <= 1'b0;
s_job_code_q <= 6'd0;
s_job_stage_q <= 4'd0;
s_job_resp_q <= 2'd0;
for (int result_word = 10; result_word < 16; result_word++) begin
s_descriptor_q[result_word] <= 32'd0;
end
s_descriptor_q[18] <= s_timestamp_q[31:0];
s_descriptor_q[19] <= s_timestamp_q[63:32];
s_descriptor_q[20] <= 32'd0;
s_descriptor_q[21] <= 32'd0;
s_descriptor_q[22] <= 32'd0;
s_descriptor_q[23] <= 32'd0;
s_state_q <= BackendRequest;
end
end
BackendRequest: begin
if (abort_i) begin
s_job_busy_q <= 1'b1;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b0;
s_job_aborted_q <= 1'b1;
s_job_code_q <= 6'd20;
s_job_stage_q <= 4'd11;
s_job_resp_q <= 2'd0;
s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN] <= 1'b0;
s_descriptor_q[1] <= 32'd1 << `APB4_APU__DESCRIPTOR_STATUS_ABORTED;
s_descriptor_q[20] <= s_timestamp_q[31:0];
s_descriptor_q[21] <= s_timestamp_q[63:32];
s_descriptor_q[22] <= 32'd0;
s_descriptor_q[23] <= 32'd0;
s_word_index_q <= 6'd1;
s_state_q <= ResultWriteRequest;
end else if (backend_job_ready_i) begin
s_state_q <= BackendWait;
end
end
BackendWait: begin
if (backend_result_valid_i) begin
s_job_err_q <= backend_result_error_i;
s_job_code_q <= backend_result_code_i;
s_job_stage_q <= backend_result_stage_i;
s_job_resp_q <= backend_result_resp_i;
s_job_aborted_q <= abort_i && backend_result_error_i;
s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN] <= 1'b0;
s_descriptor_q[1] <= (backend_result_error_i ?
(32'd1 << `APB4_APU__DESCRIPTOR_STATUS_ERROR) :
(32'd1 << `APB4_APU__DESCRIPTOR_STATUS_DONE)) |
((abort_i && backend_result_error_i) ?
(32'd1 << `APB4_APU__DESCRIPTOR_STATUS_ABORTED) : 32'd0) |
(32'(backend_result_code_i) << `APB4_APU__DESCRIPTOR_STATUS_ERROR_CODE) |
(32'(backend_result_stage_i) << `APB4_APU__DESCRIPTOR_STATUS_STAGE) |
(32'(backend_result_resp_i) << `APB4_APU__DESCRIPTOR_STATUS_AXI_RESPONSE);
s_descriptor_q[10] <= backend_input_used_i;
s_descriptor_q[11] <= backend_output_bytes_i;
s_descriptor_q[12] <= backend_frames_i;
s_descriptor_q[13] <= backend_source_info_i;
s_descriptor_q[14] <= backend_cycles_i;
s_descriptor_q[15] <= backend_detail_i;
s_descriptor_q[20] <= s_timestamp_q[31:0];
s_descriptor_q[21] <= s_timestamp_q[63:32];
s_word_index_q <= 6'd1;
s_state_q <= ResultWriteRequest;
end else if (abort_i) begin
s_job_busy_q <= 1'b1;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b0;
s_job_aborted_q <= 1'b1;
s_job_code_q <= 6'd20;
s_job_stage_q <= 4'd11;
s_job_resp_q <= 2'd0;
s_descriptor_q[0][`APB4_APU__DESCRIPTOR_CONTROL_OWN] <= 1'b0;
s_descriptor_q[1] <= 32'd1 << `APB4_APU__DESCRIPTOR_STATUS_ABORTED;
s_descriptor_q[20] <= s_timestamp_q[31:0];
s_descriptor_q[21] <= s_timestamp_q[63:32];
s_descriptor_q[22] <= 32'd0;
s_descriptor_q[23] <= 32'd0;
s_word_index_q <= 6'd1;
s_state_q <= ResultWriteRequest;
end
end
ResultWriteRequest: begin
if (dma_request_ready_i) s_state_q <= ResultWriteData;
end
ResultWriteData: begin
if (dma_done_i) begin
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= dma_error_code_i;
s_err_stage_q <= dma_error_stage_i;
s_err_resp_q <= dma_error_resp_i;
s_err_index_q <= s_head_q;
s_err_addr_q <= dma_error_addr_i;
s_active_q <= 1'b0;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_code_q <= dma_error_code_i;
s_job_stage_q <= dma_error_stage_i;
s_job_resp_q <= dma_error_resp_i;
if (abort_i || s_abort_pending_q) s_abort_done_q <= 1'b1;
s_abort_pending_q <= 1'b0;
s_state_q <= Idle;
end else if (dma_write_axis.tvalid && dma_write_axis.tready) begin
s_word_index_q <= s_word_index_q + 1'b1;
if (s_word_index_q == 6'd31) s_state_q <= ResultWriteWait;
end
end
ResultWriteWait: begin
if (dma_done_i) begin
if (dma_error_i) begin
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= dma_error_code_i;
s_err_stage_q <= dma_error_stage_i;
s_err_resp_q <= dma_error_resp_i;
s_err_index_q <= s_head_q;
s_err_addr_q <= dma_error_addr_i;
s_active_q <= 1'b0;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_code_q <= dma_error_code_i;
s_job_stage_q <= dma_error_stage_i;
s_job_resp_q <= dma_error_resp_i;
if (abort_i || s_abort_pending_q) s_abort_done_q <= 1'b1;
s_abort_pending_q <= 1'b0;
s_state_q <= Idle;
end else begin
s_state_q <= OwnerWriteRequest;
end
end
end
OwnerWriteRequest: begin
if (dma_request_ready_i) s_state_q <= OwnerWriteData;
end
OwnerWriteData: begin
if (dma_done_i) begin
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= dma_error_code_i;
s_err_stage_q <= dma_error_stage_i;
s_err_resp_q <= dma_error_resp_i;
s_err_index_q <= s_head_q;
s_err_addr_q <= dma_error_addr_i;
s_active_q <= 1'b0;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_code_q <= dma_error_code_i;
s_job_stage_q <= dma_error_stage_i;
s_job_resp_q <= dma_error_resp_i;
if (abort_i || s_abort_pending_q) s_abort_done_q <= 1'b1;
s_abort_pending_q <= 1'b0;
s_state_q <= Idle;
end else if (dma_write_axis.tvalid && dma_write_axis.tready) begin
s_state_q <= OwnerWriteWait;
end
end
OwnerWriteWait: begin
if (dma_done_i) begin
if (dma_error_i) begin
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= dma_error_code_i;
s_err_stage_q <= dma_error_stage_i;
s_err_resp_q <= dma_error_resp_i;
s_err_index_q <= s_head_q;
s_err_addr_q <= dma_error_addr_i;
s_active_q <= 1'b0;
s_job_busy_q <= 1'b0;
s_job_done_q <= 1'b0;
s_job_err_q <= 1'b1;
s_job_code_q <= dma_error_code_i;
s_job_stage_q <= dma_error_stage_i;
s_job_resp_q <= dma_error_resp_i;
end else begin
s_job_busy_q <= 1'b0;
s_job_done_q <= !s_job_err_q && !s_job_aborted_q;
if (!counter_clear_i) s_completed_q <= saturating_increment(s_completed_q);
s_last_index_q <= s_head_q;
s_head_q <= s_next_head;
if (s_next_head == 8'd0) s_wrapped_q <= 1'b1;
if (abort_i || s_abort_pending_q || s_job_aborted_q) begin
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
end else if (s_descriptor_ioc || (s_post_pending >= coalesce_count_i)) begin
s_ring_event_q <= 1'b1;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
end else begin
s_pending_q <= s_post_pending;
if (s_pending_q == 8'd0) s_coalesce_timer_q <= coalesce_timeout_i;
end
if (s_job_err_q) begin
s_ring_err_q <= 1'b1;
s_err_event_q <= 1'b1;
s_err_code_q <= s_job_code_q;
s_err_stage_q <= s_job_stage_q;
s_err_resp_q <= s_job_resp_q;
s_err_index_q <= s_head_q;
s_err_addr_q <= s_descriptor_addr;
if (stop_on_error_i) begin
s_stopped_q <= 1'b1;
s_active_q <= 1'b0;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
end
end
end
if (abort_i || s_abort_pending_q || s_job_aborted_q) begin
s_abort_pending_q <= 1'b0;
s_abort_done_q <= 1'b1;
end
s_state_q <= Idle;
end
end
Stalled: begin
if (abort_i) begin
s_state_q <= Idle;
s_job_busy_q <= 1'b0;
s_abort_pending_q <= 1'b0;
s_abort_done_q <= 1'b1;
end else if (quiesce_i) begin
s_state_q <= Idle;
s_job_busy_q <= 1'b0;
end else if ((s_head_q == ring_tail_i) || !s_active_q) begin
s_state_q <= Idle;
end else if (start_i && !quiesce_i) begin
s_word_index_q <= 6'd0;
s_state_q <= FetchRequest;
end
end
default: s_state_q <= Idle;
endcase
if ((s_pending_q != 8'd0) && (s_coalesce_timer_q != 16'd0) &&
!((s_state_q == OwnerWriteWait) && dma_done_i) && !abort_i && ring_enable_i) begin
if (s_coalesce_timer_q == 16'd1) begin
s_ring_event_q <= 1'b1;
s_pending_q <= 8'd0;
s_coalesce_timer_q <= 16'd0;
end else begin
s_coalesce_timer_q <= s_coalesce_timer_q - 1'b1;
end
end
end
end
endmodule
+205
View File
@@ -0,0 +1,205 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
module apu_stream_router #(
parameter int unsigned FifoDepth = 64
) (
// verilog_format: off -- preserve stream direction columns
input logic clk_i,
input logic rst_n_i,
input logic flush_i,
input logic counter_clear_i,
input logic xrun_clear_i,
input logic tx_route_apu_i,
input logic rx_route_apu_i,
input logic tx_session_active_i,
input logic rx_session_active_i,
input logic [7:0] rx_high_watermark_i,
input logic [7:0] tx_low_watermark_i,
input logic tx_underrun_i,
input logic rx_overrun_i,
axi4_stream_if.sink dma_tx_axis,
axi4_stream_if.source dma_rx_axis,
axi4_stream_if.source i2s_tx_axis,
axi4_stream_if.sink i2s_rx_axis,
axi4_stream_if.sink apu_tx_axis,
axi4_stream_if.source apu_rx_axis,
output logic [31:0] status_o,
output logic input_watermark_evt_o,
output logic output_watermark_evt_o,
output logic stream_xrun_evt_o,
output logic idle_o
// verilog_format: on
);
localparam int unsigned PayloadWidth = 44;
localparam int unsigned CountWidth = $clog2(FifoDepth) + 1;
logic [PayloadWidth-1:0] s_tx_push_data;
logic [PayloadWidth-1:0] s_tx_pop_data;
logic [PayloadWidth-1:0] s_rx_push_data;
logic [PayloadWidth-1:0] s_rx_pop_data;
logic [ CountWidth-1:0] s_tx_count;
logic [ CountWidth-1:0] s_rx_count;
logic s_tx_full, s_tx_empty, s_rx_full, s_rx_empty;
logic s_tx_push, s_tx_pop, s_rx_push, s_rx_pop;
logic s_tx_active, s_rx_active;
logic s_tx_low_armed_q, s_rx_high_armed_q;
logic s_tx_underrun_q, s_rx_overrun_q;
logic [7:0] s_tx_words_q, s_rx_words_q;
logic [CountWidth-1:0] s_tx_count_after;
logic [CountWidth-1:0] s_rx_count_after;
function automatic logic [7:0] saturating_increment(input logic [7:0] value_i);
return (&value_i) ? value_i : value_i + 1'b1;
endfunction
assign s_tx_push_data = {
apu_tx_axis.tuser,
apu_tx_axis.tdest,
apu_tx_axis.tid,
apu_tx_axis.tlast,
apu_tx_axis.tstrb,
apu_tx_axis.tkeep,
apu_tx_axis.tdata
};
assign s_rx_push_data = {
i2s_rx_axis.tuser,
i2s_rx_axis.tdest,
i2s_rx_axis.tid,
i2s_rx_axis.tlast,
i2s_rx_axis.tstrb,
i2s_rx_axis.tkeep,
i2s_rx_axis.tdata
};
assign s_tx_push = apu_tx_axis.tvalid && apu_tx_axis.tready;
assign s_tx_pop = tx_route_apu_i && i2s_tx_axis.tvalid && i2s_tx_axis.tready;
assign s_rx_push = rx_route_apu_i && i2s_rx_axis.tvalid && i2s_rx_axis.tready;
assign s_rx_pop = apu_rx_axis.tvalid && apu_rx_axis.tready;
assign apu_tx_axis.tready = !s_tx_full;
assign i2s_tx_axis.tdata = tx_route_apu_i ? s_tx_pop_data[31:0] : dma_tx_axis.tdata;
assign i2s_tx_axis.tkeep = tx_route_apu_i ? s_tx_pop_data[35:32] : dma_tx_axis.tkeep;
assign i2s_tx_axis.tstrb = tx_route_apu_i ? s_tx_pop_data[39:36] : dma_tx_axis.tstrb;
assign i2s_tx_axis.tlast = tx_route_apu_i ? s_tx_pop_data[40] : dma_tx_axis.tlast;
assign i2s_tx_axis.tid = tx_route_apu_i ? s_tx_pop_data[41] : dma_tx_axis.tid;
assign i2s_tx_axis.tdest = tx_route_apu_i ? s_tx_pop_data[42] : dma_tx_axis.tdest;
assign i2s_tx_axis.tuser = tx_route_apu_i ? s_tx_pop_data[43] : dma_tx_axis.tuser;
assign i2s_tx_axis.tvalid = tx_route_apu_i ? !s_tx_empty : dma_tx_axis.tvalid;
assign dma_tx_axis.tready = !tx_route_apu_i && i2s_tx_axis.tready;
assign i2s_rx_axis.tready = rx_route_apu_i ? !s_rx_full : dma_rx_axis.tready;
assign dma_rx_axis.tdata = i2s_rx_axis.tdata;
assign dma_rx_axis.tkeep = i2s_rx_axis.tkeep;
assign dma_rx_axis.tstrb = i2s_rx_axis.tstrb;
assign dma_rx_axis.tlast = i2s_rx_axis.tlast;
assign dma_rx_axis.tid = i2s_rx_axis.tid;
assign dma_rx_axis.tdest = i2s_rx_axis.tdest;
assign dma_rx_axis.tuser = i2s_rx_axis.tuser;
assign dma_rx_axis.tvalid = !rx_route_apu_i && i2s_rx_axis.tvalid;
assign apu_rx_axis.tdata = s_rx_pop_data[31:0];
assign apu_rx_axis.tkeep = s_rx_pop_data[35:32];
assign apu_rx_axis.tstrb = s_rx_pop_data[39:36];
assign apu_rx_axis.tlast = s_rx_pop_data[40];
assign apu_rx_axis.tid = s_rx_pop_data[41];
assign apu_rx_axis.tdest = s_rx_pop_data[42];
assign apu_rx_axis.tuser = s_rx_pop_data[43];
assign apu_rx_axis.tvalid = !s_rx_empty;
assign s_tx_active = tx_route_apu_i &&
(tx_session_active_i || !s_tx_empty || (i2s_tx_axis.tvalid && !i2s_tx_axis.tready));
assign s_rx_active = rx_route_apu_i && (rx_session_active_i || !s_rx_empty || s_rx_push);
assign idle_o = !s_tx_active && !s_rx_active;
assign s_tx_count_after = s_tx_count + CountWidth'(s_tx_push) - CountWidth'(s_tx_pop);
assign s_rx_count_after = s_rx_count + CountWidth'(s_rx_push) - CountWidth'(s_rx_pop);
assign input_watermark_evt_o = (rx_high_watermark_i != 8'd0) && s_rx_high_armed_q &&
(s_rx_count < CountWidth'(rx_high_watermark_i)) &&
(s_rx_count_after >= CountWidth'(rx_high_watermark_i));
assign output_watermark_evt_o = (tx_low_watermark_i != 8'd0) && s_tx_low_armed_q &&
s_tx_active && (s_tx_count > CountWidth'(tx_low_watermark_i)) &&
(s_tx_count_after <= CountWidth'(tx_low_watermark_i));
assign stream_xrun_evt_o = (tx_route_apu_i && tx_underrun_i) || (rx_route_apu_i && rx_overrun_i);
assign status_o = {
8'd0,
s_rx_words_q,
s_tx_words_q,
s_rx_overrun_q,
s_tx_underrun_q,
s_rx_full,
s_rx_empty,
s_tx_full,
s_tx_empty,
s_rx_active,
s_tx_active
};
stream_fifo #(
.DATA_WIDTH (PayloadWidth),
.BUFFER_DEPTH(FifoDepth)
) u_tx_fifo (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.flush_i(flush_i),
.full_o (s_tx_full),
.empty_o(s_tx_empty),
.cnt_o (s_tx_count),
.dat_i (s_tx_push_data),
.push_i (s_tx_push),
.dat_o (s_tx_pop_data),
.pop_i (s_tx_pop)
);
stream_fifo #(
.DATA_WIDTH (PayloadWidth),
.BUFFER_DEPTH(FifoDepth)
) u_rx_fifo (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.flush_i(flush_i),
.full_o (s_rx_full),
.empty_o(s_rx_empty),
.cnt_o (s_rx_count),
.dat_i (s_rx_push_data),
.push_i (s_rx_push),
.dat_o (s_rx_pop_data),
.pop_i (s_rx_pop)
);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i || flush_i) begin
s_tx_low_armed_q <= 1'b0;
s_rx_high_armed_q <= 1'b1;
s_tx_underrun_q <= 1'b0;
s_rx_overrun_q <= 1'b0;
s_tx_words_q <= 8'd0;
s_rx_words_q <= 8'd0;
end else begin
if ((tx_low_watermark_i == 8'd0) ||
(s_tx_count_after > CountWidth'(tx_low_watermark_i))) begin
s_tx_low_armed_q <= tx_low_watermark_i != 8'd0;
end else if (output_watermark_evt_o) begin
s_tx_low_armed_q <= 1'b0;
end
if ((rx_high_watermark_i == 8'd0) ||
(s_rx_count_after < CountWidth'(rx_high_watermark_i))) begin
s_rx_high_armed_q <= 1'b1;
end else if (input_watermark_evt_o) begin
s_rx_high_armed_q <= 1'b0;
end
s_tx_underrun_q <= (s_tx_underrun_q && !xrun_clear_i) || (tx_route_apu_i && tx_underrun_i);
s_rx_overrun_q <= (s_rx_overrun_q && !xrun_clear_i) || (rx_route_apu_i && rx_overrun_i);
if (counter_clear_i) begin
s_tx_words_q <= 8'd0;
s_rx_words_q <= 8'd0;
end else begin
if (s_tx_pop) s_tx_words_q <= saturating_increment(s_tx_words_q);
if (s_rx_push) s_rx_words_q <= saturating_increment(s_rx_words_q);
end
end
end
`ifndef SYNTHESIS
initial begin
if (FifoDepth != 64) $fatal(1, "apu_stream_router: P2 requires 64-word FIFOs");
end
`endif
endmodule
+1
View File
@@ -442,6 +442,7 @@ module jpeg_dma #(
) u_axi4_master (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clear_i (1'b0),
.read_start_valid_i (s_read_start_valid),
.read_start_ready_o (s_read_start_ready),
.read_addr_i (s_read_addr_q),
+13
View File
@@ -18,6 +18,7 @@ module dma_axi4_master #(
// verilog_format: off -- AXI command/data ports are aligned with their response groups.
input logic clk_i,
input logic rst_n_i,
input logic clear_i,
input logic read_start_valid_i,
output logic read_start_ready_o,
input logic [AddrWidth-1:0] read_addr_i,
@@ -141,6 +142,12 @@ module dma_axi4_master #(
s_read_beats_q <= 5'd1;
s_read_beat_q <= '0;
s_read_fixed_q <= 1'b0;
end else if (clear_i) begin
s_read_state_q <= ReadIdle;
s_read_addr_q <= '0;
s_read_beats_q <= 5'd1;
s_read_beat_q <= '0;
s_read_fixed_q <= 1'b0;
end else begin
unique case (s_read_state_q)
ReadIdle: begin
@@ -178,6 +185,12 @@ module dma_axi4_master #(
s_write_beats_q <= 5'd1;
s_write_beat_q <= '0;
s_write_fixed_q <= 1'b0;
end else if (clear_i) begin
s_write_state_q <= WriteIdle;
s_write_addr_q <= '0;
s_write_beats_q <= 5'd1;
s_write_beat_q <= '0;
s_write_fixed_q <= 1'b0;
end else begin
unique case (s_write_state_q)
WriteIdle: begin
+1
View File
@@ -341,6 +341,7 @@ module dma_core #(
) u_dma_axi4_master (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clear_i (1'b0),
.read_start_valid_i (s_axi_read_start_valid),
.read_start_ready_o (s_axi_read_start_ready),
.read_addr_i (s_axi_read_start_addr),
+4
View File
@@ -38,6 +38,8 @@ module apb4_i2s (
input logic rst_aud_n_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o,
output logic tx_underrun_evt_o,
output logic rx_overrun_evt_o,
apb4_if.slave apb4,
axi4_stream_if.sink tx_axis,
axi4_stream_if.source rx_axis,
@@ -126,6 +128,8 @@ module apb4_i2s (
assign s_rx_flush_busy = s_cmd_rx_flush || s_rx_dst_clear_busy || s_rx_src_busy_sys;
assign s_tx_underrun_sys = s_tx_underrun_re || s_tx_underrun_fe;
assign s_rx_overrun_sys = s_rx_overrun_re || s_rx_overrun_fe;
assign tx_underrun_evt_o = s_tx_underrun_sys;
assign rx_overrun_evt_o = s_rx_overrun_sys;
assign s_tx_push = s_tx_src_valid && s_tx_src_ready;
assign s_rx_pop = s_rx_dst_valid && s_rx_dst_ready;
assign s_tx_level = s_tx_flush_busy ? 8'd0 : (s_tx_push_cnt_q - s_tx_pop_cnt_sys_q);
+1
View File
@@ -222,6 +222,7 @@ module sdio_dma #(
) u_dma_axi4_master (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clear_i (1'b0),
.read_start_valid_i (s_read_start_valid),
.read_start_ready_o (s_read_start_ready),
.read_addr_i (s_read_addr),
+1
View File
@@ -301,6 +301,7 @@ module usb2_dma #(
) u_axi4_master (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clear_i (1'b0),
.read_start_valid_i (s_read_start_valid),
.read_start_ready_o (s_read_start_ready),
.read_addr_i (s_read_addr),
+3
View File
@@ -125,6 +125,9 @@
/ip/multimedia/dvp_core.sv
/ip/multimedia/dvp_reg.sv
/ip/multimedia/axi4s_dvp.sv
/ip/multimedia/apu_dma.sv
/ip/multimedia/apu_ring_scheduler.sv
/ip/multimedia/apu_stream_router.sv
/ip/multimedia/apu_reg.sv
/ip/multimedia/apb4_apu.sv
/ip/multimedia/jpeg_pkg.sv
+248
View File
@@ -0,0 +1,248 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
`include "axi4_define.svh"
module apu_formal_design (
// verilog_format: off -- expose the bounded DMA scenario and AXI observations
input logic clk_i,
output logic rst_n_i,
output logic f_past_valid,
output logic [2:0] scenario,
output logic [5:0] cycle,
output logic busy,
output logic done,
output logic error,
output logic aborted,
output logic [5:0] error_code,
output logic [63:0] read_bytes,
output logic [63:0] write_bytes,
output logic terminal_seen,
output logic terminal_error,
output logic terminal_aborted,
output logic [5:0] terminal_code,
output logic awvalid,
output logic awready,
output logic [31:0] awaddr,
output logic [7:0] awlen,
output logic [2:0] awsize,
output logic [1:0] awburst,
output logic [3:0] awcache,
output logic [2:0] awprot,
output logic wvalid,
output logic wready,
output logic [3:0] wstrb,
output logic wlast,
output logic bvalid,
output logic bready,
output logic arvalid,
output logic arready,
output logic [31:0] araddr,
output logic [7:0] arlen,
output logic [2:0] arsize,
output logic [1:0] arburst,
output logic [3:0] arcache,
output logic [2:0] arprot,
output logic rvalid,
output logic rready,
output logic rlast
// verilog_format: on
);
(* anyconst *)logic [ 2:0] f_scenario;
(* anyconst *)logic [31:0] f_read_data;
logic [ 5:0] s_cycle_q;
logic s_read_active_q;
logic s_write_active_q;
logic s_write_response_q;
logic s_terminal_seen_q;
logic s_terminal_error_q;
logic s_terminal_aborted_q;
logic [ 5:0] s_terminal_code_q;
logic s_request_write;
logic s_abort;
logic [ 1:0] s_source_beat_q;
logic s_done, s_error, s_aborted;
logic [ 5:0] s_error_code;
logic [ 3:0] s_error_stage;
logic [ 1:0] s_error_resp;
logic [31:0] s_error_addr;
logic [63:0] s_read_bytes, s_write_bytes;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32)
) read_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32)
) write_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
assign s_request_write = f_scenario == 2'd1;
assign s_abort = (f_scenario == 2'd3) && (s_cycle_q == 6'd4);
assign read_axis.tready = 1'b1;
assign write_axis.tdata = 32'hcafe_0000 | {30'd0, s_source_beat_q};
assign write_axis.tkeep = 4'hf;
assign write_axis.tstrb = 4'hf;
assign write_axis.tlast = s_source_beat_q == 2'd1;
assign write_axis.tid = '0;
assign write_axis.tdest = '0;
assign write_axis.tuser = '0;
assign write_axis.tvalid = f_scenario == 2'd1;
assign axi4.arready = !s_read_active_q &&
((f_scenario == 3'd0) || (f_scenario == 3'd4) || (f_scenario == 3'd5) ||
((f_scenario == 3'd2) && (s_cycle_q >= 6'd12)) ||
((f_scenario == 3'd3) && (s_cycle_q >= 6'd7)));
assign axi4.rid = 1'b0;
assign axi4.rdata = f_read_data;
assign axi4.rresp = `AXI4_RESP_OKAY;
assign axi4.rlast = f_scenario != 3'd5;
assign axi4.ruser = 1'b0;
assign axi4.rvalid = s_read_active_q;
assign axi4.awready = (f_scenario == 2'd1) && !s_write_active_q && !s_write_response_q;
assign axi4.wready = s_write_active_q;
assign axi4.bid = 1'b0;
assign axi4.bresp = `AXI4_RESP_OKAY;
assign axi4.buser = 1'b0;
assign axi4.bvalid = s_write_response_q;
apu_dma u_dut (
.clk_i,
.rst_n_i,
.abort_i(s_abort),
.quiesce_i(1'b0),
.bridge_epoch_i((f_scenario == 3'd4) ? 8'd1 : 8'd0),
.perf_enable_i(1'b1),
.counter_clear_i(1'b0),
.request_valid_i (rst_n_i &&
((s_cycle_q == 6'd0) ||
((f_scenario == 3'd4) && (s_cycle_q < 6'd3)))),
.request_ready_o(),
.request_write_i(s_request_write),
.request_addr_i(32'h0000_0ffc),
.request_bytes_i(32'd8),
.read_base_i(32'd0),
.read_limit_i(32'h0000_ffff),
.write_base_i(32'd0),
.write_limit_i(32'h0000_ffff),
.timeout_i(32'd8),
.read_axis,
.write_axis,
.busy_o(busy),
.done_o(s_done),
.error_o(s_error),
.aborted_o(s_aborted),
.aborting_o(),
.error_code_o(s_error_code),
.error_stage_o(s_error_stage),
.error_resp_o(s_error_resp),
.error_addr_o(s_error_addr),
.input_pending_o(),
.output_pending_o(),
.read_bytes_o(s_read_bytes),
.write_bytes_o(s_write_bytes),
.read_stalls_o(),
.write_stalls_o(),
.axi4
);
assign scenario = f_scenario;
assign cycle = s_cycle_q;
assign done = s_done;
assign error = s_error;
assign aborted = s_aborted;
assign error_code = s_error_code;
assign read_bytes = s_read_bytes;
assign write_bytes = s_write_bytes;
assign terminal_seen = s_terminal_seen_q;
assign terminal_error = s_terminal_error_q;
assign terminal_aborted = s_terminal_aborted_q;
assign terminal_code = s_terminal_code_q;
assign awvalid = axi4.awvalid;
assign awready = axi4.awready;
assign awaddr = axi4.awaddr;
assign awlen = axi4.awlen;
assign awsize = axi4.awsize;
assign awburst = axi4.awburst;
assign awcache = axi4.awcache;
assign awprot = axi4.awprot;
assign wvalid = axi4.wvalid;
assign wready = axi4.wready;
assign wstrb = axi4.wstrb;
assign wlast = axi4.wlast;
assign bvalid = axi4.bvalid;
assign bready = axi4.bready;
assign arvalid = axi4.arvalid;
assign arready = axi4.arready;
assign araddr = axi4.araddr;
assign arlen = axi4.arlen;
assign arsize = axi4.arsize;
assign arburst = axi4.arburst;
assign arcache = axi4.arcache;
assign arprot = axi4.arprot;
assign rvalid = axi4.rvalid;
assign rready = axi4.rready;
assign rlast = axi4.rlast;
initial begin
rst_n_i = 1'b0;
f_past_valid = 1'b0;
end
always_ff @(posedge clk_i) begin
rst_n_i <= 1'b1;
f_past_valid <= 1'b1;
if (!rst_n_i) begin
s_cycle_q <= 6'd0;
s_terminal_seen_q <= 1'b0;
s_terminal_error_q <= 1'b0;
s_terminal_aborted_q <= 1'b0;
s_terminal_code_q <= 6'd0;
end else begin
if (s_cycle_q != 6'h3f) s_cycle_q <= s_cycle_q + 1'b1;
if (s_done) begin
s_terminal_seen_q <= 1'b1;
s_terminal_error_q <= s_error;
s_terminal_aborted_q <= s_aborted;
s_terminal_code_q <= s_error_code;
end
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_read_active_q <= 1'b0;
s_write_active_q <= 1'b0;
s_write_response_q <= 1'b0;
s_source_beat_q <= 2'd0;
end else begin
if (axi4.arvalid && axi4.arready) s_read_active_q <= 1'b1;
if (axi4.rvalid && axi4.rready) s_read_active_q <= 1'b0;
if (axi4.awvalid && axi4.awready) s_write_active_q <= 1'b1;
if (axi4.wvalid && axi4.wready) begin
s_source_beat_q <= s_source_beat_q + 1'b1;
if (axi4.wlast) begin
s_write_active_q <= 1'b0;
s_write_response_q <= 1'b1;
end
end
if (axi4.bvalid && axi4.bready) s_write_response_q <= 1'b0;
end
end
logic s_unused_result;
assign s_unused_result = ^s_error_stage ^ ^s_error_resp ^ ^s_error_addr;
endmodule
+93
View File
@@ -0,0 +1,93 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
module apu_formal;
(* anyseq *) (* gclk *) reg clk_i;
wire rst_n_i, f_past_valid;
wire [2:0] scenario;
wire [5:0] cycle;
wire busy, done, error, aborted;
wire [5:0] error_code;
wire [63:0] read_bytes, write_bytes;
wire terminal_seen, terminal_error, terminal_aborted;
wire [5:0] terminal_code;
wire awvalid, awready, wvalid, wready, wlast, bvalid, bready;
wire arvalid, arready, rvalid, rready, rlast;
wire [31:0] awaddr, araddr;
wire [7:0] awlen, arlen;
wire [2:0] awsize, arsize;
wire [1:0] awburst, arburst;
wire [3:0] awcache, arcache, wstrb;
wire [2:0] awprot, arprot;
apu_formal_design u_design (.*);
always @(posedge clk_i) begin
if (rst_n_i) begin
assume (scenario <= 3'd5);
assert (!(awvalid && arvalid));
if (awvalid) begin
assert (awlen < 8'd16);
assert (awsize == 3'd2);
assert (awburst == 2'd1);
assert (awcache == 4'd0);
assert (awprot[2] == 1'b0);
assert ({1'b0, awaddr[11:0]} + (({5'd0, awlen} + 1'b1) << awsize) <= 13'd4096);
end
if (arvalid) begin
assert (arlen < 8'd16);
assert (arsize == 3'd2);
assert (arburst == 2'd1);
assert (arcache == 4'd0);
assert (arprot[2] == 1'b0);
assert ({1'b0, araddr[11:0]} + (({5'd0, arlen} + 1'b1) << arsize) <= 13'd4096);
end
if (wvalid) assert (wstrb != 4'd0);
if (done) begin
if (scenario == 3'd0) assert (!error && !aborted && (read_bytes == 64'd8));
if (scenario == 3'd1) assert (!error && !aborted && (write_bytes == 64'd8));
if (scenario == 3'd2) assert (error && !aborted && (error_code == 6'd17));
if (scenario == 3'd3) assert (!error && aborted && (error_code == 6'd20));
if (scenario == 3'd4) assert (!error && !aborted && (read_bytes == 64'd8));
if (scenario == 3'd5) assert (error && !aborted && (error_code == 6'd15));
end
if (cycle >= 6'd20) begin
assert (terminal_seen);
if (scenario == 3'd2) assert (terminal_error && (terminal_code == 6'd17));
if (scenario == 3'd3)
assert (!terminal_error && terminal_aborted && (terminal_code == 6'd20));
if (scenario == 3'd4) assert (!terminal_error && !terminal_aborted);
if (scenario == 3'd5) assert (terminal_error && (terminal_code == 6'd15));
end
end
if (f_past_valid && $past(rst_n_i)) begin
if ($past(awvalid && !awready)) begin
assert (awvalid);
assert (awaddr == $past(awaddr));
assert (awlen == $past(awlen));
end
if ($past(arvalid && !arready)) begin
assert (arvalid);
assert (araddr == $past(araddr));
assert (arlen == $past(arlen));
end
if ($past(wvalid && !wready)) begin
assert (wvalid);
assert (wstrb == $past(wstrb));
assert (wlast == $past(wlast));
end
if ($past(bvalid && !bready)) assert (bvalid);
if ($past(rvalid && !rready)) begin
assert (rvalid);
assert (rlast == $past(rlast));
end
end
cover (rst_n_i && done && (scenario == 3'd0));
cover (rst_n_i && done && (scenario == 3'd1));
cover (rst_n_i && done && (scenario == 3'd2));
cover (rst_n_i && done && (scenario == 3'd3));
cover (rst_n_i && done && (scenario == 3'd4));
cover (rst_n_i && done && (scenario == 3'd5));
end
endmodule
+220
View File
@@ -0,0 +1,220 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
module gateway_a_formal_design (
input logic clk_i,
output logic rst_n_i,
output logic f_past_valid,
output logic [ 5:0] cycle,
output logic [ 2:0] response,
output logic [ 2:0] seen,
output logic address_valid,
output logic address_ready,
output logic [31:0] address_value,
output logic address_accept,
output logic terminal
);
logic [ 5:0] s_cycle_q;
logic s_response_valid_q;
logic [31:0] s_response_data_q;
logic [ 2:0] s_seen_q;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) icache (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) dcache (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) mmio (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
.aclk (clk_i),
.aresetn(rst_n_i)
);
assign icache.arid = 1'b0;
assign dcache.arid = 1'b0;
assign mmio.arid = 1'b0;
assign icache.araddr = 32'h0000_1000;
assign dcache.araddr = 32'h0000_2000;
assign mmio.araddr = 32'h0000_3000;
assign icache.arlen = 8'd0;
assign dcache.arlen = 8'd0;
assign mmio.arlen = 8'd0;
assign icache.arsize = 3'd2;
assign dcache.arsize = 3'd2;
assign mmio.arsize = 3'd2;
assign icache.arburst = 2'd1;
assign dcache.arburst = 2'd1;
assign mmio.arburst = 2'd1;
assign icache.arlock = 1'b0;
assign dcache.arlock = 1'b0;
assign mmio.arlock = 1'b0;
assign icache.arcache = 4'd0;
assign dcache.arcache = 4'd0;
assign mmio.arcache = 4'd0;
assign icache.arprot = 3'd0;
assign dcache.arprot = 3'd0;
assign mmio.arprot = 3'd0;
assign icache.arqos = 4'd0;
assign dcache.arqos = 4'd0;
assign mmio.arqos = 4'd0;
assign icache.arregion = 4'd0;
assign dcache.arregion = 4'd0;
assign mmio.arregion = 4'd0;
assign icache.aruser = 1'b0;
assign dcache.aruser = 1'b0;
assign mmio.aruser = 1'b0;
assign icache.arvalid = rst_n_i;
assign dcache.arvalid = rst_n_i && (s_cycle_q >= 6'd1);
assign mmio.arvalid = rst_n_i && (s_cycle_q >= 6'd2);
assign icache.rready = 1'b1;
assign dcache.rready = 1'b1;
assign mmio.rready = 1'b1;
assign icache.awid = 1'b0;
assign dcache.awid = 1'b0;
assign mmio.awid = 1'b0;
assign icache.awaddr = 32'd0;
assign dcache.awaddr = 32'd0;
assign mmio.awaddr = 32'd0;
assign icache.awlen = 8'd0;
assign dcache.awlen = 8'd0;
assign mmio.awlen = 8'd0;
assign icache.awsize = 3'd2;
assign dcache.awsize = 3'd2;
assign mmio.awsize = 3'd2;
assign icache.awburst = 2'd1;
assign dcache.awburst = 2'd1;
assign mmio.awburst = 2'd1;
assign icache.awlock = 1'b0;
assign dcache.awlock = 1'b0;
assign mmio.awlock = 1'b0;
assign icache.awcache = 4'd0;
assign dcache.awcache = 4'd0;
assign mmio.awcache = 4'd0;
assign icache.awprot = 3'd0;
assign dcache.awprot = 3'd0;
assign mmio.awprot = 3'd0;
assign icache.awqos = 4'd0;
assign dcache.awqos = 4'd0;
assign mmio.awqos = 4'd0;
assign icache.awregion = 4'd0;
assign dcache.awregion = 4'd0;
assign mmio.awregion = 4'd0;
assign icache.awuser = 1'b0;
assign dcache.awuser = 1'b0;
assign mmio.awuser = 1'b0;
assign icache.awvalid = 1'b0;
assign dcache.awvalid = 1'b0;
assign mmio.awvalid = 1'b0;
assign icache.wdata = 32'd0;
assign dcache.wdata = 32'd0;
assign mmio.wdata = 32'd0;
assign icache.wstrb = 4'd0;
assign dcache.wstrb = 4'd0;
assign mmio.wstrb = 4'd0;
assign icache.wlast = 1'b0;
assign dcache.wlast = 1'b0;
assign mmio.wlast = 1'b0;
assign icache.wuser = 1'b0;
assign dcache.wuser = 1'b0;
assign mmio.wuser = 1'b0;
assign icache.wvalid = 1'b0;
assign dcache.wvalid = 1'b0;
assign mmio.wvalid = 1'b0;
assign icache.bready = 1'b1;
assign dcache.bready = 1'b1;
assign mmio.bready = 1'b1;
assign axi4.awready = 1'b0;
assign axi4.wready = 1'b0;
assign axi4.bid = 1'b0;
assign axi4.bresp = 2'd0;
assign axi4.buser = 1'b0;
assign axi4.bvalid = 1'b0;
assign axi4.arready = !s_response_valid_q && (s_cycle_q >= 6'd3);
assign axi4.rid = 1'b0;
assign axi4.rdata = s_response_data_q;
assign axi4.rresp = 2'd0;
assign axi4.rlast = 1'b1;
assign axi4.ruser = 1'b0;
assign axi4.rvalid = s_response_valid_q;
hp_axi4_mux3 #(
.RoundRobin(1'b1)
) u_dut (
.clk_i,
.rst_n_i,
.epoch_i(8'd0),
.icache,
.dcache,
.mmio,
.axi4
);
assign cycle = s_cycle_q;
assign response = {
mmio.rvalid && mmio.rready, dcache.rvalid && dcache.rready, icache.rvalid && icache.rready
};
assign seen = s_seen_q;
assign address_valid = axi4.arvalid;
assign address_ready = axi4.arready;
assign address_value = axi4.araddr;
assign address_accept = axi4.arvalid && axi4.arready;
assign terminal = axi4.rvalid && axi4.rready && axi4.rlast;
initial begin
rst_n_i = 1'b0;
f_past_valid = 1'b0;
end
always_ff @(posedge clk_i) begin
rst_n_i <= 1'b1;
f_past_valid <= 1'b1;
if (!rst_n_i) begin
s_cycle_q <= 6'd0;
s_seen_q <= 3'd0;
end else begin
if (s_cycle_q != 6'h3f) s_cycle_q <= s_cycle_q + 1'b1;
s_seen_q <= s_seen_q | response;
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_response_valid_q <= 1'b0;
s_response_data_q <= 32'd0;
end else begin
if (axi4.arvalid && axi4.arready) begin
s_response_valid_q <= 1'b1;
s_response_data_q <= axi4.araddr;
end
if (axi4.rvalid && axi4.rready) s_response_valid_q <= 1'b0;
end
end
endmodule
+43
View File
@@ -0,0 +1,43 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
module gateway_a_formal;
(* anyseq *) (* gclk *) reg clk_i;
wire rst_n_i, f_past_valid;
wire [5:0] cycle;
wire [2:0] response, seen;
wire address_valid, address_ready;
wire [31:0] address_value;
wire address_accept, terminal;
logic [1:0] f_expected_q;
gateway_a_formal_design u_design (.*);
always @(posedge clk_i) begin
if (!rst_n_i) begin
f_expected_q <= 2'd0;
end else begin
assert ($onehot0(response));
if (response != 3'd0) begin
case (f_expected_q)
2'd0: assert (response == 3'b001);
2'd1: assert (response == 3'b010);
default: assert (response == 3'b100);
endcase
f_expected_q <= (f_expected_q == 2'd2) ? 2'd0 : f_expected_q + 1'b1;
end
if (cycle >= 6'd12) assert (seen == 3'b111);
assert (terminal == (response != 3'd0));
end
if (f_past_valid && $past(rst_n_i) && $past(address_valid && !address_ready)) begin
assert (address_valid);
assert (address_value == $past(address_value));
end
cover (rst_n_i && (seen == 3'b111));
end
logic s_unused_observation;
assign s_unused_observation = f_past_valid ^ address_accept;
endmodule
@@ -22,6 +22,7 @@ PERIPHERAL = ROOT / "rtl/ip/peripheral"
SERIAL = ROOT / "rtl/ip/serial"
MEMORY = ROOT / "rtl/ip/memory"
STORAGE = ROOT / "rtl/ip/storage"
MULTIMEDIA = ROOT / "rtl/ip/multimedia"
TOP = ROOT / "rtl/mini/top"
@@ -247,6 +248,23 @@ def source_files(target: str) -> list[Path]:
PERIPHERAL / "dma_core.sv",
SCRIPT_DIR / "dma_formal.sv",
]
if target == "apu":
return [
COMMON_RTL / "interface/axi4_if.sv",
COMMON_RTL / "interface/axi4_stream_if.sv",
COMMON_RTL / "utils/register.sv",
PERIPHERAL / "dma_axi4_master.sv",
MULTIMEDIA / "apu_dma.sv",
SCRIPT_DIR / "apu_formal.sv",
]
if target == "gateway_a":
return [
COMMON_RTL / "interface/axi4_if.sv",
COMMON_RTL / "utils/register.sv",
COMMON_RTL / "stream/round_robin_arbiter.sv",
TOP / "hp_axi4_mux3.sv",
SCRIPT_DIR / "gateway_a_formal.sv",
]
if target == "sdio":
return [
COMMON_RTL / "interface/apb4_if.sv",
@@ -285,6 +303,7 @@ def generate(
PERIPHERAL,
SERIAL,
MEMORY,
MULTIMEDIA,
],
files=source_files(target),
).deduplicate()
@@ -313,6 +332,8 @@ def parse_args() -> argparse.Namespace:
"onchip_ram",
"opipsram",
"dma",
"apu",
"gateway_a",
"sdio",
),
required=True,
@@ -109,6 +109,7 @@
{"name": "sram_config", "source": "pclk", "destination": "hp", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_sram_cfg_cdc"},
{"name": "fabric_monitor", "source": "pclk", "destination": "hp", "primitive": "apb4_async_bridge", "path": "rtl/mini/top/retrosoc.sv", "instance": "u_fabric_monitor_cdc"},
{"name": "io_dma_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_io_cdc"},
{"name": "apu_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_io_cdc"},
{"name": "jpeg_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_jpeg_cdc"},
{"name": "extension_h_data", "source": "pclk", "destination": "hp", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_ext_h_cdc"},
{"name": "sdram_data", "source": "hp", "destination": "memory", "primitive": "axi4_async_bridge", "path": "rtl/mini/top/soc_data_plane.sv", "instance": "u_target_cdc"},
+21 -6
View File
@@ -14,6 +14,8 @@ FORMAL_OPIPSRAM_DEPTH ?= 40
FORMAL_OPIPSRAM_BMC_DEPTH ?= 40
FORMAL_DMA_DEPTH ?= 24
FORMAL_DMA_COVER_DEPTH ?= 32
FORMAL_APU_DEPTH ?= 24
FORMAL_GATEWAY_A_DEPTH ?= 20
FORMAL_SDIO_DEPTH ?= 20
FORMAL_SDIO_COVER_DEPTH ?= 24
FORMAL_TIMEOUT ?= 60
@@ -22,9 +24,12 @@ FORMAL_I2C_TIMEOUT ?= 300
FORMAL_OPIPSRAM_TIMEOUT ?= 300
FORMAL_OPIPSRAM_BMC_TIMEOUT ?= 600
FORMAL_DMA_TIMEOUT ?= 120
FORMAL_APU_TIMEOUT ?= 120
FORMAL_GATEWAY_A_TIMEOUT ?= 120
FORMAL_SDIO_TIMEOUT ?= 120
FORMAL_TARGET_TIMEOUT = $(if $(filter dma,$*),$(FORMAL_DMA_TIMEOUT),$(if $(filter apu,$*),$(FORMAL_APU_TIMEOUT),$(if $(filter gateway_a,$*),$(FORMAL_GATEWAY_A_TIMEOUT),$(if $(filter sdio,$*),$(FORMAL_SDIO_TIMEOUT),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_TIMEOUT),$(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(if $(filter i2c,$*),$(FORMAL_I2C_TIMEOUT),$(FORMAL_TIMEOUT))))))))
FORMAL_COMPACT_COVER_TARGETS := i2c opipsram dma
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart i2c timer clint dvp i2s psram onchip_ram opipsram dma sdio
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart i2c timer clint dvp i2s psram onchip_ram opipsram dma apu gateway_a sdio
FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py
FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py
FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py
@@ -62,6 +67,10 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(RTL_PATH)/formal/opipsram_formal_props.sv \
$(RTL_PATH)/formal/dma_formal.sv \
$(RTL_PATH)/formal/dma_formal_props.sv \
$(RTL_PATH)/formal/apu_formal.sv \
$(RTL_PATH)/formal/apu_formal_props.sv \
$(RTL_PATH)/formal/gateway_a_formal.sv \
$(RTL_PATH)/formal/gateway_a_formal_props.sv \
$(RTL_PATH)/formal/sdio_formal.sv \
$(RTL_PATH)/formal/sdio_formal_props.sv \
$(RTL_PATH)/top/rib_bus.sv \
@@ -140,10 +149,12 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(ROOT_PATH)/rtl/ip/peripheral/dma_pkg.sv \
$(ROOT_PATH)/rtl/ip/peripheral/dma_req_if.sv \
$(ROOT_PATH)/rtl/ip/peripheral/dma_axi4_master.sv \
$(ROOT_PATH)/rtl/ip/multimedia/apu_dma.sv \
$(ROOT_PATH)/rtl/ip/peripheral/dma_core.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/clkrst/counter.sv \
$(RTL_PATH)/top/rcu.sv \
$(RTL_PATH)/top/pll_rcu_controller.sv \
$(RTL_PATH)/top/hp_axi4_mux3.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/apb4_if.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/ribp_if.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/apb4_pure_if.sv \
@@ -187,14 +198,14 @@ $(FORMAL_DIR)/%/prove.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_
$(FORMAL_SBY_GENERATOR)
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
--mode $(if $(filter dma sdio onchip_ram,$*),bmc,prove) --depth $(if $(filter pll_rcu,$*),$(FORMAL_PLL_RCU_DEPTH),$(if $(filter dma,$*),$(FORMAL_DMA_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH))))))))) --output $@
--mode $(if $(filter dma apu gateway_a sdio onchip_ram,$*),bmc,prove) --depth $(if $(filter pll_rcu,$*),$(FORMAL_PLL_RCU_DEPTH),$(if $(filter dma,$*),$(FORMAL_DMA_DEPTH),$(if $(filter apu,$*),$(FORMAL_APU_DEPTH),$(if $(filter gateway_a,$*),$(FORMAL_GATEWAY_A_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH))))))))))) --output $@
@if [ "$*" = opipsram ]; then sed -i '/^async2sync/i clk2fflogic' $@; fi
$(FORMAL_DIR)/%/cover.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_props.sv \
$(FORMAL_SBY_GENERATOR)
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
--mode cover --depth $(if $(filter pll_rcu,$*),$(FORMAL_PLL_RCU_DEPTH),$(if $(filter dma,$*),$(FORMAL_DMA_COVER_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_COVER_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH))))))))) \
--mode cover --depth $(if $(filter pll_rcu,$*),$(FORMAL_PLL_RCU_DEPTH),$(if $(filter dma,$*),$(FORMAL_DMA_COVER_DEPTH),$(if $(filter apu,$*),$(FORMAL_APU_DEPTH),$(if $(filter gateway_a,$*),$(FORMAL_GATEWAY_A_DEPTH),$(if $(filter sdio,$*),$(FORMAL_SDIO_COVER_DEPTH),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_DEPTH),$(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(if $(filter psram,$*),$(FORMAL_PSRAM_DEPTH),$(FORMAL_DEPTH))))))))))) \
$(if $(filter $(FORMAL_COMPACT_COVER_TARGETS),$*),--no-vcd) --output $@
@if [ "$*" = opipsram ]; then sed -i '/^async2sync/i clk2fflogic' $@; fi
@@ -218,7 +229,7 @@ $(FORMAL_DIR)/%/prove.stamp: $(FORMAL_DIR)/%/prove.sby $(FORMAL_SOLVER_WRAPPER)
--log $(@D)/prove.log --result $(@D)/result-prove.json \
--env RETROSOC_BITWUZLA=$(FORMAL_BITWUZLA) \
--env PATH=$(FORMAL_SOLVER_DIR):$(PATH) \
-- timeout --foreground --kill-after=5s $(if $(filter dma,$*),$(FORMAL_DMA_TIMEOUT),$(if $(filter sdio,$*),$(FORMAL_SDIO_TIMEOUT),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_TIMEOUT),$(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(if $(filter i2c,$*),$(FORMAL_I2C_TIMEOUT),$(FORMAL_TIMEOUT))))))s $(FORMAL_SBY) \
-- timeout --foreground --kill-after=5s $(FORMAL_TARGET_TIMEOUT)s $(FORMAL_SBY) \
-f -d $(@D)/prove $<
@test "$$(awk '{print $$1}' $(@D)/prove/status)" = PASS
@touch $@
@@ -228,7 +239,7 @@ $(FORMAL_DIR)/%/cover.stamp: $(FORMAL_DIR)/%/cover.sby $(FORMAL_SOLVER_WRAPPER)
--log $(@D)/cover.log --result $(@D)/result-cover.json \
--env RETROSOC_BITWUZLA=$(FORMAL_BITWUZLA) \
--env PATH=$(FORMAL_SOLVER_DIR):$(PATH) \
-- timeout --foreground --kill-after=5s $(if $(filter dma,$*),$(FORMAL_DMA_TIMEOUT),$(if $(filter sdio,$*),$(FORMAL_SDIO_TIMEOUT),$(if $(filter opipsram,$*),$(FORMAL_OPIPSRAM_TIMEOUT),$(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(if $(filter i2c,$*),$(FORMAL_I2C_TIMEOUT),$(FORMAL_TIMEOUT))))))s $(FORMAL_SBY) \
-- timeout --foreground --kill-after=5s $(FORMAL_TARGET_TIMEOUT)s $(FORMAL_SBY) \
-f -d $(@D)/cover $<
@test "$$(awk '{print $$1}' $(@D)/cover/status)" = PASS
@touch $@
@@ -291,6 +302,10 @@ formal-opipsram: $(FORMAL_DIR)/opipsram/.stamp | manifest
formal-dma: $(FORMAL_DIR)/dma/.stamp | manifest
formal-apu: $(FORMAL_DIR)/apu/.stamp | manifest
formal-gateway-a: $(FORMAL_DIR)/gateway_a/.stamp | manifest
formal-sdio: $(FORMAL_DIR)/sdio/.stamp | manifest
formal-doctor:
@@ -299,4 +314,4 @@ formal-doctor:
formal-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clint formal-dvp formal-i2s formal-psram formal-onchip-ram formal-opipsram formal-dma formal-sdio formal-doctor formal-clean
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clint formal-dvp formal-i2s formal-psram formal-onchip-ram formal-opipsram formal-dma formal-apu formal-gateway-a formal-sdio formal-doctor formal-clean
+52 -21
View File
@@ -29,6 +29,7 @@ module apb4_periph (
input logic apu_owner_lock_i,
input logic apu_quiesce_i,
input logic apu_reset_i,
input logic [7:0] apu_bridge_epoch_i,
input logic jpeg_quiesce_i,
input logic jpeg_reset_i,
axi4_if.slave cfg_axi4,
@@ -50,6 +51,7 @@ module apb4_periph (
axi4_if.master sdio0_axi4,
axi4_if.master sdio1_axi4,
axi4_if.master usb2_axi4,
axi4_if.master apu_axi4,
axi4_if.master jpeg_axi4,
sysctrl_if.dut sysctrl,
pll_ctrl_if.sysctrl pll_ctrl,
@@ -100,6 +102,24 @@ axi4_stream_if #(
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32),
.ID_WIDTH (1),
.DEST_WIDTH(1),
.USER_WIDTH(1)
) u_dma_i2s_tx_axis_if (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32),
.ID_WIDTH (1),
.DEST_WIDTH(1),
.USER_WIDTH(1)
) u_dma_i2s_rx_axis_if (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32),
.ID_WIDTH (1),
@@ -157,6 +177,7 @@ axi4_stream_if #(
logic s_dma_crypto_out_proc;
logic s_crypto_irq;
logic s_apu_irq_raw;
logic s_i2s_tx_underrun_evt, s_i2s_rx_overrun_evt;
logic s_jpeg_irq_raw;
logic s_usb2_irq;
logic s_tim0_irq, s_tim1_irq;
@@ -405,16 +426,18 @@ axi4_stream_if #(
);
apb4_i2s u_apb4_i2s (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clk_aud_i (clk_aud_i),
.rst_aud_n_i (rst_aud_n_i),
.dma_tx_stall_o(s_dma_i2s_tx_stall),
.dma_rx_stall_o(s_dma_i2s_rx_stall),
.apb4 (u_i2s_apb4_if),
.tx_axis (u_i2s_tx_axis_if),
.rx_axis (u_i2s_rx_axis_if),
.i2s (i2s)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clk_aud_i (clk_aud_i),
.rst_aud_n_i (rst_aud_n_i),
.dma_tx_stall_o (s_dma_i2s_tx_stall),
.dma_rx_stall_o (s_dma_i2s_rx_stall),
.tx_underrun_evt_o(s_i2s_tx_underrun_evt),
.rx_overrun_evt_o (s_i2s_rx_overrun_evt),
.apb4 (u_i2s_apb4_if),
.tx_axis (u_i2s_tx_axis_if),
.rx_axis (u_i2s_rx_axis_if),
.i2s (i2s)
);
apb4_ws2812 u_apb4_ws2812 (
@@ -447,8 +470,8 @@ axi4_stream_if #(
.hw_trg (u_dma_req_if),
.apb4 (u_dma_apb4_if),
.axi4 (dma_axi4),
.i2s_tx_axis (u_i2s_tx_axis_if),
.i2s_rx_axis (u_i2s_rx_axis_if),
.i2s_tx_axis (u_dma_i2s_tx_axis_if),
.i2s_rx_axis (u_dma_i2s_rx_axis_if),
.dvp_rx_axis (u_dvp_rx_axis_if),
.crypto_in_axis (u_crypto_in_axis_if),
.crypto_out_axis(u_crypto_out_axis_if)
@@ -477,15 +500,23 @@ axi4_stream_if #(
);
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)
.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),
.bridge_epoch_i (apu_bridge_epoch_i),
.i2s_tx_underrun_i(s_i2s_tx_underrun_evt),
.i2s_rx_overrun_i (s_i2s_rx_overrun_evt),
.apb4 (u_apu_apb4_if),
.axi4 (apu_axi4),
.dma_tx_axis (u_dma_i2s_tx_axis_if),
.dma_rx_axis (u_dma_i2s_rx_axis_if),
.i2s_tx_axis (u_i2s_tx_axis_if),
.i2s_rx_axis (u_i2s_rx_axis_if),
.idle_o (apu_idle_o),
.irq_o (s_apu_irq_raw)
);
apb4_sysctrl u_apb4_sysctrl (
+21 -5
View File
@@ -43,6 +43,9 @@ module axi4_async_bridge #(
logic s_clear_dst_q;
logic s_clear_src_pulse;
logic s_clear_dst_pulse;
logic s_dst_rst_n_src;
logic s_dst_rst_n_src_q;
logic s_dst_reset_evt;
logic [7:0] s_epoch_d, s_epoch_q;
logic s_aw_src_clear_busy, s_aw_dst_clear_busy;
logic s_w_src_clear_busy, s_w_dst_clear_busy;
@@ -68,9 +71,19 @@ module axi4_async_bridge #(
.dat_i (clear_i),
.dat_o (s_clear_dst)
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_dst_reset_src_sync (
.clk_i (src_clk_i),
.rst_n_i(src_rst_n_i),
.dat_i (dst_rst_n_i),
.dat_o (s_dst_rst_n_src)
);
assign s_clear_src_pulse = s_clear_src && !s_clear_q;
assign s_clear_dst_pulse = s_clear_dst && !s_clear_dst_q;
assign s_dst_reset_evt = s_dst_rst_n_src_q && !s_dst_rst_n_src;
assign s_aw_src_data = {
src_axi4.awid,
@@ -238,16 +251,19 @@ module axi4_async_bridge #(
s_b_src_clear_busy || s_b_dst_clear_busy ||
s_ar_src_clear_busy || s_ar_dst_clear_busy ||
s_r_src_clear_busy || s_r_dst_clear_busy;
assign s_epoch_d = (s_clear_src_pulse && !clear_busy_o) ? s_epoch_q + 1'b1 : s_epoch_q;
assign s_epoch_d = ((s_clear_src_pulse && !clear_busy_o) || s_dst_reset_evt) ?
s_epoch_q + 1'b1 : s_epoch_q;
assign epoch_o = s_epoch_q;
always_ff @(posedge src_clk_i or negedge src_rst_n_i) begin
if (!src_rst_n_i) begin
s_clear_q <= 1'b0;
s_epoch_q <= '0;
s_clear_q <= 1'b0;
s_dst_rst_n_src_q <= 1'b0;
s_epoch_q <= '0;
end else begin
s_clear_q <= s_clear_src;
s_epoch_q <= s_epoch_d;
s_clear_q <= s_clear_src;
s_dst_rst_n_src_q <= s_dst_rst_n_src;
s_epoch_q <= s_epoch_d;
end
end
+6 -2
View File
@@ -106,6 +106,7 @@ module axi4_target_guard #(
logic s_write_progress;
logic s_read_timeout_enable;
logic s_write_timeout_enable;
logic s_read_missing_last;
assign s_ar_push_data = {
source.arid,
@@ -212,11 +213,14 @@ module axi4_target_guard #(
(sink.arready || s_timeout_read || s_isolated_q)) ||
((s_read_state_q == ReadIdle) && s_isolated_q && !s_ar_empty);
assign s_read_missing_last = (s_read_state_q == ReadForward) && sink.rvalid &&
(s_read_remaining_q == 9'd1) && !sink.rlast;
assign source.rid = (s_read_state_q == ReadSynthetic) ? s_read_id_q : sink.rid;
assign source.rdata = (s_read_state_q == ReadSynthetic) ? '0 : sink.rdata;
assign source.rresp = (s_read_state_q == ReadSynthetic) ? `AXI4_RESP_SLAVE_ERROR : sink.rresp;
assign source.rresp = ((s_read_state_q == ReadSynthetic) || s_read_missing_last) ?
`AXI4_RESP_SLAVE_ERROR : sink.rresp;
assign source.rlast = (s_read_state_q == ReadSynthetic) ?
(s_read_remaining_q == 9'd1) : sink.rlast;
(s_read_remaining_q == 9'd1) : (sink.rlast || s_read_missing_last);
assign source.ruser = (s_read_state_q == ReadSynthetic) ? '0 : sink.ruser;
assign source.rvalid = (s_read_state_q == ReadSynthetic) ||
((s_read_state_q == ReadForward) && sink.rvalid);
+238 -106
View File
@@ -2,34 +2,89 @@
// SPDX-License-Identifier: MulanPSL-2.0
// Serializes the three HP compatibility ports onto one legacy AXI4 master.
module hp_axi4_mux3 (
input logic clk_i,
input logic rst_n_i,
axi4_if.slave icache,
axi4_if.slave dcache,
axi4_if.slave mmio,
axi4_if.master axi4
module hp_axi4_mux3 #(
parameter bit RoundRobin = 1'b0,
parameter bit Client0EpochAware = 1'b0
) (
input logic clk_i,
input logic rst_n_i,
input logic [7:0] epoch_i,
axi4_if.slave icache,
axi4_if.slave dcache,
axi4_if.slave mmio,
axi4_if.master axi4
);
typedef enum logic {
typedef enum logic [2:0] {
Idle,
Active
Address,
Active,
RecoverRead,
RecoverWriteData,
RecoverWriteResponse
} state_e;
state_e s_state_d, s_state_q;
logic s_state_bits_q;
logic [2:0] s_state_bits_q;
logic [1:0] s_owner_d, s_owner_q;
logic s_write_d, s_write_q;
logic [1:0] s_selected;
logic [1:0] s_route_owner;
logic [1:0] s_rr_selected;
logic [2:0] s_rr_grant;
logic [2:0] s_rr_request;
logic s_rr_valid;
logic s_selected_write;
logic s_route_write;
logic s_addr_state;
logic s_addr_valid;
logic s_addr_accept;
logic s_terminal;
logic s_recovery_terminal;
logic s_recovery_write_last;
logic s_write_data_accept_last;
logic s_recover;
logic s_write_data_done_d, s_write_data_done_q;
logic [7:0] s_epoch_q;
assign s_state_q = state_e'(s_state_bits_q);
assign s_rr_request = {
mmio.arvalid || mmio.awvalid, dcache.arvalid || dcache.awvalid, icache.arvalid || icache.awvalid
};
assign s_route_owner = (s_state_q == Idle) ? s_selected : s_owner_q;
assign s_route_write = (s_state_q == Idle) ? s_selected_write : s_write_q;
assign s_addr_state = (s_state_q == Idle) || (s_state_q == Address);
assign s_addr_valid = s_route_write ?
((s_route_owner == 2'd2) ? mmio.awvalid :
(s_route_owner == 2'd1) ? dcache.awvalid : icache.awvalid) :
((s_route_owner == 2'd2) ? mmio.arvalid :
(s_route_owner == 2'd1) ? dcache.arvalid : icache.arvalid);
assign s_recover = epoch_i != s_epoch_q;
round_robin_arbiter #(
.CLIENTS (3),
.INDEX_WIDTH(2)
) u_round_robin (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.advance_i (s_addr_accept && RoundRobin),
.request_i (s_rr_request),
.grant_o (s_rr_grant),
.selected_o(s_rr_selected),
.valid_o (s_rr_valid)
);
always_comb begin
s_selected = 2'd0;
s_selected_write = 1'b0;
if (mmio.arvalid || mmio.awvalid) begin
if (RoundRobin && s_rr_valid) begin
s_selected = s_rr_selected;
case (s_rr_selected)
2'd2: s_selected_write = mmio.awvalid && !mmio.arvalid;
2'd1: s_selected_write = dcache.awvalid && !dcache.arvalid;
default: s_selected_write = icache.awvalid && !icache.arvalid;
endcase
end else if (mmio.arvalid || mmio.awvalid) begin
s_selected = 2'd2;
s_selected_write = mmio.awvalid && !mmio.arvalid;
end else if (dcache.arvalid || dcache.awvalid) begin
@@ -41,70 +96,69 @@ module hp_axi4_mux3 (
end
end
assign axi4.awid = (s_state_q == Idle) ?
((s_selected == 2'd2) ? mmio.awid :
(s_selected == 2'd1) ? dcache.awid : icache.awid) : '0;
assign axi4.awaddr = (s_selected == 2'd2) ? mmio.awaddr :
(s_selected == 2'd1) ? dcache.awaddr : icache.awaddr;
assign axi4.awlen = (s_selected == 2'd2) ? mmio.awlen :
(s_selected == 2'd1) ? dcache.awlen : icache.awlen;
assign axi4.awsize = (s_selected == 2'd2) ? mmio.awsize :
(s_selected == 2'd1) ? dcache.awsize : icache.awsize;
assign axi4.awburst = (s_selected == 2'd2) ? mmio.awburst :
(s_selected == 2'd1) ? dcache.awburst : icache.awburst;
assign axi4.awlock = (s_selected == 2'd2) ? mmio.awlock :
(s_selected == 2'd1) ? dcache.awlock : icache.awlock;
assign axi4.awcache = (s_selected == 2'd2) ? mmio.awcache :
(s_selected == 2'd1) ? dcache.awcache : icache.awcache;
assign axi4.awprot = (s_selected == 2'd2) ? mmio.awprot :
(s_selected == 2'd1) ? dcache.awprot : icache.awprot;
assign axi4.awqos = (s_selected == 2'd2) ? mmio.awqos :
(s_selected == 2'd1) ? dcache.awqos : icache.awqos;
assign axi4.awregion = (s_selected == 2'd2) ? mmio.awregion :
(s_selected == 2'd1) ? dcache.awregion : icache.awregion;
assign axi4.awid = (s_route_owner == 2'd2) ? mmio.awid :
(s_route_owner == 2'd1) ? dcache.awid : icache.awid;
assign axi4.awaddr = (s_route_owner == 2'd2) ? mmio.awaddr :
(s_route_owner == 2'd1) ? dcache.awaddr : icache.awaddr;
assign axi4.awlen = (s_route_owner == 2'd2) ? mmio.awlen :
(s_route_owner == 2'd1) ? dcache.awlen : icache.awlen;
assign axi4.awsize = (s_route_owner == 2'd2) ? mmio.awsize :
(s_route_owner == 2'd1) ? dcache.awsize : icache.awsize;
assign axi4.awburst = (s_route_owner == 2'd2) ? mmio.awburst :
(s_route_owner == 2'd1) ? dcache.awburst : icache.awburst;
assign axi4.awlock = (s_route_owner == 2'd2) ? mmio.awlock :
(s_route_owner == 2'd1) ? dcache.awlock : icache.awlock;
assign axi4.awcache = (s_route_owner == 2'd2) ? mmio.awcache :
(s_route_owner == 2'd1) ? dcache.awcache : icache.awcache;
assign axi4.awprot = (s_route_owner == 2'd2) ? mmio.awprot :
(s_route_owner == 2'd1) ? dcache.awprot : icache.awprot;
assign axi4.awqos = (s_route_owner == 2'd2) ? mmio.awqos :
(s_route_owner == 2'd1) ? dcache.awqos : icache.awqos;
assign axi4.awregion = (s_route_owner == 2'd2) ? mmio.awregion :
(s_route_owner == 2'd1) ? dcache.awregion : icache.awregion;
assign axi4.awuser = '0;
assign axi4.awvalid = (s_state_q == Idle) && s_selected_write &&
((s_selected == 2'd2) ? mmio.awvalid :
(s_selected == 2'd1) ? dcache.awvalid : icache.awvalid);
assign axi4.awvalid = s_addr_state && !s_recover && s_route_write &&
((s_route_owner == 2'd2) ? mmio.awvalid :
(s_route_owner == 2'd1) ? dcache.awvalid : icache.awvalid);
assign mmio.awready = (s_state_q == Idle) && (s_selected == 2'd2) &&
s_selected_write && axi4.awready;
assign dcache.awready = (s_state_q == Idle) && (s_selected == 2'd1) &&
s_selected_write && axi4.awready;
assign icache.awready = (s_state_q == Idle) && (s_selected == 2'd0) &&
s_selected_write && axi4.awready;
assign mmio.awready = s_addr_state && !s_recover && (s_route_owner == 2'd2) &&
s_route_write && axi4.awready;
assign dcache.awready = s_addr_state && !s_recover && (s_route_owner == 2'd1) &&
s_route_write && axi4.awready;
assign icache.awready = s_addr_state && !s_recover && (s_route_owner == 2'd0) &&
s_route_write && axi4.awready;
assign axi4.arid = (s_selected == 2'd2) ? mmio.arid :
(s_selected == 2'd1) ? dcache.arid : icache.arid;
assign axi4.araddr = (s_selected == 2'd2) ? mmio.araddr :
(s_selected == 2'd1) ? dcache.araddr : icache.araddr;
assign axi4.arlen = (s_selected == 2'd2) ? mmio.arlen :
(s_selected == 2'd1) ? dcache.arlen : icache.arlen;
assign axi4.arsize = (s_selected == 2'd2) ? mmio.arsize :
(s_selected == 2'd1) ? dcache.arsize : icache.arsize;
assign axi4.arburst = (s_selected == 2'd2) ? mmio.arburst :
(s_selected == 2'd1) ? dcache.arburst : icache.arburst;
assign axi4.arlock = (s_selected == 2'd2) ? mmio.arlock :
(s_selected == 2'd1) ? dcache.arlock : icache.arlock;
assign axi4.arcache = (s_selected == 2'd2) ? mmio.arcache :
(s_selected == 2'd1) ? dcache.arcache : icache.arcache;
assign axi4.arprot = (s_selected == 2'd2) ? mmio.arprot :
(s_selected == 2'd1) ? dcache.arprot : icache.arprot;
assign axi4.arqos = (s_selected == 2'd2) ? mmio.arqos :
(s_selected == 2'd1) ? dcache.arqos : icache.arqos;
assign axi4.arregion = (s_selected == 2'd2) ? mmio.arregion :
(s_selected == 2'd1) ? dcache.arregion : icache.arregion;
assign axi4.arid = (s_route_owner == 2'd2) ? mmio.arid :
(s_route_owner == 2'd1) ? dcache.arid : icache.arid;
assign axi4.araddr = (s_route_owner == 2'd2) ? mmio.araddr :
(s_route_owner == 2'd1) ? dcache.araddr : icache.araddr;
assign axi4.arlen = (s_route_owner == 2'd2) ? mmio.arlen :
(s_route_owner == 2'd1) ? dcache.arlen : icache.arlen;
assign axi4.arsize = (s_route_owner == 2'd2) ? mmio.arsize :
(s_route_owner == 2'd1) ? dcache.arsize : icache.arsize;
assign axi4.arburst = (s_route_owner == 2'd2) ? mmio.arburst :
(s_route_owner == 2'd1) ? dcache.arburst : icache.arburst;
assign axi4.arlock = (s_route_owner == 2'd2) ? mmio.arlock :
(s_route_owner == 2'd1) ? dcache.arlock : icache.arlock;
assign axi4.arcache = (s_route_owner == 2'd2) ? mmio.arcache :
(s_route_owner == 2'd1) ? dcache.arcache : icache.arcache;
assign axi4.arprot = (s_route_owner == 2'd2) ? mmio.arprot :
(s_route_owner == 2'd1) ? dcache.arprot : icache.arprot;
assign axi4.arqos = (s_route_owner == 2'd2) ? mmio.arqos :
(s_route_owner == 2'd1) ? dcache.arqos : icache.arqos;
assign axi4.arregion = (s_route_owner == 2'd2) ? mmio.arregion :
(s_route_owner == 2'd1) ? dcache.arregion : icache.arregion;
assign axi4.aruser = '0;
assign axi4.arvalid = (s_state_q == Idle) && !s_selected_write &&
((s_selected == 2'd2) ? mmio.arvalid :
(s_selected == 2'd1) ? dcache.arvalid : icache.arvalid);
assign axi4.arvalid = s_addr_state && !s_recover && !s_route_write &&
((s_route_owner == 2'd2) ? mmio.arvalid :
(s_route_owner == 2'd1) ? dcache.arvalid : icache.arvalid);
assign mmio.arready = (s_state_q == Idle) && (s_selected == 2'd2) &&
!s_selected_write && axi4.arready;
assign dcache.arready = (s_state_q == Idle) && (s_selected == 2'd1) &&
!s_selected_write && axi4.arready;
assign icache.arready = (s_state_q == Idle) && (s_selected == 2'd0) &&
!s_selected_write && axi4.arready;
assign mmio.arready = s_addr_state && !s_recover && (s_route_owner == 2'd2) &&
!s_route_write && axi4.arready;
assign dcache.arready = s_addr_state && !s_recover && (s_route_owner == 2'd1) &&
!s_route_write && axi4.arready;
assign icache.arready = s_addr_state && !s_recover && (s_route_owner == 2'd0) &&
!s_route_write && axi4.arready;
assign axi4.wdata = (s_owner_q == 2'd2) ? mmio.wdata :
(s_owner_q == 2'd1) ? dcache.wdata : icache.wdata;
@@ -116,44 +170,56 @@ module hp_axi4_mux3 (
assign axi4.wvalid = (s_state_q == Active) && s_write_q &&
((s_owner_q == 2'd2) ? mmio.wvalid :
(s_owner_q == 2'd1) ? dcache.wvalid : icache.wvalid);
assign mmio.wready = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd2) && axi4.wready;
assign dcache.wready = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd1) && axi4.wready;
assign icache.wready = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd0) && axi4.wready;
assign mmio.wready = s_write_q && (s_owner_q == 2'd2) &&
(((s_state_q == Active) && axi4.wready) || (s_state_q == RecoverWriteData));
assign dcache.wready = s_write_q && (s_owner_q == 2'd1) &&
(((s_state_q == Active) && axi4.wready) || (s_state_q == RecoverWriteData));
assign icache.wready = s_write_q && (s_owner_q == 2'd0) &&
(((s_state_q == Active) && axi4.wready) || (s_state_q == RecoverWriteData));
assign mmio.bid = axi4.bid;
assign dcache.bid = axi4.bid;
assign icache.bid = axi4.bid;
assign mmio.bresp = axi4.bresp;
assign dcache.bresp = axi4.bresp;
assign icache.bresp = axi4.bresp;
assign mmio.bid = (s_state_q == RecoverWriteResponse) ? 1'b0 : axi4.bid;
assign dcache.bid = (s_state_q == RecoverWriteResponse) ? 1'b0 : axi4.bid;
assign icache.bid = (s_state_q == RecoverWriteResponse) ? 1'b0 : axi4.bid;
assign mmio.bresp = (s_state_q == RecoverWriteResponse) ? 2'b11 : axi4.bresp;
assign dcache.bresp = (s_state_q == RecoverWriteResponse) ? 2'b11 : axi4.bresp;
assign icache.bresp = (s_state_q == RecoverWriteResponse) ? 2'b11 : axi4.bresp;
assign mmio.buser = '0;
assign dcache.buser = '0;
assign icache.buser = '0;
assign mmio.bvalid = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd2) && axi4.bvalid;
assign dcache.bvalid = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd1) && axi4.bvalid;
assign icache.bvalid = (s_state_q == Active) && s_write_q && (s_owner_q == 2'd0) && axi4.bvalid;
assign mmio.bvalid = s_write_q && (s_owner_q == 2'd2) &&
(((s_state_q == Active) && !s_recover && axi4.bvalid) ||
(s_state_q == RecoverWriteResponse));
assign dcache.bvalid = s_write_q && (s_owner_q == 2'd1) &&
(((s_state_q == Active) && !s_recover && axi4.bvalid) ||
(s_state_q == RecoverWriteResponse));
assign icache.bvalid = s_write_q && (s_owner_q == 2'd0) &&
(((s_state_q == Active) && !s_recover && axi4.bvalid) ||
(s_state_q == RecoverWriteResponse));
assign axi4.bready = ((s_state_q == Active) && s_write_q) ?
((s_owner_q == 2'd2) ? mmio.bready :
(s_owner_q == 2'd1) ? dcache.bready : icache.bready) : 1'b0;
assign mmio.rid = axi4.rid;
assign dcache.rid = axi4.rid;
assign icache.rid = axi4.rid;
assign mmio.rdata = axi4.rdata;
assign dcache.rdata = axi4.rdata;
assign icache.rdata = axi4.rdata;
assign mmio.rresp = axi4.rresp;
assign dcache.rresp = axi4.rresp;
assign icache.rresp = axi4.rresp;
assign mmio.rlast = axi4.rlast;
assign dcache.rlast = axi4.rlast;
assign icache.rlast = axi4.rlast;
assign mmio.rid = (s_state_q == RecoverRead) ? 1'b0 : axi4.rid;
assign dcache.rid = (s_state_q == RecoverRead) ? 1'b0 : axi4.rid;
assign icache.rid = (s_state_q == RecoverRead) ? 1'b0 : axi4.rid;
assign mmio.rdata = (s_state_q == RecoverRead) ? 32'd0 : axi4.rdata;
assign dcache.rdata = (s_state_q == RecoverRead) ? 32'd0 : axi4.rdata;
assign icache.rdata = (s_state_q == RecoverRead) ? 32'd0 : axi4.rdata;
assign mmio.rresp = (s_state_q == RecoverRead) ? 2'b11 : axi4.rresp;
assign dcache.rresp = (s_state_q == RecoverRead) ? 2'b11 : axi4.rresp;
assign icache.rresp = (s_state_q == RecoverRead) ? 2'b11 : axi4.rresp;
assign mmio.rlast = (s_state_q == RecoverRead) ? 1'b1 : axi4.rlast;
assign dcache.rlast = (s_state_q == RecoverRead) ? 1'b1 : axi4.rlast;
assign icache.rlast = (s_state_q == RecoverRead) ? 1'b1 : axi4.rlast;
assign mmio.ruser = '0;
assign dcache.ruser = '0;
assign icache.ruser = '0;
assign mmio.rvalid = (s_state_q == Active) && !s_write_q && (s_owner_q == 2'd2) && axi4.rvalid;
assign dcache.rvalid = (s_state_q == Active) && !s_write_q && (s_owner_q == 2'd1) && axi4.rvalid;
assign icache.rvalid = (s_state_q == Active) && !s_write_q && (s_owner_q == 2'd0) && axi4.rvalid;
assign mmio.rvalid = !s_write_q && (s_owner_q == 2'd2) &&
(((s_state_q == Active) && !s_recover && axi4.rvalid) || (s_state_q == RecoverRead));
assign dcache.rvalid = !s_write_q && (s_owner_q == 2'd1) &&
(((s_state_q == Active) && !s_recover && axi4.rvalid) || (s_state_q == RecoverRead));
assign icache.rvalid = !s_write_q && (s_owner_q == 2'd0) &&
(((s_state_q == Active) && !s_recover && axi4.rvalid) || (s_state_q == RecoverRead));
assign axi4.rready = ((s_state_q == Active) && !s_write_q) ?
((s_owner_q == 2'd2) ? mmio.rready :
(s_owner_q == 2'd1) ? dcache.rready : icache.rready) : 1'b0;
@@ -161,21 +227,68 @@ module hp_axi4_mux3 (
assign s_addr_accept = (axi4.awvalid && axi4.awready) || (axi4.arvalid && axi4.arready);
assign s_terminal = (s_write_q && axi4.bvalid && axi4.bready) ||
(!s_write_q && axi4.rvalid && axi4.rready && axi4.rlast);
assign s_recovery_terminal = ((s_state_q == RecoverWriteResponse) &&
((s_owner_q == 2'd2) ? mmio.bready :
(s_owner_q == 2'd1) ? dcache.bready : icache.bready)) ||
((s_state_q == RecoverRead) &&
((s_owner_q == 2'd2) ? mmio.rready :
(s_owner_q == 2'd1) ? dcache.rready : icache.rready));
assign s_recovery_write_last = (s_state_q == RecoverWriteData) &&
((s_owner_q == 2'd2) ? (mmio.wvalid && mmio.wready && mmio.wlast) :
(s_owner_q == 2'd1) ? (dcache.wvalid && dcache.wready && dcache.wlast) :
(icache.wvalid && icache.wready && icache.wlast));
assign s_write_data_accept_last = (s_state_q == Active) && s_write_q &&
axi4.wvalid && axi4.wready && axi4.wlast;
always_comb begin
s_state_d = s_state_q;
s_owner_d = s_owner_q;
s_write_d = s_write_q;
if ((s_state_q == Idle) && s_addr_accept) begin
s_state_d = Active;
s_owner_d = s_selected;
s_write_d = axi4.awvalid && axi4.awready;
s_state_d = s_state_q;
s_owner_d = s_owner_q;
s_write_d = s_write_q;
s_write_data_done_d = s_write_data_done_q;
if (s_recover) begin
unique case (s_state_q)
Active: begin
if (Client0EpochAware && (s_owner_q == 2'd0)) begin
s_state_d = Idle;
end else if (s_write_q) begin
s_state_d = (s_write_data_done_q || s_write_data_accept_last) ?
RecoverWriteResponse : RecoverWriteData;
end else begin
s_state_d = RecoverRead;
end
end
RecoverRead, RecoverWriteData, RecoverWriteResponse: s_state_d = s_state_q;
default: s_state_d = Idle;
endcase
end else begin
unique case (s_state_q)
Idle: begin
if (s_addr_valid) begin
s_owner_d = s_selected;
s_write_d = s_selected_write;
s_write_data_done_d = 1'b0;
s_state_d = s_addr_accept ? Active : Address;
end
end
Address: if (s_addr_accept) s_state_d = Active;
Active: begin
if (s_write_data_accept_last) begin
s_write_data_done_d = 1'b1;
end
if (s_terminal) s_state_d = Idle;
end
RecoverRead: if (s_recovery_terminal) s_state_d = Idle;
RecoverWriteData: begin
if (s_recovery_write_last) s_state_d = RecoverWriteResponse;
end
RecoverWriteResponse: if (s_recovery_terminal) s_state_d = Idle;
default: s_state_d = Idle;
endcase
end
if ((s_state_q == Active) && s_terminal) s_state_d = Idle;
end
dffr #(
.DATA_WIDTH(1)
.DATA_WIDTH(3)
) u_state_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
@@ -198,4 +311,23 @@ module hp_axi4_mux3 (
.dat_i (s_write_d),
.dat_o (s_write_q)
);
dffr #(
.DATA_WIDTH(1)
) u_write_data_done_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_write_data_done_d),
.dat_o (s_write_data_done_q)
);
dffr #(
.DATA_WIDTH(8)
) u_epoch_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (epoch_i),
.dat_o (s_epoch_q)
);
logic [2:0] s_unused_rr_grant;
assign s_unused_rr_grant = RoundRobin ? 3'd0 : s_rr_grant;
endmodule
+16 -9
View File
@@ -87,6 +87,8 @@ module retrosoc (
u_ext_h_wide_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
u_jpeg_wide_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(32), .ID_WIDTH(1), .USER_WIDTH(1))
u_apu_axi4_if (.aclk(clk_pclk_i), .aresetn(rst_pclk_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
u_hp_icache_axi4_if (.aclk(clk_hp_i), .aresetn(rst_hp_n_i));
axi4_if #(.ADDR_WIDTH(32), .DATA_WIDTH(64), .ID_WIDTH(3), .USER_WIDTH(1))
@@ -191,6 +193,7 @@ module retrosoc (
logic s_mgmt_router_idle;
logic [ 7:0] s_data_plane_outstanding_read;
logic [ 7:0] s_data_plane_outstanding_write;
logic [ 7:0] s_apu_bridge_epoch;
logic s_data_plane_fault_valid;
logic [ 2:0] s_data_plane_fault_master;
logic [ 2:0] s_data_plane_fault_target;
@@ -236,10 +239,10 @@ module retrosoc (
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 [ 7:0] s_resource_idle_hp;
logic [ 7:0] s_resource_idle_pclk;
logic [ 7:0] s_resource_block_ack_hp;
logic [ 7:0] s_resource_block_ack_pclk;
logic [ 6:0] s_resource_irq_raw;
logic [ 6:0] s_resource_irq_lp;
logic [ 6:0] s_resource_irq_hp;
@@ -558,7 +561,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[6:0] | s_resource_reset[6:0]),
.resource_block_i (s_resource_quiesce | s_resource_reset),
.mem_pad_mode_i (s_mem_pad_mode_lp),
.ext_h_block_i (s_ext_h_block),
.ext_h_read_base_i (s_ext_h_read_base),
@@ -572,6 +575,7 @@ core_wrapper u_core_wrapper (
.sdio1_axi4 (u_sdio1_axi4_if),
.spisd_axi4 (u_spisd_axi4_if),
.usb2_axi4 (u_usb2_axi4_if),
.apu_axi4 (u_apu_axi4_if),
.jpeg_axi4 (u_jpeg_wide_axi4_if),
.lp_data_axi4 (u_mgmt_data_axi4_if),
.ext_h_axi4 (u_ext_h_wide_axi4_if),
@@ -584,6 +588,7 @@ core_wrapper u_core_wrapper (
.idle_o (s_data_plane_idle),
.flush_busy_o (s_data_plane_flush_busy),
.ext_h_idle_o (s_ext_h_data_idle),
.apu_bridge_epoch_o (s_apu_bridge_epoch),
.resource_idle_o (s_resource_idle_hp),
.resource_block_ack_o(s_resource_block_ack_hp),
.outstanding_read_o (s_data_plane_outstanding_read),
@@ -598,7 +603,7 @@ core_wrapper u_core_wrapper (
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(7)
.DATA_WIDTH(8)
) u_resource_idle_sync (
.clk_i (clk_pclk_i),
.rst_n_i(rst_pclk_n_i),
@@ -607,7 +612,7 @@ core_wrapper u_core_wrapper (
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(7)
.DATA_WIDTH(8)
) u_resource_block_ack_sync (
.clk_i (clk_pclk_i),
.rst_n_i(rst_pclk_n_i),
@@ -804,6 +809,7 @@ core_wrapper u_core_wrapper (
.apu_owner_lock_i (s_resource_owner_lock[7]),
.apu_quiesce_i (s_resource_quiesce[7]),
.apu_reset_i (s_resource_reset[7]),
.apu_bridge_epoch_i (s_apu_bridge_epoch),
.jpeg_quiesce_i (s_resource_quiesce[6]),
.jpeg_reset_i (s_resource_reset[6]),
.cfg_axi4 (u_cfg_pclk_axi4_if),
@@ -811,6 +817,7 @@ core_wrapper u_core_wrapper (
.sdio0_axi4 (u_sdio0_axi4_if),
.sdio1_axi4 (u_sdio1_axi4_if),
.usb2_axi4 (u_usb2_axi4_if),
.apu_axi4 (u_apu_axi4_if),
.jpeg_axi4 (u_jpeg_wide_axi4_if),
.psram_axi4 (u_data_qpi_axi4_if),
.xpi_axi4 (u_data_xpi_axi4_if),
@@ -899,13 +906,13 @@ core_wrapper u_core_wrapper (
);
assign s_resource_idle_combined = {
s_apu_idle,
s_apu_idle && s_resource_idle_pclk[7],
s_jpeg_idle && s_resource_idle_pclk[6],
s_ext_h_data_idle && s_resource_idle_pclk[5],
s_resource_idle_pclk[4:0]
};
assign s_resource_block_ack_combined = {
s_apu_idle && (s_resource_quiesce[7] || s_resource_reset[7]), s_resource_block_ack_pclk
s_apu_idle && s_resource_block_ack_pclk[7], s_resource_block_ack_pclk[6:0]
};
logic [36:0] s_unused_domain_inputs;
+20 -12
View File
@@ -16,7 +16,7 @@ module soc_data_plane (
input logic block_new_i,
input logic recovery_i,
input logic flush_i,
input logic [6:0] resource_block_i,
input logic [7:0] resource_block_i,
input logic [1:0] mem_pad_mode_i,
input logic ext_h_block_i,
input logic [31:0] ext_h_read_base_i,
@@ -30,6 +30,7 @@ module soc_data_plane (
axi4_if.slave sdio1_axi4,
axi4_if.slave spisd_axi4,
axi4_if.slave usb2_axi4,
axi4_if.slave apu_axi4,
axi4_if.slave jpeg_axi4,
axi4_if.slave lp_data_axi4,
axi4_if.slave ext_h_axi4,
@@ -42,8 +43,9 @@ module soc_data_plane (
output logic idle_o,
output logic flush_busy_o,
output logic ext_h_idle_o,
output logic [6:0] resource_idle_o,
output logic [6:0] resource_block_ack_o,
output logic [7:0] apu_bridge_epoch_o,
output logic [7:0] resource_idle_o,
output logic [7:0] resource_block_ack_o,
output logic [7:0] outstanding_read_o,
output logic [7:0] outstanding_write_o,
output logic fault_valid_o,
@@ -86,7 +88,7 @@ module soc_data_plane (
logic [ 7:0] unused_ext_epoch;
logic [ 7:0] unused_jpeg_epoch;
logic [ 2:0] s_unused_epoch;
logic [ 6:0] s_resource_block_hp;
logic [ 7:0] s_resource_block_hp;
logic [ 7:0] s_master_idle;
logic [ 7:0] s_master_block;
logic [ 7:0] s_monitor_master_read_accept;
@@ -193,7 +195,7 @@ module soc_data_plane (
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) u_io_idle_axi4[2] (
) u_io_idle_axi4[1] (
.aclk (clk_io_i),
.aresetn(rst_io_n_i)
);
@@ -262,7 +264,7 @@ module soc_data_plane (
);
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(7)
.DATA_WIDTH(8)
) u_resource_block_sync (
.clk_i (clk_hp_i),
.rst_n_i(rst_hp_n_i),
@@ -275,11 +277,12 @@ module soc_data_plane (
s_resource_block_hp[6],
1'b0,
s_resource_block_hp[4] || s_resource_block_hp[3],
s_resource_block_hp[2] || s_resource_block_hp[1],
s_resource_block_hp[7] || s_resource_block_hp[2] || s_resource_block_hp[1],
s_resource_block_hp[0],
2'b00
};
assign resource_idle_o = {
s_master_idle[3],
s_master_idle[6],
s_master_idle[7],
s_master_idle[4],
@@ -315,10 +318,14 @@ module soc_data_plane (
.source(dma_axi4),
.sink (u_io_lp_axi4[0])
);
hp_axi4_mux3 u_io_gateway_a (
hp_axi4_mux3 #(
.RoundRobin (1'b1),
.Client0EpochAware(1'b1)
) u_io_gateway_a (
.clk_i (clk_io_i),
.rst_n_i(rst_io_n_i),
.icache (u_io_idle_axi4[0]),
.epoch_i(unused_io_epoch[1]),
.icache (apu_axi4),
.dcache (sdio0_axi4),
.mmio (usb2_axi4),
.axi4 (u_io_lp_axi4[1])
@@ -326,13 +333,13 @@ module soc_data_plane (
hp_axi4_mux3 u_io_gateway_b (
.clk_i (clk_io_i),
.rst_n_i(rst_io_n_i),
.icache (u_io_idle_axi4[1]),
.epoch_i(unused_io_epoch[2]),
.icache (u_io_idle_axi4[0]),
.dcache (spisd_axi4),
.mmio (sdio1_axi4),
.axi4 (u_io_lp_axi4[2])
);
axi4_master_idle u_io_gateway_a_idle (.axi4(u_io_idle_axi4[0]));
axi4_master_idle u_io_gateway_b_idle (.axi4(u_io_idle_axi4[1]));
axi4_master_idle u_io_gateway_b_idle (.axi4(u_io_idle_axi4[0]));
for (genvar master = 0; master < NumIoMasters; master++) begin : gen_io_master
axi4_async_bridge #(
@@ -638,6 +645,7 @@ module soc_data_plane (
assign flush_busy_o = (|s_io_clear_busy) || (|s_target_clear_busy) ||
(|s_guard_clear_busy) || s_lp_clear_busy || s_ext_clear_busy ||
s_jpeg_clear_busy;
assign apu_bridge_epoch_o = unused_io_epoch[1];
assign s_unused_epoch = {
^unused_io_epoch, ^unused_target_epoch, ^{unused_lp_epoch, unused_ext_epoch, unused_jpeg_epoch}
};
+3
View File
@@ -135,8 +135,11 @@
"rtl/ip/multimedia": [
"apb4_apu.sv",
"apb4_jpeg.sv",
"apu_dma.sv",
"apu_define.svh",
"apu_ring_scheduler.sv",
"apu_reg.sv",
"apu_stream_router.sv",
"axi4s_dvp.sv",
"dvp_core.sv",
"dvp_define.svh",
+4 -3
View File
@@ -16,9 +16,10 @@ 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_apu.py` checks the fail-closed APU APB4/IRQ shell plus the P2 private
DMA, ring scheduler, stream router, Gateway A, and verification-only backend;
`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.
+516
View File
@@ -0,0 +1,516 @@
`timescale 1ns / 1ps
`include "axi4_define.svh"
module apu_dma_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic abort_i = 1'b0;
logic quiesce_i = 1'b0;
logic counter_clear_i = 1'b0;
logic [ 7:0] bridge_epoch_i = 8'd0;
logic request_valid_i = 1'b0;
logic request_ready_o;
logic request_write_i;
logic [31:0] request_addr_i;
logic [31:0] request_bytes_i;
logic [31:0] timeout_i = 32'd32;
logic [31:0] read_acl_base_i = 32'd0;
logic [31:0] read_acl_limit_i = 32'h0000_ffff;
logic [31:0] write_acl_base_i = 32'd0;
logic [31:0] write_acl_limit_i = 32'h0000_ffff;
logic busy_o, done_o, error_o, aborted_o, aborting_o;
logic [ 5:0] error_code_o;
logic [ 3:0] error_stage_o;
logic [ 1:0] error_resp_o;
logic [31:0] error_addr_o;
logic [63:0] read_bytes_o, write_bytes_o;
logic [31:0] memory [0:32767];
logic [31:0] buffer [ 0:31];
logic [ 3:0] buffer_keep[ 0:31];
logic read_active, write_active, write_source_active;
logic [31:0] read_base, write_base;
logic [7:0] read_len, write_len, read_index, write_index, source_index;
logic bvalid;
logic allow_addresses = 1'b1;
logic read_sink_ready = 1'b1;
logic [1:0] read_response = `AXI4_RESP_OKAY;
logic [1:0] write_response = `AXI4_RESP_OKAY;
logic read_id = 1'b0;
logic write_id = 1'b0;
logic early_read_last = 1'b0;
logic suppress_read_last = 1'b0;
logic allow_write_response = 1'b1;
logic [7:0] source_last_index = 8'd0;
int unsigned read_bursts, write_bursts;
string s_phase;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) read_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) write_axis (
clk_i,
rst_n_i
);
always #5 clk_i = ~clk_i;
assign read_axis.tready = read_sink_ready;
assign write_axis.tdata = buffer[source_index];
assign write_axis.tkeep = buffer_keep[source_index];
assign write_axis.tstrb = buffer_keep[source_index];
assign write_axis.tlast = source_index == source_last_index;
assign write_axis.tid = '0;
assign write_axis.tdest = '0;
assign write_axis.tuser = '0;
assign write_axis.tvalid = write_source_active;
assign axi4.arready = allow_addresses && !read_active;
assign axi4.rid = read_id;
assign axi4.rdata = memory[(read_base>>2)+read_index];
assign axi4.rresp = read_response;
assign axi4.rlast = !suppress_read_last &&
(early_read_last ? (read_index == 8'd0) : (read_index == read_len));
assign axi4.ruser = 1'b0;
assign axi4.rvalid = read_active;
assign axi4.awready = allow_addresses && !write_active && !bvalid;
assign axi4.wready = write_active;
assign axi4.bid = write_id;
assign axi4.bresp = write_response;
assign axi4.buser = 1'b0;
assign axi4.bvalid = bvalid && allow_write_response;
apu_dma u_dut (
.clk_i,
.rst_n_i,
.abort_i,
.quiesce_i,
.bridge_epoch_i,
.perf_enable_i (1'b1),
.counter_clear_i,
.request_valid_i,
.request_ready_o,
.request_write_i,
.request_addr_i,
.request_bytes_i,
.read_base_i (read_acl_base_i),
.read_limit_i (read_acl_limit_i),
.write_base_i (write_acl_base_i),
.write_limit_i (write_acl_limit_i),
.timeout_i,
.read_axis,
.write_axis,
.busy_o,
.done_o,
.error_o,
.aborted_o,
.aborting_o,
.error_code_o,
.error_stage_o,
.error_resp_o,
.error_addr_o,
.input_pending_o (),
.output_pending_o(),
.read_bytes_o,
.write_bytes_o,
.read_stalls_o (),
.write_stalls_o (),
.axi4
);
task automatic issue_request(input logic write_i, input logic [31:0] addr_i,
input logic [31:0] bytes_i);
begin
@(negedge clk_i);
request_write_i = write_i;
request_addr_i = addr_i;
request_bytes_i = bytes_i;
if (write_i) source_last_index = ((bytes_i + 32'd3) >> 2) - 1'b1;
request_valid_i = 1'b1;
while (!request_ready_o) @(negedge clk_i);
@(posedge clk_i);
@(negedge clk_i);
request_valid_i = 1'b0;
end
endtask
always @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
read_active <= 1'b0;
write_active <= 1'b0;
bvalid <= 1'b0;
read_index <= 8'd0;
write_index <= 8'd0;
source_index <= 8'd0;
read_bursts <= 0;
write_bursts <= 0;
end else begin
if (axi4.arvalid && axi4.arready) begin
read_active <= 1'b1;
read_base <= axi4.araddr;
read_len <= axi4.arlen;
read_index <= 8'd0;
read_bursts <= read_bursts + 1;
end else if (axi4.rvalid && axi4.rready) begin
if (axi4.rlast) read_active <= 1'b0;
else read_index <= read_index + 1'b1;
end
if (read_axis.tvalid && read_axis.tready) begin
buffer[source_index] <= read_axis.tdata;
buffer_keep[source_index] <= read_axis.tkeep;
source_index <= source_index + 1'b1;
end
if (axi4.awvalid && axi4.awready) begin
write_active <= 1'b1;
write_base <= axi4.awaddr;
write_len <= axi4.awlen;
write_index <= 8'd0;
write_bursts <= write_bursts + 1;
end
if (axi4.wvalid && axi4.wready) begin
for (int byte_index = 0; byte_index < 4; byte_index++) begin
if (axi4.wstrb[byte_index]) begin
memory[(write_base>>2)+write_index][byte_index*8+:8] <= axi4.wdata[byte_index*8+:8];
end
end
if (axi4.wlast) begin
write_active <= 1'b0;
bvalid <= 1'b1;
end else begin
write_index <= write_index + 1'b1;
end
end
if (write_axis.tvalid && write_axis.tready) source_index <= source_index + 1'b1;
if (axi4.bvalid && axi4.bready) bvalid <= 1'b0;
end
end
initial begin
request_write_i = 1'b0;
request_addr_i = 32'd0;
request_bytes_i = 32'd0;
write_source_active = 1'b0;
for (int index = 0; index < 32768; index++) memory[index] = 32'hdead_beef;
for (int index = 0; index < 17; index++) memory[(32'h0ff0>>2)+index] = 32'h1000 + index;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
source_index = 8'd0;
s_phase = "read";
issue_request(1'b0, 32'h0000_0ff0, 32'd67);
while (!done_o) @(posedge clk_i);
if (error_o || (read_bytes_o != 64'd67) || (read_bursts < 2)) begin
$fatal(1, "APU DMA read/split failed");
end
source_index = 8'd0;
s_phase = "write";
write_source_active = 1'b1;
issue_request(1'b1, 32'h0000_2000, 32'd67);
while (!done_o) @(posedge clk_i);
write_source_active = 1'b0;
if (error_o || (write_bytes_o != 64'd67) || (write_bursts < 2)) begin
$fatal(1, "APU DMA write/split failed");
end
for (int index = 0; index < 16; index++) begin
if (memory[(32'h2000>>2)+index] != 32'h1000 + index) $fatal(1, "DMA copy mismatch");
end
if ((memory[(32'h2040>>2)][23:0] != 24'h001010) || (memory[(32'h2040>>2)][31:24] != 8'hde))
$fatal(1, "DMA tail strobe mismatch");
s_phase = "acl";
issue_request(1'b0, 32'h0002_0000, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd15)) $fatal(1, "DMA ACL denial failed");
read_acl_limit_i = 32'hffff_ffff;
issue_request(1'b0, 32'hffff_fffc, 32'd8);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd15) || busy_o) begin
$fatal(1, "DMA ACL arithmetic overflow was accepted");
end
read_acl_limit_i = 32'h0000_ffff;
s_phase = "read response faults";
read_response = `AXI4_RESP_SLAVE_ERROR;
issue_request(1'b0, 32'h0000_4000, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd15) || (error_resp_o != `AXI4_RESP_SLAVE_ERROR))
$fatal(1, "DMA read SLVERR failed");
read_response = `AXI4_RESP_DECODE_ERROR;
issue_request(1'b0, 32'h0000_4000, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_resp_o != `AXI4_RESP_DECODE_ERROR)) begin
$fatal(1, "DMA read DECERR failed");
end
read_response = `AXI4_RESP_OKAY;
read_id = 1'b1;
issue_request(1'b0, 32'h0000_4000, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd15)) $fatal(1, "DMA read ID failure missed");
read_id = 1'b0;
early_read_last = 1'b1;
issue_request(1'b0, 32'h0000_4000, 32'd8);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd15)) $fatal(1, "DMA malformed RLAST missed");
early_read_last = 1'b0;
suppress_read_last = 1'b1;
issue_request(1'b0, 32'h0000_4000, 32'd8);
while (!done_o) @(posedge clk_i);
if (!error_o || busy_o || (error_code_o != 6'd15)) begin
$fatal(1, "DMA missing terminal RLAST did not terminate boundedly");
end
suppress_read_last = 1'b0;
read_active = 1'b0;
s_phase = "epoch/request coincidence";
@(negedge clk_i);
request_write_i = 1'b0;
request_addr_i = 32'h0000_4000;
request_bytes_i = 32'd4;
request_valid_i = 1'b1;
bridge_epoch_i = bridge_epoch_i + 1'b1;
#1;
if (request_ready_o) $fatal(1, "DMA accepted a request during epoch recovery");
@(posedge clk_i);
do @(posedge clk_i); while (!request_ready_o);
@(negedge clk_i);
request_valid_i = 1'b0;
while (!done_o) @(posedge clk_i);
if (error_o || (read_bytes_o != 64'd75)) begin
$fatal(1, "DMA lost the request coincident with epoch recovery");
end
s_phase = "write response faults";
source_index = 8'd0;
write_source_active = 1'b1;
write_response = `AXI4_RESP_SLAVE_ERROR;
issue_request(1'b1, 32'h0000_5000, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd16) || (error_resp_o != `AXI4_RESP_SLAVE_ERROR))
$fatal(1, "DMA write SLVERR failed");
source_index = 8'd0;
write_response = `AXI4_RESP_DECODE_ERROR;
issue_request(1'b1, 32'h0000_5004, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_resp_o != `AXI4_RESP_DECODE_ERROR)) begin
$fatal(1, "DMA write DECERR failed");
end
source_index = 8'd0;
write_response = `AXI4_RESP_OKAY;
write_id = 1'b1;
issue_request(1'b1, 32'h0000_5008, 32'd4);
while (!done_o) @(posedge clk_i);
if (!error_o || (error_code_o != 6'd16)) $fatal(1, "DMA write ID failure missed");
write_id = 1'b0;
write_source_active = 1'b0;
s_phase = "read-start abort";
issue_request(1'b0, 32'h0000_6000, 32'd4);
if (u_dut.s_state_q != 3'd1) $fatal(1, "DMA did not hold ReadStart for abort injection");
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
while (!done_o) @(posedge clk_i);
if (error_o || !aborted_o || busy_o) $fatal(1, "DMA ReadStart abort failed");
s_phase = "write-start abort";
source_index = 8'd0;
write_source_active = 1'b1;
issue_request(1'b1, 32'h0000_5010, 32'd4);
if (u_dut.s_state_q != 3'd3) $fatal(1, "DMA did not hold WriteStart for abort injection");
abort_i = 1'b1;
@(posedge clk_i);
#1;
if (!aborted_o || !aborting_o) begin
$fatal(1, "DMA did not latch the WriteStart abort state=%0d drain=%0d", u_dut.s_state_q,
u_dut.s_drain_q);
end
@(negedge clk_i);
abort_i = 1'b0;
while (!done_o) @(posedge clk_i);
write_source_active = 1'b0;
if (error_o || !aborted_o || busy_o) begin
$fatal(1, "DMA WriteStart abort failed error=%0d aborted=%0d busy=%0d code=%0d state=%0d",
error_o, aborted_o, busy_o, error_code_o, u_dut.s_state_q);
end
s_phase = "write-data abort";
source_index = 8'd0;
write_source_active = 1'b0;
issue_request(1'b1, 32'h0000_5020, 32'd16);
wait (write_active && (u_dut.s_state_q == 3'd4));
@(negedge clk_i);
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
while (!done_o) @(posedge clk_i);
if (error_o || !aborted_o || busy_o) $fatal(1, "DMA WriteData abort failed");
s_phase = "write response abort";
source_index = 8'd0;
write_source_active = 1'b1;
allow_write_response = 1'b0;
issue_request(1'b1, 32'h0000_5010, 32'd4);
while (!bvalid) @(posedge clk_i);
@(negedge clk_i);
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
if (!aborting_o) $fatal(1, "DMA did not report aborting while waiting for B");
allow_write_response = 1'b1;
while (!done_o) @(posedge clk_i);
write_source_active = 1'b0;
if (error_o || !aborted_o || (error_code_o != 6'd20)) begin
$fatal(1, "DMA write-response abort did not drain");
end
s_phase = "write error over abort";
source_index = 8'd0;
write_source_active = 1'b1;
write_response = `AXI4_RESP_SLAVE_ERROR;
allow_write_response = 1'b0;
issue_request(1'b1, 32'h0000_5014, 32'd4);
while (!bvalid) @(posedge clk_i);
@(negedge clk_i);
abort_i = 1'b1;
allow_write_response = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
while (!done_o) @(posedge clk_i);
write_source_active = 1'b0;
write_response = `AXI4_RESP_OKAY;
if (!error_o || !aborted_o || (error_code_o != 6'd16) ||
(error_resp_o != `AXI4_RESP_SLAVE_ERROR)) begin
$fatal(1, "DMA write error did not outrank simultaneous abort");
end
s_phase = "accepted abort drain";
read_sink_ready = 1'b0;
issue_request(1'b0, 32'h0000_6000, 32'd16);
while (!read_active) @(posedge clk_i);
@(negedge clk_i);
abort_i = 1'b1;
@(negedge clk_i);
if (!aborting_o) $fatal(1, "DMA live aborting status was not asserted");
abort_i = 1'b0;
while (!done_o) @(posedge clk_i);
read_sink_ready = 1'b1;
if (error_o || !aborted_o || (error_code_o != 6'd20)) begin
$fatal(1, "DMA accepted-read abort drain failed");
end
if (aborting_o) $fatal(1, "DMA live aborting status remained set after drain");
s_phase = "read error over abort";
read_sink_ready = 1'b0;
issue_request(1'b0, 32'h0000_6000, 32'd16);
while (!read_active) @(posedge clk_i);
read_response = `AXI4_RESP_SLAVE_ERROR;
@(negedge clk_i);
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
while (!done_o) @(posedge clk_i);
read_response = `AXI4_RESP_OKAY;
read_sink_ready = 1'b1;
if (!error_o || !aborted_o || (error_code_o != 6'd15)) begin
$fatal(1, "DMA read error did not outrank abort");
end
s_phase = "unaccepted abort cancellation";
allow_addresses = 1'b0;
issue_request(1'b0, 32'h0000_6000, 32'd4);
repeat (2) @(posedge clk_i);
@(negedge clk_i);
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
while (!aborted_o) @(posedge clk_i);
if (!axi4.arvalid || !busy_o) $fatal(1, "aborted AR was withdrawn before handshake");
allow_addresses = 1'b1;
while (!done_o) @(posedge clk_i);
if (error_o || !aborted_o || (error_code_o != 6'd20)) begin
$fatal(1, "DMA unaccepted-address abort drain failed");
end
s_phase = "deterministic random lengths";
for (int unsigned transfer = 0; transfer < 12; transfer++) begin
automatic int unsigned length = ((transfer * 29) % 95) + 1;
automatic int unsigned source_addr = 32'h0000_7000 + (transfer * 32'h100);
automatic int unsigned dest_addr = 32'h0000_9000 + (transfer * 32'h100);
automatic int unsigned beats = (length + 3) / 4;
automatic logic [63:0] read_before = read_bytes_o;
automatic logic [63:0] write_before = write_bytes_o;
for (int unsigned word_index = 0; word_index < beats; word_index++) begin
memory[(source_addr>>2)+word_index] = 32'h600d_0000 ^ (transfer << 8) ^ word_index;
memory[(dest_addr>>2)+word_index] = 32'hdead_beef;
end
source_index = 8'd0;
issue_request(1'b0, source_addr, length);
while (!done_o) @(posedge clk_i);
if (error_o || (read_bytes_o != read_before + length)) begin
$fatal(1, "DMA randomized read failed");
end
source_index = 8'd0;
write_source_active = 1'b1;
issue_request(1'b1, dest_addr, length);
while (!done_o) @(posedge clk_i);
write_source_active = 1'b0;
if (error_o || (write_bytes_o != write_before + length)) begin
$fatal(1, "DMA randomized write failed");
end
for (int unsigned byte_index = 0; byte_index < length; byte_index++) begin
if (memory[(dest_addr >> 2) + (byte_index / 4)][(byte_index%4)*8+:8] !==
memory[(source_addr >> 2) + (byte_index / 4)][(byte_index%4)*8+:8]) begin
$fatal(1, "DMA randomized copy mismatch");
end
end
end
allow_addresses = 1'b0;
s_phase = "timeout";
timeout_i = 32'd1;
source_index = 8'd0;
write_source_active = 1'b1;
issue_request(1'b1, 32'h0000_3000, 32'd4);
while (!error_o) @(posedge clk_i);
if (!axi4.awvalid || !busy_o || (error_code_o != 6'd17)) begin
$fatal(1, "timed-out AW was withdrawn before handshake");
end
allow_addresses = 1'b1;
while (!done_o) @(posedge clk_i);
write_source_active = 1'b0;
if (!error_o || (error_code_o != 6'd17) || aborted_o) $fatal(1, "DMA timeout failed");
@(negedge clk_i);
counter_clear_i = 1'b1;
@(negedge clk_i);
counter_clear_i = 1'b0;
#1;
if ((read_bytes_o != 64'd0) || (write_bytes_o != 64'd0) ||
(u_dut.s_read_stalls_q != 64'd0) || (u_dut.s_write_stalls_q != 64'd0)) begin
$fatal(1, "DMA counter clear failed");
end
$display("APU-P2 DMA tests passed");
$finish;
end
initial begin
repeat (3000) @(posedge clk_i);
$fatal(1, "APU-P2 DMA test timed out in %s state=%0d remaining=%0d", s_phase, u_dut.s_state_q,
u_dut.s_remaining_q);
end
endmodule
+81 -9
View File
@@ -45,6 +45,39 @@ module apu_irq_topology_tb;
.pclk (clk_i),
.presetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) u_apu_axi4_if (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_dma_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_dma_rx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_i2s_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) u_i2s_rx_axis (
clk_i,
rst_n_i
);
always #5 clk_i = ~clk_i;
@@ -62,15 +95,23 @@ module apu_irq_topology_tb;
`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)
.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]),
.bridge_epoch_i (8'd0),
.i2s_tx_underrun_i(1'b0),
.i2s_rx_overrun_i (1'b0),
.apb4 (u_apu_apb4_if),
.axi4 (u_apu_axi4_if),
.dma_tx_axis (u_dma_tx_axis),
.dma_rx_axis (u_dma_rx_axis),
.i2s_tx_axis (u_i2s_tx_axis),
.i2s_rx_axis (u_i2s_rx_axis),
.idle_o (s_apu_idle),
.irq_o (s_apu_irq_raw)
);
resource_controller #(
@@ -214,6 +255,37 @@ apb4_apu u_apu (
initial begin
drive_apb_idle();
u_apu_axi4_if.awready = 1'b0;
u_apu_axi4_if.wready = 1'b0;
u_apu_axi4_if.bid = '0;
u_apu_axi4_if.bresp = '0;
u_apu_axi4_if.buser = '0;
u_apu_axi4_if.bvalid = 1'b0;
u_apu_axi4_if.arready = 1'b0;
u_apu_axi4_if.rid = '0;
u_apu_axi4_if.rdata = '0;
u_apu_axi4_if.rresp = '0;
u_apu_axi4_if.rlast = 1'b0;
u_apu_axi4_if.ruser = '0;
u_apu_axi4_if.rvalid = 1'b0;
u_dma_tx_axis.tdata = '0;
u_dma_tx_axis.tkeep = '1;
u_dma_tx_axis.tstrb = '1;
u_dma_tx_axis.tlast = 1'b0;
u_dma_tx_axis.tid = '0;
u_dma_tx_axis.tdest = '0;
u_dma_tx_axis.tuser = '0;
u_dma_tx_axis.tvalid = 1'b0;
u_dma_rx_axis.tready = 1'b1;
u_i2s_tx_axis.tready = 1'b1;
u_i2s_rx_axis.tdata = '0;
u_i2s_rx_axis.tkeep = '1;
u_i2s_rx_axis.tstrb = '1;
u_i2s_rx_axis.tlast = 1'b0;
u_i2s_rx_axis.tid = '0;
u_i2s_rx_axis.tdest = '0;
u_i2s_rx_axis.tuser = '0;
u_i2s_rx_axis.tvalid = 1'b0;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
// Verification-only deterministic endpoint for the production P2 ring scheduler.
module apu_p2_backend (
input logic clk_i,
input logic rst_n_i,
input logic abort_i,
input logic hold_result_i,
input logic result_error_i,
input logic [ 5:0] result_code_i,
input logic [ 3:0] result_stage_i,
input logic [ 1:0] result_resp_i,
input logic job_valid_i,
output logic job_ready_o,
input logic [1023:0] descriptor_i,
input logic [ 7:0] index_i,
output logic result_valid_o,
input logic result_ready_i,
output logic result_error_o,
output logic [ 5:0] result_code_o,
output logic [ 3:0] result_stage_o,
output logic [ 1:0] result_resp_o,
output logic [ 31:0] input_used_o,
output logic [ 31:0] output_bytes_o,
output logic [ 31:0] frames_o,
output logic [ 31:0] source_info_o,
output logic [ 31:0] cycles_o,
output logic [ 31:0] detail_o,
output logic [ 31:0] accepted_jobs_o
);
logic s_pending_q;
logic s_error_q;
logic [ 5:0] s_code_q;
logic [ 3:0] s_stage_q;
logic [ 1:0] s_resp_q;
logic [ 7:0] s_index_q;
logic [31:0] s_input_length_q;
logic [31:0] s_output_capacity_q;
logic [31:0] s_accepted_jobs_q;
assign job_ready_o = !s_pending_q && !abort_i;
assign result_valid_o = s_pending_q && !hold_result_i;
assign result_error_o = s_error_q;
assign result_code_o = s_code_q;
assign result_stage_o = s_stage_q;
assign result_resp_o = s_resp_q;
assign input_used_o = s_input_length_q;
assign output_bytes_o = s_output_capacity_q;
assign frames_o = s_input_length_q >> 2;
assign source_info_o = 32'h0004_0000 | {24'd0, s_index_q};
assign cycles_o = 32'd64 + {24'd0, s_index_q};
assign detail_o = 32'h5032_0000 | {24'd0, s_index_q};
assign accepted_jobs_o = s_accepted_jobs_q;
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_pending_q <= 1'b0;
s_error_q <= 1'b0;
s_code_q <= 6'd0;
s_stage_q <= 4'd0;
s_resp_q <= 2'd0;
s_index_q <= 8'd0;
s_input_length_q <= 32'd0;
s_output_capacity_q <= 32'd0;
s_accepted_jobs_q <= 32'd0;
end else begin
if (abort_i) s_pending_q <= 1'b0;
if (job_valid_i && job_ready_o) begin
s_pending_q <= 1'b1;
s_error_q <= result_error_i;
s_code_q <= result_code_i;
s_stage_q <= result_stage_i;
s_resp_q <= result_resp_i;
s_index_q <= index_i;
s_input_length_q <= descriptor_i[(3*32)+:32];
s_output_capacity_q <= descriptor_i[(5*32)+:32];
s_accepted_jobs_q <= s_accepted_jobs_q + 1'b1;
end
if (result_valid_o && result_ready_i) s_pending_q <= 1'b0;
end
end
endmodule
File diff suppressed because it is too large. Load diff
+312
View File
@@ -0,0 +1,312 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// SPDX-License-Identifier: MulanPSL-2.0
// Verification-only direct/ring client for the production APU DMA.
module apu_p2_transport_backend (
// verilog_format: off -- preserve job, request, stream, and result columns
input logic clk_i,
input logic rst_n_i,
input logic abort_i,
input logic direct_start_i,
input logic [31:0] direct_source_i,
input logic [31:0] direct_destination_i,
input logic [31:0] direct_bytes_i,
input logic job_valid_i,
output logic job_ready_o,
input logic [1023:0] descriptor_i,
input logic [7:0] index_i,
input logic hold_result_i,
input logic inject_result_error_i,
input logic [5:0] inject_result_code_i,
input logic [3:0] inject_result_stage_i,
input logic [1:0] inject_result_resp_i,
output logic result_valid_o,
input logic result_ready_i,
output logic result_error_o,
output logic [5:0] result_code_o,
output logic [3:0] result_stage_o,
output logic [1:0] result_resp_o,
output logic [31:0] input_used_o,
output logic [31:0] output_bytes_o,
output logic [31:0] frames_o,
output logic [31:0] source_info_o,
output logic [31:0] cycles_o,
output logic [31:0] detail_o,
output logic [31:0] accepted_jobs_o,
output logic request_valid_o,
input logic request_ready_i,
output logic request_write_o,
output logic [31:0] request_addr_o,
output logic [31:0] request_bytes_o,
axi4_stream_if.sink read_axis,
axi4_stream_if.source write_axis,
input logic dma_done_i,
input logic dma_error_i,
input logic dma_aborted_i,
input logic [5:0] dma_error_code_i,
input logic [3:0] dma_error_stage_i,
input logic [1:0] dma_error_resp_i,
output logic busy_o,
output logic direct_done_o,
output logic direct_error_o
// verilog_format: on
);
typedef enum logic [3:0] {
Idle,
ReadRequest,
ReadData,
ReadWait,
WriteRequest,
WriteData,
WriteWait,
Result
} state_e;
state_e s_state_q;
logic s_ring_q;
logic [ 7:0] s_index_q;
logic [31:0] s_source_addr_q;
logic [31:0] s_destination_addr_q;
logic [31:0] s_bytes_q;
logic [ 5:0] s_read_index_q;
logic [ 5:0] s_write_index_q;
logic [31:0] s_buffer_q [32];
logic [ 3:0] s_keep_q [32];
logic s_result_error_q;
logic [ 5:0] s_result_code_q;
logic [ 3:0] s_result_stage_q;
logic [ 1:0] s_result_resp_q;
logic [31:0] s_accepted_jobs_q;
logic s_direct_done_q;
logic s_direct_error_q;
logic s_abort_pending_q;
function automatic logic [31:0] bounded_bytes(input logic [31:0] length_i,
input logic [31:0] capacity_i);
return (length_i < capacity_i) ? length_i : capacity_i;
endfunction
assign job_ready_o = (s_state_q == Idle) && !direct_start_i && !abort_i;
assign result_valid_o = (s_state_q == Result) && !hold_result_i;
assign result_error_o = s_result_error_q;
assign result_code_o = s_result_code_q;
assign result_stage_o = s_result_stage_q;
assign result_resp_o = s_result_resp_q;
assign input_used_o = s_bytes_q;
assign output_bytes_o = s_bytes_q;
assign frames_o = s_bytes_q >> 2;
assign source_info_o = 32'h0004_0000 | {24'd0, s_index_q};
assign cycles_o = 32'd64 + {24'd0, s_index_q};
assign detail_o = 32'h5032_0000 | {24'd0, s_index_q};
assign accepted_jobs_o = s_accepted_jobs_q;
assign request_valid_o = !abort_i && ((s_state_q == ReadRequest) || (s_state_q == WriteRequest));
assign request_write_o = s_state_q == WriteRequest;
assign request_addr_o = request_write_o ? s_destination_addr_q : s_source_addr_q;
assign request_bytes_o = s_bytes_q;
assign read_axis.tready = s_state_q == ReadData;
assign write_axis.tdata = s_buffer_q[s_write_index_q[4:0]];
assign write_axis.tkeep = s_keep_q[s_write_index_q[4:0]];
assign write_axis.tstrb = s_keep_q[s_write_index_q[4:0]];
assign write_axis.tlast = s_write_index_q == s_read_index_q;
assign write_axis.tid = '0;
assign write_axis.tdest = '0;
assign write_axis.tuser = '0;
assign write_axis.tvalid = s_state_q == WriteData;
assign busy_o = s_state_q != Idle;
assign direct_done_o = s_direct_done_q;
assign direct_error_o = s_direct_error_q;
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_state_q <= Idle;
s_ring_q <= 1'b0;
s_index_q <= 8'd0;
s_source_addr_q <= 32'd0;
s_destination_addr_q <= 32'd0;
s_bytes_q <= 32'd0;
s_read_index_q <= 6'd0;
s_write_index_q <= 6'd0;
s_result_error_q <= 1'b0;
s_result_code_q <= 6'd0;
s_result_stage_q <= 4'd0;
s_result_resp_q <= 2'd0;
s_accepted_jobs_q <= 32'd0;
s_direct_done_q <= 1'b0;
s_direct_error_q <= 1'b0;
s_abort_pending_q <= 1'b0;
end else begin
s_direct_done_q <= 1'b0;
if (abort_i && (s_state_q != Idle)) s_abort_pending_q <= 1'b1;
unique case (s_state_q)
Idle: begin
if (job_valid_i && job_ready_o) begin
s_ring_q <= 1'b1;
s_index_q <= index_i;
s_source_addr_q <= descriptor_i[(2*32)+:32];
s_destination_addr_q <= descriptor_i[(4*32)+:32];
s_bytes_q <= bounded_bytes(descriptor_i[(3*32)+:32], descriptor_i[(5*32)+:32]);
s_read_index_q <= 6'd0;
s_write_index_q <= 6'd0;
s_result_error_q <= 1'b0;
s_result_code_q <= 6'd0;
s_result_stage_q <= 4'd0;
s_result_resp_q <= 2'd0;
s_accepted_jobs_q <= s_accepted_jobs_q + 1'b1;
s_abort_pending_q <= 1'b0;
s_state_q <= ReadRequest;
end else if (direct_start_i && !abort_i) begin
s_ring_q <= 1'b0;
s_index_q <= 8'd0;
s_source_addr_q <= direct_source_i;
s_destination_addr_q <= direct_destination_i;
s_bytes_q <= direct_bytes_i;
s_read_index_q <= 6'd0;
s_write_index_q <= 6'd0;
s_direct_error_q <= 1'b0;
s_abort_pending_q <= 1'b0;
s_state_q <= ReadRequest;
end
end
ReadRequest: begin
if (abort_i) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else if (request_ready_i) begin
s_state_q <= ReadData;
end
end
ReadData: begin
if (read_axis.tvalid && read_axis.tready) begin
s_buffer_q[s_read_index_q[4:0]] <= read_axis.tdata;
s_keep_q[s_read_index_q[4:0]] <= read_axis.tkeep;
if (read_axis.tlast) s_state_q <= ReadWait;
else s_read_index_q <= s_read_index_q + 1'b1;
end
if (dma_done_i && (s_abort_pending_q || dma_aborted_i)) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else if (dma_done_i && dma_error_i) begin
s_result_error_q <= 1'b1;
s_result_code_q <= dma_error_code_i;
s_result_stage_q <= dma_error_stage_i;
s_result_resp_q <= dma_error_resp_i;
s_state_q <= s_ring_q ? Result : Idle;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end
end
ReadWait: begin
if (dma_done_i) begin
if (s_abort_pending_q || dma_aborted_i) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else if (dma_error_i) begin
s_result_error_q <= 1'b1;
s_result_code_q <= dma_error_code_i;
s_result_stage_q <= dma_error_stage_i;
s_result_resp_q <= dma_error_resp_i;
s_state_q <= s_ring_q ? Result : Idle;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else begin
s_write_index_q <= 6'd0;
s_state_q <= WriteRequest;
end
end
end
WriteRequest: begin
if (abort_i) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else if (request_ready_i) begin
s_state_q <= WriteData;
end
end
WriteData: begin
if (dma_done_i && (s_abort_pending_q || dma_aborted_i)) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else if (dma_done_i && dma_error_i) begin
s_result_error_q <= 1'b1;
s_result_code_q <= dma_error_code_i;
s_result_stage_q <= dma_error_stage_i;
s_result_resp_q <= dma_error_resp_i;
s_state_q <= s_ring_q ? Result : Idle;
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= 1'b1;
end
end else if (write_axis.tvalid && write_axis.tready) begin
if (write_axis.tlast) s_state_q <= WriteWait;
else s_write_index_q <= s_write_index_q + 1'b1;
end
end
WriteWait: begin
if (dma_done_i) begin
s_result_error_q <= dma_error_i || inject_result_error_i;
s_result_code_q <= dma_error_i ? dma_error_code_i : inject_result_code_i;
s_result_stage_q <= dma_error_i ? dma_error_stage_i : inject_result_stage_i;
s_result_resp_q <= dma_error_i ? dma_error_resp_i : inject_result_resp_i;
if (s_abort_pending_q || dma_aborted_i) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
end else begin
s_state_q <= s_ring_q ? Result : Idle;
end
if (!s_ring_q) begin
s_direct_done_q <= 1'b1;
s_direct_error_q <= dma_error_i || dma_aborted_i || s_abort_pending_q;
end
end
end
Result: begin
if (result_valid_o && result_ready_i) begin
s_state_q <= Idle;
s_abort_pending_q <= 1'b0;
end
end
default: s_state_q <= Idle;
endcase
end
end
`ifndef SYNTHESIS
always_ff @(posedge clk_i) begin
if (rst_n_i && job_valid_i && job_ready_o && ((bounded_bytes(
descriptor_i[(3*32)+:32], descriptor_i[(5*32)+:32]
) == 32'd0) || (bounded_bytes(
descriptor_i[(3*32)+:32], descriptor_i[(5*32)+:32]
) > 32'd128))) begin
$fatal(1, "apu_p2_transport_backend: ring transfer bytes must be in [1, 128]");
end
if (rst_n_i && direct_start_i &&
((direct_bytes_i == 32'd0) || (direct_bytes_i > 32'd128))) begin
$fatal(1, "apu_p2_transport_backend: direct transfer bytes must be in [1, 128]");
end
end
`endif
endmodule
+146 -17
View File
@@ -4,7 +4,7 @@
module apu_reg_tb;
localparam logic [31:0] ApuBase = 32'h1001_3000;
localparam int unsigned RegisterCount = 95;
localparam int unsigned RegisterCount = 96;
localparam logic [1:0] AccessRo = 2'd0;
localparam logic [1:0] AccessWo = 2'd1;
localparam logic [1:0] AccessRw = 2'd2;
@@ -23,24 +23,98 @@ module apu_reg_tb;
logic [31:0] s_reg_reset [RegisterCount];
logic s_reg_full_strobe [RegisterCount];
int unsigned s_reg_count;
string s_phase;
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) dma_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) dma_rx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) i2s_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) i2s_rx_axis (
clk_i,
rst_n_i
);
assign axi4.awready = 1'b0;
assign axi4.wready = 1'b0;
assign axi4.bid = '0;
assign axi4.bresp = '0;
assign axi4.buser = '0;
assign axi4.bvalid = 1'b0;
assign axi4.arready = 1'b0;
assign axi4.rid = '0;
assign axi4.rdata = '0;
assign axi4.rresp = '0;
assign axi4.rlast = 1'b0;
assign axi4.ruser = '0;
assign axi4.rvalid = 1'b0;
assign dma_tx_axis.tdata = '0;
assign dma_tx_axis.tkeep = '1;
assign dma_tx_axis.tstrb = '1;
assign dma_tx_axis.tlast = 1'b0;
assign dma_tx_axis.tid = '0;
assign dma_tx_axis.tdest = '0;
assign dma_tx_axis.tuser = '0;
assign dma_tx_axis.tvalid = 1'b0;
assign dma_rx_axis.tready = 1'b1;
assign i2s_tx_axis.tready = 1'b1;
assign i2s_rx_axis.tdata = '0;
assign i2s_rx_axis.tkeep = '1;
assign i2s_rx_axis.tstrb = '1;
assign i2s_rx_axis.tlast = 1'b0;
assign i2s_rx_axis.tid = '0;
assign i2s_rx_axis.tdest = '0;
assign i2s_rx_axis.tuser = '0;
assign i2s_rx_axis.tvalid = 1'b0;
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)
.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),
.bridge_epoch_i (8'd0),
.i2s_tx_underrun_i(1'b0),
.i2s_rx_overrun_i (1'b0),
.apb4 (apb4),
.axi4 (axi4),
.dma_tx_axis (dma_tx_axis),
.dma_rx_axis (dma_rx_axis),
.i2s_tx_axis (i2s_tx_axis),
.i2s_rx_axis (i2s_rx_axis),
.idle_o (idle_o),
.irq_o (irq_o)
);
function automatic logic [31:0] legal_write_value(input logic [11:0] offset_i);
@@ -50,6 +124,7 @@ module apu_reg_tb;
`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__STREAM_WATERMARK: legal_write_value = 32'h0000_2020;
`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;
@@ -116,7 +191,7 @@ module apu_reg_tb;
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__CAPABILITY0, AccessRo, 32'h0000_0018, 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);
@@ -128,7 +203,7 @@ module apu_reg_tb;
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__STREAM_STATUS, AccessRo, 32'h0000_0014, 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);
@@ -138,6 +213,7 @@ module apu_reg_tb;
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__STREAM_WATERMARK, AccessRw, 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);
@@ -168,7 +244,7 @@ module apu_reg_tb;
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_STATUS, AccessRo, 32'h0000_0004, 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);
@@ -269,7 +345,9 @@ module apu_reg_tb;
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);
if (apb4.pslverr != expected_err_i) begin
$fatal(1, "APU write response mismatch at %h in %s", offset_i, s_phase);
end
s_response_err = apb4.pslverr;
#2;
if (!apb4.pready || (apb4.pslverr != s_response_err)) begin
@@ -307,7 +385,9 @@ module apu_reg_tb;
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);
if (apb4.pslverr != expected_err_i) begin
$fatal(1, "APU read response mismatch at %h during %s", offset_i, s_phase);
end
s_response_data = apb4.prdata;
s_response_err = apb4.pslverr;
#2;
@@ -383,10 +463,12 @@ module apu_reg_tb;
initial begin
initialize_register_table();
s_phase = "initial reset matrix";
drive_apb_idle();
hard_reset();
if (!idle_o || irq_o) $fatal(1, "APU reset lifecycle outputs mismatch");
s_phase = "access matrix";
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
hard_reset();
if (s_reg_access[register_index] == AccessWo) begin
@@ -429,6 +511,7 @@ module apu_reg_tb;
endcase
end
s_phase = "valid byte strobes";
hard_reset();
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'h0000_00aa, 4'h1, 1'b0);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'h0000_ffaa);
@@ -439,6 +522,7 @@ module apu_reg_tb;
apb_write(`APB4_APU__SEQUENCER_TIMEOUT, 32'hdd00_0000, 4'h8, 1'b0);
expect_read(`APB4_APU__SEQUENCER_TIMEOUT, 32'hddcc_bbaa);
s_phase = "invalid full strobes";
for (int unsigned register_index = 0; register_index < RegisterCount; register_index++) begin
if (s_reg_full_strobe[register_index]) begin
hard_reset();
@@ -452,9 +536,12 @@ module apu_reg_tb;
end
end
s_phase = "rejected values";
check_rejected_write(`APB4_APU__COMMAND, 32'h0000_0080, `APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__COMMAND, 32'h0000_0002, `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_ABORT) &&
(bit_index != `APB4_APU__COMMAND_CLEAR_COUNTERS)) begin
check_rejected_write(`APB4_APU__COMMAND, 32'd1 << bit_index,
`APB4_APU__ERROR_CODE_UNSUPPORTED);
@@ -469,6 +556,10 @@ module apu_reg_tb;
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__STREAM_WATERMARK, 32'h0000_0041,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
check_rejected_write(`APB4_APU__STREAM_WATERMARK, 32'h0001_0000,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
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);
@@ -500,6 +591,7 @@ module apu_reg_tb;
check_rejected_write(`APB4_APU__PERF_CONTROL, 32'h0000_0008,
`APB4_APU__ERROR_CODE_INVALID_CONFIG);
s_phase = "set over clear";
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;
@@ -509,34 +601,71 @@ module apu_reg_tb;
apb_write(`APB4_APU__IRQ_STATE, 32'h0000_0001, 4'h1, 1'b0);
expect_read(`APB4_APU__IRQ_STATE, 32'd0);
s_phase = "soft reset";
hard_reset();
program_rw_registers();
apb_write(`APB4_APU__COMMAND, 32'h0000_0004, 4'hf, 1'b0);
check_reset_state(1'b1);
s_phase = "resource reset";
hard_reset();
program_rw_registers();
force u_dut.s_dma_busy = 1'b1;
@(negedge clk_i);
resource_reset_i = 1'b1;
repeat (3) @(posedge clk_i);
if (u_dut.s_resource_reset_apply_q || (u_dut.u_apu_reg.s_timeout_q[0] != 32'h1234_5678)) begin
$fatal(1, "resource reset applied before transport drain");
end
force u_dut.s_dma_busy = 1'b0;
wait (u_dut.s_resource_reset_apply_q);
release u_dut.s_dma_busy;
@(posedge clk_i);
@(negedge clk_i);
resource_reset_i = 1'b0;
check_reset_state(1'b1);
s_phase = "performance enable";
hard_reset();
force u_dut.s_dma_busy = 1'b1;
repeat (5) @(posedge clk_i);
if (u_dut.s_active_cycles_q != 64'd0) begin
$fatal(1, "disabled performance counter advanced");
end
force u_dut.s_dma_busy = 1'b0;
release u_dut.s_dma_busy;
hard_reset();
apb_write(`APB4_APU__PERF_CONTROL, 32'h0000_0001, 4'hf, 1'b0);
force u_dut.s_dma_busy = 1'b1;
repeat (5) @(posedge clk_i);
if (u_dut.s_active_cycles_q == 64'd0) begin
$fatal(1, "enabled performance counter did not advance");
end
force u_dut.s_dma_busy = 1'b0;
release u_dut.s_dma_busy;
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'h064, s_value, 1'b1);
apb_read(12'h001, s_value, 1'b1);
s_phase = "command state predicates";
hard_reset();
force u_dut.u_apu_reg.core_busy_i = 1'b1;
force u_dut.u_apu_reg.core_idle_i = 1'b0;
apb_write(`APB4_APU__COMMAND, 32'h0000_0002, 4'hf, 1'b0);
apb_write(`APB4_APU__COMMAND, 32'h0000_0040, 4'hf, 1'b1);
expect_read(`APB4_APU__ERROR_STATUS, 32'd1 | (32'(`APB4_APU__ERROR_CODE_INVALID_CONFIG) << 1));
$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");
$fatal(1, "APU-P1 APB register matrix timed out in %s", s_phase);
end
endmodule
+626
View File
@@ -0,0 +1,626 @@
`timescale 1ns / 1ps
`include "apu_define.svh"
module apu_ring_scheduler_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic soft_reset_i = 1'b0;
logic counter_clear_i = 1'b0;
logic abort_i = 1'b0;
logic quiesce_i = 1'b0;
logic start_i = 1'b0;
logic [31:0] ring_base_i = 32'h0000_1000;
logic [ 8:0] ring_size_i = 9'd2;
logic [ 7:0] ring_tail_i = 8'd0;
logic ring_enable_i = 1'b0;
logic stop_on_error_i = 1'b0;
logic [ 7:0] coalesce_count_i = 8'd3;
logic [15:0] coalesce_timeout_i = 16'd4;
logic dma_request_valid_o, dma_request_ready_i, dma_request_write_o;
logic [31:0] dma_request_addr_o, dma_request_bytes_o;
logic dma_done_i = 1'b0;
logic dma_error_i = 1'b0;
logic [ 5:0] dma_error_code_i = 6'd0;
logic [ 3:0] dma_error_stage_i = 4'd0;
logic [ 1:0] dma_error_resp_i = 2'd0;
logic [31:0] dma_error_addr_i = 32'd0;
logic backend_job_valid, backend_job_ready;
logic [1023:0] backend_descriptor;
logic [ 7:0] backend_index;
logic backend_result_valid, backend_result_ready;
logic backend_result_error = 1'b0;
logic [5:0] backend_result_code = 6'd0;
logic [3:0] backend_result_stage = 4'd0;
logic [1:0] backend_result_resp = 2'd0;
logic backend_latched_error;
logic [5:0] backend_latched_code;
logic [3:0] backend_latched_stage;
logic [1:0] backend_latched_resp;
logic [31:0] backend_input_used, backend_output_bytes, backend_frames;
logic [31:0] backend_source_info, backend_cycles, backend_detail;
logic backend_hold = 1'b0;
logic hold_dma_request = 1'b0;
logic hold_dma_read = 1'b0;
logic hold_dma_write = 1'b0;
logic [31:0] backend_accepted;
logic [31:0] job_status_o, ring_status_o;
logic [ 7:0] ring_head_o;
logic [31:0] ring_completed_o;
logic ring_event_o, error_event_o, abort_done_o, aborting_o, idle_o;
logic [ 5:0] error_code_o;
logic [ 3:0] error_stage_o;
logic [ 1:0] error_resp_o;
logic [ 7:0] error_index_o;
logic [31:0] error_addr_o;
logic [31:0] memory [0:63];
logic dma_active_q, dma_write_q;
logic [5:0] dma_word_q, dma_last_word_q;
logic inject_dma_error_q;
int unsigned ring_events, error_events, abort_events;
int unsigned events_before_invalid, errors_before_invalid;
string s_phase;
axi4_stream_if #(
.DATA_WIDTH(32)
) dma_read_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) dma_write_axis (
clk_i,
rst_n_i
);
always #5 clk_i = ~clk_i;
assign dma_request_ready_i = !dma_active_q && !hold_dma_request;
assign dma_read_axis.tdata = memory[((dma_request_addr_o-ring_base_i)>>2)+dma_word_q];
assign dma_read_axis.tkeep = 4'hf;
assign dma_read_axis.tstrb = 4'hf;
assign dma_read_axis.tlast = dma_word_q == dma_last_word_q;
assign dma_read_axis.tid = '0;
assign dma_read_axis.tdest = '0;
assign dma_read_axis.tuser = '0;
assign dma_read_axis.tvalid = dma_active_q && !dma_write_q && !hold_dma_read;
assign dma_write_axis.tready = dma_active_q && dma_write_q && !hold_dma_write;
apu_ring_scheduler u_dut (
.clk_i,
.rst_n_i,
.soft_reset_i,
.counter_clear_i,
.abort_i,
.quiesce_i,
.start_i,
.ring_base_i,
.ring_size_i,
.ring_tail_i,
.ring_enable_i,
.stop_on_error_i,
.coalesce_count_i,
.coalesce_timeout_i,
.dma_request_valid_o,
.dma_request_ready_i,
.dma_request_write_o,
.dma_request_addr_o,
.dma_request_bytes_o,
.dma_read_axis,
.dma_write_axis,
.dma_done_i,
.dma_error_i,
.dma_error_code_i,
.dma_error_stage_i,
.dma_error_resp_i,
.dma_error_addr_i,
.backend_job_valid_o (backend_job_valid),
.backend_job_ready_i (backend_job_ready),
.backend_descriptor_o (backend_descriptor),
.backend_index_o (backend_index),
.backend_result_valid_i(backend_result_valid),
.backend_result_ready_o(backend_result_ready),
.backend_result_error_i(backend_latched_error),
.backend_result_code_i (backend_latched_code),
.backend_result_stage_i(backend_latched_stage),
.backend_result_resp_i (backend_latched_resp),
.backend_input_used_i (backend_input_used),
.backend_output_bytes_i(backend_output_bytes),
.backend_frames_i (backend_frames),
.backend_source_info_i (backend_source_info),
.backend_cycles_i (backend_cycles),
.backend_detail_i (backend_detail),
.job_status_o,
.ring_status_o,
.ring_head_o,
.ring_completed_o,
.ring_event_o,
.error_event_o,
.error_code_o,
.error_stage_o,
.error_resp_o,
.error_index_o,
.error_addr_o,
.abort_done_o,
.aborting_o,
.idle_o
);
apu_p2_backend u_backend (
.clk_i,
.rst_n_i,
.abort_i,
.hold_result_i (backend_hold),
.result_error_i (backend_result_error),
.result_code_i (backend_result_code),
.result_stage_i (backend_result_stage),
.result_resp_i (backend_result_resp),
.job_valid_i (backend_job_valid),
.job_ready_o (backend_job_ready),
.descriptor_i (backend_descriptor),
.index_i (backend_index),
.result_valid_o (backend_result_valid),
.result_ready_i (backend_result_ready),
.result_error_o (backend_latched_error),
.result_code_o (backend_latched_code),
.result_stage_o (backend_latched_stage),
.result_resp_o (backend_latched_resp),
.input_used_o (backend_input_used),
.output_bytes_o (backend_output_bytes),
.frames_o (backend_frames),
.source_info_o (backend_source_info),
.cycles_o (backend_cycles),
.detail_o (backend_detail),
.accepted_jobs_o(backend_accepted)
);
task automatic pulse_start;
begin
@(negedge clk_i);
start_i = 1'b1;
@(negedge clk_i);
start_i = 1'b0;
end
endtask
task automatic pulse_abort;
begin
@(negedge clk_i);
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
end
endtask
task automatic hard_reset;
begin
rst_n_i = 1'b0;
repeat (3) @(posedge clk_i);
@(negedge clk_i);
rst_n_i = 1'b1;
repeat (2) @(posedge clk_i);
end
endtask
task automatic wait_completed(input logic [31:0] expected_i);
int unsigned timeout;
begin
timeout = 0;
while ((ring_completed_o != expected_i) && (timeout < 1000)) begin
@(posedge clk_i);
timeout++;
end
if (ring_completed_o != expected_i) $fatal(1, "ring completion timeout in %s", s_phase);
end
endtask
task automatic clear_descriptor(input int unsigned descriptor_i);
for (int unsigned word_index = 0; word_index < 32; word_index++) begin
memory[(descriptor_i*32)+word_index] = 32'd0;
end
endtask
task automatic make_valid_descriptor(input int unsigned descriptor_i, input logic ioc_i);
begin
clear_descriptor(descriptor_i);
memory[descriptor_i*32] = (32'd1 << `APB4_APU__DESCRIPTOR_CONTROL_OWN) |
(ioc_i ? (32'd1 << `APB4_APU__DESCRIPTOR_CONTROL_IOC) : 32'd0);
memory[(descriptor_i*32)+2] = 32'h0000_4000 + (descriptor_i * 32'h100);
memory[(descriptor_i*32)+3] = 32'd256 + descriptor_i;
memory[(descriptor_i*32)+4] = 32'h0000_8000 + (descriptor_i * 32'h100);
memory[(descriptor_i*32)+5] = 32'd512 + descriptor_i;
memory[(descriptor_i*32)+16] = 32'hc001_0000 + descriptor_i;
memory[(descriptor_i*32)+17] = 32'hc002_0000 + descriptor_i;
end
endtask
task automatic abort_writeback_state(input logic [3:0] state_i);
begin
hard_reset();
clear_descriptor(0);
make_valid_descriptor(0, 1'b0);
ring_size_i = 9'd2;
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
backend_hold = 1'b1;
hold_dma_request = 1'b0;
hold_dma_write = 1'b0;
pulse_start();
wait (u_dut.s_state_q == 4'd5);
@(negedge clk_i);
if (state_i == 4'd6) hold_dma_request = 1'b1;
if (state_i == 4'd7) hold_dma_write = 1'b1;
backend_hold = 1'b0;
if (state_i == 4'd9) begin
wait (u_dut.s_state_q == 4'd8);
@(negedge clk_i);
hold_dma_request = 1'b1;
end
if (state_i == 4'd10) begin
wait (u_dut.s_state_q == 4'd9);
@(negedge clk_i);
hold_dma_write = 1'b1;
end
wait (u_dut.s_state_q == state_i);
pulse_abort();
hold_dma_request = 1'b0;
hold_dma_write = 1'b0;
wait (abort_done_o);
wait (idle_o);
if (memory[0][31] || (ring_completed_o != 32'd1)) begin
$fatal(1, "abort did not retire ordered writeback state %0d", state_i);
end
end
endtask
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
dma_active_q <= 1'b0;
dma_write_q <= 1'b0;
dma_word_q <= 6'd0;
dma_last_word_q <= 6'd0;
dma_done_i <= 1'b0;
dma_error_i <= 1'b0;
inject_dma_error_q <= 1'b0;
ring_events <= 0;
error_events <= 0;
abort_events <= 0;
end else begin
dma_done_i <= 1'b0;
dma_error_i <= 1'b0;
if (dma_request_valid_o && dma_request_ready_i) begin
if ((!dma_request_write_o &&
((dma_request_bytes_o != 32'd128) || (dma_request_addr_o[6:0] != 7'd0))) ||
(dma_request_write_o && (dma_request_bytes_o == 32'd124) &&
(dma_request_addr_o[6:0] != 7'd4)) ||
(dma_request_write_o && (dma_request_bytes_o == 32'd4) &&
(dma_request_addr_o[6:0] != 7'd0)) ||
(dma_request_write_o && (dma_request_bytes_o != 32'd124) &&
(dma_request_bytes_o != 32'd4))) begin
$fatal(1, "malformed descriptor DMA request");
end
if (dma_request_write_o && (dma_request_bytes_o == 32'd124) &&
!memory[((dma_request_addr_o-ring_base_i)>>2)-1][31]) begin
$fatal(1, "descriptor OWN cleared before result writeback");
end
if (dma_request_write_o && (dma_request_bytes_o == 32'd4) &&
(!memory[((dma_request_addr_o-ring_base_i)>>2)][31] ||
(memory[((dma_request_addr_o-ring_base_i)>>2)+1] == 32'd0))) begin
$fatal(1, "descriptor OWN publication preceded result retirement");
end
dma_active_q <= 1'b1;
dma_write_q <= dma_request_write_o;
dma_word_q <= 6'd0;
dma_last_word_q <= 6'(((dma_request_bytes_o + 32'd3) >> 2) - 1'b1);
end
if (dma_read_axis.tvalid && dma_read_axis.tready) begin
if (dma_word_q == dma_last_word_q) begin
dma_active_q <= 1'b0;
dma_done_i <= 1'b1;
dma_error_i <= inject_dma_error_q;
dma_error_code_i <= inject_dma_error_q ? 6'd15 : 6'd0;
dma_error_stage_i <= inject_dma_error_q ? 4'd3 : 4'd0;
dma_error_resp_i <= inject_dma_error_q ? 2'd2 : 2'd0;
dma_error_addr_i <= dma_request_addr_o;
inject_dma_error_q <= 1'b0;
end else begin
dma_word_q <= dma_word_q + 1'b1;
end
end
if (dma_write_axis.tvalid && dma_write_axis.tready) begin
memory[((dma_request_addr_o-ring_base_i)>>2)+dma_word_q] <= dma_write_axis.tdata;
if (dma_word_q == dma_last_word_q) begin
dma_active_q <= 1'b0;
dma_done_i <= 1'b1;
end else begin
dma_word_q <= dma_word_q + 1'b1;
end
end
if (ring_event_o) ring_events <= ring_events + 1;
if (error_event_o) error_events <= error_events + 1;
if (abort_done_o) abort_events <= abort_events + 1;
end
end
initial begin
for (int unsigned index = 0; index < 64; index++) memory[index] = 32'd0;
s_phase = "reset";
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
repeat (2) @(posedge clk_i);
if (ring_status_o != 32'h0000_0004 || job_status_o != 32'd0) begin
$fatal(1, "ring/job reset status mismatch");
end
ring_size_i = 9'd256;
force u_dut.s_head_q = 8'd254;
#1;
if (u_dut.s_next_head != 8'd255) $fatal(1, "256-entry ring truncated before index 255");
force u_dut.s_head_q = 8'd255;
#1;
if (u_dut.s_next_head != 8'd0) $fatal(1, "256-entry ring did not wrap after index 255");
release u_dut.s_head_q;
s_phase = "stale head validation";
ring_size_i = 9'd2;
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
force u_dut.s_head_q = 8'd3;
pulse_start();
#1;
if (!error_event_o || (error_code_o != 6'd2) || dma_active_q) begin
$fatal(1, "stale ring head outside the configured extent was accepted");
end
release u_dut.s_head_q;
soft_reset_i = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
soft_reset_i = 1'b0;
ring_size_i = 9'd2;
s_phase = "backend request abort exclusion";
make_valid_descriptor(0, 1'b0);
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
pulse_start();
wait (u_dut.s_state_q == 4'd4);
@(negedge clk_i);
abort_i = 1'b1;
#1;
if (backend_job_valid || backend_job_ready) begin
$fatal(1, "backend handshake remained eligible during abort");
end
@(negedge clk_i);
abort_i = 1'b0;
wait_completed(32'd1);
if ((backend_accepted != 32'd0) || !memory[1][2]) begin
$fatal(1, "backend request abort was accepted or not published");
end
hard_reset();
clear_descriptor(0);
s_phase = "simultaneous backend error and abort";
backend_hold = 1'b1;
backend_result_error = 1'b1;
backend_result_code = 6'd7;
backend_result_stage = 4'd4;
make_valid_descriptor(0, 1'b0);
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
pulse_start();
wait (u_dut.s_state_q == 4'd5);
@(negedge clk_i);
backend_hold = 1'b0;
abort_i = 1'b1;
@(negedge clk_i);
abort_i = 1'b0;
wait_completed(32'd1);
@(posedge clk_i);
if (!memory[1][1] || !memory[1][2] || (memory[1][8:3] != 6'd7) ||
(error_events != 1) || (abort_events != 1)) begin
$fatal(1, "simultaneous backend error did not outrank and retain abort");
end
backend_result_error = 1'b0;
backend_result_code = 6'd0;
backend_result_stage = 4'd0;
hard_reset();
clear_descriptor(0);
s_phase = "idle-active abort";
ring_tail_i = 8'd0;
ring_enable_i = 1'b1;
pulse_start();
wait (ring_status_o[`APB4_APU__RING_STATUS_ACTIVE] && idle_o);
pulse_abort();
wait (abort_done_o);
hard_reset();
clear_descriptor(0);
make_valid_descriptor(0, 1'b0);
s_phase = "fetch-request abort";
hold_dma_request = 1'b1;
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
pulse_start();
wait (u_dut.s_state_q == 4'd1);
pulse_abort();
hold_dma_request = 1'b0;
wait (abort_done_o);
if (!memory[0][31]) $fatal(1, "FetchRequest abort mutated descriptor ownership");
hard_reset();
clear_descriptor(0);
s_phase = "stalled-unowned abort";
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
pulse_start();
wait (u_dut.s_state_q == 4'd12);
pulse_abort();
wait (abort_done_o);
hard_reset();
clear_descriptor(0);
for (int unsigned writeback_state = 6; writeback_state <= 11; writeback_state++) begin
s_phase = "writeback abort matrix";
abort_writeback_state(4'(writeback_state));
end
hard_reset();
clear_descriptor(0);
s_phase = "timeout coalescing";
make_valid_descriptor(0, 1'b0);
ring_enable_i = 1'b1;
ring_tail_i = 8'd1;
pulse_start();
wait_completed(32'd1);
if (memory[0][31] || !memory[1][0] || (ring_head_o != 8'd1) || !job_status_o[1] ||
(memory[16] != 32'hc001_0000) || (memory[17] != 32'hc002_0000) ||
({memory[21], memory[20]} < {memory[19], memory[18]}) ||
(memory[22] != 32'd0) || (memory[23] != 32'd0)) begin
$fatal(1, "successful descriptor writeback mismatch");
end
while (ring_events == 0) @(posedge clk_i);
if (ring_status_o[5] || (ring_status_o[15:8] != 8'd0)) begin
$fatal(1, "coalescing timeout did not clear pending state");
end
s_phase = "unowned and IOC wrap";
clear_descriptor(1);
ring_tail_i = 8'd0;
repeat (40) @(posedge clk_i);
if (!ring_status_o[1] || (ring_head_o != 8'd1) || (ring_completed_o != 32'd1)) begin
$fatal(1, "unowned descriptor was not stalled");
end
make_valid_descriptor(1, 1'b1);
pulse_start();
wait_completed(32'd2);
@(posedge clk_i);
if ((ring_head_o != 8'd0) || !ring_status_o[4] || (ring_events != 2)) begin
$fatal(1, "IOC/wrap behavior mismatch events=%0d", ring_events);
end
s_phase = "count coalescing";
coalesce_count_i = 8'd2;
coalesce_timeout_i = 16'd100;
make_valid_descriptor(0, 1'b0);
ring_tail_i = 8'd1;
pulse_start();
wait_completed(32'd3);
if ((ring_events != 2) || !ring_status_o[5] || (ring_status_o[15:8] != 8'd1)) begin
$fatal(1, "coalescing count epoch did not retain first completion");
end
make_valid_descriptor(1, 1'b0);
ring_tail_i = 8'd0;
pulse_start();
wait_completed(32'd4);
@(posedge clk_i);
if ((ring_events != 3) || ring_status_o[5] || (ring_status_o[15:8] != 8'd0)) begin
$fatal(1, "coalescing count threshold mismatch");
end
s_phase = "deterministic randomized descriptors";
coalesce_count_i = 8'd4;
coalesce_timeout_i = 16'd7;
for (int unsigned job = 0; job < 8; job++) begin
automatic int unsigned descriptor = ring_head_o;
automatic logic expected_error = ((job * 5 + 1) % 7) == 2;
make_valid_descriptor(descriptor, ((job * 3 + 1) % 5) == 0);
memory[(descriptor*32)+3] = 32'd33 + ((job * 29) % 511);
memory[(descriptor*32)+5] = 32'd65 + ((job * 17) % 1023);
backend_result_error = expected_error;
backend_result_code = expected_error ? 6'd7 : 6'd0;
backend_result_stage = expected_error ? 4'd4 : 4'd0;
ring_tail_i = descriptor == 0 ? 8'd1 : 8'd0;
pulse_start();
wait_completed(32'(5 + job));
@(posedge clk_i);
if (memory[descriptor*32][31] ||
(memory[(descriptor*32)+1][1] != expected_error) ||
(memory[(descriptor*32)+1][0] == expected_error)) begin
$fatal(1, "randomized descriptor result mismatch job=%0d", job);
end
end
backend_result_error = 1'b0;
backend_result_code = 6'd0;
backend_result_stage = 4'd0;
s_phase = "invalid stop on error";
events_before_invalid = ring_events;
errors_before_invalid = error_events;
ring_enable_i = 1'b0;
repeat (2) @(posedge clk_i);
stop_on_error_i = 1'b1;
make_valid_descriptor(0, 1'b1);
memory[0][12] = 1'b1;
memory[10] = 32'hdead_beef;
ring_tail_i = 8'd1;
ring_enable_i = 1'b1;
pulse_start();
wait_completed(32'd13);
@(posedge clk_i);
if (memory[0][31] || !memory[1][1] || (memory[1][8:3] != 6'd2) ||
(memory[10] != 32'd0) ||
!ring_status_o[3] || !ring_status_o[7] || ring_status_o[0] ||
(ring_events != events_before_invalid + 1) ||
(error_events != errors_before_invalid + 1)) begin
$fatal(1, "invalid-owned stop-on-error behavior mismatch");
end
s_phase = "abort writeback";
ring_enable_i = 1'b0;
stop_on_error_i = 1'b0;
repeat (2) @(posedge clk_i);
make_valid_descriptor(1, 1'b0);
ring_tail_i = 8'd0;
backend_hold = 1'b1;
ring_enable_i = 1'b1;
pulse_start();
while (!backend_job_valid && !backend_result_ready) @(posedge clk_i);
repeat (2) @(posedge clk_i);
pulse_abort();
if (!aborting_o) $fatal(1, "scheduler live aborting status was not asserted");
backend_hold = 1'b0;
wait_completed(32'd14);
@(posedge clk_i);
if (memory[32][31] || !memory[33][2] || !job_status_o[3] ||
(abort_events != 1) || ring_status_o[0]) begin
$fatal(1, "abort terminal writeback mismatch");
end
if (aborting_o) $fatal(1, "scheduler live aborting status remained set after writeback");
s_phase = "descriptor DMA error";
ring_enable_i = 1'b0;
repeat (2) @(posedge clk_i);
make_valid_descriptor(0, 1'b0);
ring_tail_i = 8'd1;
inject_dma_error_q = 1'b1;
ring_enable_i = 1'b1;
pulse_start();
while (!error_event_o) @(posedge clk_i);
repeat (2) @(posedge clk_i);
if ((ring_completed_o != 32'd14) || !ring_status_o[3] || ring_status_o[0] ||
(error_code_o != 6'd15) || (error_stage_o != 4'd3) ||
(error_resp_o != 2'd2) || (error_index_o != 8'd0) ||
(error_addr_o != ring_base_i)) begin
$fatal(1, "descriptor DMA error attribution mismatch");
end
if (backend_accepted != 32'd13) $fatal(1, "unexpected backend job count");
@(negedge clk_i);
counter_clear_i = 1'b1;
@(negedge clk_i);
counter_clear_i = 1'b0;
#1;
if (ring_completed_o != 32'd0) $fatal(1, "ring completion counter clear failed");
$display("APU-P2 ring scheduler/backend tests passed");
$finish;
end
initial begin
repeat (10000) @(posedge clk_i);
$fatal(1, "APU-P2 ring scheduler test timed out in %s state=%0d", s_phase, u_dut.s_state_q);
end
endmodule
+294
View File
@@ -0,0 +1,294 @@
`timescale 1ns / 1ps
module apu_stream_router_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic flush_i = 1'b0;
logic counter_clear_i = 1'b0;
logic xrun_clear_i = 1'b0;
logic tx_route_apu_i = 1'b0;
logic rx_route_apu_i = 1'b0;
logic tx_session_active_i = 1'b0;
logic rx_session_active_i = 1'b0;
logic [ 7:0] rx_high_watermark_i = 8'd0;
logic [ 7:0] tx_low_watermark_i = 8'd0;
logic tx_underrun_i = 1'b0;
logic rx_overrun_i = 1'b0;
logic [31:0] status_o;
logic input_watermark_evt_o;
logic output_watermark_evt_o;
logic stream_xrun_evt_o;
logic idle_o;
logic input_watermark_seen;
logic output_watermark_seen;
axi4_stream_if #(
.DATA_WIDTH(32)
) dma_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) dma_rx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) i2s_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) i2s_rx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) apu_tx_axis (
clk_i,
rst_n_i
);
axi4_stream_if #(
.DATA_WIDTH(32)
) apu_rx_axis (
clk_i,
rst_n_i
);
always #5 clk_i = ~clk_i;
always @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
input_watermark_seen <= 1'b0;
output_watermark_seen <= 1'b0;
end else begin
if (input_watermark_evt_o) input_watermark_seen <= 1'b1;
if (output_watermark_evt_o) output_watermark_seen <= 1'b1;
end
end
apu_stream_router u_dut (
.clk_i,
.rst_n_i,
.flush_i,
.counter_clear_i,
.xrun_clear_i,
.tx_route_apu_i,
.rx_route_apu_i,
.tx_session_active_i,
.rx_session_active_i,
.rx_high_watermark_i,
.tx_low_watermark_i,
.tx_underrun_i,
.rx_overrun_i,
.dma_tx_axis,
.dma_rx_axis,
.i2s_tx_axis,
.i2s_rx_axis,
.apu_tx_axis,
.apu_rx_axis,
.status_o,
.input_watermark_evt_o,
.output_watermark_evt_o,
.stream_xrun_evt_o,
.idle_o
);
task automatic push_apu_tx(input logic [31:0] data_i);
begin
@(negedge clk_i);
apu_tx_axis.tdata = data_i;
apu_tx_axis.tvalid = 1'b1;
do @(posedge clk_i); while (!apu_tx_axis.tready);
@(negedge clk_i);
apu_tx_axis.tvalid = 1'b0;
end
endtask
task automatic push_i2s_rx(input logic [31:0] data_i);
begin
@(negedge clk_i);
i2s_rx_axis.tdata = data_i;
i2s_rx_axis.tvalid = 1'b1;
do @(posedge clk_i); while (!i2s_rx_axis.tready);
@(negedge clk_i);
i2s_rx_axis.tvalid = 1'b0;
end
endtask
task automatic pop_i2s_tx(input logic [31:0] expected_i, input int unsigned stall_cycles_i);
logic [31:0] held_data;
begin
i2s_tx_axis.tready = 1'b0;
held_data = i2s_tx_axis.tdata;
repeat (stall_cycles_i) begin
@(posedge clk_i);
#1;
if (!i2s_tx_axis.tvalid || (i2s_tx_axis.tdata != held_data)) begin
$fatal(1, "TX payload changed under backpressure");
end
end
if (held_data != expected_i) $fatal(1, "TX FIFO ordering mismatch");
@(negedge clk_i);
i2s_tx_axis.tready = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
i2s_tx_axis.tready = 1'b0;
end
endtask
task automatic pop_apu_rx(input logic [31:0] expected_i, input int unsigned stall_cycles_i);
logic [31:0] held_data;
begin
apu_rx_axis.tready = 1'b0;
held_data = apu_rx_axis.tdata;
repeat (stall_cycles_i) begin
@(posedge clk_i);
#1;
if (!apu_rx_axis.tvalid || (apu_rx_axis.tdata != held_data)) begin
$fatal(1, "RX payload changed under backpressure");
end
end
if (held_data != expected_i) $fatal(1, "RX FIFO ordering mismatch");
@(negedge clk_i);
apu_rx_axis.tready = 1'b1;
@(posedge clk_i);
@(negedge clk_i);
apu_rx_axis.tready = 1'b0;
end
endtask
initial begin
dma_tx_axis.tdata = 32'h1122_3344;
dma_tx_axis.tkeep = 4'hf;
dma_tx_axis.tstrb = 4'hf;
dma_tx_axis.tlast = 1'b1;
dma_tx_axis.tid = '0;
dma_tx_axis.tdest = '0;
dma_tx_axis.tuser = '0;
dma_tx_axis.tvalid = 1'b0;
dma_rx_axis.tready = 1'b1;
i2s_tx_axis.tready = 1'b1;
i2s_rx_axis.tdata = 32'd0;
i2s_rx_axis.tkeep = 4'hf;
i2s_rx_axis.tstrb = 4'hf;
i2s_rx_axis.tlast = 1'b0;
i2s_rx_axis.tid = '0;
i2s_rx_axis.tdest = '0;
i2s_rx_axis.tuser = '0;
i2s_rx_axis.tvalid = 1'b0;
apu_tx_axis.tdata = 32'd0;
apu_tx_axis.tkeep = 4'hf;
apu_tx_axis.tstrb = 4'hf;
apu_tx_axis.tlast = 1'b0;
apu_tx_axis.tid = '0;
apu_tx_axis.tdest = '0;
apu_tx_axis.tuser = '0;
apu_tx_axis.tvalid = 1'b0;
apu_rx_axis.tready = 1'b0;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
#1;
if ((status_o != 32'h0000_0014) || !idle_o) $fatal(1, "stream reset status mismatch");
dma_tx_axis.tvalid = 1'b1;
#1;
if (!i2s_tx_axis.tvalid || (i2s_tx_axis.tdata != 32'h1122_3344) || !dma_tx_axis.tready)
$fatal(1, "central DMA TX bypass failed");
dma_tx_axis.tvalid = 1'b0;
i2s_rx_axis.tdata = 32'haabb_ccdd;
i2s_rx_axis.tvalid = 1'b1;
#1;
if (!dma_rx_axis.tvalid || (dma_rx_axis.tdata != 32'haabb_ccdd) || !i2s_rx_axis.tready)
$fatal(1, "central DMA RX bypass failed");
i2s_rx_axis.tvalid = 1'b0;
tx_route_apu_i = 1'b1;
rx_route_apu_i = 1'b1;
tx_session_active_i = 1'b1;
rx_session_active_i = 1'b1;
tx_low_watermark_i = 8'd2;
rx_high_watermark_i = 8'd2;
i2s_tx_axis.tready = 1'b0;
push_apu_tx(32'd1);
push_apu_tx(32'd2);
push_apu_tx(32'd3);
if (!status_o[0]) $fatal(1, "APU TX route did not become active");
i2s_tx_axis.tready = 1'b1;
@(posedge clk_i);
#1;
if (!output_watermark_seen) $fatal(1, "TX low-watermark crossing was not detected");
push_i2s_rx(32'h1010_1010);
push_i2s_rx(32'h2020_2020);
if (!input_watermark_seen) $fatal(1, "RX high-watermark crossing was not detected");
apu_rx_axis.tready = 1'b1;
repeat (2) @(posedge clk_i);
@(negedge clk_i);
flush_i = 1'b1;
@(negedge clk_i);
flush_i = 1'b0;
i2s_tx_axis.tready = 1'b0;
apu_rx_axis.tready = 1'b0;
for (int unsigned word_index = 0; word_index < 64; word_index++) begin
push_apu_tx(32'h7100_0000 + word_index);
end
#1;
if (!status_o[3] || apu_tx_axis.tready) $fatal(1, "TX FIFO did not reach depth 64");
for (int unsigned word_index = 0; word_index < 64; word_index++) begin
pop_i2s_tx(32'h7100_0000 + word_index, (word_index * 5 + 1) % 4);
end
#1;
if (!status_o[2] || (status_o[15:8] != 8'd64)) begin
$fatal(1, "TX FIFO empty/count status mismatch");
end
for (int unsigned word_index = 0; word_index < 64; word_index++) begin
push_i2s_rx(32'h7200_0000 + word_index);
end
#1;
if (!status_o[5] || i2s_rx_axis.tready) $fatal(1, "RX FIFO did not reach depth 64");
for (int unsigned word_index = 0; word_index < 64; word_index++) begin
pop_apu_rx(32'h7200_0000 + word_index, (word_index * 7 + 2) % 5);
end
#1;
if (!status_o[4] || (status_o[23:16] != 8'd64)) begin
$fatal(1, "RX FIFO empty/count status mismatch");
end
counter_clear_i = 1'b1;
@(posedge clk_i);
counter_clear_i = 1'b0;
#1;
if (status_o[23:8] != 16'd0) $fatal(1, "stream counter clear failed");
tx_underrun_i = 1'b1;
rx_overrun_i = 1'b1;
#1;
if (!stream_xrun_evt_o) $fatal(1, "xrun event pulse failed");
@(posedge clk_i);
tx_underrun_i = 1'b0;
rx_overrun_i = 1'b0;
#1;
if (status_o[7:6] != 2'b11) $fatal(1, "xrun capture failed");
xrun_clear_i = 1'b1;
tx_underrun_i = 1'b1;
@(posedge clk_i);
xrun_clear_i = 1'b0;
tx_underrun_i = 1'b0;
#1;
if (!status_o[6]) $fatal(1, "hardware xrun did not win same-cycle clear");
$display("APU-P2 stream router tests passed");
$finish;
end
initial begin
repeat (5000) @(posedge clk_i);
$fatal(1, "APU-P2 stream router timed out");
end
endmodule
+8 -1
View File
@@ -118,7 +118,14 @@ module axi4_async_bridge_tb;
wait (!clear_busy_o);
if (epoch_o != 8'd1) $fatal(1, "async bridge epoch did not advance");
$display("AXI4 async bridge transfer and warm flush test passed");
@(negedge dst_clk_i);
dst_rst_n_i = 1'b0;
repeat (3) @(posedge src_clk_i);
@(negedge dst_clk_i);
dst_rst_n_i = 1'b1;
wait (epoch_o == 8'd2);
$display("AXI4 async bridge transfer and warm flush test passed; unilateral reset passed");
$finish;
end
+31
View File
@@ -74,6 +74,28 @@ module axi4_target_guard_tb;
end
endtask
task automatic return_read_beat(input logic [5:0] id, input logic last,
input logic expected_last, input logic [1:0] expected_resp);
begin
@(negedge clk_i);
sink.rid = id;
sink.rdata = 64'h0123_4567_89ab_cdef;
sink.rresp = 2'b00;
sink.rlast = last;
sink.rvalid = 1'b1;
wait (source.rvalid);
#1;
if ((source.rid != id) || (source.rresp != expected_resp) ||
(source.rlast != expected_last)) begin
$fatal(1, "target guard read normalization mismatch");
end
do @(posedge clk_i); while (!sink.rready);
@(negedge clk_i);
sink.rvalid = 1'b0;
sink.rlast = 1'b0;
end
endtask
initial begin
source.awid = '0;
source.awaddr = '0;
@@ -124,6 +146,15 @@ module axi4_target_guard_tb;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
issue_read(6'h07, 8'd1, 32'h3800_0020);
do @(posedge clk_i); while (!sink.arvalid);
return_read_beat(6'h07, 1'b0, 1'b0, 2'b00);
return_read_beat(6'h07, 1'b0, 1'b1, 2'b10);
issue_read(6'h08, 8'd0, 32'h3800_0030);
do @(posedge clk_i); while (!sink.arvalid);
return_read_beat(6'h08, 1'b1, 1'b1, 2'b00);
issue_read(6'h09, 8'd1, 32'h3800_0040);
wait (timeout_valid_o);
if (timeout_write_o || (timeout_id_o != 6'h09) || (timeout_addr_o != 32'h3800_0040)) begin
+532
View File
@@ -0,0 +1,532 @@
`timescale 1ns / 1ps
module hp_axi4_mux3_rr_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic [ 7:0] epoch_i = 8'd0;
logic [ 2:0] read_request = 3'd0;
logic [ 2:0] write_request = 3'd0;
logic [ 2:0] write_data_valid = 3'b111;
logic [ 2:0] read_ready = 3'b111;
logic [ 2:0] write_response_ready = 3'b111;
logic response_valid_q;
logic [31:0] response_data_q;
logic write_active_q;
logic write_response_valid_q;
logic [31:0] write_address_q;
logic mixed_mode_q;
logic recovery_response_q = 1'b0;
logic allow_read_address = 1'b1;
logic allow_write_address = 1'b1;
int unsigned response_count [0:2];
int unsigned write_response_count [0:2];
int unsigned mixed_response_count [0:2];
int unsigned total_responses;
int unsigned total_write_responses;
int unsigned total_mixed_responses;
logic [15:0] cycle_q;
string s_phase;
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) icache (
clk_i,
rst_n_i
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) dcache (
clk_i,
rst_n_i
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) mmio (
clk_i,
rst_n_i
);
axi4_if #(
.ADDR_WIDTH(32),
.DATA_WIDTH(32),
.ID_WIDTH (1),
.USER_WIDTH(1)
) axi4 (
clk_i,
rst_n_i
);
always #5 clk_i = ~clk_i;
assign icache.arid = 1'b0;
assign icache.araddr = 32'h0000_1000;
assign dcache.arid = 1'b0;
assign dcache.araddr = 32'h0000_2000;
assign mmio.arid = 1'b0;
assign mmio.araddr = 32'h0000_3000;
assign icache.arvalid = read_request[0];
assign dcache.arvalid = read_request[1];
assign mmio.arvalid = read_request[2];
assign icache.arlen = 8'd0;
assign dcache.arlen = 8'd0;
assign mmio.arlen = 8'd0;
assign icache.arsize = 3'd2;
assign dcache.arsize = 3'd2;
assign mmio.arsize = 3'd2;
assign icache.arburst = 2'd1;
assign dcache.arburst = 2'd1;
assign mmio.arburst = 2'd1;
assign icache.arlock = 1'b0;
assign dcache.arlock = 1'b0;
assign mmio.arlock = 1'b0;
assign icache.arcache = 4'd0;
assign dcache.arcache = 4'd0;
assign mmio.arcache = 4'd0;
assign icache.arprot = 3'd0;
assign dcache.arprot = 3'd0;
assign mmio.arprot = 3'd0;
assign icache.arqos = 4'd0;
assign dcache.arqos = 4'd0;
assign mmio.arqos = 4'd0;
assign icache.arregion = 4'd0;
assign dcache.arregion = 4'd0;
assign mmio.arregion = 4'd0;
assign icache.aruser = 1'b0;
assign dcache.aruser = 1'b0;
assign mmio.aruser = 1'b0;
assign icache.rready = read_ready[0];
assign dcache.rready = read_ready[1];
assign mmio.rready = read_ready[2];
assign icache.awid = 1'b0;
assign dcache.awid = 1'b0;
assign mmio.awid = 1'b0;
assign icache.awaddr = 32'h0000_4000;
assign dcache.awaddr = 32'h0000_5000;
assign mmio.awaddr = 32'h0000_6000;
assign icache.awlen = 8'd0;
assign dcache.awlen = 8'd0;
assign mmio.awlen = 8'd0;
assign icache.awsize = 3'd2;
assign dcache.awsize = 3'd2;
assign mmio.awsize = 3'd2;
assign icache.awburst = 2'd1;
assign dcache.awburst = 2'd1;
assign mmio.awburst = 2'd1;
assign icache.awlock = 1'b0;
assign dcache.awlock = 1'b0;
assign mmio.awlock = 1'b0;
assign icache.awcache = 4'd0;
assign dcache.awcache = 4'd0;
assign mmio.awcache = 4'd0;
assign icache.awprot = 3'd0;
assign dcache.awprot = 3'd0;
assign mmio.awprot = 3'd0;
assign icache.awqos = 4'd0;
assign dcache.awqos = 4'd0;
assign mmio.awqos = 4'd0;
assign icache.awregion = 4'd0;
assign dcache.awregion = 4'd0;
assign mmio.awregion = 4'd0;
assign icache.awuser = 1'b0;
assign dcache.awuser = 1'b0;
assign mmio.awuser = 1'b0;
assign icache.awvalid = write_request[0];
assign dcache.awvalid = write_request[1];
assign mmio.awvalid = write_request[2];
assign icache.wdata = 32'ha000_0000;
assign dcache.wdata = 32'hb000_0000;
assign mmio.wdata = 32'hc000_0000;
assign icache.wstrb = 4'hf;
assign dcache.wstrb = 4'hf;
assign mmio.wstrb = 4'hf;
assign icache.wlast = 1'b1;
assign dcache.wlast = 1'b1;
assign mmio.wlast = 1'b1;
assign icache.wuser = 1'b0;
assign dcache.wuser = 1'b0;
assign mmio.wuser = 1'b0;
assign icache.wvalid = write_request[0] && write_data_valid[0];
assign dcache.wvalid = write_request[1] && write_data_valid[1];
assign mmio.wvalid = write_request[2] && write_data_valid[2];
assign icache.bready = write_response_ready[0];
assign dcache.bready = write_response_ready[1];
assign mmio.bready = write_response_ready[2];
assign axi4.awready = allow_write_address && !write_active_q &&
!write_response_valid_q && cycle_q[0];
assign axi4.wready = write_active_q && cycle_q[1];
assign axi4.bid = 1'b0;
assign axi4.bresp = 2'd0;
assign axi4.buser = 1'b0;
assign axi4.bvalid = write_response_valid_q;
assign axi4.arready = allow_read_address && !response_valid_q && cycle_q[0];
assign axi4.rid = 1'b0;
assign axi4.rdata = response_data_q;
assign axi4.rresp = 2'd0;
assign axi4.rlast = 1'b1;
assign axi4.ruser = 1'b0;
assign axi4.rvalid = response_valid_q;
hp_axi4_mux3 #(
.RoundRobin (1'b1),
.Client0EpochAware(1'b1)
) u_dut (
.clk_i,
.rst_n_i,
.epoch_i,
.icache,
.dcache,
.mmio,
.axi4
);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
response_valid_q <= 1'b0;
response_data_q <= 32'd0;
response_count[0] <= 0;
response_count[1] <= 0;
response_count[2] <= 0;
write_response_count[0] <= 0;
write_response_count[1] <= 0;
write_response_count[2] <= 0;
mixed_response_count[0] <= 0;
mixed_response_count[1] <= 0;
mixed_response_count[2] <= 0;
total_responses <= 0;
total_write_responses <= 0;
total_mixed_responses <= 0;
write_active_q <= 1'b0;
write_response_valid_q <= 1'b0;
write_address_q <= 32'd0;
cycle_q <= 16'd0;
end else if (epoch_i != u_dut.s_epoch_q) begin
response_valid_q <= 1'b0;
write_active_q <= 1'b0;
write_response_valid_q <= 1'b0;
end else begin
cycle_q <= cycle_q + 1'b1;
if (axi4.arvalid && axi4.arready) begin
response_valid_q <= 1'b1;
response_data_q <= axi4.araddr;
end
if (axi4.rvalid && axi4.rready) response_valid_q <= 1'b0;
if (axi4.awvalid && axi4.awready) begin
write_active_q <= 1'b1;
write_address_q <= axi4.awaddr;
end
if (axi4.wvalid && axi4.wready) begin
unique case (write_address_q)
32'h0000_4000: if (axi4.wdata != 32'ha000_0000) $fatal(1, "APU write data mismatch");
32'h0000_5000: if (axi4.wdata != 32'hb000_0000) $fatal(1, "SDIO0 write data mismatch");
32'h0000_6000: if (axi4.wdata != 32'hc000_0000) $fatal(1, "USB2 write data mismatch");
default: $fatal(1, "Gateway A write owner address changed");
endcase
write_active_q <= 1'b0;
write_response_valid_q <= 1'b1;
end
if (axi4.bvalid && axi4.bready) write_response_valid_q <= 1'b0;
if (icache.rvalid && icache.rready) begin
if (recovery_response_q) begin
if ((icache.rresp != 2'b11) || !icache.rlast) begin
$fatal(1, "Gateway A malformed synthetic APU read response");
end
end else if ((!mixed_mode_q && ((total_responses % 3) != 0)) ||
(icache.rdata != 32'h0000_1000)) begin
$fatal(1, "Gateway A round-robin order/ownership failure for APU");
end
if (mixed_mode_q) begin
mixed_response_count[0] <= mixed_response_count[0] + 1;
total_mixed_responses <= total_mixed_responses + 1;
end else begin
response_count[0] <= response_count[0] + 1;
total_responses <= total_responses + 1;
end
end
if (dcache.rvalid && dcache.rready) begin
if (recovery_response_q) begin
if ((dcache.rresp != 2'b11) || !dcache.rlast) begin
$fatal(1, "Gateway A malformed synthetic SDIO0 read response");
end
end else if ((!mixed_mode_q && ((total_responses % 3) != 1)) ||
(dcache.rdata != 32'h0000_2000)) begin
$fatal(1, "Gateway A round-robin order/ownership failure for SDIO0");
end
if (mixed_mode_q) begin
mixed_response_count[1] <= mixed_response_count[1] + 1;
total_mixed_responses <= total_mixed_responses + 1;
end else begin
response_count[1] <= response_count[1] + 1;
total_responses <= total_responses + 1;
end
end
if (mmio.rvalid && mmio.rready) begin
if (recovery_response_q) begin
if ((mmio.rresp != 2'b11) || !mmio.rlast) begin
$fatal(1, "Gateway A malformed synthetic USB2 read response");
end
end else if ((!mixed_mode_q && ((total_responses % 3) != 2)) ||
(mmio.rdata != 32'h0000_3000)) begin
$fatal(1, "Gateway A round-robin order/ownership failure for USB2");
end
if (mixed_mode_q) begin
mixed_response_count[2] <= mixed_response_count[2] + 1;
total_mixed_responses <= total_mixed_responses + 1;
end else begin
response_count[2] <= response_count[2] + 1;
total_responses <= total_responses + 1;
end
end
if (icache.bvalid && icache.bready) begin
if (recovery_response_q) begin
if (icache.bresp != 2'b11) $fatal(1, "Gateway A malformed synthetic APU B response");
end else if (mixed_mode_q) begin
mixed_response_count[0] <= mixed_response_count[0] + 1;
total_mixed_responses <= total_mixed_responses + 1;
end else begin
write_response_count[0] <= write_response_count[0] + 1;
total_write_responses <= total_write_responses + 1;
end
end
if (dcache.bvalid && dcache.bready) begin
if (recovery_response_q) begin
if (dcache.bresp != 2'b11) begin
$fatal(1, "Gateway A malformed synthetic SDIO0 B response");
end
end else if (mixed_mode_q) begin
mixed_response_count[1] <= mixed_response_count[1] + 1;
total_mixed_responses <= total_mixed_responses + 1;
end else begin
write_response_count[1] <= write_response_count[1] + 1;
total_write_responses <= total_write_responses + 1;
end
end
if (mmio.bvalid && mmio.bready) begin
if (recovery_response_q) begin
if (mmio.bresp != 2'b11) $fatal(1, "Gateway A malformed synthetic USB2 B response");
end else if (mixed_mode_q) begin
mixed_response_count[2] <= mixed_response_count[2] + 1;
total_mixed_responses <= total_mixed_responses + 1;
end else begin
write_response_count[2] <= write_response_count[2] + 1;
total_write_responses <= total_write_responses + 1;
end
end
end
end
initial begin
s_phase = "read fairness";
mixed_mode_q = 1'b0;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
@(negedge clk_i);
read_request = 3'b111;
read_ready = 3'd0;
wait (axi4.rvalid);
repeat (3) begin
@(posedge clk_i);
#1;
unique case (response_data_q)
32'h0000_1000:
if (!icache.rvalid || dcache.rvalid || mmio.rvalid || !axi4.rlast)
$fatal(1, "Gateway A did not retain the APU R owner/RLAST");
32'h0000_2000:
if (icache.rvalid || !dcache.rvalid || mmio.rvalid || !axi4.rlast)
$fatal(1, "Gateway A did not retain the SDIO0 R owner/RLAST");
32'h0000_3000:
if (icache.rvalid || dcache.rvalid || !mmio.rvalid || !axi4.rlast)
$fatal(1, "Gateway A did not retain the USB2 R owner/RLAST");
default: $fatal(1, "Gateway A retained an unknown R owner");
endcase
end
read_ready = 3'b111;
wait (total_responses >= 18);
@(negedge clk_i);
read_request = 3'd0;
if ((response_count[0] != 6) || (response_count[1] != 6) || (response_count[2] != 6)) begin
$fatal(1, "Gateway A client starvation detected");
end
s_phase = "write fairness";
write_response_ready = 3'd0;
write_request = 3'b111;
wait (axi4.bvalid);
repeat (3) begin
@(posedge clk_i);
#1;
unique case (write_address_q)
32'h0000_4000:
if (!icache.bvalid || dcache.bvalid || mmio.bvalid || !axi4.bvalid)
$fatal(1, "Gateway A did not retain the APU B owner");
32'h0000_5000:
if (icache.bvalid || !dcache.bvalid || mmio.bvalid || !axi4.bvalid)
$fatal(1, "Gateway A did not retain the SDIO0 B owner");
32'h0000_6000:
if (icache.bvalid || dcache.bvalid || !mmio.bvalid || !axi4.bvalid)
$fatal(1, "Gateway A did not retain the USB2 B owner");
default: $fatal(1, "Gateway A retained an unknown B owner");
endcase
end
write_response_ready = 3'b111;
wait (total_write_responses >= 18);
@(negedge clk_i);
write_request = 3'd0;
if ((write_response_count[0] != 6) || (write_response_count[1] != 6) ||
(write_response_count[2] != 6)) begin
$fatal(1, "Gateway A write client starvation detected");
end
s_phase = "mixed fairness";
wait (!write_active_q && !write_response_valid_q);
mixed_mode_q = 1'b1;
read_request = 3'b101;
write_request = 3'b010;
wait (total_mixed_responses >= 9);
@(negedge clk_i);
read_request = 3'd0;
write_request = 3'd0;
if ((mixed_response_count[0] != 3) || (mixed_response_count[1] != 3) ||
(mixed_response_count[2] != 3)) begin
$fatal(1, "Gateway A mixed-traffic fairness mismatch");
end
s_phase = "dynamic read address hold";
wait (!response_valid_q && !write_active_q && !write_response_valid_q);
mixed_mode_q = 1'b1;
allow_read_address = 1'b0;
read_request = 3'b010;
wait (axi4.arvalid);
repeat (2) @(posedge clk_i);
@(negedge clk_i);
read_request = 3'b011;
repeat (3) begin
@(posedge clk_i);
#1;
if (!axi4.arvalid || (axi4.araddr != 32'h0000_2000)) begin
$fatal(1, "Gateway A changed a stalled read address owner");
end
end
allow_read_address = 1'b1;
do @(posedge clk_i); while (!dcache.arready);
@(negedge clk_i);
read_request = 3'd0;
wait (u_dut.s_state_q == 3'd0);
s_phase = "dynamic write address hold";
allow_write_address = 1'b0;
write_request = 3'b100;
wait (axi4.awvalid);
repeat (2) @(posedge clk_i);
@(negedge clk_i);
write_request = 3'b101;
repeat (3) begin
@(posedge clk_i);
#1;
if (!axi4.awvalid || (axi4.awaddr != 32'h0000_6000)) begin
$fatal(1, "Gateway A changed a stalled write address owner");
end
end
allow_write_address = 1'b1;
do @(posedge clk_i); while (!mmio.awready);
@(negedge clk_i);
write_request = 3'b100;
wait (u_dut.s_state_q == 3'd0);
write_request = 3'd0;
s_phase = "active response flush recovery";
read_ready = 3'd0;
read_request = 3'b001;
wait (icache.rvalid);
@(negedge clk_i);
epoch_i = epoch_i + 1'b1;
@(negedge clk_i);
read_request = 3'b010;
read_ready = 3'b111;
do @(posedge clk_i); while (!dcache.arready);
@(negedge clk_i);
read_request = 3'd0;
wait (u_dut.s_state_q == 3'd0);
@(negedge clk_i);
s_phase = "non-aware read recovery";
read_ready = 3'd0;
read_request = 3'b010;
s_phase = "non-aware read accepted";
do @(posedge clk_i); while (!dcache.rvalid);
@(negedge clk_i);
epoch_i = epoch_i + 1'b1;
read_request = 3'd0;
s_phase = "non-aware read recovery state";
wait (u_dut.s_state_q == 3'd3);
s_phase = "non-aware read retained response";
repeat (3) begin
@(posedge clk_i);
#1;
if (!dcache.rvalid || icache.rvalid || mmio.rvalid || (dcache.rresp != 2'b11) ||
!dcache.rlast || axi4.arvalid || axi4.awvalid) begin
$fatal(1, "Gateway A did not retain synthetic read recovery response");
end
end
@(negedge clk_i);
recovery_response_q = 1'b1;
read_ready = 3'b111;
@(posedge clk_i);
@(negedge clk_i);
recovery_response_q = 1'b0;
s_phase = "non-aware read completion";
wait (u_dut.s_state_q == 3'd0);
s_phase = "non-aware write recovery";
write_response_ready = 3'd0;
write_data_valid = 3'b011;
write_request = 3'b100;
wait (u_dut.s_state_q == 3'd2);
@(negedge clk_i);
epoch_i = epoch_i + 1'b1;
wait (u_dut.s_state_q == 3'd4);
if (axi4.awvalid || axi4.arvalid) $fatal(1, "Gateway A issued an address during recovery");
repeat (2) @(posedge clk_i);
@(negedge clk_i);
write_data_valid = 3'b111;
wait (u_dut.s_state_q == 3'd5);
write_request = 3'd0;
repeat (3) begin
@(posedge clk_i);
#1;
if (!mmio.bvalid || icache.bvalid || dcache.bvalid || (mmio.bresp != 2'b11) ||
axi4.awvalid || axi4.arvalid) begin
$fatal(1, "Gateway A did not retain synthetic write recovery response");
end
end
@(negedge clk_i);
recovery_response_q = 1'b1;
write_response_ready = 3'b111;
@(posedge clk_i);
@(negedge clk_i);
recovery_response_q = 1'b0;
wait (u_dut.s_state_q == 3'd0);
$display("APU-P2 Gateway A round-robin fairness passed with read/write/mixed retention");
$finish;
end
initial begin
repeat (1000) @(posedge clk_i);
$fatal(
1,
"Gateway A round-robin test timed out in %s state=%0d rr=%0d read=%b write=%b rv=%0d bv=%0d",
s_phase, u_dut.s_state_q, u_dut.s_rr_selected, read_request, write_request,
response_valid_q, write_response_valid_q);
end
endmodule
+290
View File
@@ -32,7 +32,14 @@ def test_apu_p1_apb_register_shell(tmp_path: Path) -> None:
f"+incdir+{common / 'interface'}",
f"+incdir+{multimedia}",
str(common / "interface/apb4_if.sv"),
str(common / "interface/axi4_if.sv"),
str(common / "interface/axi4_stream_if.sv"),
str(common / "utils/register.sv"),
str(common / "utils/fifo.sv"),
str(ROOT / "rtl/ip/peripheral/dma_axi4_master.sv"),
str(multimedia / "apu_dma.sv"),
str(multimedia / "apu_ring_scheduler.sv"),
str(multimedia / "apu_stream_router.sv"),
str(multimedia / "apu_reg.sv"),
str(multimedia / "apb4_apu.sv"),
str(ROOT / "tests/rtl/apu_reg_tb.sv"),
@@ -97,7 +104,14 @@ def test_apu_p1_integrated_irq_ownership_topology(tmp_path: Path) -> None:
f"+incdir+{common / 'interface'}",
f"+incdir+{multimedia}",
str(common / "interface/apb4_if.sv"),
str(common / "interface/axi4_if.sv"),
str(common / "interface/axi4_stream_if.sv"),
str(common / "utils/register.sv"),
str(common / "utils/fifo.sv"),
str(ROOT / "rtl/ip/peripheral/dma_axi4_master.sv"),
str(multimedia / "apu_dma.sv"),
str(multimedia / "apu_ring_scheduler.sv"),
str(multimedia / "apu_stream_router.sv"),
str(multimedia / "apu_reg.sv"),
str(multimedia / "apb4_apu.sv"),
str(ROOT / "rtl/mini/top/resource_controller.sv"),
@@ -135,3 +149,279 @@ def test_apu_p1_integrated_irq_ownership_topology(tmp_path: Path) -> None:
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "APU-P1 integrated IRQ ownership topology passed" in result.stdout
def test_apu_p2_stream_router(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
if iverilog is None or vvp is None:
return
common = ROOT / "rtl/managed/clusterip/common/rtl"
source_list = tmp_path / "apu_stream_router.fl"
source_list.write_text(
"\n".join(
[
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
str(common / "interface/axi4_stream_if.sv"),
str(common / "utils/fifo.sv"),
str(ROOT / "rtl/ip/multimedia/apu_stream_router.sv"),
str(ROOT / "tests/rtl/apu_stream_router_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apu_stream_router_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_stream_router_tb"
subprocess.run(
[
iverilog,
"-g2012",
"-s",
"apu_stream_router_tb",
"-o",
str(simulation),
str(converted),
],
check=True,
)
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
assert "APU-P2 stream router tests passed" in result.stdout
def test_apu_p2_private_dma(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
if iverilog is None or vvp is None:
return
common = ROOT / "rtl/managed/clusterip/common/rtl"
source_list = tmp_path / "apu_dma.fl"
source_list.write_text(
"\n".join(
[
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{ROOT / 'rtl/ip/multimedia'}",
str(common / "interface/axi4_if.sv"),
str(common / "interface/axi4_stream_if.sv"),
str(common / "utils/register.sv"),
str(ROOT / "rtl/ip/peripheral/dma_axi4_master.sv"),
str(ROOT / "rtl/ip/multimedia/apu_dma.sv"),
str(ROOT / "tests/rtl/apu_dma_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apu_dma_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_dma_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "apu_dma_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
assert "APU-P2 DMA tests passed" in result.stdout
def test_apu_p2_ring_scheduler_backend(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"
source_list = tmp_path / "apu_ring_scheduler.fl"
source_list.write_text(
"\n".join(
[
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{ROOT / 'rtl/ip/multimedia'}",
str(common / "interface/axi4_stream_if.sv"),
str(ROOT / "rtl/ip/multimedia/apu_ring_scheduler.sv"),
str(ROOT / "tests/rtl/apu_p2_backend.sv"),
str(ROOT / "tests/rtl/apu_ring_scheduler_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apu_ring_scheduler_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_ring_scheduler_tb"
subprocess.run(
[
iverilog,
"-g2012",
"-s",
"apu_ring_scheduler_tb",
"-o",
str(simulation),
str(converted),
],
check=True,
)
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
assert "APU-P2 ring scheduler/backend tests passed" in result.stdout
def test_apu_p2_integrated_dma_ring_backend(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_p2_integration.fl"
source_list.write_text(
"\n".join(
[
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{common / 'cdc'}",
f"+incdir+{multimedia}",
str(common / "interface/axi4_if.sv"),
str(common / "interface/axi4_stream_if.sv"),
str(common / "utils/register.sv"),
str(common / "utils/fifo.sv"),
str(common / "utils/xchecker.sv"),
str(common / "utils/spill_register.sv"),
str(common / "utils/bin2gray.sv"),
str(common / "utils/gray2bin.sv"),
str(common / "stream/round_robin_arbiter.sv"),
str(common / "cdc/cdc_sync.sv"),
str(common / "cdc/cdc_rst_ctrlr.sv"),
str(common / "cdc/cdc_2phase.sv"),
str(common / "clkrst/rst_sync.sv"),
str(ROOT / "rtl/ip/peripheral/dma_axi4_master.sv"),
str(multimedia / "apu_dma.sv"),
str(multimedia / "apu_ring_scheduler.sv"),
str(ROOT / "rtl/mini/top/soc_common_cdc.sv"),
str(ROOT / "rtl/mini/top/axi4_async_bridge.sv"),
str(ROOT / "rtl/mini/top/axi4_target_guard.sv"),
str(ROOT / "rtl/mini/top/hp_axi4_mux3.sv"),
str(ROOT / "tests/rtl/apu_p2_transport_backend.sv"),
str(ROOT / "tests/rtl/apu_p2_integration_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "apu_p2_integration_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_p2_integration_tb"
subprocess.run(
[
iverilog,
"-g2012",
"-s",
"apu_p2_integration_tb",
"-o",
str(simulation),
str(converted),
],
check=True,
)
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
assert "APU-P2 integrated DMA/ring/backend tests passed" in result.stdout
def test_apu_p2_gateway_a_round_robin_fairness(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"
source_list = tmp_path / "gateway_a_rr.fl"
source_list.write_text(
"\n".join(
[
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
str(common / "interface/axi4_if.sv"),
str(common / "utils/register.sv"),
str(common / "stream/round_robin_arbiter.sv"),
str(ROOT / "rtl/mini/top/hp_axi4_mux3.sv"),
str(ROOT / "tests/rtl/hp_axi4_mux3_rr_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "hp_axi4_mux3_rr_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 / "hp_axi4_mux3_rr_tb"
subprocess.run(
[
iverilog,
"-g2012",
"-s",
"hp_axi4_mux3_rr_tb",
"-o",
str(simulation),
str(converted),
],
check=True,
)
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
assert "APU-P2 Gateway A round-robin fairness passed with read/write/mixed retention" in result.stdout
+1
View File
@@ -52,6 +52,7 @@ def test_clock_reset_domain_inventory_matches_the_rcu() -> None:
("jtag_dmi", "jtag", "lp"),
("hp_mmio", "hp", "lp"),
("io_dma_data", "pclk", "hp"),
("apu_data", "pclk", "hp"),
}
clint = next(
crossing for crossing in document["crossings"] if crossing["name"] == "clint_timebase"
+13
View File
@@ -329,6 +329,8 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
clint_filelist = tmp_path / "clint.fl"
onchip_ram_filelist = tmp_path / "onchip_ram.fl"
opipsram_filelist = tmp_path / "opipsram.fl"
apu_filelist = tmp_path / "apu.fl"
gateway_a_filelist = tmp_path / "gateway_a.fl"
assert generate_formal_filelist("bus", bus_filelist, memory_map, topology, user_extensions)
assert generate_formal_filelist(
"rib_adapter", rib_adapter_filelist, memory_map, topology, user_extensions
@@ -354,6 +356,10 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
assert generate_formal_filelist(
"opipsram", opipsram_filelist, memory_map, topology, user_extensions
)
assert generate_formal_filelist("apu", apu_filelist, memory_map, topology, user_extensions)
assert generate_formal_filelist(
"gateway_a", gateway_a_filelist, memory_map, topology, user_extensions
)
bus = parse_filelists([bus_filelist], require_files=False)
rib_adapter = parse_filelists([rib_adapter_filelist], require_files=False)
@@ -366,6 +372,8 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
clint = parse_filelists([clint_filelist], require_files=False)
onchip_ram = parse_filelists([onchip_ram_filelist], require_files=False)
opipsram = parse_filelists([opipsram_filelist], require_files=False)
apu = parse_filelists([apu_filelist], require_files=False)
gateway_a = parse_filelists([gateway_a_filelist], require_files=False)
assert "+define+SV_ASSRT_DISABLE" in bus.defines
assert "+define+PDK_BEHAV" in onchip_ram.defines
assert "+define+SYNTHESIS" in onchip_ram.defines
@@ -421,6 +429,11 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
assert ROOT / "rtl/tech/tc_clk.sv" in opipsram.files
assert ROOT / "rtl/tech/tc_opipsram_delay.sv" in opipsram.files
assert ROOT / "rtl/mini/formal/opipsram_formal.sv" in opipsram.files
assert ROOT / "rtl/ip/multimedia/apu_dma.sv" in apu.files
assert ROOT / "rtl/mini/formal/apu_formal.sv" in apu.files
assert ROOT / "rtl/mini/top/hp_axi4_mux3.sv" in gateway_a.files
assert ROOT / "rtl/managed/clusterip/common/rtl/stream/round_robin_arbiter.sv" in gateway_a.files
assert ROOT / "rtl/mini/formal/gateway_a_formal.sv" in gateway_a.files
def test_opipsram_formal_keeps_full_depth_with_hosted_runner_budget() -> None: