mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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:
48 files changed
+7485
-469
No files matched your search
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user