mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: enhance GA2D RTL and Test Infrastructure
- Updated resource_controller_tb.sv to include additional checks for IRQ handling and lifecycle states for GA2D resource. - Modified soc_irq_topology_tb.sv to accommodate 64-bit IRQ vector handling and updated expectations for IRQ routing. - Introduced test_ga2d.py for directed verification of GA2D Phase 3 APB4 shell functionality. - Revised test_ga2d_platform.py to reflect changes in GA2D integration and ensure proper IRQ routing. - Added test_ga2d_register_parity.py to synchronize GA2D RTL and SDK register constants. - Updated test_lp_irq.py to reflect changes in IRQ allocation and metadata for GA2D. - Enhanced test_memory_map.py to verify GA2D MMIO region presence in the memory map. - Adjusted test_publication_software.py to include GA2D in application results. - Modified test_soc_topology.py to ensure correct topology generation for GA2D, including IRQ and APB bindings.
This commit is contained in:
51 files changed
+3573
-172
No files matched your search
@@ -42,7 +42,9 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
||||
[bidirectional PS/2](docs/ip/ps2.md),
|
||||
WS2812, SPI/QSPI, SDIO, PSRAM/[OPI-PSRAM](docs/ip/opipsram.md), SDRAM, DMA, LCD, RTC, an
|
||||
independent-clock window watchdog, CRC, and a
|
||||
management-only RNG entropy controller. The current deterministic RNG integration source is
|
||||
management-only RNG entropy controller. The P3 [GA2D](docs/ip/ga2d.md) APB4 shell and
|
||||
ownership-routed IRQ are integrated, while its 2D DMA and pixel operations remain unavailable.
|
||||
The current deterministic RNG integration source is
|
||||
explicitly unqualified and intended only for diagnostics until a PDK-qualified entropy source is integrated.
|
||||
support. Available interfaces depend on the selected SoC configuration.
|
||||
- A standalone RISC-V runtime, HAL, board support, middleware, and `benchmark`, `bringup`,
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include <retrosoc/core/irq.h>
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/arch/riscv/system_base.h>
|
||||
#include <retrosoc/generated/irq_metadata.h>
|
||||
#include <retrosoc/hal/apu.h>
|
||||
#include <retrosoc/hal/clint.h>
|
||||
#include <retrosoc/hal/crypto.h>
|
||||
#include <retrosoc/hal/extension.h>
|
||||
#include <retrosoc/hal/fabric_monitor.h>
|
||||
#include <retrosoc/hal/ga2d.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/onchip_sram.h>
|
||||
#include <retrosoc/hal/rng.h>
|
||||
@@ -34,6 +36,7 @@ static volatile uint32_t rs_ci_smoke_external_irq_sequence[4];
|
||||
static volatile uint32_t rs_ci_smoke_external_irq_sequence_count;
|
||||
static volatile uint32_t rs_ci_smoke_timer_irq_count;
|
||||
static volatile uint32_t rs_ci_smoke_software_irq_count;
|
||||
static volatile uint32_t rs_ci_smoke_ga2d_irq_count;
|
||||
|
||||
static void rs_ci_smoke_external_irq_handler(uintptr_t mcause, uintptr_t stack_pointer) {
|
||||
const uint32_t context = (uint32_t)__RV_CSR_READ(CSR_HAZARD3_MEICONTEXT);
|
||||
@@ -66,6 +69,13 @@ static void rs_ci_smoke_software_irq_handler(uintptr_t mcause, uintptr_t stack_p
|
||||
++rs_ci_smoke_software_irq_count;
|
||||
}
|
||||
|
||||
static void rs_ci_smoke_ga2d_irq_handler(uintptr_t mcause, uintptr_t stack_pointer) {
|
||||
(void)mcause;
|
||||
(void)stack_pointer;
|
||||
RS_GA2D_REG(RS_GA2D_REG_IRQ_STATE) = RS_GA2D_IRQ_DONE;
|
||||
++rs_ci_smoke_ga2d_irq_count;
|
||||
}
|
||||
|
||||
static void rs_ci_smoke_force_external_irq(uint32_t id) {
|
||||
const uint32_t bank = id >> 4U;
|
||||
const uint32_t mask = UINT32_C(1) << (id & UINT32_C(0xf));
|
||||
@@ -125,26 +135,27 @@ static bool rs_ci_smoke_external_priority_matrix(void) {
|
||||
rs_ci_smoke_external_irq_sequence_count = 0U;
|
||||
__RV_CSR_WRITE(CSR_HAZARD3_MEICONTEXT, UINT32_C(0));
|
||||
if ((rs_irq_set_external_priority(29U, UINT8_C(0)) != RS_OK) ||
|
||||
(rs_irq_set_external_priority(30U, UINT8_C(1)) != RS_OK) ||
|
||||
(rs_irq_set_external_priority(RS_SOC_EXT_IRQ_GA2D, UINT8_C(1)) != RS_OK) ||
|
||||
(rs_irq_set_external_priority(31U, UINT8_C(2)) != RS_OK) ||
|
||||
(rs_irq_set_external_priority(32U, UINT8_C(3)) != RS_OK) ||
|
||||
(rs_irq_enable_external(29U, rs_ci_smoke_external_irq_handler) != RS_OK) ||
|
||||
(rs_irq_enable_external(30U, rs_ci_smoke_external_irq_handler) != RS_OK) ||
|
||||
(rs_irq_enable_external(RS_SOC_EXT_IRQ_GA2D, rs_ci_smoke_external_irq_handler) != RS_OK) ||
|
||||
(rs_irq_enable_external(31U, rs_ci_smoke_external_irq_handler) != RS_OK) ||
|
||||
(rs_irq_enable_external(32U, rs_ci_smoke_external_irq_handler) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
rs_ci_smoke_force_external_irq(29U);
|
||||
rs_ci_smoke_force_external_irq(30U);
|
||||
rs_ci_smoke_force_external_irq(RS_SOC_EXT_IRQ_GA2D);
|
||||
rs_ci_smoke_force_external_irq(31U);
|
||||
rs_ci_smoke_force_external_irq(32U);
|
||||
__enable_irq();
|
||||
passed = rs_ci_smoke_wait_external_count(4U) && (rs_ci_smoke_external_irq_sequence[0] == 32U) &&
|
||||
(rs_ci_smoke_external_irq_sequence[1] == 31U) &&
|
||||
(rs_ci_smoke_external_irq_sequence[2] == 30U) &&
|
||||
(rs_ci_smoke_external_irq_sequence[2] == RS_SOC_EXT_IRQ_GA2D) &&
|
||||
(rs_ci_smoke_external_irq_sequence[3] == 29U);
|
||||
__disable_irq();
|
||||
if ((rs_irq_disable_external(29U) != RS_OK) || (rs_irq_disable_external(30U) != RS_OK) ||
|
||||
if ((rs_irq_disable_external(29U) != RS_OK) ||
|
||||
(rs_irq_disable_external(RS_SOC_EXT_IRQ_GA2D) != RS_OK) ||
|
||||
(rs_irq_disable_external(31U) != RS_OK) || (rs_irq_disable_external(32U) != RS_OK)) {
|
||||
passed = false;
|
||||
}
|
||||
@@ -153,7 +164,8 @@ static bool rs_ci_smoke_external_priority_matrix(void) {
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_external_irq(void) {
|
||||
static const uint32_t tested_ordinals[] = {0U, 15U, 16U, 29U, 30U, 31U, 32U, 61U};
|
||||
static const uint32_t tested_ordinals[] = {0U, 15U, 16U, 29U, RS_SOC_EXT_IRQ_GA2D,
|
||||
31U, 32U, 61U};
|
||||
uint64_t now;
|
||||
uint32_t index;
|
||||
|
||||
@@ -255,10 +267,46 @@ static bool rs_ci_smoke_external_irq(void) {
|
||||
__disable_ext_irq();
|
||||
return (rs_ci_smoke_timer_irq_count != 0U) && (rs_ci_smoke_software_irq_count != 0U);
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_ga2d_irq(void) {
|
||||
rs_ga2d_capability_t capability;
|
||||
|
||||
rs_ci_smoke_ga2d_irq_count = 0U;
|
||||
if ((rs_ga2d_get_capability(&capability) != RS_OK) ||
|
||||
(capability.features != RS_GA2D_CAPABILITY_P3) ||
|
||||
(rs_ga2d_irq_clear(RS_GA2D_IRQ_ALL) != RS_OK) ||
|
||||
(rs_ga2d_irq_enable(RS_GA2D_IRQ_DONE) != RS_OK) ||
|
||||
(rs_irq_enable_external(RS_SOC_EXT_IRQ_GA2D, rs_ci_smoke_ga2d_irq_handler) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
RS_GA2D_REG(RS_GA2D_REG_IRQ_TEST) = RS_GA2D_IRQ_DONE;
|
||||
__enable_irq();
|
||||
for (rs_timeout_t timeout = 100000U; (timeout != 0U) && (rs_ci_smoke_ga2d_irq_count < 1U);
|
||||
--timeout) {
|
||||
}
|
||||
if (rs_ci_smoke_ga2d_irq_count != 1U) {
|
||||
__disable_irq();
|
||||
(void)rs_irq_disable_external(RS_SOC_EXT_IRQ_GA2D);
|
||||
__disable_ext_irq();
|
||||
return false;
|
||||
}
|
||||
__disable_irq();
|
||||
if ((rs_irq_disable_external(RS_SOC_EXT_IRQ_GA2D) != RS_OK) ||
|
||||
(rs_ga2d_irq_enable(0U) != RS_OK)) {
|
||||
__disable_ext_irq();
|
||||
return false;
|
||||
}
|
||||
__disable_ext_irq();
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static bool rs_ci_smoke_external_irq(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_ga2d_irq(void) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool rs_ci_smoke_apu(void) {
|
||||
@@ -624,6 +672,10 @@ int main(void) {
|
||||
rs_test_finish(RS_TEST_FAILED, 15U);
|
||||
}
|
||||
printf("ci_smoke: external irq passed\n");
|
||||
if (!rs_ci_smoke_ga2d_irq()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 15U);
|
||||
}
|
||||
printf("ci_smoke: GA2D shell IRQ passed\n");
|
||||
if (!rs_ci_smoke_apu()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 14U);
|
||||
}
|
||||
|
||||
+6
-2
@@ -59,8 +59,8 @@ See the [extension contract](../docs/ip/extensions.md) and
|
||||
[legacy user-IP contract](../docs/ip/user-ip.md).
|
||||
|
||||
`<retrosoc/hal/resource.h>` owns the central DMA, USB2, SDIO0/1, SPI-SD,
|
||||
EXT-H, JPEG, and APU owner/lock, lifecycle-request, fault, and HP cache-maintenance
|
||||
handshake.
|
||||
EXT-H, JPEG, APU, and GA2D owner/lock, lifecycle-request, fault, and HP
|
||||
cache-maintenance handshake.
|
||||
See the [Resource Controller contract](../docs/ip/resource-controller.md).
|
||||
|
||||
`<retrosoc/hal/apu.h>` provides APU discovery, ACL and microcode loading,
|
||||
@@ -69,6 +69,10 @@ abort/reset, interrupt, and first-error access. The P5 surface remains coreless;
|
||||
MP3, KWS, model loading, and the APU RX route stay unavailable until their
|
||||
frozen later phases.
|
||||
|
||||
`<retrosoc/hal/ga2d.h>` provides GA2D shell discovery, status/error, IRQ,
|
||||
and bounded abort/reset access. In Phase 3 its private DMA, 2D job, and pixel
|
||||
operations remain unavailable and return `RS_ENOTSUP`.
|
||||
|
||||
`<retrosoc/hal/fabric_monitor.h>` owns root-management access to native AXI64
|
||||
master/target counters, stable snapshots, warm-flush counts, target isolation,
|
||||
and the sticky first-fault record. See the
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#ifndef RETROSOC_HAL_GA2D_H
|
||||
#define RETROSOC_HAL_GA2D_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
#include <retrosoc/hal/ga2d_regs.h>
|
||||
|
||||
typedef enum {
|
||||
RS_GA2D_OP_FILL = 0,
|
||||
RS_GA2D_OP_COPY = 1,
|
||||
RS_GA2D_OP_CONVERT = 2,
|
||||
RS_GA2D_OP_BLEND = 3,
|
||||
} rs_ga2d_operation_t;
|
||||
|
||||
typedef enum {
|
||||
RS_GA2D_FORMAT_RGB565 = 0,
|
||||
RS_GA2D_FORMAT_RGB888 = 1,
|
||||
RS_GA2D_FORMAT_XRGB8888 = 2,
|
||||
RS_GA2D_FORMAT_ARGB8888 = 3,
|
||||
RS_GA2D_FORMAT_A8 = 4,
|
||||
} rs_ga2d_format_t;
|
||||
|
||||
typedef struct {
|
||||
uintptr_t address;
|
||||
uint32_t pitch;
|
||||
rs_ga2d_format_t format;
|
||||
} rs_ga2d_surface_t;
|
||||
|
||||
typedef struct {
|
||||
rs_ga2d_operation_t operation;
|
||||
rs_ga2d_surface_t foreground;
|
||||
rs_ga2d_surface_t background;
|
||||
rs_ga2d_surface_t destination;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t global_alpha;
|
||||
uint32_t color;
|
||||
} rs_ga2d_job_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t features;
|
||||
uint32_t limits;
|
||||
uint32_t formats;
|
||||
} rs_ga2d_capability_t;
|
||||
|
||||
typedef struct {
|
||||
bool busy;
|
||||
bool draining;
|
||||
bool quiesced;
|
||||
bool data_ready;
|
||||
bool done;
|
||||
bool aborted;
|
||||
bool error;
|
||||
bool recovery_required;
|
||||
uint32_t irq_state;
|
||||
} rs_ga2d_status_t;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
uint8_t code;
|
||||
uint8_t stage;
|
||||
uint8_t axi_response;
|
||||
uintptr_t address;
|
||||
} rs_ga2d_error_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t cycles;
|
||||
uint64_t read_bytes;
|
||||
uint64_t write_bytes;
|
||||
uint64_t read_stalls;
|
||||
uint64_t write_stalls;
|
||||
uint64_t pipe_stalls;
|
||||
uint16_t lines_done;
|
||||
} rs_ga2d_stats_t;
|
||||
|
||||
rs_status_t rs_ga2d_get_capability(rs_ga2d_capability_t *capability);
|
||||
rs_status_t rs_ga2d_job_validate(const rs_ga2d_job_t *job);
|
||||
rs_status_t rs_ga2d_configure(const rs_ga2d_job_t *job);
|
||||
rs_status_t rs_ga2d_start(void);
|
||||
rs_status_t rs_ga2d_wait(rs_timeout_t timeout);
|
||||
rs_status_t rs_ga2d_abort_wait(rs_timeout_t timeout);
|
||||
rs_status_t rs_ga2d_reset(void);
|
||||
rs_status_t rs_ga2d_get_status(rs_ga2d_status_t *status);
|
||||
rs_status_t rs_ga2d_get_error(rs_ga2d_error_t *error);
|
||||
rs_status_t rs_ga2d_get_stats(rs_ga2d_stats_t *stats);
|
||||
rs_status_t rs_ga2d_irq_enable(uint32_t mask);
|
||||
rs_status_t rs_ga2d_irq_pending(uint32_t *pending);
|
||||
rs_status_t rs_ga2d_irq_clear(uint32_t mask);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
#ifndef RETROSOC_HAL_GA2D_REGS_H
|
||||
#define RETROSOC_HAL_GA2D_REGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
|
||||
#define RS_GA2D_REG_IP_ID UINT32_C(0x000)
|
||||
#define RS_GA2D_REG_IP_VERSION UINT32_C(0x004)
|
||||
#define RS_GA2D_REG_CAPABILITY UINT32_C(0x008)
|
||||
#define RS_GA2D_REG_LIMITS UINT32_C(0x00C)
|
||||
#define RS_GA2D_REG_COMMAND UINT32_C(0x010)
|
||||
#define RS_GA2D_REG_STATUS UINT32_C(0x014)
|
||||
#define RS_GA2D_REG_IRQ_STATE UINT32_C(0x018)
|
||||
#define RS_GA2D_REG_IRQ_ENABLE UINT32_C(0x01C)
|
||||
#define RS_GA2D_REG_IRQ_TEST UINT32_C(0x020)
|
||||
#define RS_GA2D_REG_ERROR_STATUS UINT32_C(0x024)
|
||||
#define RS_GA2D_REG_ERROR_ADDRESS UINT32_C(0x028)
|
||||
#define RS_GA2D_REG_TIMEOUT_CYCLES UINT32_C(0x02C)
|
||||
#define RS_GA2D_REG_JOB_CONFIG UINT32_C(0x030)
|
||||
#define RS_GA2D_REG_GLOBAL_ALPHA UINT32_C(0x034)
|
||||
#define RS_GA2D_REG_COLOR UINT32_C(0x038)
|
||||
#define RS_GA2D_REG_SIZE UINT32_C(0x03C)
|
||||
#define RS_GA2D_REG_FG_ADDRESS UINT32_C(0x040)
|
||||
#define RS_GA2D_REG_FG_PITCH UINT32_C(0x044)
|
||||
#define RS_GA2D_REG_FG_FORMAT UINT32_C(0x048)
|
||||
#define RS_GA2D_REG_BG_ADDRESS UINT32_C(0x04C)
|
||||
#define RS_GA2D_REG_BG_PITCH UINT32_C(0x050)
|
||||
#define RS_GA2D_REG_BG_FORMAT UINT32_C(0x054)
|
||||
#define RS_GA2D_REG_DST_ADDRESS UINT32_C(0x058)
|
||||
#define RS_GA2D_REG_DST_PITCH UINT32_C(0x05C)
|
||||
#define RS_GA2D_REG_DST_FORMAT UINT32_C(0x060)
|
||||
#define RS_GA2D_REG_PERF_SNAPSHOT UINT32_C(0x064)
|
||||
#define RS_GA2D_REG_FORMAT_CAPABILITY UINT32_C(0x068)
|
||||
#define RS_GA2D_REG_SNAP_CYCLES_LO UINT32_C(0x080)
|
||||
#define RS_GA2D_REG_SNAP_CYCLES_HI UINT32_C(0x084)
|
||||
#define RS_GA2D_REG_SNAP_READ_BYTES_LO UINT32_C(0x088)
|
||||
#define RS_GA2D_REG_SNAP_READ_BYTES_HI UINT32_C(0x08C)
|
||||
#define RS_GA2D_REG_SNAP_WRITE_BYTES_LO UINT32_C(0x090)
|
||||
#define RS_GA2D_REG_SNAP_WRITE_BYTES_HI UINT32_C(0x094)
|
||||
#define RS_GA2D_REG_SNAP_READ_STALL_LO UINT32_C(0x098)
|
||||
#define RS_GA2D_REG_SNAP_READ_STALL_HI UINT32_C(0x09C)
|
||||
#define RS_GA2D_REG_SNAP_WRITE_STALL_LO UINT32_C(0x0A0)
|
||||
#define RS_GA2D_REG_SNAP_WRITE_STALL_HI UINT32_C(0x0A4)
|
||||
#define RS_GA2D_REG_SNAP_PIPE_STALL_LO UINT32_C(0x0A8)
|
||||
#define RS_GA2D_REG_SNAP_PIPE_STALL_HI UINT32_C(0x0AC)
|
||||
#define RS_GA2D_REG_SNAP_LINES_DONE UINT32_C(0x0B0)
|
||||
|
||||
#define RS_GA2D_IP_ID_VALUE UINT32_C(0x47413244)
|
||||
#define RS_GA2D_IP_VERSION_VALUE UINT32_C(0x00010000)
|
||||
#define RS_GA2D_IP_VERSION_MAJOR_MASK UINT32_C(0xFFFF0000)
|
||||
#define RS_GA2D_IP_VERSION_MAJOR_1 UINT32_C(0x00010000)
|
||||
#define RS_GA2D_CAPABILITY_P3 UINT32_C(0x00000040)
|
||||
#define RS_GA2D_LIMITS_P3 UINT32_C(0x00000000)
|
||||
#define RS_GA2D_FORMAT_CAPABILITY_P3 UINT32_C(0x00000000)
|
||||
#define RS_GA2D_TIMEOUT_CYCLES_RESET UINT32_C(0x00100000)
|
||||
#define RS_GA2D_GLOBAL_ALPHA_RESET UINT32_C(0x000000FF)
|
||||
|
||||
#define RS_GA2D_COMMAND_START UINT32_C(0x00000001)
|
||||
#define RS_GA2D_COMMAND_ABORT UINT32_C(0x00000002)
|
||||
#define RS_GA2D_COMMAND_SOFT_RESET UINT32_C(0x00000004)
|
||||
|
||||
#define RS_GA2D_STATUS_BUSY UINT32_C(0x00000001)
|
||||
#define RS_GA2D_STATUS_DRAINING UINT32_C(0x00000002)
|
||||
#define RS_GA2D_STATUS_QUIESCED UINT32_C(0x00000004)
|
||||
#define RS_GA2D_STATUS_DATA_READY UINT32_C(0x00000008)
|
||||
#define RS_GA2D_STATUS_DONE UINT32_C(0x00000010)
|
||||
#define RS_GA2D_STATUS_ABORTED UINT32_C(0x00000020)
|
||||
#define RS_GA2D_STATUS_ERROR UINT32_C(0x00000040)
|
||||
#define RS_GA2D_STATUS_RECOVERY_REQUIRED UINT32_C(0x00000080)
|
||||
|
||||
#define RS_GA2D_IRQ_DONE UINT32_C(0x00000001)
|
||||
#define RS_GA2D_IRQ_ERROR UINT32_C(0x00000002)
|
||||
#define RS_GA2D_IRQ_ABORT_DONE UINT32_C(0x00000004)
|
||||
#define RS_GA2D_IRQ_ALL UINT32_C(0x00000007)
|
||||
|
||||
#define RS_GA2D_ERROR_STATUS_VALID UINT32_C(0x00000001)
|
||||
#define RS_GA2D_ERROR_STATUS_CODE_SHIFT 1U
|
||||
#define RS_GA2D_ERROR_STATUS_CODE_MASK UINT32_C(0x000000FE)
|
||||
#define RS_GA2D_ERROR_STATUS_STAGE_SHIFT 8U
|
||||
#define RS_GA2D_ERROR_STATUS_STAGE_MASK UINT32_C(0x00000F00)
|
||||
#define RS_GA2D_ERROR_STATUS_AXI_RESPONSE_SHIFT 12U
|
||||
#define RS_GA2D_ERROR_STATUS_AXI_RESPONSE_MASK UINT32_C(0x00003000)
|
||||
|
||||
#define RS_GA2D_JOB_CONFIG_OPERATION_SHIFT 0U
|
||||
#define RS_GA2D_JOB_CONFIG_OPERATION_MASK UINT32_C(0x00000003)
|
||||
#define RS_GA2D_GLOBAL_ALPHA_VALUE_SHIFT 0U
|
||||
#define RS_GA2D_GLOBAL_ALPHA_VALUE_MASK UINT32_C(0x000000FF)
|
||||
#define RS_GA2D_SIZE_WIDTH_SHIFT 0U
|
||||
#define RS_GA2D_SIZE_WIDTH_MASK UINT32_C(0x0000FFFF)
|
||||
#define RS_GA2D_SIZE_HEIGHT_SHIFT 16U
|
||||
#define RS_GA2D_SIZE_HEIGHT_MASK UINT32_C(0xFFFF0000)
|
||||
#define RS_GA2D_FG_FORMAT_VALUE_SHIFT 0U
|
||||
#define RS_GA2D_BG_FORMAT_VALUE_SHIFT 0U
|
||||
#define RS_GA2D_DST_FORMAT_VALUE_SHIFT 0U
|
||||
#define RS_GA2D_FORMAT_VALUE_MASK UINT32_C(0x00000007)
|
||||
#define RS_GA2D_FORMAT_CAPABILITY_FOREGROUND_SHIFT 0U
|
||||
#define RS_GA2D_FORMAT_CAPABILITY_BACKGROUND_SHIFT 8U
|
||||
#define RS_GA2D_FORMAT_CAPABILITY_DESTINATION_SHIFT 16U
|
||||
#define RS_GA2D_FORMAT_CAPABILITY_MASK UINT32_C(0x0000001F)
|
||||
|
||||
#define RS_GA2D_CAPABILITY_FILL UINT32_C(0x00000001)
|
||||
#define RS_GA2D_CAPABILITY_COPY UINT32_C(0x00000002)
|
||||
#define RS_GA2D_CAPABILITY_CONVERT UINT32_C(0x00000004)
|
||||
#define RS_GA2D_CAPABILITY_BLEND UINT32_C(0x00000008)
|
||||
#define RS_GA2D_CAPABILITY_A8_MASK UINT32_C(0x00000010)
|
||||
#define RS_GA2D_CAPABILITY_PRIVATE_DMA UINT32_C(0x00000020)
|
||||
#define RS_GA2D_CAPABILITY_IRQ UINT32_C(0x00000040)
|
||||
#define RS_GA2D_CAPABILITY_SNAPSHOT UINT32_C(0x00000080)
|
||||
#define RS_GA2D_CAPABILITY_TWO_DIMENSIONAL_PITCH UINT32_C(0x00000100)
|
||||
#define RS_GA2D_CAPABILITY_BYTE_EDGES UINT32_C(0x00000200)
|
||||
#define RS_GA2D_CAPABILITY_INPLACE_BACKGROUND UINT32_C(0x00000400)
|
||||
|
||||
#define RS_GA2D_ERROR_CODE_NONE 0U
|
||||
#define RS_GA2D_ERROR_CODE_INVALID_SIZE 1U
|
||||
#define RS_GA2D_ERROR_CODE_INVALID_FORMAT 2U
|
||||
#define RS_GA2D_ERROR_CODE_INVALID_PITCH 3U
|
||||
#define RS_GA2D_ERROR_CODE_INVALID_ALIGNMENT 4U
|
||||
#define RS_GA2D_ERROR_CODE_ADDRESS_OVERFLOW 5U
|
||||
#define RS_GA2D_ERROR_CODE_ADDRESS_RANGE 6U
|
||||
#define RS_GA2D_ERROR_CODE_OVERLAP 7U
|
||||
#define RS_GA2D_ERROR_CODE_AXI_READ 8U
|
||||
#define RS_GA2D_ERROR_CODE_AXI_WRITE 9U
|
||||
#define RS_GA2D_ERROR_CODE_AXI_PROTOCOL 10U
|
||||
#define RS_GA2D_ERROR_CODE_TIMEOUT 11U
|
||||
#define RS_GA2D_ERROR_CODE_EPOCH_LOST 12U
|
||||
#define RS_GA2D_ERROR_CODE_INTERNAL 13U
|
||||
|
||||
#define RS_GA2D_ERROR_STAGE_NONE 0U
|
||||
#define RS_GA2D_ERROR_STAGE_VALIDATE 1U
|
||||
#define RS_GA2D_ERROR_STAGE_FOREGROUND 2U
|
||||
#define RS_GA2D_ERROR_STAGE_BACKGROUND 3U
|
||||
#define RS_GA2D_ERROR_STAGE_DESTINATION 4U
|
||||
#define RS_GA2D_ERROR_STAGE_LIFECYCLE 5U
|
||||
|
||||
#define RS_GA2D_REG(offset) RS_SOC_REG32(RS_SOC_APB4_GA2D_BASE, (offset))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/hal/ga2d.h>
|
||||
|
||||
#if defined(RS_GA2D_TEST_MMIO)
|
||||
extern volatile uint32_t rs_ga2d_test_mmio[1024];
|
||||
#undef RS_GA2D_REG
|
||||
#define RS_GA2D_REG(offset) rs_ga2d_test_mmio[(offset) / 4U]
|
||||
#endif
|
||||
|
||||
static void rs_ga2d_fence(void) {
|
||||
#if defined(__riscv)
|
||||
__asm__ volatile("fence rw, rw" ::: "memory");
|
||||
#else
|
||||
__asm__ volatile("" ::: "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t rs_ga2d_poll_count(rs_timeout_t timeout) {
|
||||
return (timeout == 0U) ? 1U : timeout;
|
||||
}
|
||||
|
||||
static uint32_t rs_ga2d_bit(uint32_t value, uint32_t mask) {
|
||||
return ((value & mask) != 0U) ? 1U : 0U;
|
||||
}
|
||||
|
||||
static rs_status_t rs_ga2d_require_shell(void) {
|
||||
rs_ga2d_capability_t capability;
|
||||
|
||||
return rs_ga2d_get_capability(&capability);
|
||||
}
|
||||
|
||||
static rs_status_t rs_ga2d_require_irq(void) {
|
||||
rs_ga2d_capability_t capability;
|
||||
rs_status_t status;
|
||||
|
||||
status = rs_ga2d_get_capability(&capability);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
return ((capability.features & RS_GA2D_CAPABILITY_IRQ) != 0U) ? RS_OK : RS_ENOTSUP;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_get_capability(rs_ga2d_capability_t *capability) {
|
||||
uint32_t ip_id;
|
||||
|
||||
if (capability == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
ip_id = RS_GA2D_REG(RS_GA2D_REG_IP_ID);
|
||||
capability->version = RS_GA2D_REG(RS_GA2D_REG_IP_VERSION);
|
||||
capability->features = RS_GA2D_REG(RS_GA2D_REG_CAPABILITY);
|
||||
capability->limits = RS_GA2D_REG(RS_GA2D_REG_LIMITS);
|
||||
capability->formats = RS_GA2D_REG(RS_GA2D_REG_FORMAT_CAPABILITY);
|
||||
if ((ip_id != RS_GA2D_IP_ID_VALUE) ||
|
||||
((capability->version & RS_GA2D_IP_VERSION_MAJOR_MASK) != RS_GA2D_IP_VERSION_MAJOR_1)) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_job_validate(const rs_ga2d_job_t *job) {
|
||||
if (job == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_configure(const rs_ga2d_job_t *job) {
|
||||
if (job == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_start(void) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_wait(rs_timeout_t timeout) {
|
||||
(void)timeout;
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_abort_wait(rs_timeout_t timeout) {
|
||||
uint32_t polls;
|
||||
|
||||
if (rs_ga2d_require_shell() != RS_OK) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
RS_GA2D_REG(RS_GA2D_REG_COMMAND) = RS_GA2D_COMMAND_ABORT;
|
||||
polls = rs_ga2d_poll_count(timeout);
|
||||
while (polls-- != 0U) {
|
||||
const uint32_t status = RS_GA2D_REG(RS_GA2D_REG_STATUS);
|
||||
|
||||
if ((status & (RS_GA2D_STATUS_BUSY | RS_GA2D_STATUS_DRAINING)) == 0U) {
|
||||
rs_ga2d_fence();
|
||||
return RS_OK;
|
||||
}
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_reset(void) {
|
||||
uint32_t status;
|
||||
rs_status_t result;
|
||||
|
||||
result = rs_ga2d_require_shell();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
status = RS_GA2D_REG(RS_GA2D_REG_STATUS);
|
||||
if ((status & (RS_GA2D_STATUS_BUSY | RS_GA2D_STATUS_DRAINING | RS_GA2D_STATUS_QUIESCED |
|
||||
RS_GA2D_STATUS_RECOVERY_REQUIRED)) != 0U ||
|
||||
(rs_ga2d_bit(status, RS_GA2D_STATUS_DATA_READY) == 0U)) {
|
||||
return RS_EIO;
|
||||
}
|
||||
RS_GA2D_REG(RS_GA2D_REG_COMMAND) = RS_GA2D_COMMAND_SOFT_RESET;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_get_status(rs_ga2d_status_t *status) {
|
||||
uint32_t flags;
|
||||
rs_status_t result;
|
||||
|
||||
if (status == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
result = rs_ga2d_require_shell();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
flags = RS_GA2D_REG(RS_GA2D_REG_STATUS);
|
||||
status->busy = rs_ga2d_bit(flags, RS_GA2D_STATUS_BUSY) != 0U;
|
||||
status->draining = rs_ga2d_bit(flags, RS_GA2D_STATUS_DRAINING) != 0U;
|
||||
status->quiesced = rs_ga2d_bit(flags, RS_GA2D_STATUS_QUIESCED) != 0U;
|
||||
status->data_ready = rs_ga2d_bit(flags, RS_GA2D_STATUS_DATA_READY) != 0U;
|
||||
status->done = rs_ga2d_bit(flags, RS_GA2D_STATUS_DONE) != 0U;
|
||||
status->aborted = rs_ga2d_bit(flags, RS_GA2D_STATUS_ABORTED) != 0U;
|
||||
status->error = rs_ga2d_bit(flags, RS_GA2D_STATUS_ERROR) != 0U;
|
||||
status->recovery_required = rs_ga2d_bit(flags, RS_GA2D_STATUS_RECOVERY_REQUIRED) != 0U;
|
||||
status->irq_state = RS_GA2D_REG(RS_GA2D_REG_IRQ_STATE) & RS_GA2D_IRQ_ALL;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_get_error(rs_ga2d_error_t *error) {
|
||||
uint32_t status;
|
||||
rs_status_t result;
|
||||
|
||||
if (error == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
result = rs_ga2d_require_shell();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
status = RS_GA2D_REG(RS_GA2D_REG_ERROR_STATUS);
|
||||
error->valid = rs_ga2d_bit(status, RS_GA2D_ERROR_STATUS_VALID) != 0U;
|
||||
error->code =
|
||||
(uint8_t)((status & RS_GA2D_ERROR_STATUS_CODE_MASK) >> RS_GA2D_ERROR_STATUS_CODE_SHIFT);
|
||||
error->stage =
|
||||
(uint8_t)((status & RS_GA2D_ERROR_STATUS_STAGE_MASK) >> RS_GA2D_ERROR_STATUS_STAGE_SHIFT);
|
||||
error->axi_response = (uint8_t)((status & RS_GA2D_ERROR_STATUS_AXI_RESPONSE_MASK) >>
|
||||
RS_GA2D_ERROR_STATUS_AXI_RESPONSE_SHIFT);
|
||||
error->address = (uintptr_t)RS_GA2D_REG(RS_GA2D_REG_ERROR_ADDRESS);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_get_stats(rs_ga2d_stats_t *stats) {
|
||||
if (stats == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_irq_enable(uint32_t mask) {
|
||||
rs_status_t result;
|
||||
|
||||
if ((mask & ~RS_GA2D_IRQ_ALL) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
result = rs_ga2d_require_irq();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
RS_GA2D_REG(RS_GA2D_REG_IRQ_ENABLE) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_irq_pending(uint32_t *pending) {
|
||||
rs_status_t result;
|
||||
|
||||
if (pending == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
result = rs_ga2d_require_irq();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
*pending =
|
||||
RS_GA2D_REG(RS_GA2D_REG_IRQ_STATE) & RS_GA2D_REG(RS_GA2D_REG_IRQ_ENABLE) & RS_GA2D_IRQ_ALL;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ga2d_irq_clear(uint32_t mask) {
|
||||
rs_status_t result;
|
||||
|
||||
if ((mask & ~RS_GA2D_IRQ_ALL) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
result = rs_ga2d_require_irq();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
RS_GA2D_REG(RS_GA2D_REG_IRQ_STATE) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
@@ -115,6 +115,8 @@ static void rs_print_mmio_map(void) {
|
||||
(void *)(uintptr_t)RS_SOC_APB4_OPIPSRAM_BASE);
|
||||
printf(" 1 x I2C1 @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_APB4_I2C1_BASE);
|
||||
printf(" 1 x GA2D SHELL @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_APB4_GA2D_BASE);
|
||||
printf(" 1 x GPIO ADMIN @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_APB4_GPIO_ADMIN_BASE);
|
||||
printf(" 1 x SDIO1 @%p\n",
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
Mini uses two cooperating AXI fabrics. `axi4_interconnect` is the 32-bit LP
|
||||
control/compatibility plane; `axi4_data_crossbar` is the 64-bit HP payload
|
||||
plane. Common `axi4_if`, `memory_map.json`, and `soc_topology.json` are the
|
||||
executable protocol, address, and integration sources of truth.
|
||||
executable protocol, address, and integration sources of truth. GA2D Phase 3
|
||||
activates the PCLK-only `APB4_GA2D` shell and its resource-owned interrupt;
|
||||
the dedicated master-8 AXI bridge remains an idle source until a later phase
|
||||
implements payload/DMA traffic.
|
||||
|
||||
[GA2D Phase 2](ip/ga2d.md#phase-2---expand-axi64-fabric-and-resource-integration)
|
||||
expands the fabric to nine native masters and seven-bit global IDs. It adds
|
||||
master 8 and preserves all existing identities, target policy, and timeout
|
||||
behavior. Master 8 is fed only by its dedicated PCLK-to-HP AXI64/ID3 bridge,
|
||||
whose source is idle. `APB4_GA` remains reserved and inactive; the GA2D APB
|
||||
shell, IRQ, payload/DMA, and pixel function remain deferred. The GA2D
|
||||
specification also records the existing master-6/JPEG admission discrepancy;
|
||||
it must not be interpreted as a free port.
|
||||
whose source remains idle. Phase 3 activates the separate PCLK `APB4_GA2D`
|
||||
shell and resource-owned IRQ, while payload/DMA, pixel work, and START remain
|
||||
deferred. The GA2D specification also records the existing master-6/JPEG
|
||||
admission discrepancy; it must not be interpreted as a free port.
|
||||
|
||||
## LP control plane
|
||||
|
||||
@@ -74,7 +77,7 @@ the integration RTL:
|
||||
| HP I-cache | all five memories | none | allowed | cache attributes preserved |
|
||||
| HP D-cache | all five memories | SRAM, SDRAM, QPI, OPI | denied | cache attributes preserved |
|
||||
| DMA, I/O A/B, LP gateway | all five memories | SRAM, SDRAM, QPI, OPI | denied | `AxCACHE=0` required |
|
||||
| GA2D bridge placeholder | all five memories | SRAM, SDRAM, QPI, OPI | denied | `AxCACHE=0` required; source is idle in P2 |
|
||||
| GA2D bridge placeholder | all five memories | SRAM, SDRAM, QPI, OPI | denied | `AxCACHE=0` required; source remains idle in P3 |
|
||||
| JPEG | none | none | denied | zero normal admission credit (`GA2D-GAP-01`) |
|
||||
| EXT-H | all five memories within slot ACL | SRAM, SDRAM, QPI, OPI within slot ACL | denied | `AxCACHE=0` required |
|
||||
|
||||
|
||||
@@ -23,11 +23,12 @@ Mini remains a small, non-coherent, performance-first SoC. Hazard3 is the
|
||||
only root-management master. Vexii I/D, DMA, I/O gateways, the LP data gateway,
|
||||
EXT-H, and an idle GA2D bridge placeholder use a nine-master native AXI64 data
|
||||
plane with seven-bit global IDs. The placeholder is a dedicated
|
||||
PCLK-to-HP AXI64/ID3 bridge only: `APB4_GA` remains reserved and inactive, and
|
||||
the GA2D APB shell, IRQ, payload/DMA, and pixel function remain deferred. APB
|
||||
remains a separate control plane. Every data initiator has a generated fixed
|
||||
identity, target permissions, execute/cache-attribute rules, outstanding
|
||||
limit, QoS class, and fault attribution.
|
||||
PCLK-to-HP AXI64/ID3 bridge whose source remains idle. Phase 3 activates a
|
||||
separate PCLK `APB4_GA2D` register shell and resource-owned IRQ route, but
|
||||
payload/DMA and pixel functions remain deferred. APB remains a separate control
|
||||
plane. Every data initiator has a generated fixed identity, target permissions,
|
||||
execute/cache-attribute rules, outstanding limit, QoS class, and fault
|
||||
attribution.
|
||||
|
||||
The design combines the references at their smallest useful boundary:
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ adds master bank 8, version 1.1, and master bit 3 at `FAULT[12]`, preserving
|
||||
the existing packed fields. It also carries the complete four-bit master
|
||||
identity through SYSCTRL. Bank 8 observes the dedicated PCLK-to-HP
|
||||
AXI64/ID3 GA2D bridge placeholder, whose source is idle; it does not imply an
|
||||
implemented GA2D APB shell, IRQ, payload/DMA, or pixel function.
|
||||
implemented GA2D payload/DMA or pixel function. Phase 3 adds an `APB4_GA2D`
|
||||
register shell and resource-owned IRQ without changing the idle bridge source.
|
||||
|
||||
## Scope
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
[GA2D Phase 2](ga2d.md#phase-2---expand-axi64-fabric-and-resource-integration)
|
||||
adds resource 8 and version 1.1. It covers only the dedicated PCLK-to-HP
|
||||
AXI64/ID3 GA2D bridge placeholder, whose source is idle. LP vector 32 / HP
|
||||
PLIC source 11 and GA2D APB-shell wiring remain Phase 3 work; `APB4_GA`
|
||||
therefore remains reserved and inactive. Its source-stop/drain-before-block
|
||||
PLIC source 11 and `APB4_GA2D` shell wiring are implemented in Phase 3. The
|
||||
shell has IRQ-only capability; it does not create GA2D payload/DMA or pixel
|
||||
work, and the bridge source remains idle. Its source-stop/drain-before-block
|
||||
sequence is specified there. Existing resources and register fields are not
|
||||
renumbered or reinterpreted.
|
||||
|
||||
@@ -29,13 +30,13 @@ Resource indices are fixed:
|
||||
| 5 | EXT-H | 3 |
|
||||
| 6 | JPEG | 9 |
|
||||
| 7 | APU | 10 |
|
||||
| 8 | GA2D bridge placeholder (idle) | 11, not routed until Phase 3 |
|
||||
| 8 | GA2D APB shell and idle bridge placeholder | 11 |
|
||||
|
||||
For resources 0 through 7, owner `0` routes the resource interrupt to the
|
||||
existing LP vector. Owner `1` removes it from LP and routes it to the listed HP
|
||||
PLIC source. Resource 8 has a fixed-inactive raw IRQ and no LP or HP IRQ route
|
||||
until Phase 3. Reset masks both applicable routes. Hardware never delivers one
|
||||
resource interrupt to both owners.
|
||||
PLIC source. Resource 8 routes the GA2D shell raw IRQ to LP vector 32/external
|
||||
ordinal 30 for owner `0`, or HP PLIC source 11 for owner `1`. Reset masks both
|
||||
routes. Hardware never delivers one resource interrupt to both owners.
|
||||
|
||||
## Register ABI
|
||||
|
||||
@@ -90,9 +91,9 @@ and a Linux platform driver remain software responsibilities.
|
||||
## Delivery Boundary
|
||||
|
||||
Central owner/lock, quiesce-gated handoff, cache request/ACK, fault IRQ, and
|
||||
LP/HP IRQ routing are implemented and directed-tested. P2 appends resource 8
|
||||
for the idle GA2D bridge placeholder only; it creates no GA2D IRQ route or
|
||||
functional GA2D peripheral. `CONTROL.QUIESCE` blocks the corresponding
|
||||
LP/HP IRQ routing are implemented and directed-tested. Phase 3 adds the GA2D
|
||||
PCLK shell raw IRQ to resource 8, while its AXI bridge remains idle and it does
|
||||
not provide a functional GA2D engine. `CONTROL.QUIESCE` blocks the corresponding
|
||||
data-crossbar master and waits per-master outstanding zero; shared I/O gateways
|
||||
are conservatively blocked as a pair. `CONTROL.RESET` also blocks new data and
|
||||
masks IRQ but is not yet connected to every peripheral engine's internal reset
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ offset macros.
|
||||
| `0x01C` | `PLL_STATUS` | RO | Active profile, valid, busy, error/error reason, safe clock, lock, and capability. |
|
||||
| `0x020` | `USER_CORE_RESET` | RO/unsupported | Product reads all ones and rejects writes. MPW retains its reset mask. |
|
||||
| `0x024` | `USER_CORE_STATUS` | RO/unsupported | Product reports present=0, idle=1, and sticky unsupported-write error. |
|
||||
| `0x028` | `FAULT_MASTER` | RO | First fault master, a four-bit AXI master ID (0..8); HP is 7 and the P2 GA2D bridge placeholder is 8. The offset is unchanged. |
|
||||
| `0x028` | `FAULT_MASTER` | RO | First fault master, a four-bit AXI master ID (0..8); HP is 7 and the P3 GA2D shell's idle bridge placeholder is 8. The offset is unchanged. |
|
||||
| `0x02C` | `FAULT_DETAIL` | RO | First raw RIB response code. |
|
||||
| `0x040` | `PERF_CTRL` | RW | Bit 0 enable, bit 1 clear pulse, bit 2 snapshot pulse. |
|
||||
| `0x044`-`0x098` | `PERF_*_WAIT_{LO,HI}` | RO | Snapshot of management, user, central DMA, SDIO0, SDIO1, APB4, SDRAM, PSRAM, and flash wait counters. |
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
The frozen [GA2D specification](ip/ga2d.md) defines the phased GA2D delivery.
|
||||
Phase 2 expands the implemented platform to nine AXI64 masters with seven-bit
|
||||
global IDs and Resource Controller entry 8. Its dedicated PCLK-to-HP
|
||||
AXI64/ID3 bridge is an idle placeholder only. `APB4_GA` remains reserved and
|
||||
inactive, and the GA2D APB shell, IRQ, payload/DMA, and pixel function remain
|
||||
deferred. Existing hart, memory, and source identities remain fixed.
|
||||
AXI64/ID3 bridge remains an idle placeholder. Phase 3 activates
|
||||
`APB4_GA2D` as a PCLK register shell and connects its resource-owned IRQ, but
|
||||
payload/DMA, pixel function, and START remain deferred. Existing hart, memory,
|
||||
and source identities remain fixed.
|
||||
|
||||
## Product contract
|
||||
|
||||
@@ -94,6 +95,7 @@ and a Common FIFO preserves write-data order where AXI4 W has no ID.
|
||||
| I/O gateway A | USB2 and SDIO0, then PCLK-to-HP CDC and upsizer |
|
||||
| I/O gateway B | SDIO1 and SPI-SD, then PCLK-to-HP CDC and upsizer |
|
||||
| LP data gateway | Hazard3 memory traffic, LP-to-HP CDC and upsizer |
|
||||
| JPEG | PCLK-to-HP AXI64 async bridge, ID prefix 6; zero normal admission credit (`GA2D-GAP-01`) |
|
||||
| EXT-H | PCLK-to-HP AXI64 async bridge, ID prefix 7 |
|
||||
| GA2D bridge placeholder | dedicated PCLK-to-HP AXI64/ID3 async bridge; source held idle |
|
||||
|
||||
@@ -154,12 +156,13 @@ Its IRQ is delivered to LP IRQ 28 or HP PLIC source 3 according to owner,
|
||||
never both. Software discovers it through `<retrosoc/hal/extension.h>`.
|
||||
|
||||
The Resource Controller at `0x2000_A000` is the central owner and IRQ authority
|
||||
for DMA, USB2, SDIO0/1, SPI-SD, EXT-H, JPEG, and APU, and the lifecycle
|
||||
authority for the idle GA2D bridge placeholder. Resource 8 has no routed IRQ
|
||||
until Phase 3. Handoff requires idle,
|
||||
owner lock is sticky, and rejected handoffs raise LP IRQ 29. APU index 7 routes
|
||||
exclusively to LP IRQ31 or HP PLIC source10. The controller also carries the
|
||||
AON cache request/clean acknowledgement used before HP drain. See
|
||||
for DMA, USB2, SDIO0/1, SPI-SD, EXT-H, JPEG, APU, and the P3 GA2D shell. Resource
|
||||
8 routes its raw IRQ exclusively to LP vector 32/external ordinal 30 or HP PLIC
|
||||
source 11 according to owner, while the associated AXI bridge remains idle.
|
||||
Handoff requires idle, owner lock is sticky, and rejected handoffs raise LP IRQ
|
||||
29. APU index 7 routes exclusively to LP IRQ31 or HP PLIC source10. The
|
||||
controller also carries the AON cache request/clean acknowledgement used before
|
||||
HP drain. See
|
||||
[`ip/resource-controller.md`](ip/resource-controller.md).
|
||||
Resource 8 qualifies its HP block acknowledgement with a fresh synchronized
|
||||
source-quiesced state, so an old idle sample cannot hand off a
|
||||
|
||||
@@ -145,8 +145,9 @@ capabilities:
|
||||
with seven-bit global IDs. Vexii I/D ports remain independent; DMA and I/O
|
||||
masters cross into HP and current memory frontends are reached through
|
||||
64-to-32 target adapters. Master 8 is a dedicated PCLK-to-HP AXI64/ID3 GA2D
|
||||
bridge whose source is idle; `APB4_GA` remains reserved and inactive, and no
|
||||
GA2D APB shell, IRQ, payload/DMA, or pixel function is implemented.
|
||||
bridge whose source is idle. `APB4_GA2D` is an active PCLK register shell
|
||||
with resource-owned IRQ routing, while GA2D payload/DMA and pixel functions
|
||||
remain unavailable.
|
||||
- Current external-memory targets serialize accepted AXI4 bursts into ordered
|
||||
scalar engine accesses. They do not yet combine a burst into a native SDRAM,
|
||||
PSRAM, flash, or SPI-SD physical transaction.
|
||||
|
||||
@@ -8131,7 +8131,7 @@
|
||||
"from": "resources.p1",
|
||||
"to": "core.p1",
|
||||
"kind": "control",
|
||||
"label": "IDLE / 8",
|
||||
"label": "IDLE / 9",
|
||||
"style": "direct",
|
||||
"bindings": [
|
||||
{
|
||||
@@ -8159,7 +8159,7 @@
|
||||
"from": "core.p2",
|
||||
"to": "owners.p2",
|
||||
"kind": "control",
|
||||
"label": "OWNER / 16",
|
||||
"label": "OWNER / 18",
|
||||
"style": "direct",
|
||||
"bindings": [
|
||||
{
|
||||
@@ -8187,7 +8187,7 @@
|
||||
"from": "core.p3",
|
||||
"to": "irq.p3",
|
||||
"kind": "control",
|
||||
"label": "LP IRQ / 8",
|
||||
"label": "LP IRQ / 9",
|
||||
"style": "direct",
|
||||
"bindings": [
|
||||
{
|
||||
@@ -8213,7 +8213,7 @@
|
||||
"zigzag-dir": "horizontal"
|
||||
}
|
||||
],
|
||||
"note": "Nine resources retain independent owner/lock/quiesce/reset state; resource 8 is the idle GA2D bridge placeholder only. IRQ steering and cache-clean coordination are control relationships, not a hardware cache-coherence implementation."
|
||||
"note": "Nine resources retain independent owner/lock/quiesce/reset state; resource 8 routes the P3 GA2D shell IRQ while its AXI bridge stays idle. IRQ steering and cache-clean coordination are control relationships, not a hardware cache-coherence implementation."
|
||||
},
|
||||
"monitor": {
|
||||
"nodes": [
|
||||
|
||||
@@ -150,12 +150,12 @@
|
||||
"Lifecycle-gated device identity reads."
|
||||
],
|
||||
"resource": [
|
||||
"Nine independently managed shared resources; resource 8 is the idle GA2D bridge placeholder only.",
|
||||
"Nine independently managed shared resources; resource 8 owns the P3 GA2D shell IRQ and idle bridge placeholder.",
|
||||
"Owner locks, quiesce/reset and LP/HP IRQ routing.",
|
||||
"Explicit cache-maintenance handoff and sticky faults."
|
||||
],
|
||||
"monitor": [
|
||||
"Nine master and six target observation banks; bank 8 observes the idle GA2D bridge placeholder.",
|
||||
"Nine master and six target observation banks; bank 8 observes the idle GA2D bridge behind the P3 shell.",
|
||||
"Saturating counters, snapshots and outstanding high-water marks.",
|
||||
"Sticky first-fault attribution and live isolation status."
|
||||
],
|
||||
|
||||
@@ -333,7 +333,7 @@
|
||||
"sources": [
|
||||
"docs/ip/resource-controller.md"
|
||||
],
|
||||
"summary": "LP-controlled ownership, quiesce, reset and LP/HP IRQ routing for nine resources; resource 8 is the idle GA2D bridge placeholder only."
|
||||
"summary": "LP-controlled ownership, quiesce, reset and LP/HP IRQ routing for nine resources; resource 8 owns the P3 GA2D shell IRQ and an idle AXI bridge placeholder."
|
||||
},
|
||||
{
|
||||
"id": "monitor",
|
||||
@@ -344,7 +344,7 @@
|
||||
"sources": [
|
||||
"docs/ip/fabric-monitor.md"
|
||||
],
|
||||
"summary": "Nine-master/six-target snapshot counters and sticky fault attribution beside the HP data crossbar; bank 8 observes the idle GA2D bridge placeholder."
|
||||
"summary": "Nine-master/six-target snapshot counters and sticky fault attribution beside the HP data crossbar; bank 8 observes the idle GA2D bridge behind the P3 shell."
|
||||
},
|
||||
{
|
||||
"id": "i2s",
|
||||
@@ -476,16 +476,30 @@
|
||||
],
|
||||
"summary": "MPW selectable user-IP window; PRODUCT exposes a compatibility responder."
|
||||
},
|
||||
{
|
||||
"id": "ga2d",
|
||||
"regions": [
|
||||
"APB4_GA2D"
|
||||
],
|
||||
"irqs": [
|
||||
"ga2d"
|
||||
],
|
||||
"sources": [
|
||||
"docs/ip/ga2d.md",
|
||||
"rtl/ip/multimedia/apb4_ga2d.sv",
|
||||
"rtl/ip/multimedia/ga2d_reg.sv"
|
||||
],
|
||||
"summary": "P3 APB4 register shell with resource-owned IRQ; START, 2D DMA, and pixel operations remain unavailable."
|
||||
},
|
||||
{
|
||||
"id": "reserved",
|
||||
"regions": [
|
||||
"APB4_GA",
|
||||
"SPISD"
|
||||
],
|
||||
"irqs": [],
|
||||
"sources": [
|
||||
"rtl/mini/address_map/memory_map.json"
|
||||
],
|
||||
"summary": "Reserved address ranges; no integrated graphics accelerator or card data aperture."
|
||||
"summary": "Reserved card data aperture."
|
||||
}
|
||||
]
|
||||
@@ -1,6 +1,6 @@
|
||||
#import "../style.typ": *
|
||||
|
||||
#import "../ip-reference.typ": ip-reference
|
||||
#import "../ip-reference.typ": ip-reference, register-section
|
||||
|
||||
#pagebreak(weak:true)
|
||||
|
||||
@@ -12,10 +12,14 @@
|
||||
|
||||
#ip-reference("resource","resource",4,legacy:[
|
||||
Nine resources are managed: central DMA, USB2, SDIO0, SDIO1, SPI-SD, EXT-H, JPEG,
|
||||
APU, and the idle GA2D bridge placeholder. Resource 8 has no routed IRQ in Phase 2.
|
||||
APU, and the P3 GA2D shell with its idle AXI bridge placeholder. Resource 8 routes
|
||||
the shell IRQ according to its current owner; the shell does not submit GA2D work.
|
||||
Ownership changes require quiesce, completion of accepted traffic and cache-maintenance
|
||||
handoff. HP can inspect allowed status but cannot take over root writes. An ownership grant
|
||||
does not bypass the target access policy or EXT-H address bounds.
|
||||
])
|
||||
|
||||
#heading(level:5,numbering:none,outlined:false,bookmarked:false)[GA2D Phase 3 Register Shell] <ga2d>
|
||||
#register-section("ga2d",4)
|
||||
|
||||
#context metadata((kind:"ip-end",id:"resource",page:here().page()))
|
||||
@@ -76,7 +76,8 @@
|
||||
"I2S",
|
||||
"DVP",
|
||||
"JPEG",
|
||||
"APU"
|
||||
"APU",
|
||||
"GA2D"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -962,6 +962,30 @@
|
||||
"rtl/ip/multimedia/apu_transform_engine.sv"
|
||||
]
|
||||
},
|
||||
"ga2d": {
|
||||
"document": "docs/ip/ga2d.md",
|
||||
"defines": [
|
||||
"rtl/ip/multimedia/ga2d_define.svh"
|
||||
],
|
||||
"rtl": [
|
||||
"rtl/ip/multimedia/ga2d_reg.sv"
|
||||
],
|
||||
"parameters": {},
|
||||
"groups": [
|
||||
{
|
||||
"id": "main",
|
||||
"title": "Phase 3 register shell",
|
||||
"pattern": "APB4_GA2D__.+",
|
||||
"strip": "^APB4_GA2D__",
|
||||
"base": 0,
|
||||
"stride": 0,
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"support": [
|
||||
"rtl/ip/multimedia/apb4_ga2d.sv"
|
||||
]
|
||||
},
|
||||
"dvp": {
|
||||
"document": "docs/ip/dvp.md",
|
||||
"defines": [
|
||||
@@ -1746,7 +1770,7 @@
|
||||
"parameters": {
|
||||
"NumMasters": 8,
|
||||
"NumTargets": 6,
|
||||
"ResourceCount": 8
|
||||
"ResourceCount": 9
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
@@ -1765,7 +1789,7 @@
|
||||
"strip": "^",
|
||||
"base": 256,
|
||||
"stride": 32,
|
||||
"count": 8
|
||||
"count": 9
|
||||
}
|
||||
],
|
||||
"support": []
|
||||
@@ -1777,7 +1801,7 @@
|
||||
"rtl/mini/top/fabric_monitor.sv"
|
||||
],
|
||||
"parameters": {
|
||||
"NumMasters": 8,
|
||||
"NumMasters": 9,
|
||||
"NumTargets": 6,
|
||||
"ResourceCount": 8
|
||||
},
|
||||
@@ -1798,7 +1822,7 @@
|
||||
"strip": "^",
|
||||
"base": 256,
|
||||
"stride": 32,
|
||||
"count": 8
|
||||
"count": 9
|
||||
},
|
||||
{
|
||||
"id": "target",
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
"id": "resource",
|
||||
"title": "Resource Controller",
|
||||
"implementation": "Partial",
|
||||
"scope": "Nine independently managed shared resources; resource 8 is the idle GA2D bridge placeholder only.",
|
||||
"scope": "Nine independently managed shared resources; resource 8 owns the P3 GA2D shell IRQ and an idle AXI bridge placeholder.",
|
||||
"dependencies": "No additional off-chip component implied; use the selected clock/reset and access policy.",
|
||||
"hal": "Published API and syntax example; see the IP chapter.",
|
||||
"linux": "Native driver support not established in this publication.",
|
||||
@@ -610,7 +610,7 @@
|
||||
"id": "monitor",
|
||||
"title": "Fabric Monitor",
|
||||
"implementation": "Integrated",
|
||||
"scope": "Nine master and six target observation banks; bank 8 observes the idle GA2D bridge placeholder.",
|
||||
"scope": "Nine master and six target observation banks; bank 8 observes the idle GA2D bridge behind the P3 shell.",
|
||||
"dependencies": "No additional off-chip component implied; use the selected clock/reset and access policy.",
|
||||
"hal": "Published API and syntax example; see the IP chapter.",
|
||||
"linux": "Native driver support not established in this publication.",
|
||||
@@ -3625,6 +3625,20 @@
|
||||
"rtl/ip/multimedia/apb4_apu.sv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "apb4_ga2d",
|
||||
"chapter": "resource",
|
||||
"family": "ga2d",
|
||||
"mode": "PRODUCT",
|
||||
"region": "APB4_GA2D",
|
||||
"catalog": "ga2d",
|
||||
"qualification": "Phase 3 exposes only the GA2D APB4 shell and its resource-owned IRQ route. START, private DMA, and pixel operations remain unavailable.",
|
||||
"sources": [
|
||||
"docs/ip/ga2d.md",
|
||||
"rtl/ip/multimedia/ga2d_reg.sv",
|
||||
"rtl/ip/multimedia/apb4_ga2d.sv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "apb4_crypto",
|
||||
"chapter": "crypto",
|
||||
@@ -5307,7 +5321,16 @@
|
||||
"code": 15,
|
||||
"trigger": "rs_ci_smoke_external_irq(",
|
||||
"coverage": "Exercise Xh3irq ordinals 0/15/16/29/30/31/32/61, invalid 62, priority/masking, no-handler masking, timer/software coexistence, and handler entry/return.",
|
||||
"boundary": "Only the CSR-enabled build exercises dispatch; no peripheral GA2D source is wired."
|
||||
"boundary": "Only the CSR-enabled build exercises dispatch; the physical P3 GA2D shell route is covered by the following stage."
|
||||
},
|
||||
{
|
||||
"id": "ga2d-irq",
|
||||
"title": "GA2D shell IRQ route",
|
||||
"kind": "test-fail",
|
||||
"code": 15,
|
||||
"trigger": "rs_ci_smoke_ga2d_irq(",
|
||||
"coverage": "Discover the P3 shell and use IRQ_TEST to exercise its resource-owned LP external route.",
|
||||
"boundary": "Does not submit a GA2D datapath job or claim private DMA or pixel-operation availability."
|
||||
},
|
||||
{
|
||||
"id": "apu",
|
||||
|
||||
+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 GA2D graphics accelerator has a frozen architecture and ABI, with
|
||||
implementation pending. Its approved phases expand the LP interrupt platform
|
||||
and native AXI64 fabric before activating the former GA reservation as an
|
||||
APB4-controlled fill/copy/convert/alpha engine with private 2D DMA. The exact
|
||||
allocations, Common reuse limits, lifecycle, HAL, and evidence gates are in
|
||||
[GA2D](../docs/ip/ga2d.md). The freeze itself changes no RTL or filelists.
|
||||
The Mini GA2D graphics accelerator has a frozen architecture and ABI. Phase 3
|
||||
activates `APB4_GA2D` as a PCLK register shell with ownership-routed IRQ
|
||||
support; it does not implement START, 2D DMA, pixel operations, or AXI payload
|
||||
traffic. Its approved phases first expanded the LP interrupt platform and
|
||||
native AXI64 fabric, then activated the former GA reservation before later
|
||||
fill/copy/convert/alpha engine work. The exact allocations, Common reuse
|
||||
limits, lifecycle, HAL, and evidence gates are in [GA2D](../docs/ip/ga2d.md).
|
||||
|
||||
The Mini Audio Processing Unit has a frozen coreless architecture. APU-P5 adds
|
||||
the private AXI4 DMA and scheduler, microcode loader/sequencer, 112 KiB local
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
module apb4_ga2d (
|
||||
// verilog_format: off -- preserve the shell lifecycle boundary columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic resource_quiesce_i,
|
||||
input logic resource_reset_i,
|
||||
input logic source_stop_i,
|
||||
input logic source_safe_idle_i,
|
||||
input logic block_ack_i,
|
||||
input logic bridge_clear_busy_i,
|
||||
input logic [7:0] bridge_epoch_i,
|
||||
input logic data_ready_i,
|
||||
apb4_if.slave apb4,
|
||||
output logic idle_o,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
ga2d_pkg::ga2d_config_t s_config;
|
||||
logic [7:0] s_epoch_seen_d, s_epoch_seen_q;
|
||||
logic s_epoch_changed;
|
||||
logic s_quiesced;
|
||||
logic s_data_ready;
|
||||
logic s_recovery_required;
|
||||
logic s_soft_reset;
|
||||
logic s_abort;
|
||||
logic s_reg_idle;
|
||||
logic s_unused;
|
||||
|
||||
assign s_epoch_seen_d = bridge_epoch_i;
|
||||
assign s_epoch_changed = bridge_epoch_i != s_epoch_seen_q;
|
||||
assign s_quiesced = (resource_quiesce_i || resource_reset_i) && source_stop_i &&
|
||||
source_safe_idle_i && block_ack_i;
|
||||
assign s_data_ready = data_ready_i && !resource_quiesce_i && !resource_reset_i;
|
||||
assign s_recovery_required = bridge_clear_busy_i || !data_ready_i || s_epoch_changed;
|
||||
assign idle_o = s_reg_idle && source_safe_idle_i;
|
||||
assign s_unused = ^s_config ^ s_soft_reset ^ s_abort;
|
||||
|
||||
dffr #(
|
||||
.DATA_WIDTH(8)
|
||||
) u_epoch_seen (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_epoch_seen_d),
|
||||
.dat_o (s_epoch_seen_q)
|
||||
);
|
||||
|
||||
ga2d_reg u_ga2d_reg (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.busy_i (1'b0),
|
||||
.draining_i (1'b0),
|
||||
.quiesced_i (s_quiesced),
|
||||
.data_ready_i (s_data_ready),
|
||||
.recovery_required_i (s_recovery_required),
|
||||
.idle_i (source_safe_idle_i),
|
||||
.done_i (1'b0),
|
||||
.aborted_i (1'b0),
|
||||
.irq_event_i (3'd0),
|
||||
.error_valid_i (1'b0),
|
||||
.error_code_i (7'd0),
|
||||
.error_stage_i (4'd0),
|
||||
.error_axi_response_i(2'd0),
|
||||
.error_address_i (32'd0),
|
||||
.apb4 (apb4),
|
||||
.config_o (s_config),
|
||||
.soft_reset_o (s_soft_reset),
|
||||
.abort_o (s_abort),
|
||||
.idle_o (s_reg_idle),
|
||||
.irq_o (irq_o)
|
||||
);
|
||||
endmodule
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
`ifndef RETROSOC_GA2D_DEFINE_SVH
|
||||
`define RETROSOC_GA2D_DEFINE_SVH
|
||||
|
||||
// verilog_format: off -- keep the handwritten hardware/software ABI columns aligned
|
||||
`define APB4_GA2D__IP_ID 12'h000
|
||||
`define APB4_GA2D__IP_VERSION 12'h004
|
||||
`define APB4_GA2D__CAPABILITY 12'h008
|
||||
`define APB4_GA2D__LIMITS 12'h00c
|
||||
`define APB4_GA2D__COMMAND 12'h010
|
||||
`define APB4_GA2D__STATUS 12'h014
|
||||
`define APB4_GA2D__IRQ_STATE 12'h018
|
||||
`define APB4_GA2D__IRQ_ENABLE 12'h01c
|
||||
`define APB4_GA2D__IRQ_TEST 12'h020
|
||||
`define APB4_GA2D__ERROR_STATUS 12'h024
|
||||
`define APB4_GA2D__ERROR_ADDRESS 12'h028
|
||||
`define APB4_GA2D__TIMEOUT_CYCLES 12'h02c
|
||||
`define APB4_GA2D__JOB_CONFIG 12'h030
|
||||
`define APB4_GA2D__GLOBAL_ALPHA 12'h034
|
||||
`define APB4_GA2D__COLOR 12'h038
|
||||
`define APB4_GA2D__SIZE 12'h03c
|
||||
`define APB4_GA2D__FG_ADDRESS 12'h040
|
||||
`define APB4_GA2D__FG_PITCH 12'h044
|
||||
`define APB4_GA2D__FG_FORMAT 12'h048
|
||||
`define APB4_GA2D__BG_ADDRESS 12'h04c
|
||||
`define APB4_GA2D__BG_PITCH 12'h050
|
||||
`define APB4_GA2D__BG_FORMAT 12'h054
|
||||
`define APB4_GA2D__DST_ADDRESS 12'h058
|
||||
`define APB4_GA2D__DST_PITCH 12'h05c
|
||||
`define APB4_GA2D__DST_FORMAT 12'h060
|
||||
`define APB4_GA2D__PERF_SNAPSHOT 12'h064
|
||||
`define APB4_GA2D__FORMAT_CAPABILITY 12'h068
|
||||
`define APB4_GA2D__SNAP_CYCLES_LO 12'h080
|
||||
`define APB4_GA2D__SNAP_CYCLES_HI 12'h084
|
||||
`define APB4_GA2D__SNAP_READ_BYTES_LO 12'h088
|
||||
`define APB4_GA2D__SNAP_READ_BYTES_HI 12'h08c
|
||||
`define APB4_GA2D__SNAP_WRITE_BYTES_LO 12'h090
|
||||
`define APB4_GA2D__SNAP_WRITE_BYTES_HI 12'h094
|
||||
`define APB4_GA2D__SNAP_READ_STALL_LO 12'h098
|
||||
`define APB4_GA2D__SNAP_READ_STALL_HI 12'h09c
|
||||
`define APB4_GA2D__SNAP_WRITE_STALL_LO 12'h0a0
|
||||
`define APB4_GA2D__SNAP_WRITE_STALL_HI 12'h0a4
|
||||
`define APB4_GA2D__SNAP_PIPE_STALL_LO 12'h0a8
|
||||
`define APB4_GA2D__SNAP_PIPE_STALL_HI 12'h0ac
|
||||
`define APB4_GA2D__SNAP_LINES_DONE 12'h0b0
|
||||
|
||||
`define APB4_GA2D__IP_ID_VALUE 32'h4741_3244
|
||||
`define APB4_GA2D__IP_VERSION_VALUE 32'h0001_0000
|
||||
`define APB4_GA2D__CAPABILITY_P3 32'h0000_0040
|
||||
`define APB4_GA2D__LIMITS_P3 32'h0000_0000
|
||||
`define APB4_GA2D__FORMAT_CAPABILITY_P3 32'h0000_0000
|
||||
`define APB4_GA2D__TIMEOUT_CYCLES_RESET 32'h0010_0000
|
||||
`define APB4_GA2D__GLOBAL_ALPHA_RESET 32'h0000_00ff
|
||||
|
||||
`define APB4_GA2D__COMMAND_START 0
|
||||
`define APB4_GA2D__COMMAND_ABORT 1
|
||||
`define APB4_GA2D__COMMAND_SOFT_RESET 2
|
||||
|
||||
`define APB4_GA2D__STATUS_BUSY 0
|
||||
`define APB4_GA2D__STATUS_DRAINING 1
|
||||
`define APB4_GA2D__STATUS_QUIESCED 2
|
||||
`define APB4_GA2D__STATUS_DATA_READY 3
|
||||
`define APB4_GA2D__STATUS_DONE 4
|
||||
`define APB4_GA2D__STATUS_ABORTED 5
|
||||
`define APB4_GA2D__STATUS_ERROR 6
|
||||
`define APB4_GA2D__STATUS_RECOVERY_REQUIRED 7
|
||||
|
||||
`define APB4_GA2D__IRQ_DONE 0
|
||||
`define APB4_GA2D__IRQ_ERROR 1
|
||||
`define APB4_GA2D__IRQ_ABORT_DONE 2
|
||||
`define APB4_GA2D__IRQ_ALL 3'h7
|
||||
|
||||
`define APB4_GA2D__ERROR_STATUS_VALID 0
|
||||
`define APB4_GA2D__ERROR_STATUS_CODE 1
|
||||
`define APB4_GA2D__ERROR_STATUS_STAGE 8
|
||||
`define APB4_GA2D__ERROR_STATUS_AXI_RESPONSE 12
|
||||
|
||||
`define APB4_GA2D__JOB_CONFIG_OPERATION 0
|
||||
`define APB4_GA2D__GLOBAL_ALPHA_VALUE 0
|
||||
`define APB4_GA2D__SIZE_WIDTH 0
|
||||
`define APB4_GA2D__SIZE_HEIGHT 16
|
||||
`define APB4_GA2D__FG_FORMAT_VALUE 0
|
||||
`define APB4_GA2D__BG_FORMAT_VALUE 0
|
||||
`define APB4_GA2D__DST_FORMAT_VALUE 0
|
||||
`define APB4_GA2D__FORMAT_CAPABILITY_FOREGROUND 0
|
||||
`define APB4_GA2D__FORMAT_CAPABILITY_BACKGROUND 8
|
||||
`define APB4_GA2D__FORMAT_CAPABILITY_DESTINATION 16
|
||||
|
||||
`define APB4_GA2D__CAPABILITY_FILL 0
|
||||
`define APB4_GA2D__CAPABILITY_COPY 1
|
||||
`define APB4_GA2D__CAPABILITY_CONVERT 2
|
||||
`define APB4_GA2D__CAPABILITY_BLEND 3
|
||||
`define APB4_GA2D__CAPABILITY_A8_MASK 4
|
||||
`define APB4_GA2D__CAPABILITY_PRIVATE_DMA 5
|
||||
`define APB4_GA2D__CAPABILITY_IRQ 6
|
||||
`define APB4_GA2D__CAPABILITY_SNAPSHOT 7
|
||||
`define APB4_GA2D__CAPABILITY_TWO_DIMENSIONAL_PITCH 8
|
||||
`define APB4_GA2D__CAPABILITY_BYTE_EDGES 9
|
||||
`define APB4_GA2D__CAPABILITY_INPLACE_BACKGROUND 10
|
||||
|
||||
`define APB4_GA2D__OP_FILL 0
|
||||
`define APB4_GA2D__OP_COPY 1
|
||||
`define APB4_GA2D__OP_CONVERT 2
|
||||
`define APB4_GA2D__OP_BLEND 3
|
||||
|
||||
`define APB4_GA2D__FORMAT_RGB565 0
|
||||
`define APB4_GA2D__FORMAT_RGB888 1
|
||||
`define APB4_GA2D__FORMAT_XRGB8888 2
|
||||
`define APB4_GA2D__FORMAT_ARGB8888 3
|
||||
`define APB4_GA2D__FORMAT_A8 4
|
||||
|
||||
`define APB4_GA2D__ERROR_NONE 0
|
||||
`define APB4_GA2D__ERROR_INVALID_SIZE 1
|
||||
`define APB4_GA2D__ERROR_INVALID_FORMAT 2
|
||||
`define APB4_GA2D__ERROR_INVALID_PITCH 3
|
||||
`define APB4_GA2D__ERROR_INVALID_ALIGNMENT 4
|
||||
`define APB4_GA2D__ERROR_ADDRESS_OVERFLOW 5
|
||||
`define APB4_GA2D__ERROR_ADDRESS_RANGE 6
|
||||
`define APB4_GA2D__ERROR_OVERLAP 7
|
||||
`define APB4_GA2D__ERROR_AXI_READ 8
|
||||
`define APB4_GA2D__ERROR_AXI_WRITE 9
|
||||
`define APB4_GA2D__ERROR_AXI_PROTOCOL 10
|
||||
`define APB4_GA2D__ERROR_TIMEOUT 11
|
||||
`define APB4_GA2D__ERROR_EPOCH_LOST 12
|
||||
`define APB4_GA2D__ERROR_INTERNAL 13
|
||||
|
||||
`define APB4_GA2D__ERROR_STAGE_NONE 0
|
||||
`define APB4_GA2D__ERROR_STAGE_VALIDATE 1
|
||||
`define APB4_GA2D__ERROR_STAGE_FOREGROUND 2
|
||||
`define APB4_GA2D__ERROR_STAGE_BACKGROUND 3
|
||||
`define APB4_GA2D__ERROR_STAGE_DESTINATION 4
|
||||
`define APB4_GA2D__ERROR_STAGE_LIFECYCLE 5
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
`include "ga2d_define.svh"
|
||||
|
||||
package ga2d_pkg;
|
||||
typedef enum logic [1:0] {
|
||||
Fill = `APB4_GA2D__OP_FILL,
|
||||
Copy = `APB4_GA2D__OP_COPY,
|
||||
Convert = `APB4_GA2D__OP_CONVERT,
|
||||
Blend = `APB4_GA2D__OP_BLEND
|
||||
} ga2d_operation_e;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
Rgb565 = `APB4_GA2D__FORMAT_RGB565,
|
||||
Rgb888 = `APB4_GA2D__FORMAT_RGB888,
|
||||
Xrgb8888 = `APB4_GA2D__FORMAT_XRGB8888,
|
||||
Argb8888 = `APB4_GA2D__FORMAT_ARGB8888,
|
||||
A8 = `APB4_GA2D__FORMAT_A8
|
||||
} ga2d_format_e;
|
||||
|
||||
typedef struct packed {
|
||||
logic [31:0] timeout_cycles;
|
||||
logic [31:0] job_config;
|
||||
logic [31:0] global_alpha;
|
||||
logic [31:0] color;
|
||||
logic [31:0] size;
|
||||
logic [31:0] fg_address;
|
||||
logic [31:0] fg_pitch;
|
||||
logic [31:0] fg_format;
|
||||
logic [31:0] bg_address;
|
||||
logic [31:0] bg_pitch;
|
||||
logic [31:0] bg_format;
|
||||
logic [31:0] dst_address;
|
||||
logic [31:0] dst_pitch;
|
||||
logic [31:0] dst_format;
|
||||
} ga2d_config_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic valid;
|
||||
logic [6:0] code;
|
||||
logic [3:0] stage;
|
||||
logic [1:0] axi_response;
|
||||
logic [31:0] address;
|
||||
} ga2d_error_t;
|
||||
endpackage
|
||||
@@ -0,0 +1,372 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
`include "ga2d_define.svh"
|
||||
|
||||
module ga2d_reg (
|
||||
// verilog_format: off -- preserve the APB, lifecycle, and event boundary columns
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic busy_i,
|
||||
input logic draining_i,
|
||||
input logic quiesced_i,
|
||||
input logic data_ready_i,
|
||||
input logic recovery_required_i,
|
||||
input logic idle_i,
|
||||
input logic done_i,
|
||||
input logic aborted_i,
|
||||
input logic [2:0] irq_event_i,
|
||||
input logic error_valid_i,
|
||||
input logic [6:0] error_code_i,
|
||||
input logic [3:0] error_stage_i,
|
||||
input logic [1:0] error_axi_response_i,
|
||||
input logic [31:0] error_address_i,
|
||||
apb4_if.slave apb4,
|
||||
output ga2d_pkg::ga2d_config_t config_o,
|
||||
output logic soft_reset_o,
|
||||
output logic abort_o,
|
||||
output logic idle_o,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
import ga2d_pkg::ga2d_config_t;
|
||||
import ga2d_pkg::ga2d_error_t;
|
||||
|
||||
localparam ga2d_config_t ConfigReset = '{
|
||||
timeout_cycles: `APB4_GA2D__TIMEOUT_CYCLES_RESET,
|
||||
job_config: '0,
|
||||
global_alpha: `APB4_GA2D__GLOBAL_ALPHA_RESET,
|
||||
color: '0,
|
||||
size: '0,
|
||||
fg_address: '0,
|
||||
fg_pitch: '0,
|
||||
fg_format: '0,
|
||||
bg_address: '0,
|
||||
bg_pitch: '0,
|
||||
bg_format: '0,
|
||||
dst_address: '0,
|
||||
dst_pitch: '0,
|
||||
dst_format: '0
|
||||
};
|
||||
|
||||
logic s_apb4_ready_d, s_apb4_ready_q;
|
||||
logic s_access_seen_d, s_access_seen_q;
|
||||
logic [31:0] s_apb4_rdata_d, s_apb4_rdata_q;
|
||||
logic s_apb4_resp_err_d, s_apb4_resp_err_q;
|
||||
ga2d_config_t s_config_d, s_config_q;
|
||||
ga2d_error_t s_err_d, s_err_q;
|
||||
logic [2:0] s_irq_state_d, s_irq_state_q;
|
||||
logic [2:0] s_irq_en_d, s_irq_en_q;
|
||||
logic s_req_accept;
|
||||
logic s_write;
|
||||
logic [11:0] s_offset;
|
||||
logic [31:0] s_write_value;
|
||||
logic [31:0] s_read_data;
|
||||
logic s_read_valid;
|
||||
logic s_read_err;
|
||||
logic s_write_err;
|
||||
logic [ 2:0] s_irq_clear;
|
||||
logic [ 2:0] s_irq_test;
|
||||
logic s_err_clear;
|
||||
logic s_cmd_soft_reset;
|
||||
logic s_cmd_abort;
|
||||
|
||||
assign s_req_accept = apb4.psel && apb4.penable && !s_access_seen_q;
|
||||
assign s_write = s_req_accept && apb4.pwrite;
|
||||
assign s_offset = apb4.paddr[11:0];
|
||||
assign s_write_value = apb4.pwdata;
|
||||
|
||||
assign apb4.pready = s_apb4_ready_q;
|
||||
assign apb4.prdata = s_apb4_rdata_q;
|
||||
assign apb4.pslverr = s_apb4_resp_err_q;
|
||||
assign config_o = s_config_q;
|
||||
assign soft_reset_o = s_cmd_soft_reset;
|
||||
assign abort_o = s_cmd_abort;
|
||||
assign idle_o = idle_i;
|
||||
assign irq_o = (s_irq_state_q & s_irq_en_q) != 3'd0;
|
||||
|
||||
always_comb begin
|
||||
s_read_data = 32'd0;
|
||||
s_read_valid = 1'b1;
|
||||
unique case (s_offset)
|
||||
`APB4_GA2D__IP_ID: s_read_data = `APB4_GA2D__IP_ID_VALUE;
|
||||
`APB4_GA2D__IP_VERSION: s_read_data = `APB4_GA2D__IP_VERSION_VALUE;
|
||||
`APB4_GA2D__CAPABILITY: s_read_data = `APB4_GA2D__CAPABILITY_P3;
|
||||
`APB4_GA2D__LIMITS: s_read_data = `APB4_GA2D__LIMITS_P3;
|
||||
`APB4_GA2D__STATUS:
|
||||
s_read_data = {
|
||||
24'd0,
|
||||
recovery_required_i,
|
||||
s_err_q.valid,
|
||||
aborted_i,
|
||||
done_i,
|
||||
data_ready_i,
|
||||
quiesced_i,
|
||||
draining_i,
|
||||
busy_i
|
||||
};
|
||||
`APB4_GA2D__IRQ_STATE: s_read_data = {29'd0, s_irq_state_q};
|
||||
`APB4_GA2D__IRQ_ENABLE: s_read_data = {29'd0, s_irq_en_q};
|
||||
`APB4_GA2D__ERROR_STATUS:
|
||||
s_read_data = {18'd0, s_err_q.axi_response, s_err_q.stage, s_err_q.code, s_err_q.valid};
|
||||
`APB4_GA2D__ERROR_ADDRESS: s_read_data = s_err_q.address;
|
||||
`APB4_GA2D__TIMEOUT_CYCLES: s_read_data = s_config_q.timeout_cycles;
|
||||
`APB4_GA2D__JOB_CONFIG: s_read_data = s_config_q.job_config;
|
||||
`APB4_GA2D__GLOBAL_ALPHA: s_read_data = s_config_q.global_alpha;
|
||||
`APB4_GA2D__COLOR: s_read_data = s_config_q.color;
|
||||
`APB4_GA2D__SIZE: s_read_data = s_config_q.size;
|
||||
`APB4_GA2D__FG_ADDRESS: s_read_data = s_config_q.fg_address;
|
||||
`APB4_GA2D__FG_PITCH: s_read_data = s_config_q.fg_pitch;
|
||||
`APB4_GA2D__FG_FORMAT: s_read_data = s_config_q.fg_format;
|
||||
`APB4_GA2D__BG_ADDRESS: s_read_data = s_config_q.bg_address;
|
||||
`APB4_GA2D__BG_PITCH: s_read_data = s_config_q.bg_pitch;
|
||||
`APB4_GA2D__BG_FORMAT: s_read_data = s_config_q.bg_format;
|
||||
`APB4_GA2D__DST_ADDRESS: s_read_data = s_config_q.dst_address;
|
||||
`APB4_GA2D__DST_PITCH: s_read_data = s_config_q.dst_pitch;
|
||||
`APB4_GA2D__DST_FORMAT: s_read_data = s_config_q.dst_format;
|
||||
`APB4_GA2D__FORMAT_CAPABILITY: s_read_data = `APB4_GA2D__FORMAT_CAPABILITY_P3;
|
||||
`APB4_GA2D__SNAP_CYCLES_LO,
|
||||
`APB4_GA2D__SNAP_CYCLES_HI,
|
||||
`APB4_GA2D__SNAP_READ_BYTES_LO,
|
||||
`APB4_GA2D__SNAP_READ_BYTES_HI,
|
||||
`APB4_GA2D__SNAP_WRITE_BYTES_LO,
|
||||
`APB4_GA2D__SNAP_WRITE_BYTES_HI,
|
||||
`APB4_GA2D__SNAP_READ_STALL_LO,
|
||||
`APB4_GA2D__SNAP_READ_STALL_HI,
|
||||
`APB4_GA2D__SNAP_WRITE_STALL_LO,
|
||||
`APB4_GA2D__SNAP_WRITE_STALL_HI,
|
||||
`APB4_GA2D__SNAP_PIPE_STALL_LO,
|
||||
`APB4_GA2D__SNAP_PIPE_STALL_HI,
|
||||
`APB4_GA2D__SNAP_LINES_DONE,
|
||||
`APB4_GA2D__COMMAND,
|
||||
`APB4_GA2D__IRQ_TEST,
|
||||
`APB4_GA2D__PERF_SNAPSHOT: begin
|
||||
end
|
||||
default: s_read_valid = 1'b0;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_read_err = (s_offset[1:0] != 2'b00) || !s_read_valid;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_write_err = 1'b0;
|
||||
s_irq_clear = 3'd0;
|
||||
s_irq_test = 3'd0;
|
||||
s_err_clear = 1'b0;
|
||||
s_cmd_soft_reset = 1'b0;
|
||||
s_cmd_abort = 1'b0;
|
||||
if (s_write) begin
|
||||
if ((s_offset[1:0] != 2'b00) || (apb4.pstrb != 4'hf)) begin
|
||||
s_write_err = 1'b1;
|
||||
end else begin
|
||||
unique case (s_offset)
|
||||
`APB4_GA2D__COMMAND: begin
|
||||
unique case (s_write_value)
|
||||
32'd0: begin
|
||||
end
|
||||
32'h0000_0001: s_write_err = 1'b1;
|
||||
32'h0000_0002: s_cmd_abort = 1'b1;
|
||||
32'h0000_0004: begin
|
||||
if (busy_i || draining_i || recovery_required_i || !idle_i || !data_ready_i) begin
|
||||
s_write_err = 1'b1;
|
||||
end else begin
|
||||
s_cmd_soft_reset = 1'b1;
|
||||
end
|
||||
end
|
||||
default: s_write_err = 1'b1;
|
||||
endcase
|
||||
end
|
||||
`APB4_GA2D__IRQ_STATE: begin
|
||||
if (s_write_value[31:3] != '0) begin
|
||||
s_write_err = 1'b1;
|
||||
end else begin
|
||||
s_irq_clear = s_write_value[2:0];
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__IRQ_ENABLE: begin
|
||||
if (s_write_value[31:3] != '0) begin
|
||||
s_write_err = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__IRQ_TEST: begin
|
||||
if (s_write_value[31:3] != '0) begin
|
||||
s_write_err = 1'b1;
|
||||
end else begin
|
||||
s_irq_test = s_write_value[2:0];
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__ERROR_STATUS: begin
|
||||
if (busy_i || recovery_required_i ||
|
||||
((s_write_value != 32'd0) && (s_write_value != 32'd1))) begin
|
||||
s_write_err = 1'b1;
|
||||
end else if (s_write_value == 32'd1) begin
|
||||
s_err_clear = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__TIMEOUT_CYCLES: begin
|
||||
if (busy_i || (s_write_value == 32'd0)) begin
|
||||
s_write_err = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__JOB_CONFIG: begin
|
||||
if (busy_i || (s_write_value[31:2] != '0)) begin
|
||||
s_write_err = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__GLOBAL_ALPHA: begin
|
||||
if (busy_i || (s_write_value[31:8] != '0)) begin
|
||||
s_write_err = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__COLOR,
|
||||
`APB4_GA2D__SIZE,
|
||||
`APB4_GA2D__FG_ADDRESS,
|
||||
`APB4_GA2D__FG_PITCH,
|
||||
`APB4_GA2D__BG_ADDRESS,
|
||||
`APB4_GA2D__BG_PITCH,
|
||||
`APB4_GA2D__DST_ADDRESS,
|
||||
`APB4_GA2D__DST_PITCH: begin
|
||||
if (busy_i) begin
|
||||
s_write_err = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__FG_FORMAT, `APB4_GA2D__BG_FORMAT, `APB4_GA2D__DST_FORMAT: begin
|
||||
if (busy_i || (s_write_value[31:3] != '0)) begin
|
||||
s_write_err = 1'b1;
|
||||
end
|
||||
end
|
||||
`APB4_GA2D__PERF_SNAPSHOT: s_write_err = 1'b1;
|
||||
default: s_write_err = 1'b1;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_apb4_ready_d = s_req_accept;
|
||||
s_access_seen_d = s_access_seen_q;
|
||||
if (!apb4.psel || !apb4.penable) begin
|
||||
s_access_seen_d = 1'b0;
|
||||
end else if (s_req_accept) begin
|
||||
s_access_seen_d = 1'b1;
|
||||
end
|
||||
s_apb4_rdata_d = s_apb4_rdata_q;
|
||||
s_apb4_resp_err_d = s_req_accept && (s_write ? s_write_err : s_read_err);
|
||||
if (s_req_accept) begin
|
||||
s_apb4_rdata_d = (!s_write && !s_read_err) ? s_read_data : 32'd0;
|
||||
end
|
||||
|
||||
s_config_d = s_config_q;
|
||||
s_irq_state_d = (s_irq_state_q & ~s_irq_clear) | irq_event_i | s_irq_test;
|
||||
s_irq_en_d = s_irq_en_q;
|
||||
s_err_d = s_err_q;
|
||||
|
||||
if (s_err_clear) begin
|
||||
s_err_d = '0;
|
||||
end
|
||||
if (error_valid_i && !s_err_q.valid) begin
|
||||
s_err_d = '{
|
||||
valid: 1'b1,
|
||||
code: error_code_i,
|
||||
stage: error_stage_i,
|
||||
axi_response: error_axi_response_i,
|
||||
address: error_address_i
|
||||
};
|
||||
end
|
||||
|
||||
if (s_cmd_soft_reset) begin
|
||||
s_config_d = ConfigReset;
|
||||
s_irq_state_d = '0;
|
||||
s_irq_en_d = '0;
|
||||
s_err_d = '0;
|
||||
end else if (s_write && !s_write_err) begin
|
||||
unique case (s_offset)
|
||||
`APB4_GA2D__IRQ_ENABLE: s_irq_en_d = s_write_value[2:0];
|
||||
`APB4_GA2D__TIMEOUT_CYCLES: s_config_d.timeout_cycles = s_write_value;
|
||||
`APB4_GA2D__JOB_CONFIG: s_config_d.job_config = s_write_value;
|
||||
`APB4_GA2D__GLOBAL_ALPHA: s_config_d.global_alpha = s_write_value;
|
||||
`APB4_GA2D__COLOR: s_config_d.color = s_write_value;
|
||||
`APB4_GA2D__SIZE: s_config_d.size = s_write_value;
|
||||
`APB4_GA2D__FG_ADDRESS: s_config_d.fg_address = s_write_value;
|
||||
`APB4_GA2D__FG_PITCH: s_config_d.fg_pitch = s_write_value;
|
||||
`APB4_GA2D__FG_FORMAT: s_config_d.fg_format = s_write_value;
|
||||
`APB4_GA2D__BG_ADDRESS: s_config_d.bg_address = s_write_value;
|
||||
`APB4_GA2D__BG_PITCH: s_config_d.bg_pitch = s_write_value;
|
||||
`APB4_GA2D__BG_FORMAT: s_config_d.bg_format = s_write_value;
|
||||
`APB4_GA2D__DST_ADDRESS: s_config_d.dst_address = s_write_value;
|
||||
`APB4_GA2D__DST_PITCH: s_config_d.dst_pitch = s_write_value;
|
||||
`APB4_GA2D__DST_FORMAT: s_config_d.dst_format = s_write_value;
|
||||
default: begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_apb4_ready (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_apb4_ready_d),
|
||||
.dat_o (s_apb4_ready_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_access_seen (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_access_seen_d),
|
||||
.dat_o (s_access_seen_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_apb4_rdata (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_apb4_rdata_d),
|
||||
.dat_o (s_apb4_rdata_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_apb4_resp_err (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_apb4_resp_err_d),
|
||||
.dat_o (s_apb4_resp_err_q)
|
||||
);
|
||||
dffrc #(
|
||||
.DATA_WIDTH($bits(ga2d_config_t)),
|
||||
.RESET_VAL (ConfigReset)
|
||||
) u_config (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_config_d),
|
||||
.dat_o (s_config_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH($bits(ga2d_error_t))
|
||||
) u_error (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_err_d),
|
||||
.dat_o (s_err_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(3)
|
||||
) u_irq_state (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_irq_state_d),
|
||||
.dat_o (s_irq_state_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(3)
|
||||
) u_irq_enable (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_irq_en_d),
|
||||
.dat_o (s_irq_en_q)
|
||||
);
|
||||
endmodule
|
||||
@@ -409,12 +409,12 @@
|
||||
"user_access": "rw"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_GA",
|
||||
"symbol": "APB4_GA2D",
|
||||
"base": "0x10012000",
|
||||
"size": "0x00001000",
|
||||
"route": "reserved",
|
||||
"kind": "reserved",
|
||||
"public": false,
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -144,6 +144,9 @@
|
||||
/ip/multimedia/apu_codec_controller.sv
|
||||
/ip/multimedia/apu_reg.sv
|
||||
/ip/multimedia/apb4_apu.sv
|
||||
/ip/multimedia/ga2d_pkg.sv
|
||||
/ip/multimedia/ga2d_reg.sv
|
||||
/ip/multimedia/apb4_ga2d.sv
|
||||
/ip/multimedia/jpeg_pkg.sv
|
||||
/ip/multimedia/jpeg_transform.sv
|
||||
/ip/multimedia/jpeg_quantizer.sv
|
||||
|
||||
@@ -5,11 +5,12 @@ that is not part of the software address-map ABI or the package pad map.
|
||||
|
||||
[GA2D](../../../docs/ip/ga2d.md) Phase 2 expands the topology to data
|
||||
master/resource 8 and seven-bit global IDs while retaining all existing
|
||||
allocations. It adds only a dedicated PCLK-to-HP AXI64/ID3 GA2D bridge whose
|
||||
source is held idle. `APB4_GA` remains reserved and inactive; the GA2D APB
|
||||
shell, IRQ wiring, payload/DMA, and pixel function remain deferred to later
|
||||
phases. Phase 3 appends APB slot 28 and GA2D's LP32/HP PLIC11 interrupt. The
|
||||
Xh3irq SDK path also requires the Phase 1 implementation; a wiring-only
|
||||
allocations. It adds a dedicated PCLK-to-HP AXI64/ID3 GA2D bridge whose source
|
||||
remains idle. Phase 3 activates `APB4_GA2D` at slot 28 as a PCLK register
|
||||
shell and routes its raw IRQ through resource 8: LP group bit 24, core vector
|
||||
bit 32/external ordinal 30, or HP PLIC source 11 according to owner. The shell
|
||||
exposes IRQ-only capability; payload/DMA, pixel work, and START remain deferred.
|
||||
The Xh3irq SDK path also requires the Phase 1 implementation; a wiring-only
|
||||
expansion is insufficient.
|
||||
|
||||
The topology generator validates APB4 island ownership against
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"irq_groups": [
|
||||
{
|
||||
"name": "apb4_periph",
|
||||
"width": 24,
|
||||
"width": 25,
|
||||
"top_signal": "s_apb4_periph_irq"
|
||||
},
|
||||
{
|
||||
@@ -285,6 +285,15 @@
|
||||
"core_bit": 31,
|
||||
"signal": "resource_irq_lp_i[6]",
|
||||
"user_visible": false
|
||||
},
|
||||
{
|
||||
"name": "ga2d",
|
||||
"description": "GA2D shell completion and error interrupt",
|
||||
"group": "apb4_periph",
|
||||
"group_bit": 24,
|
||||
"core_bit": 32,
|
||||
"signal": "resource_irq_lp_i[7]",
|
||||
"user_visible": false
|
||||
}
|
||||
],
|
||||
"wake_sources": [
|
||||
@@ -624,6 +633,13 @@
|
||||
"timed_interface": "u_apu_apb4_if",
|
||||
"pure_interface": "u_apu_apb4_pure_if",
|
||||
"region": "APB4_APU"
|
||||
},
|
||||
{
|
||||
"slot": 28,
|
||||
"name": "ga2d",
|
||||
"timed_interface": "u_ga2d_apb4_if",
|
||||
"pure_interface": "u_ga2d_apb4_pure_if",
|
||||
"region": "APB4_GA2D"
|
||||
}
|
||||
],
|
||||
"apb4_system_targets": [
|
||||
|
||||
@@ -103,6 +103,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/dma.c \
|
||||
$(ROOT_PATH)/crt/src/hal/crypto.c \
|
||||
$(ROOT_PATH)/crt/src/hal/apu.c \
|
||||
$(ROOT_PATH)/crt/src/hal/ga2d.c \
|
||||
$(ROOT_PATH)/crt/src/hal/jpeg_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/jpeg.c \
|
||||
$(ROOT_PATH)/crt/src/hal/dvp.c \
|
||||
|
||||
@@ -23,8 +23,8 @@ module apb4_periph (
|
||||
input logic debug_halted_i,
|
||||
input logic timebase_tick_i,
|
||||
input logic ext_h_hp_irq_i,
|
||||
input logic [6:0] resource_irq_lp_i,
|
||||
input logic [6:0] resource_irq_hp_i,
|
||||
input logic [7:0] resource_irq_lp_i,
|
||||
input logic [7:0] resource_irq_hp_i,
|
||||
input logic [1:0] apu_owner_i,
|
||||
input logic apu_owner_lock_i,
|
||||
input logic apu_quiesce_i,
|
||||
@@ -32,6 +32,14 @@ module apb4_periph (
|
||||
input logic [7:0] apu_bridge_epoch_i,
|
||||
input logic jpeg_quiesce_i,
|
||||
input logic jpeg_reset_i,
|
||||
input logic ga2d_quiesce_i,
|
||||
input logic ga2d_reset_i,
|
||||
input logic ga2d_source_stop_i,
|
||||
input logic ga2d_source_safe_idle_i,
|
||||
input logic ga2d_block_ack_i,
|
||||
input logic ga2d_bridge_clear_busy_i,
|
||||
input logic [7:0] ga2d_bridge_epoch_i,
|
||||
input logic ga2d_data_ready_i,
|
||||
axi4_if.slave cfg_axi4,
|
||||
axi4_if.slave psram_axi4,
|
||||
axi4_if.slave xpi_axi4,
|
||||
@@ -75,7 +83,8 @@ module apb4_periph (
|
||||
output logic hp_supervisor_external_irq_o,
|
||||
output logic apu_idle_o,
|
||||
output logic jpeg_idle_o,
|
||||
output logic [6:0] resource_irq_raw_o,
|
||||
output logic ga2d_idle_o,
|
||||
output logic [7:0] resource_irq_raw_o,
|
||||
output logic [`SOC_IRQ_APB4_PERIPH_WIDTH-1:0] irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
@@ -179,6 +188,7 @@ axi4_stream_if #(
|
||||
logic s_apu_irq_raw;
|
||||
logic s_i2s_tx_underrun_evt, s_i2s_rx_overrun_evt;
|
||||
logic s_jpeg_irq_raw;
|
||||
logic s_ga2d_irq_raw;
|
||||
logic s_usb2_irq;
|
||||
logic s_tim0_irq, s_tim1_irq;
|
||||
logic s_dvp_irq;
|
||||
@@ -237,7 +247,14 @@ axi4_stream_if #(
|
||||
assign hp_machine_external_irq_o = s_hp_plic_context_irq[0];
|
||||
assign hp_supervisor_external_irq_o = s_hp_plic_context_irq[1];
|
||||
assign resource_irq_raw_o = {
|
||||
s_apu_irq_raw, s_jpeg_irq_raw, spisd.irq_o, sdio1.irq_o, sdio0.irq_o, s_usb2_irq, s_dma_irq
|
||||
s_ga2d_irq_raw,
|
||||
s_apu_irq_raw,
|
||||
s_jpeg_irq_raw,
|
||||
spisd.irq_o,
|
||||
sdio1.irq_o,
|
||||
sdio0.irq_o,
|
||||
s_usb2_irq,
|
||||
s_dma_irq
|
||||
};
|
||||
|
||||
apb4_async_bridge u_psram_cfg_mem_cdc (
|
||||
@@ -319,6 +336,7 @@ axi4_stream_if #(
|
||||
s_hp_plic_source[8] = resource_irq_hp_i[4];
|
||||
s_hp_plic_source[9] = resource_irq_hp_i[5];
|
||||
s_hp_plic_source[10] = resource_irq_hp_i[6];
|
||||
s_hp_plic_source[11] = resource_irq_hp_i[7];
|
||||
end
|
||||
|
||||
`include "apb4_periph_irq_bindings.svh"
|
||||
@@ -519,6 +537,22 @@ axi4_stream_if #(
|
||||
.irq_o (s_apu_irq_raw)
|
||||
);
|
||||
|
||||
apb4_ga2d u_apb4_ga2d (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.resource_quiesce_i (ga2d_quiesce_i),
|
||||
.resource_reset_i (ga2d_reset_i),
|
||||
.source_stop_i (ga2d_source_stop_i),
|
||||
.source_safe_idle_i (ga2d_source_safe_idle_i),
|
||||
.block_ack_i (ga2d_block_ack_i),
|
||||
.bridge_clear_busy_i(ga2d_bridge_clear_busy_i),
|
||||
.bridge_epoch_i (ga2d_bridge_epoch_i),
|
||||
.data_ready_i (ga2d_data_ready_i),
|
||||
.apb4 (u_ga2d_apb4_if),
|
||||
.idle_o (ga2d_idle_o),
|
||||
.irq_o (s_ga2d_irq_raw)
|
||||
);
|
||||
|
||||
apb4_sysctrl u_apb4_sysctrl (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
|
||||
+15
-13
@@ -25,7 +25,7 @@ module apb4_system (
|
||||
input logic ext_h_data_idle_i,
|
||||
input logic [8:0] resource_idle_i,
|
||||
input logic [8:0] resource_block_ack_i,
|
||||
input logic [6:0] resource_irq_i,
|
||||
input logic [7:0] resource_irq_i,
|
||||
input logic cache_request_i,
|
||||
axi4_if.slave axi4,
|
||||
axi4_if.master ext_h_axi4,
|
||||
@@ -49,8 +49,8 @@ module apb4_system (
|
||||
output logic [8:0] resource_owner_lock_o,
|
||||
output logic [8:0] resource_quiesce_o,
|
||||
output logic [8:0] resource_reset_o,
|
||||
output logic [6:0] resource_irq_lp_o,
|
||||
output logic [6:0] resource_irq_hp_o,
|
||||
output logic [7:0] resource_irq_lp_o,
|
||||
output logic [7:0] resource_irq_hp_o,
|
||||
output logic [`SOC_IRQ_APB4_SYSTEM_WIDTH-1:0] irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
@@ -112,17 +112,19 @@ module apb4_system (
|
||||
logic s_unused_product_input;
|
||||
`endif
|
||||
|
||||
assign s_resource_irq = {1'b0, resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]};
|
||||
assign s_ext_h_irq = s_resource_irq_lp[5];
|
||||
assign ext_h_irq_raw_o = s_ext_h_irq_raw;
|
||||
assign ext_h_owner_o = s_resource_owner[5];
|
||||
assign cache_clean_o = s_cache_clean;
|
||||
assign resource_owner_o = s_resource_owner;
|
||||
assign s_resource_irq = {
|
||||
resource_irq_i[7], resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]
|
||||
};
|
||||
assign s_ext_h_irq = s_resource_irq_lp[5];
|
||||
assign ext_h_irq_raw_o = s_ext_h_irq_raw;
|
||||
assign ext_h_owner_o = s_resource_owner[5];
|
||||
assign cache_clean_o = s_cache_clean;
|
||||
assign resource_owner_o = s_resource_owner;
|
||||
assign resource_owner_lock_o = s_resource_owner_lock;
|
||||
assign resource_quiesce_o = s_resource_quiesce;
|
||||
assign resource_reset_o = s_resource_reset;
|
||||
assign resource_irq_lp_o = {s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]};
|
||||
assign resource_irq_hp_o = {s_resource_irq_hp[7:6], s_resource_irq_hp[4:0]};
|
||||
assign resource_quiesce_o = s_resource_quiesce;
|
||||
assign resource_reset_o = s_resource_reset;
|
||||
assign resource_irq_lp_o = {s_resource_irq_lp[8], s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]};
|
||||
assign resource_irq_hp_o = {s_resource_irq_hp[8], s_resource_irq_hp[7:6], s_resource_irq_hp[4:0]};
|
||||
|
||||
`ifdef PDK_IHP130
|
||||
localparam logic [31:0] ARCHINFO_TECHNOLOGY = 32'h0201_0082;
|
||||
|
||||
@@ -252,11 +252,12 @@ module retrosoc (
|
||||
logic [ 8:0] s_resource_idle_pclk;
|
||||
logic [ 8:0] s_resource_block_ack_hp;
|
||||
logic [ 8: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;
|
||||
logic [ 7:0] s_resource_irq_raw;
|
||||
logic [ 7:0] s_resource_irq_lp;
|
||||
logic [ 7:0] s_resource_irq_hp;
|
||||
logic s_apu_idle;
|
||||
logic s_jpeg_idle;
|
||||
logic s_ga2d_idle;
|
||||
logic [ 8:0] s_resource_idle_combined;
|
||||
logic [ 8:0] s_resource_block_ack_combined;
|
||||
logic s_ga2d_source_stop;
|
||||
@@ -869,6 +870,14 @@ module retrosoc (
|
||||
.apu_bridge_epoch_i (s_apu_bridge_epoch),
|
||||
.jpeg_quiesce_i (s_resource_quiesce[6]),
|
||||
.jpeg_reset_i (s_resource_reset[6]),
|
||||
.ga2d_quiesce_i (s_resource_quiesce[8]),
|
||||
.ga2d_reset_i (s_resource_reset[8]),
|
||||
.ga2d_source_stop_i (s_ga2d_source_stop),
|
||||
.ga2d_source_safe_idle_i (s_ga2d_source_safe_idle),
|
||||
.ga2d_block_ack_i (s_resource_block_ack_pclk[8]),
|
||||
.ga2d_bridge_clear_busy_i (s_ga2d_bridge_clear_busy),
|
||||
.ga2d_bridge_epoch_i (s_ga2d_bridge_epoch),
|
||||
.ga2d_data_ready_i (s_ga2d_data_ready),
|
||||
.cfg_axi4 (u_cfg_pclk_axi4_if),
|
||||
.dma_axi4 (u_dma_axi4_if),
|
||||
.sdio0_axi4 (u_sdio0_axi4_if),
|
||||
@@ -913,6 +922,7 @@ module retrosoc (
|
||||
.resource_irq_raw_o (s_resource_irq_raw),
|
||||
.apu_idle_o (s_apu_idle),
|
||||
.jpeg_idle_o (s_jpeg_idle),
|
||||
.ga2d_idle_o (s_ga2d_idle),
|
||||
.irq_o (s_apb4_periph_irq)
|
||||
);
|
||||
|
||||
@@ -963,14 +973,14 @@ module retrosoc (
|
||||
);
|
||||
|
||||
assign s_resource_idle_combined = {
|
||||
s_ga2d_source_safe_idle && s_resource_idle_pclk[8],
|
||||
s_ga2d_idle && s_ga2d_source_safe_idle && s_resource_idle_pclk[8],
|
||||
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_ga2d_source_safe_idle && s_resource_block_ack_pclk[8],
|
||||
s_ga2d_idle && s_ga2d_source_safe_idle && s_resource_block_ack_pclk[8],
|
||||
s_apu_idle && s_resource_block_ack_pclk[7],
|
||||
s_resource_block_ack_pclk[6:0]
|
||||
};
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
],
|
||||
"rtl/ip/multimedia": [
|
||||
"apb4_apu.sv",
|
||||
"apb4_ga2d.sv",
|
||||
"apb4_jpeg.sv",
|
||||
"apu_bitstream_engine.sv",
|
||||
"apu_codec_controller.sv",
|
||||
@@ -158,6 +159,9 @@
|
||||
"dvp_core.sv",
|
||||
"dvp_define.svh",
|
||||
"dvp_reg.sv",
|
||||
"ga2d_define.svh",
|
||||
"ga2d_pkg.sv",
|
||||
"ga2d_reg.sv",
|
||||
"jpeg_bit_packer.sv",
|
||||
"jpeg_bit_reader.sv",
|
||||
"jpeg_block_decoder.sv",
|
||||
|
||||
@@ -34,6 +34,7 @@ TEST_SOURCES = (
|
||||
"crt/src/hal/dma_math.c",
|
||||
"crt/src/hal/jpeg_math.c",
|
||||
"crt/src/hal/apu.c",
|
||||
"crt/src/hal/ga2d.c",
|
||||
"crt/src/hal/fabric_monitor.c",
|
||||
"crt/src/hal/sysctrl.c",
|
||||
"crt/src/hal/clock.c",
|
||||
@@ -96,6 +97,7 @@ def main() -> int:
|
||||
"-Werror",
|
||||
"-fno-builtin",
|
||||
"-DRS_APU_TEST_MMIO",
|
||||
"-DRS_GA2D_TEST_MMIO",
|
||||
"-DRS_FABRIC_MONITOR_TEST_MMIO",
|
||||
"-I",
|
||||
str(memory_map_root / "include"),
|
||||
|
||||
+102
-4
@@ -12,6 +12,7 @@
|
||||
#include <retrosoc/hal/extension.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/fabric_monitor.h>
|
||||
#include <retrosoc/hal/ga2d.h>
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
#include <retrosoc/hal/lcd.h>
|
||||
#include <retrosoc/hal/i2s.h>
|
||||
@@ -45,9 +46,11 @@ unsigned long long __umoddi3(unsigned long long dividend, unsigned long long div
|
||||
static uint8_t storage[32];
|
||||
static uint32_t image_call_count;
|
||||
volatile uint32_t rs_apu_test_mmio[1024];
|
||||
volatile uint32_t rs_ga2d_test_mmio[1024];
|
||||
volatile uint32_t rs_fabric_monitor_test_mmio[1024];
|
||||
|
||||
#define APU_TEST_REG(offset) rs_apu_test_mmio[(offset) / 4U]
|
||||
#define APU_TEST_REG(offset) rs_apu_test_mmio[(offset) / 4U]
|
||||
#define GA2D_TEST_REG(offset) rs_ga2d_test_mmio[(offset) / 4U]
|
||||
#define FABRIC_MONITOR_TEST_REG(offset) rs_fabric_monitor_test_mmio[(offset) / 4U]
|
||||
|
||||
void putch(char ch) {
|
||||
@@ -899,9 +902,9 @@ static int test_fabric_monitor_hal_contract(void) {
|
||||
|
||||
test_fabric_monitor_mmio_reset();
|
||||
FABRIC_MONITOR_TEST_REG(UINT32_C(0x004)) = UINT32_C(0x00010000);
|
||||
FABRIC_MONITOR_TEST_REG(UINT32_C(0x014)) =
|
||||
UINT32_C(0x00001000) | UINT32_C(0x0A00) | UINT32_C(0x0080) | UINT32_C(0x000C) |
|
||||
UINT32_C(0x0003);
|
||||
FABRIC_MONITOR_TEST_REG(UINT32_C(0x014)) = UINT32_C(0x00001000) | UINT32_C(0x0A00) |
|
||||
UINT32_C(0x0080) | UINT32_C(0x000C) |
|
||||
UINT32_C(0x0003);
|
||||
FABRIC_MONITOR_TEST_REG(UINT32_C(0x018)) = UINT32_C(0x12345678);
|
||||
FABRIC_MONITOR_TEST_REG(UINT32_C(0x020)) = UINT32_C(0x0000002A);
|
||||
if ((rs_fabric_monitor_read_fault(&fault) != RS_OK) || (fault.master != 3U) ||
|
||||
@@ -1108,6 +1111,100 @@ static int test_apu_hal_contract(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_ga2d_mmio_reset(void) {
|
||||
for (size_t index = 0U; index < (sizeof(rs_ga2d_test_mmio) / sizeof(rs_ga2d_test_mmio[0]));
|
||||
++index) {
|
||||
rs_ga2d_test_mmio[index] = 0U;
|
||||
}
|
||||
GA2D_TEST_REG(RS_GA2D_REG_IP_ID) = RS_GA2D_IP_ID_VALUE;
|
||||
GA2D_TEST_REG(RS_GA2D_REG_IP_VERSION) = RS_GA2D_IP_VERSION_VALUE;
|
||||
GA2D_TEST_REG(RS_GA2D_REG_CAPABILITY) = RS_GA2D_CAPABILITY_P3;
|
||||
GA2D_TEST_REG(RS_GA2D_REG_STATUS) = RS_GA2D_STATUS_DATA_READY;
|
||||
}
|
||||
|
||||
static int test_ga2d_hal_contract(void) {
|
||||
rs_ga2d_capability_t capability;
|
||||
rs_ga2d_status_t status;
|
||||
rs_ga2d_error_t error;
|
||||
rs_ga2d_stats_t stats;
|
||||
rs_ga2d_job_t job = {0};
|
||||
|
||||
test_ga2d_mmio_reset();
|
||||
if ((rs_ga2d_get_capability(NULL) != RS_EINVAL) ||
|
||||
(rs_ga2d_get_capability(&capability) != RS_OK) ||
|
||||
(capability.version != RS_GA2D_IP_VERSION_VALUE) ||
|
||||
(capability.features != RS_GA2D_CAPABILITY_P3) || (capability.limits != 0U) ||
|
||||
(capability.formats != 0U)) {
|
||||
return 1;
|
||||
}
|
||||
GA2D_TEST_REG(RS_GA2D_REG_IP_VERSION) = UINT32_C(0x00020000);
|
||||
if (rs_ga2d_get_capability(&capability) != RS_ENOTSUP) {
|
||||
return 2;
|
||||
}
|
||||
test_ga2d_mmio_reset();
|
||||
GA2D_TEST_REG(RS_GA2D_REG_COMMAND) = UINT32_C(0xA5A5A5A5);
|
||||
if ((rs_ga2d_job_validate(NULL) != RS_EINVAL) || (rs_ga2d_job_validate(&job) != RS_ENOTSUP) ||
|
||||
(rs_ga2d_configure(NULL) != RS_EINVAL) || (rs_ga2d_configure(&job) != RS_ENOTSUP) ||
|
||||
(rs_ga2d_start() != RS_ENOTSUP) || (rs_ga2d_wait(1U) != RS_ENOTSUP) ||
|
||||
(rs_ga2d_get_stats(NULL) != RS_EINVAL) || (rs_ga2d_get_stats(&stats) != RS_ENOTSUP) ||
|
||||
(GA2D_TEST_REG(RS_GA2D_REG_COMMAND) != UINT32_C(0xA5A5A5A5))) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
GA2D_TEST_REG(RS_GA2D_REG_STATUS) =
|
||||
RS_GA2D_STATUS_BUSY | RS_GA2D_STATUS_DATA_READY | RS_GA2D_STATUS_ERROR;
|
||||
GA2D_TEST_REG(RS_GA2D_REG_IRQ_STATE) = RS_GA2D_IRQ_DONE | RS_GA2D_IRQ_ABORT_DONE;
|
||||
if ((rs_ga2d_get_status(NULL) != RS_EINVAL) || (rs_ga2d_get_status(&status) != RS_OK) ||
|
||||
!status.busy || !status.data_ready || !status.error ||
|
||||
(status.irq_state != (RS_GA2D_IRQ_DONE | RS_GA2D_IRQ_ABORT_DONE))) {
|
||||
return 4;
|
||||
}
|
||||
GA2D_TEST_REG(RS_GA2D_REG_ERROR_STATUS) =
|
||||
RS_GA2D_ERROR_STATUS_VALID | (UINT32_C(11) << RS_GA2D_ERROR_STATUS_CODE_SHIFT) |
|
||||
(UINT32_C(5) << RS_GA2D_ERROR_STATUS_STAGE_SHIFT) |
|
||||
(UINT32_C(2) << RS_GA2D_ERROR_STATUS_AXI_RESPONSE_SHIFT);
|
||||
GA2D_TEST_REG(RS_GA2D_REG_ERROR_ADDRESS) = UINT32_C(0x30000040);
|
||||
if ((rs_ga2d_get_error(NULL) != RS_EINVAL) || (rs_ga2d_get_error(&error) != RS_OK) ||
|
||||
!error.valid || (error.code != 11U) || (error.stage != 5U) || (error.axi_response != 2U) ||
|
||||
(error.address != (uintptr_t)UINT32_C(0x30000040))) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
if ((rs_ga2d_irq_enable(RS_GA2D_IRQ_ALL) != RS_OK) ||
|
||||
(GA2D_TEST_REG(RS_GA2D_REG_IRQ_ENABLE) != RS_GA2D_IRQ_ALL) ||
|
||||
(rs_ga2d_irq_pending(NULL) != RS_EINVAL) ||
|
||||
(rs_ga2d_irq_pending(&capability.features) != RS_OK) ||
|
||||
(capability.features != (RS_GA2D_IRQ_DONE | RS_GA2D_IRQ_ABORT_DONE)) ||
|
||||
(rs_ga2d_irq_clear(RS_GA2D_IRQ_ERROR) != RS_OK) ||
|
||||
(GA2D_TEST_REG(RS_GA2D_REG_IRQ_STATE) != RS_GA2D_IRQ_ERROR) ||
|
||||
(rs_ga2d_irq_enable(UINT32_C(0x8)) != RS_EINVAL)) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
GA2D_TEST_REG(RS_GA2D_REG_STATUS) = RS_GA2D_STATUS_DATA_READY;
|
||||
if ((rs_ga2d_reset() != RS_OK) ||
|
||||
(GA2D_TEST_REG(RS_GA2D_REG_COMMAND) != RS_GA2D_COMMAND_SOFT_RESET)) {
|
||||
return 7;
|
||||
}
|
||||
GA2D_TEST_REG(RS_GA2D_REG_STATUS) = RS_GA2D_STATUS_RECOVERY_REQUIRED;
|
||||
GA2D_TEST_REG(RS_GA2D_REG_COMMAND) = UINT32_C(0x5A5A5A5A);
|
||||
if ((rs_ga2d_reset() != RS_EIO) ||
|
||||
(GA2D_TEST_REG(RS_GA2D_REG_COMMAND) != UINT32_C(0x5A5A5A5A))) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
GA2D_TEST_REG(RS_GA2D_REG_STATUS) = 0U;
|
||||
if ((rs_ga2d_abort_wait(0U) != RS_OK) ||
|
||||
(GA2D_TEST_REG(RS_GA2D_REG_COMMAND) != RS_GA2D_COMMAND_ABORT)) {
|
||||
return 9;
|
||||
}
|
||||
GA2D_TEST_REG(RS_GA2D_REG_STATUS) = RS_GA2D_STATUS_BUSY;
|
||||
if (rs_ga2d_abort_wait(1U) != RS_ETIMEOUT) {
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_jpeg_validation(void) {
|
||||
static _Alignas(RS_JPEG_DESCRIPTOR_ALIGNMENT) rs_jpeg_descriptor_t ring[2];
|
||||
rs_jpeg_descriptor_t descriptor;
|
||||
@@ -1263,6 +1360,7 @@ int main(void) {
|
||||
test_fabric_monitor_hal_contract(),
|
||||
test_apu_validation(),
|
||||
test_apu_hal_contract(),
|
||||
test_ga2d_hal_contract(),
|
||||
test_jpeg_validation(),
|
||||
test_ps2_decoders(),
|
||||
test_wav_parser(),
|
||||
|
||||
@@ -16,22 +16,12 @@ module apb4_topology_tb;
|
||||
begin
|
||||
s_decode_addr = address;
|
||||
#1;
|
||||
if (s_psel_comb !== (28'd1 << slot)) begin
|
||||
if (s_psel_comb !== (29'd1 << slot)) begin
|
||||
$fatal(1, "unexpected APB4 target slot for %h: got %b", address, s_psel_comb);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic expect_disabled(input logic [31:0] address);
|
||||
begin
|
||||
s_decode_addr = address;
|
||||
#1;
|
||||
if (s_psel_comb !== '0) begin
|
||||
$fatal(1, "disabled APB4 target accepted %h: got %b", address, s_psel_comb);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
expect_select(`SOC_ADDR_APB4_GPIO_BASE, 1);
|
||||
expect_select(`SOC_ADDR_APB4_GPIO_ADMIN_BASE, 1);
|
||||
@@ -43,7 +33,7 @@ module apb4_topology_tb;
|
||||
expect_select(`SOC_ADDR_APB4_SDIO0_BASE, 15);
|
||||
expect_select(`SOC_ADDR_APB4_SDIO1_BASE, 18);
|
||||
expect_select(`SOC_ADDR_APB4_CRYPTO_BASE, 19);
|
||||
expect_disabled(`SOC_ADDR_APB4_GA_BASE);
|
||||
expect_select(`SOC_ADDR_APB4_GA2D_BASE, 28);
|
||||
expect_select(`SOC_ADDR_APB4_APU_BASE, 27);
|
||||
$display("SoC topology APB4 routing test passed");
|
||||
$finish;
|
||||
|
||||
@@ -154,7 +154,7 @@ module bus_fault_tb;
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
expect_fault(32'h1001_2000, 4'hF, 1'b1, `RIB_RESP_RESERVED);
|
||||
expect_fault(32'h6000_0000, 4'hF, 1'b1, `RIB_RESP_RESERVED);
|
||||
expect_fault(32'hA000_0000, 4'h0, 1'b0, `RIB_RESP_DECERR);
|
||||
expect_user_denied(32'h1000_B000, 4'hF);
|
||||
$display("bus fault responder test passed");
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "ga2d_define.svh"
|
||||
|
||||
module ga2d_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic busy_i = 1'b0;
|
||||
logic draining_i = 1'b0;
|
||||
logic quiesced_i = 1'b0;
|
||||
logic data_ready_i = 1'b1;
|
||||
logic recovery_required_i = 1'b0;
|
||||
logic idle_i = 1'b1;
|
||||
logic done_i = 1'b0;
|
||||
logic aborted_i = 1'b0;
|
||||
logic [ 2:0] irq_event_i = 3'd0;
|
||||
logic error_valid_i = 1'b0;
|
||||
logic [ 6:0] error_code_i = 7'd0;
|
||||
logic [ 3:0] error_stage_i = 4'd0;
|
||||
logic [ 1:0] error_axi_response_i = 2'd0;
|
||||
logic [31:0] error_address_i = 32'd0;
|
||||
logic soft_reset_o;
|
||||
logic abort_o;
|
||||
logic idle_o;
|
||||
logic irq_o;
|
||||
logic [31:0] read_data;
|
||||
int unsigned soft_reset_count;
|
||||
|
||||
apb4_if apb4 (
|
||||
.pclk (clk_i),
|
||||
.presetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (soft_reset_o) begin
|
||||
soft_reset_count++;
|
||||
end
|
||||
end
|
||||
|
||||
ga2d_reg u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.busy_i (busy_i),
|
||||
.draining_i (draining_i),
|
||||
.quiesced_i (quiesced_i),
|
||||
.data_ready_i (data_ready_i),
|
||||
.recovery_required_i (recovery_required_i),
|
||||
.idle_i (idle_i),
|
||||
.done_i (done_i),
|
||||
.aborted_i (aborted_i),
|
||||
.irq_event_i (irq_event_i),
|
||||
.error_valid_i (error_valid_i),
|
||||
.error_code_i (error_code_i),
|
||||
.error_stage_i (error_stage_i),
|
||||
.error_axi_response_i(error_axi_response_i),
|
||||
.error_address_i (error_address_i),
|
||||
.apb4 (apb4),
|
||||
.config_o (),
|
||||
.soft_reset_o (soft_reset_o),
|
||||
.abort_o (abort_o),
|
||||
.idle_o (idle_o),
|
||||
.irq_o (irq_o)
|
||||
);
|
||||
|
||||
task automatic apb_write(input logic [11:0] offset_i, input logic [31:0] value_i,
|
||||
input logic [3:0] strb_i, input logic expected_error_i);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, offset_i};
|
||||
apb4.pwrite = 1'b1;
|
||||
apb4.pwdata = value_i;
|
||||
apb4.pstrb = strb_i;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!apb4.pready || (apb4.pslverr != expected_error_i)) begin
|
||||
$fatal(1, "GA2D APB write response mismatch at %h", offset_i);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic apb_read(input logic [11:0] offset_i, input logic expected_error_i,
|
||||
output logic [31:0] value_o);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, offset_i};
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!apb4.pready || (apb4.pslverr != expected_error_i)) begin
|
||||
$fatal(1, "GA2D APB read response mismatch at %h", offset_i);
|
||||
end
|
||||
value_o = apb4.prdata;
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic held_soft_reset;
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, `APB4_GA2D__COMMAND};
|
||||
apb4.pwrite = 1'b1;
|
||||
apb4.pwdata = 32'h0000_0004;
|
||||
apb4.pstrb = 4'hf;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!apb4.pready || apb4.pslverr) begin
|
||||
$fatal(1, "GA2D soft reset response mismatch");
|
||||
end
|
||||
repeat (3) begin
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (apb4.pready) begin
|
||||
$fatal(1, "held GA2D APB access produced a second response");
|
||||
end
|
||||
end
|
||||
if (soft_reset_count != 1) begin
|
||||
$fatal(1, "held GA2D APB access repeated SOFT_RESET");
|
||||
end
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
apb4.paddr = '0;
|
||||
apb4.pprot = '0;
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pwdata = '0;
|
||||
apb4.pstrb = '0;
|
||||
soft_reset_count = 0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
apb_read(`APB4_GA2D__IP_ID, 1'b0, read_data);
|
||||
if (read_data != 32'h4741_3244) $fatal(1, "GA2D IP_ID mismatch");
|
||||
apb_read(`APB4_GA2D__IP_VERSION, 1'b0, read_data);
|
||||
if (read_data != 32'h0001_0000) $fatal(1, "GA2D IP_VERSION mismatch");
|
||||
apb_read(`APB4_GA2D__CAPABILITY, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_0040) $fatal(1, "GA2D shell capability mismatch");
|
||||
apb_read(`APB4_GA2D__TIMEOUT_CYCLES, 1'b0, read_data);
|
||||
if (read_data != 32'h0010_0000) $fatal(1, "GA2D timeout reset mismatch");
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_00ff) $fatal(1, "GA2D alpha reset mismatch");
|
||||
|
||||
apb_write(`APB4_GA2D__TIMEOUT_CYCLES, 32'd0, 4'hf, 1'b1);
|
||||
apb_write(`APB4_GA2D__TIMEOUT_CYCLES, 32'h1122_3344, 4'h7, 1'b1);
|
||||
apb_write(`APB4_GA2D__GLOBAL_ALPHA, 32'h0000_0055, 4'hf, 1'b0);
|
||||
apb_write(`APB4_GA2D__FG_FORMAT, 32'h0000_0005, 4'hf, 1'b0);
|
||||
apb_write(`APB4_GA2D__JOB_CONFIG, 32'h0000_0004, 4'hf, 1'b1);
|
||||
apb_write(`APB4_GA2D__IP_ID, 32'h0000_0000, 4'hf, 1'b1);
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_0055) $fatal(1, "GA2D alpha write mismatch");
|
||||
apb_read(`APB4_GA2D__FG_FORMAT, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_0005) $fatal(1, "GA2D format shadow mismatch");
|
||||
apb_read(12'h06c, 1'b1, read_data);
|
||||
apb_read(12'h003, 1'b1, read_data);
|
||||
|
||||
apb_write(`APB4_GA2D__COMMAND, 32'h0000_0001, 4'hf, 1'b1);
|
||||
apb_write(`APB4_GA2D__PERF_SNAPSHOT, 32'h0000_0001, 4'hf, 1'b1);
|
||||
apb_read(`APB4_GA2D__SNAP_CYCLES_LO, 1'b0, read_data);
|
||||
if (read_data != 32'd0) $fatal(1, "GA2D P3 counter stub is nonzero");
|
||||
|
||||
@(negedge clk_i);
|
||||
irq_event_i = `APB4_GA2D__IRQ_ALL;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
irq_event_i = '0;
|
||||
apb_write(`APB4_GA2D__IRQ_ENABLE, `APB4_GA2D__IRQ_ALL, 4'hf, 1'b0);
|
||||
if (!irq_o) $fatal(1, "GA2D raw IRQ did not assert");
|
||||
irq_event_i = 3'b001;
|
||||
apb_write(`APB4_GA2D__IRQ_STATE, 32'h0000_0007, 4'hf, 1'b0);
|
||||
irq_event_i = '0;
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_0001) $fatal(1, "GA2D IRQ set did not dominate W1C");
|
||||
apb_write(`APB4_GA2D__IRQ_STATE, 32'h0000_0001, 4'hf, 1'b0);
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, 1'b0, read_data);
|
||||
if (read_data != 32'd0 || irq_o) $fatal(1, "GA2D IRQ clear mismatch");
|
||||
apb_write(`APB4_GA2D__IRQ_ENABLE, 32'h0000_0008, 4'hf, 1'b1);
|
||||
|
||||
@(negedge clk_i);
|
||||
error_valid_i = 1'b1;
|
||||
error_code_i = 7'd11;
|
||||
error_stage_i = 4'd5;
|
||||
error_axi_response_i = 2'd2;
|
||||
error_address_i = 32'h3000_0040;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
error_valid_i = 1'b0;
|
||||
apb_read(`APB4_GA2D__ERROR_STATUS, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_2517) $fatal(1, "GA2D first error status mismatch");
|
||||
apb_read(`APB4_GA2D__ERROR_ADDRESS, 1'b0, read_data);
|
||||
if (read_data != 32'h3000_0040) $fatal(1, "GA2D first error address mismatch");
|
||||
apb_write(`APB4_GA2D__ERROR_STATUS, 32'h0000_0001, 4'hf, 1'b0);
|
||||
apb_read(`APB4_GA2D__ERROR_STATUS, 1'b0, read_data);
|
||||
if (read_data != 32'd0) $fatal(1, "GA2D error W1C mismatch");
|
||||
|
||||
held_soft_reset();
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_00ff) $fatal(1, "GA2D soft reset did not restore alpha");
|
||||
apb_read(`APB4_GA2D__IRQ_ENABLE, 1'b0, read_data);
|
||||
if (read_data != 32'd0) $fatal(1, "GA2D soft reset did not clear IRQ enable");
|
||||
|
||||
data_ready_i = 1'b0;
|
||||
apb_write(`APB4_GA2D__COMMAND, 32'h0000_0004, 4'hf, 1'b1);
|
||||
data_ready_i = 1'b1;
|
||||
busy_i = 1'b1;
|
||||
apb_write(`APB4_GA2D__COLOR, 32'h1122_3344, 4'hf, 1'b1);
|
||||
busy_i = 1'b0;
|
||||
|
||||
busy_i = 1'b1;
|
||||
draining_i = 1'b1;
|
||||
quiesced_i = 1'b1;
|
||||
data_ready_i = 1'b0;
|
||||
done_i = 1'b1;
|
||||
aborted_i = 1'b1;
|
||||
recovery_required_i = 1'b1;
|
||||
apb_read(`APB4_GA2D__STATUS, 1'b0, read_data);
|
||||
if (read_data != 32'h0000_00b7) $fatal(1, "GA2D live status mismatch");
|
||||
|
||||
$display("GA2D P3 APB shell test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat (400) @(posedge clk_i);
|
||||
$fatal(1, "GA2D P3 APB shell test timed out");
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,259 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "ga2d_define.svh"
|
||||
|
||||
module ga2d_wrapper_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic resource_quiesce_i = 1'b0;
|
||||
logic resource_reset_i = 1'b0;
|
||||
logic source_stop_i = 1'b0;
|
||||
logic source_safe_idle_i = 1'b1;
|
||||
logic block_ack_i = 1'b0;
|
||||
logic bridge_clear_busy_i = 1'b0;
|
||||
logic [ 7:0] bridge_epoch_i = 8'd0;
|
||||
logic data_ready_i = 1'b1;
|
||||
logic idle_o;
|
||||
logic irq_o;
|
||||
logic [31:0] read_data;
|
||||
|
||||
apb4_if apb4 (
|
||||
.pclk (clk_i),
|
||||
.presetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
apb4_ga2d u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.resource_quiesce_i (resource_quiesce_i),
|
||||
.resource_reset_i (resource_reset_i),
|
||||
.source_stop_i (source_stop_i),
|
||||
.source_safe_idle_i (source_safe_idle_i),
|
||||
.block_ack_i (block_ack_i),
|
||||
.bridge_clear_busy_i(bridge_clear_busy_i),
|
||||
.bridge_epoch_i (bridge_epoch_i),
|
||||
.data_ready_i (data_ready_i),
|
||||
.apb4 (apb4),
|
||||
.idle_o (idle_o),
|
||||
.irq_o (irq_o)
|
||||
);
|
||||
|
||||
task automatic apb_write(input logic [11:0] offset_i, input logic [31:0] value_i,
|
||||
input logic expected_error_i);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, offset_i};
|
||||
apb4.pwrite = 1'b1;
|
||||
apb4.pwdata = value_i;
|
||||
apb4.pstrb = 4'hf;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!apb4.pready || (apb4.pslverr != expected_error_i)) begin
|
||||
$fatal(1, "GA2D wrapper APB write response mismatch at %h", offset_i);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic apb_read(input logic [11:0] offset_i, output logic [31:0] value_o);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
apb4.paddr = {20'd0, offset_i};
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!apb4.pready || apb4.pslverr) begin
|
||||
$fatal(1, "GA2D wrapper APB read response mismatch at %h", offset_i);
|
||||
end
|
||||
value_o = apb4.prdata;
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic apb_lifecycle_soft_reset(input logic reset_request_i);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
resource_quiesce_i = !reset_request_i;
|
||||
resource_reset_i = reset_request_i;
|
||||
apb4.paddr = {20'd0, `APB4_GA2D__COMMAND};
|
||||
apb4.pwrite = 1'b1;
|
||||
apb4.pwdata = 32'h0000_0004;
|
||||
apb4.pstrb = 4'hf;
|
||||
apb4.psel = 1'b1;
|
||||
apb4.penable = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!apb4.pready || !apb4.pslverr) begin
|
||||
$fatal(1, "GA2D lifecycle request allowed unsafe soft reset");
|
||||
end
|
||||
@(negedge clk_i);
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
apb4.paddr = '0;
|
||||
apb4.pprot = '0;
|
||||
apb4.psel = 1'b0;
|
||||
apb4.penable = 1'b0;
|
||||
apb4.pwrite = 1'b0;
|
||||
apb4.pwdata = '0;
|
||||
apb4.pstrb = '0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
if (!idle_o) $fatal(1, "GA2D wrapper did not expose source-safe idle");
|
||||
apb_write(`APB4_GA2D__GLOBAL_ALPHA, 32'h0000_0055, 1'b0);
|
||||
apb_write(`APB4_GA2D__IRQ_ENABLE, 32'h0000_0001, 1'b0);
|
||||
apb_write(`APB4_GA2D__IRQ_TEST, 32'h0000_0001, 1'b0);
|
||||
if (!irq_o) $fatal(1, "GA2D wrapper IRQ_TEST did not assert raw IRQ");
|
||||
|
||||
apb_lifecycle_soft_reset(1'b0);
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (read_data[`APB4_GA2D__STATUS_DATA_READY]) begin
|
||||
$fatal(1, "GA2D resource quiesce left data ready asserted");
|
||||
end
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, read_data);
|
||||
if (read_data != 32'h0000_0055) begin
|
||||
$fatal(1, "GA2D resource quiesce allowed unsafe soft reset");
|
||||
end
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, read_data);
|
||||
if (read_data != 32'h0000_0001 || !irq_o) begin
|
||||
$fatal(1, "GA2D resource quiesce cleared retained diagnostics");
|
||||
end
|
||||
resource_quiesce_i = 1'b0;
|
||||
apb_write(`APB4_GA2D__COMMAND, 32'h0000_0004, 1'b0);
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, read_data);
|
||||
if (read_data != 32'h0000_00ff) begin
|
||||
$fatal(1, "GA2D post-quiesce soft reset did not clear configuration");
|
||||
end
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, read_data);
|
||||
if (read_data != 32'd0 || irq_o) begin
|
||||
$fatal(1, "GA2D post-quiesce soft reset did not clear diagnostics");
|
||||
end
|
||||
|
||||
apb_write(`APB4_GA2D__GLOBAL_ALPHA, 32'h0000_0055, 1'b0);
|
||||
apb_write(`APB4_GA2D__IRQ_ENABLE, 32'h0000_0001, 1'b0);
|
||||
apb_write(`APB4_GA2D__IRQ_TEST, 32'h0000_0001, 1'b0);
|
||||
apb_lifecycle_soft_reset(1'b1);
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (read_data[`APB4_GA2D__STATUS_DATA_READY]) begin
|
||||
$fatal(1, "GA2D resource reset left data ready asserted");
|
||||
end
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, read_data);
|
||||
if (read_data != 32'h0000_0055) begin
|
||||
$fatal(1, "GA2D resource reset allowed unsafe soft reset");
|
||||
end
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, read_data);
|
||||
if (read_data != 32'h0000_0001 || !irq_o) begin
|
||||
$fatal(1, "GA2D resource reset cleared retained diagnostics");
|
||||
end
|
||||
resource_reset_i = 1'b0;
|
||||
apb_write(`APB4_GA2D__COMMAND, 32'h0000_0004, 1'b0);
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, read_data);
|
||||
if (read_data != 32'h0000_00ff) begin
|
||||
$fatal(1, "GA2D post-reset soft reset did not clear configuration");
|
||||
end
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, read_data);
|
||||
if (read_data != 32'd0 || irq_o) begin
|
||||
$fatal(1, "GA2D post-reset soft reset did not clear diagnostics");
|
||||
end
|
||||
|
||||
apb_write(`APB4_GA2D__GLOBAL_ALPHA, 32'h0000_0055, 1'b0);
|
||||
apb_write(`APB4_GA2D__IRQ_ENABLE, 32'h0000_0001, 1'b0);
|
||||
apb_write(`APB4_GA2D__IRQ_TEST, 32'h0000_0001, 1'b0);
|
||||
resource_reset_i = 1'b1;
|
||||
source_stop_i = 1'b1;
|
||||
source_safe_idle_i = 1'b0;
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (read_data[`APB4_GA2D__STATUS_QUIESCED]) begin
|
||||
$fatal(1, "GA2D resource reset quiesced before source drain");
|
||||
end
|
||||
if (!irq_o) $fatal(1, "GA2D resource reset cleared local IRQ state");
|
||||
|
||||
source_safe_idle_i = 1'b1;
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (read_data[`APB4_GA2D__STATUS_QUIESCED]) begin
|
||||
$fatal(1, "GA2D resource reset quiesced before HP block acknowledgement");
|
||||
end
|
||||
if (!idle_o) $fatal(1, "GA2D wrapper did not reassert idle after source drain");
|
||||
|
||||
block_ack_i = 1'b1;
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (!read_data[`APB4_GA2D__STATUS_QUIESCED]) begin
|
||||
$fatal(1, "GA2D resource reset did not report drain-and-hold quiesce");
|
||||
end
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, read_data);
|
||||
if (read_data != 32'h0000_0055) begin
|
||||
$fatal(1, "GA2D resource reset cleared local configuration");
|
||||
end
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, read_data);
|
||||
if (read_data != 32'h0000_0001 || !irq_o) begin
|
||||
$fatal(1, "GA2D resource reset cleared local diagnostic state");
|
||||
end
|
||||
|
||||
bridge_clear_busy_i = 1'b1;
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (!read_data[`APB4_GA2D__STATUS_RECOVERY_REQUIRED]) begin
|
||||
$fatal(1, "GA2D wrapper missed bridge clear-busy recovery state");
|
||||
end
|
||||
bridge_clear_busy_i = 1'b0;
|
||||
data_ready_i = 1'b0;
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (!read_data[`APB4_GA2D__STATUS_RECOVERY_REQUIRED] ||
|
||||
read_data[`APB4_GA2D__STATUS_DATA_READY]) begin
|
||||
$fatal(1, "GA2D wrapper missed data-ready recovery state");
|
||||
end
|
||||
data_ready_i = 1'b1;
|
||||
bridge_epoch_i = 8'd1;
|
||||
#1;
|
||||
if (!u_dut.s_epoch_changed) begin
|
||||
$fatal(1, "GA2D wrapper missed bridge epoch change");
|
||||
end
|
||||
data_ready_i = 1'b0;
|
||||
apb_read(`APB4_GA2D__STATUS, read_data);
|
||||
if (!read_data[`APB4_GA2D__STATUS_RECOVERY_REQUIRED] ||
|
||||
read_data[`APB4_GA2D__STATUS_DATA_READY]) begin
|
||||
$fatal(1, "GA2D wrapper missed bridge epoch recovery state");
|
||||
end
|
||||
data_ready_i = 1'b1;
|
||||
|
||||
resource_reset_i = 1'b0;
|
||||
source_stop_i = 1'b0;
|
||||
block_ack_i = 1'b0;
|
||||
apb_write(`APB4_GA2D__COMMAND, 32'h0000_0004, 1'b0);
|
||||
apb_read(`APB4_GA2D__GLOBAL_ALPHA, read_data);
|
||||
if (read_data != 32'h0000_00ff) begin
|
||||
$fatal(1, "GA2D soft reset did not clear retained configuration");
|
||||
end
|
||||
apb_read(`APB4_GA2D__IRQ_STATE, read_data);
|
||||
if (read_data != 32'd0 || irq_o) begin
|
||||
$fatal(1, "GA2D soft reset did not clear retained diagnostic state");
|
||||
end
|
||||
|
||||
$display("GA2D P3 wrapper lifecycle test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat (400) @(posedge clk_i);
|
||||
$fatal(1, "GA2D P3 wrapper lifecycle test timed out");
|
||||
end
|
||||
endmodule
|
||||
@@ -151,15 +151,21 @@ module resource_controller_tb;
|
||||
$fatal(1, "APU resource index 7 ownership or IRQ routing mismatch");
|
||||
end
|
||||
|
||||
irq_i[8] = 1'b1;
|
||||
apb_read(12'h200, read_data);
|
||||
if (read_data != 32'd0 || owner_o[8] != 2'd0 || owner_lock_o[8]) begin
|
||||
if (read_data != 32'd0 || owner_o[8] != 2'd0 || owner_lock_o[8] || !irq_lp_o[8] ||
|
||||
irq_hp_o[8]) begin
|
||||
$fatal(1, "GA2D resource 8 did not reset to unlocked LP ownership");
|
||||
end
|
||||
apb_write(12'h204, 32'h0000_0001, 1'b0);
|
||||
block_ack_i[8] = 1'b1;
|
||||
apb_write(12'h200, 32'h0000_0001, 1'b0);
|
||||
if ((owner_o[8] != 2'd1) || irq_lp_o[8] || irq_hp_o[8]) begin
|
||||
$fatal(1, "GA2D resource 8 lifecycle or inactive IRQ mismatch");
|
||||
if ((owner_o[8] != 2'd1) || irq_lp_o[8] || !irq_hp_o[8]) begin
|
||||
$fatal(1, "GA2D resource 8 LP-to-HP IRQ handoff mismatch");
|
||||
end
|
||||
apb_write(12'h204, 32'h0000_0003, 1'b0);
|
||||
if (irq_lp_o[8] || irq_hp_o[8]) begin
|
||||
$fatal(1, "GA2D resource reset did not mask both IRQ routes");
|
||||
end
|
||||
|
||||
$display("Resource Controller ownership, IRQ, and cache handshake test passed");
|
||||
|
||||
@@ -27,24 +27,25 @@ module soc_irq_topology_tb;
|
||||
s_apb4_periph_irq = '0;
|
||||
s_apb4_periph_irq[bit_index] = 1'b1;
|
||||
s_apb4_system_irq = '0;
|
||||
expect_irq(32'd1 << bit_index);
|
||||
expect_irq(64'd1 << bit_index);
|
||||
end
|
||||
|
||||
for (int bit_index = 10; bit_index < `SOC_IRQ_APB4_PERIPH_WIDTH; bit_index++) begin
|
||||
s_apb4_periph_irq = '0;
|
||||
s_apb4_periph_irq[bit_index] = 1'b1;
|
||||
case (bit_index)
|
||||
13: expect_irq(32'd1 << 15);
|
||||
14: expect_irq(32'd1 << 20);
|
||||
16: expect_irq(32'd1 << 10);
|
||||
17: expect_irq(32'd1 << 21);
|
||||
18: expect_irq(32'd1 << 23);
|
||||
19: expect_irq(32'd1 << 24);
|
||||
20: expect_irq(32'd1 << 25);
|
||||
21: expect_irq(32'd1 << 26);
|
||||
22: expect_irq(32'd1 << 30);
|
||||
23: expect_irq(32'd1 << 31);
|
||||
default: expect_irq(32'd1 << (bit_index + 7));
|
||||
13: expect_irq(64'd1 << 15);
|
||||
14: expect_irq(64'd1 << 20);
|
||||
16: expect_irq(64'd1 << 10);
|
||||
17: expect_irq(64'd1 << 21);
|
||||
18: expect_irq(64'd1 << 23);
|
||||
19: expect_irq(64'd1 << 24);
|
||||
20: expect_irq(64'd1 << 25);
|
||||
21: expect_irq(64'd1 << 26);
|
||||
22: expect_irq(64'd1 << 30);
|
||||
23: expect_irq(64'd1 << 31);
|
||||
24: expect_irq(64'd1 << 32);
|
||||
default: expect_irq(64'd1 << (bit_index + 7));
|
||||
endcase
|
||||
end
|
||||
|
||||
@@ -53,22 +54,22 @@ module soc_irq_topology_tb;
|
||||
s_apb4_system_irq = '0;
|
||||
s_apb4_system_irq[bit_index] = 1'b1;
|
||||
case (bit_index)
|
||||
0: expect_irq(32'd1 << 11);
|
||||
1: expect_irq(32'd1 << 12);
|
||||
2: expect_irq(32'd1 << 13);
|
||||
3: expect_irq(32'd1 << 14);
|
||||
4: expect_irq(32'd1 << 16);
|
||||
5: expect_irq(32'd1 << 27);
|
||||
6: expect_irq(32'd1 << 28);
|
||||
7: expect_irq(32'd1 << 29);
|
||||
0: expect_irq(64'd1 << 11);
|
||||
1: expect_irq(64'd1 << 12);
|
||||
2: expect_irq(64'd1 << 13);
|
||||
3: expect_irq(64'd1 << 14);
|
||||
4: expect_irq(64'd1 << 16);
|
||||
5: expect_irq(64'd1 << 27);
|
||||
6: expect_irq(64'd1 << 28);
|
||||
7: expect_irq(64'd1 << 29);
|
||||
default: $fatal(1, "unexpected APB IRQ bit %0d", bit_index);
|
||||
endcase
|
||||
end
|
||||
|
||||
s_apb4_system_irq = '0;
|
||||
expect_irq('0);
|
||||
if (s_irq[63:32] !== '0) begin
|
||||
$fatal(1, "unallocated high IRQ vector bits are not low: %h", s_irq[63:32]);
|
||||
if (s_irq[63:33] !== '0) begin
|
||||
$fatal(1, "unallocated high IRQ vector bits are not low: %h", s_irq[63:33]);
|
||||
end
|
||||
if ((s_irq[10] !== 1'b0) || (s_irq[21] !== 1'b0)) begin
|
||||
$fatal(1, "SDIO core IRQ bits are not low when sources are low: IRQ10=%b IRQ21=%b",
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
"""Directed GA2D Phase 3 APB4 shell verification."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def run_ga2d_rtl_test(
|
||||
tmp_path: Path, top_module: str, testbench: str, success_marker: str
|
||||
) -> None:
|
||||
verilator = shutil.which("verilator")
|
||||
if verilator is None:
|
||||
pytest.fail("GA2D P3 RTL tests require Verilator")
|
||||
|
||||
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||
multimedia = ROOT / "rtl/ip/multimedia"
|
||||
output = tmp_path / top_module
|
||||
ccache_tmp = tmp_path / "ccache"
|
||||
ccache_tmp.mkdir()
|
||||
subprocess.run(
|
||||
[
|
||||
verilator,
|
||||
"--binary",
|
||||
"--timing",
|
||||
"-Wno-fatal",
|
||||
"--top-module",
|
||||
top_module,
|
||||
"-I" + str(common),
|
||||
"-I" + str(common / "interface"),
|
||||
"-I" + str(multimedia),
|
||||
str(common / "interface/apb4_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(multimedia / "ga2d_pkg.sv"),
|
||||
str(multimedia / "ga2d_reg.sv"),
|
||||
str(multimedia / "apb4_ga2d.sv"),
|
||||
str(ROOT / "tests/rtl" / testbench),
|
||||
"-Mdir",
|
||||
str(tmp_path / "obj"),
|
||||
"-o",
|
||||
str(output),
|
||||
],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env={
|
||||
**os.environ,
|
||||
"CCACHE_DIR": str(ccache_tmp),
|
||||
"CCACHE_TEMPDIR": str(ccache_tmp),
|
||||
},
|
||||
)
|
||||
result = subprocess.run([output], check=True, capture_output=True, text=True)
|
||||
assert success_marker in result.stdout
|
||||
|
||||
|
||||
def test_ga2d_p3_apb_shell(tmp_path: Path) -> None:
|
||||
run_ga2d_rtl_test(
|
||||
tmp_path,
|
||||
"ga2d_tb",
|
||||
"ga2d_tb.sv",
|
||||
"GA2D P3 APB shell test passed",
|
||||
)
|
||||
|
||||
|
||||
def test_ga2d_p3_wrapper_lifecycle(tmp_path: Path) -> None:
|
||||
run_ga2d_rtl_test(
|
||||
tmp_path,
|
||||
"ga2d_wrapper_tb",
|
||||
"ga2d_wrapper_tb.sv",
|
||||
"GA2D P3 wrapper lifecycle test passed",
|
||||
)
|
||||
+31
-13
@@ -1,4 +1,4 @@
|
||||
"""Directed GA2D Phase 2 fabric and lifecycle verification."""
|
||||
"""Directed GA2D Phase 2 fabric/lifecycle and Phase 3 shell boundaries."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -13,7 +13,7 @@ from pathlib import Path
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_ga2d_p2_preserves_deferred_apb_irq_and_payload_boundaries() -> None:
|
||||
def test_ga2d_p3_activates_only_the_apb_shell_and_irq_route() -> None:
|
||||
memory_map = json.loads(
|
||||
(ROOT / "rtl/mini/address_map/memory_map.json").read_text(encoding="utf-8")
|
||||
)
|
||||
@@ -21,25 +21,43 @@ def test_ga2d_p2_preserves_deferred_apb_irq_and_payload_boundaries() -> None:
|
||||
topology = json.loads(
|
||||
(ROOT / "rtl/mini/integration/soc_topology.json").read_text(encoding="utf-8")
|
||||
)
|
||||
apb4_periph = (ROOT / "rtl/mini/top/apb4_periph.sv").read_text(encoding="utf-8")
|
||||
apb4_system = (ROOT / "rtl/mini/top/apb4_system.sv").read_text(encoding="utf-8")
|
||||
top = (ROOT / "rtl/mini/top/retrosoc.sv").read_text(encoding="utf-8")
|
||||
|
||||
assert regions["APB4_GA"] == {
|
||||
"symbol": "APB4_GA",
|
||||
assert "APB4_GA" not in regions
|
||||
assert regions["APB4_GA2D"] == {
|
||||
"symbol": "APB4_GA2D",
|
||||
"base": "0x10012000",
|
||||
"size": "0x00001000",
|
||||
"route": "reserved",
|
||||
"kind": "reserved",
|
||||
"public": False,
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": True,
|
||||
"user_access": "none",
|
||||
}
|
||||
assert all("ga2d" not in interrupt["name"].lower() for interrupt in topology["interrupts"])
|
||||
assert not list((ROOT / "rtl/ip/multimedia").glob("ga2d_*.sv"))
|
||||
assert topology["apb4_periph_targets"][-1] == {
|
||||
"slot": 28,
|
||||
"name": "ga2d",
|
||||
"timed_interface": "u_ga2d_apb4_if",
|
||||
"pure_interface": "u_ga2d_apb4_pure_if",
|
||||
"region": "APB4_GA2D",
|
||||
}
|
||||
assert topology["interrupts"][-1]["name"] == "ga2d"
|
||||
assert topology["interrupts"][-1]["group_bit"] == 24
|
||||
assert topology["interrupts"][-1]["core_bit"] == 32
|
||||
assert topology["interrupts"][-1]["signal"] == "resource_irq_lp_i[7]"
|
||||
assert {
|
||||
"ga2d_pkg.sv",
|
||||
"ga2d_reg.sv",
|
||||
"apb4_ga2d.sv",
|
||||
} <= {path.name for path in (ROOT / "rtl/ip/multimedia").glob("*ga2d*.sv")}
|
||||
assert ".ResourceCount(9)" in apb4_system
|
||||
assert "1'b0, resource_irq_i[6:5], s_ext_h_irq_raw, resource_irq_i[4:0]" in apb4_system
|
||||
assert "resource_irq_lp_o = {s_resource_irq_lp[7:6], s_resource_irq_lp[4:0]}" in apb4_system
|
||||
assert "s_ga2d_source_safe_idle && s_resource_idle_pclk[8]" in top
|
||||
assert "s_ga2d_source_safe_idle && s_resource_block_ack_pclk[8]" in top
|
||||
assert "resource_irq_i[7]" in apb4_system
|
||||
assert "s_resource_irq_lp[8]" in apb4_system
|
||||
assert "s_hp_plic_source[11] = resource_irq_hp_i[7];" in apb4_periph
|
||||
assert "s_ga2d_idle && s_ga2d_source_safe_idle && s_resource_idle_pclk[8]" in top
|
||||
assert "s_ga2d_idle && s_ga2d_source_safe_idle && s_resource_block_ack_pclk[8]" in top
|
||||
assert "axi4_master_idle u_ga2d_master_idle" in top
|
||||
|
||||
|
||||
def test_ga2d_p2_bridge_prefix_lifecycle_and_recovery(tmp_path: Path) -> None:
|
||||
|
||||
@@ -0,0 +1,377 @@
|
||||
"""Keep the handwritten GA2D RTL and SDK register constants synchronized."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
RTL_DEFINE = ROOT / "rtl/ip/multimedia/ga2d_define.svh"
|
||||
C_DEFINE = ROOT / "crt/include/retrosoc/hal/ga2d_regs.h"
|
||||
C_API = ROOT / "crt/include/retrosoc/hal/ga2d.h"
|
||||
|
||||
|
||||
def _literal_value(value: str) -> int:
|
||||
value = value.replace("_", "")
|
||||
if "'" in value:
|
||||
_, encoded = value.split("'", maxsplit=1)
|
||||
base = 16 if encoded[0].lower() == "h" else 10
|
||||
return int(encoded[1:], base)
|
||||
return int(value, 10)
|
||||
|
||||
|
||||
def _rtl_values() -> dict[str, int]:
|
||||
pattern = re.compile(
|
||||
r"^`define\s+(APB4_GA2D__\w+)\s+((?:\d+)'[hHdD][0-9a-fA-F_]+|\d+)\s*$"
|
||||
)
|
||||
values: dict[str, int] = {}
|
||||
for line in RTL_DEFINE.read_text(encoding="utf-8").splitlines():
|
||||
match = pattern.match(line)
|
||||
if match is not None:
|
||||
values[match.group(1)] = _literal_value(match.group(2))
|
||||
return values
|
||||
|
||||
|
||||
def _c_values() -> dict[str, int]:
|
||||
pattern = re.compile(r"^#define\s+(RS_GA2D_\w+)\s+(?:UINT32_C\((0x[0-9a-fA-F]+)\)|(\d+)U)\s*$")
|
||||
values: dict[str, int] = {}
|
||||
for line in C_DEFINE.read_text(encoding="utf-8").splitlines():
|
||||
match = pattern.match(line)
|
||||
if match is not None:
|
||||
values[match.group(1)] = int(
|
||||
match.group(2) if match.group(2) is not None else match.group(3), 0
|
||||
)
|
||||
return values
|
||||
|
||||
|
||||
def _enum_values() -> dict[str, int]:
|
||||
pattern = re.compile(r"^\s*(RS_GA2D_(?:OP|FORMAT)_\w+)\s*=\s*(\d+),\s*$")
|
||||
values: dict[str, int] = {}
|
||||
for line in C_API.read_text(encoding="utf-8").splitlines():
|
||||
match = pattern.match(line)
|
||||
if match is not None:
|
||||
values[match.group(1)] = int(match.group(2), 10)
|
||||
return values
|
||||
|
||||
|
||||
OFFSETS = (
|
||||
"IP_ID",
|
||||
"IP_VERSION",
|
||||
"CAPABILITY",
|
||||
"LIMITS",
|
||||
"COMMAND",
|
||||
"STATUS",
|
||||
"IRQ_STATE",
|
||||
"IRQ_ENABLE",
|
||||
"IRQ_TEST",
|
||||
"ERROR_STATUS",
|
||||
"ERROR_ADDRESS",
|
||||
"TIMEOUT_CYCLES",
|
||||
"JOB_CONFIG",
|
||||
"GLOBAL_ALPHA",
|
||||
"COLOR",
|
||||
"SIZE",
|
||||
"FG_ADDRESS",
|
||||
"FG_PITCH",
|
||||
"FG_FORMAT",
|
||||
"BG_ADDRESS",
|
||||
"BG_PITCH",
|
||||
"BG_FORMAT",
|
||||
"DST_ADDRESS",
|
||||
"DST_PITCH",
|
||||
"DST_FORMAT",
|
||||
"PERF_SNAPSHOT",
|
||||
"FORMAT_CAPABILITY",
|
||||
"SNAP_CYCLES_LO",
|
||||
"SNAP_CYCLES_HI",
|
||||
"SNAP_READ_BYTES_LO",
|
||||
"SNAP_READ_BYTES_HI",
|
||||
"SNAP_WRITE_BYTES_LO",
|
||||
"SNAP_WRITE_BYTES_HI",
|
||||
"SNAP_READ_STALL_LO",
|
||||
"SNAP_READ_STALL_HI",
|
||||
"SNAP_WRITE_STALL_LO",
|
||||
"SNAP_WRITE_STALL_HI",
|
||||
"SNAP_PIPE_STALL_LO",
|
||||
"SNAP_PIPE_STALL_HI",
|
||||
"SNAP_LINES_DONE",
|
||||
)
|
||||
|
||||
|
||||
def test_ga2d_register_offsets_and_scalar_encodings_are_exhaustive() -> None:
|
||||
rtl = _rtl_values()
|
||||
c = _c_values()
|
||||
offset_mapping = {f"APB4_GA2D__{name}": f"RS_GA2D_REG_{name}" for name in OFFSETS}
|
||||
scalar_mapping = {
|
||||
"APB4_GA2D__IP_ID_VALUE": "RS_GA2D_IP_ID_VALUE",
|
||||
"APB4_GA2D__IP_VERSION_VALUE": "RS_GA2D_IP_VERSION_VALUE",
|
||||
"APB4_GA2D__CAPABILITY_P3": "RS_GA2D_CAPABILITY_P3",
|
||||
"APB4_GA2D__LIMITS_P3": "RS_GA2D_LIMITS_P3",
|
||||
"APB4_GA2D__FORMAT_CAPABILITY_P3": "RS_GA2D_FORMAT_CAPABILITY_P3",
|
||||
"APB4_GA2D__TIMEOUT_CYCLES_RESET": "RS_GA2D_TIMEOUT_CYCLES_RESET",
|
||||
"APB4_GA2D__GLOBAL_ALPHA_RESET": "RS_GA2D_GLOBAL_ALPHA_RESET",
|
||||
"APB4_GA2D__IRQ_ALL": "RS_GA2D_IRQ_ALL",
|
||||
}
|
||||
expected_c = set(offset_mapping.values()) | set(scalar_mapping.values())
|
||||
|
||||
for rtl_name, c_name in {**offset_mapping, **scalar_mapping}.items():
|
||||
assert rtl[rtl_name] == c[c_name], f"{rtl_name} != {c_name}"
|
||||
|
||||
assert {name for name in rtl if name.endswith(tuple(OFFSETS))} >= set(offset_mapping)
|
||||
assert expected_c <= set(c)
|
||||
|
||||
|
||||
def test_ga2d_register_bit_shifts_and_enums_are_exhaustive() -> None:
|
||||
rtl = _rtl_values()
|
||||
c = _c_values()
|
||||
enums = _enum_values()
|
||||
bit_mapping = {
|
||||
"APB4_GA2D__COMMAND_START": "RS_GA2D_COMMAND_START",
|
||||
"APB4_GA2D__COMMAND_ABORT": "RS_GA2D_COMMAND_ABORT",
|
||||
"APB4_GA2D__COMMAND_SOFT_RESET": "RS_GA2D_COMMAND_SOFT_RESET",
|
||||
"APB4_GA2D__STATUS_BUSY": "RS_GA2D_STATUS_BUSY",
|
||||
"APB4_GA2D__STATUS_DRAINING": "RS_GA2D_STATUS_DRAINING",
|
||||
"APB4_GA2D__STATUS_QUIESCED": "RS_GA2D_STATUS_QUIESCED",
|
||||
"APB4_GA2D__STATUS_DATA_READY": "RS_GA2D_STATUS_DATA_READY",
|
||||
"APB4_GA2D__STATUS_DONE": "RS_GA2D_STATUS_DONE",
|
||||
"APB4_GA2D__STATUS_ABORTED": "RS_GA2D_STATUS_ABORTED",
|
||||
"APB4_GA2D__STATUS_ERROR": "RS_GA2D_STATUS_ERROR",
|
||||
"APB4_GA2D__STATUS_RECOVERY_REQUIRED": "RS_GA2D_STATUS_RECOVERY_REQUIRED",
|
||||
"APB4_GA2D__IRQ_DONE": "RS_GA2D_IRQ_DONE",
|
||||
"APB4_GA2D__IRQ_ERROR": "RS_GA2D_IRQ_ERROR",
|
||||
"APB4_GA2D__IRQ_ABORT_DONE": "RS_GA2D_IRQ_ABORT_DONE",
|
||||
"APB4_GA2D__ERROR_STATUS_VALID": "RS_GA2D_ERROR_STATUS_VALID",
|
||||
"APB4_GA2D__CAPABILITY_FILL": "RS_GA2D_CAPABILITY_FILL",
|
||||
"APB4_GA2D__CAPABILITY_COPY": "RS_GA2D_CAPABILITY_COPY",
|
||||
"APB4_GA2D__CAPABILITY_CONVERT": "RS_GA2D_CAPABILITY_CONVERT",
|
||||
"APB4_GA2D__CAPABILITY_BLEND": "RS_GA2D_CAPABILITY_BLEND",
|
||||
"APB4_GA2D__CAPABILITY_A8_MASK": "RS_GA2D_CAPABILITY_A8_MASK",
|
||||
"APB4_GA2D__CAPABILITY_PRIVATE_DMA": "RS_GA2D_CAPABILITY_PRIVATE_DMA",
|
||||
"APB4_GA2D__CAPABILITY_IRQ": "RS_GA2D_CAPABILITY_IRQ",
|
||||
"APB4_GA2D__CAPABILITY_SNAPSHOT": "RS_GA2D_CAPABILITY_SNAPSHOT",
|
||||
"APB4_GA2D__CAPABILITY_TWO_DIMENSIONAL_PITCH": (
|
||||
"RS_GA2D_CAPABILITY_TWO_DIMENSIONAL_PITCH"
|
||||
),
|
||||
"APB4_GA2D__CAPABILITY_BYTE_EDGES": "RS_GA2D_CAPABILITY_BYTE_EDGES",
|
||||
"APB4_GA2D__CAPABILITY_INPLACE_BACKGROUND": (
|
||||
"RS_GA2D_CAPABILITY_INPLACE_BACKGROUND"
|
||||
),
|
||||
}
|
||||
shift_mapping = {
|
||||
"APB4_GA2D__ERROR_STATUS_CODE": "RS_GA2D_ERROR_STATUS_CODE_SHIFT",
|
||||
"APB4_GA2D__ERROR_STATUS_STAGE": "RS_GA2D_ERROR_STATUS_STAGE_SHIFT",
|
||||
"APB4_GA2D__ERROR_STATUS_AXI_RESPONSE": "RS_GA2D_ERROR_STATUS_AXI_RESPONSE_SHIFT",
|
||||
"APB4_GA2D__JOB_CONFIG_OPERATION": "RS_GA2D_JOB_CONFIG_OPERATION_SHIFT",
|
||||
"APB4_GA2D__GLOBAL_ALPHA_VALUE": "RS_GA2D_GLOBAL_ALPHA_VALUE_SHIFT",
|
||||
"APB4_GA2D__SIZE_WIDTH": "RS_GA2D_SIZE_WIDTH_SHIFT",
|
||||
"APB4_GA2D__SIZE_HEIGHT": "RS_GA2D_SIZE_HEIGHT_SHIFT",
|
||||
"APB4_GA2D__FG_FORMAT_VALUE": "RS_GA2D_FG_FORMAT_VALUE_SHIFT",
|
||||
"APB4_GA2D__BG_FORMAT_VALUE": "RS_GA2D_BG_FORMAT_VALUE_SHIFT",
|
||||
"APB4_GA2D__DST_FORMAT_VALUE": "RS_GA2D_DST_FORMAT_VALUE_SHIFT",
|
||||
"APB4_GA2D__FORMAT_CAPABILITY_FOREGROUND": (
|
||||
"RS_GA2D_FORMAT_CAPABILITY_FOREGROUND_SHIFT"
|
||||
),
|
||||
"APB4_GA2D__FORMAT_CAPABILITY_BACKGROUND": (
|
||||
"RS_GA2D_FORMAT_CAPABILITY_BACKGROUND_SHIFT"
|
||||
),
|
||||
"APB4_GA2D__FORMAT_CAPABILITY_DESTINATION": (
|
||||
"RS_GA2D_FORMAT_CAPABILITY_DESTINATION_SHIFT"
|
||||
),
|
||||
}
|
||||
error_mapping = {
|
||||
f"APB4_GA2D__ERROR_{name}": f"RS_GA2D_ERROR_CODE_{name}"
|
||||
for name in (
|
||||
"NONE",
|
||||
"INVALID_SIZE",
|
||||
"INVALID_FORMAT",
|
||||
"INVALID_PITCH",
|
||||
"INVALID_ALIGNMENT",
|
||||
"ADDRESS_OVERFLOW",
|
||||
"ADDRESS_RANGE",
|
||||
"OVERLAP",
|
||||
"AXI_READ",
|
||||
"AXI_WRITE",
|
||||
"AXI_PROTOCOL",
|
||||
"TIMEOUT",
|
||||
"EPOCH_LOST",
|
||||
"INTERNAL",
|
||||
)
|
||||
}
|
||||
stage_mapping = {
|
||||
f"APB4_GA2D__ERROR_STAGE_{name}": f"RS_GA2D_ERROR_STAGE_{name}"
|
||||
for name in ("NONE", "VALIDATE", "FOREGROUND", "BACKGROUND", "DESTINATION", "LIFECYCLE")
|
||||
}
|
||||
enum_mapping = {
|
||||
"APB4_GA2D__OP_FILL": "RS_GA2D_OP_FILL",
|
||||
"APB4_GA2D__OP_COPY": "RS_GA2D_OP_COPY",
|
||||
"APB4_GA2D__OP_CONVERT": "RS_GA2D_OP_CONVERT",
|
||||
"APB4_GA2D__OP_BLEND": "RS_GA2D_OP_BLEND",
|
||||
"APB4_GA2D__FORMAT_RGB565": "RS_GA2D_FORMAT_RGB565",
|
||||
"APB4_GA2D__FORMAT_RGB888": "RS_GA2D_FORMAT_RGB888",
|
||||
"APB4_GA2D__FORMAT_XRGB8888": "RS_GA2D_FORMAT_XRGB8888",
|
||||
"APB4_GA2D__FORMAT_ARGB8888": "RS_GA2D_FORMAT_ARGB8888",
|
||||
"APB4_GA2D__FORMAT_A8": "RS_GA2D_FORMAT_A8",
|
||||
}
|
||||
|
||||
for rtl_name, c_name in bit_mapping.items():
|
||||
assert c[c_name] == 1 << rtl[rtl_name], f"{rtl_name} != {c_name}"
|
||||
for rtl_name, c_name in {**shift_mapping, **error_mapping, **stage_mapping}.items():
|
||||
assert rtl[rtl_name] == c[c_name], f"{rtl_name} != {c_name}"
|
||||
for rtl_name, enum_name in enum_mapping.items():
|
||||
assert rtl[rtl_name] == enums[enum_name], f"{rtl_name} != {enum_name}"
|
||||
|
||||
assert set(enums) == set(enum_mapping.values())
|
||||
|
||||
|
||||
def test_ga2d_handwritten_definition_sets_have_no_missing_or_extra_entries() -> None:
|
||||
rtl = _rtl_values()
|
||||
c = _c_values()
|
||||
rtl_scalar_names = {
|
||||
"IP_ID_VALUE",
|
||||
"IP_VERSION_VALUE",
|
||||
"CAPABILITY_P3",
|
||||
"LIMITS_P3",
|
||||
"FORMAT_CAPABILITY_P3",
|
||||
"TIMEOUT_CYCLES_RESET",
|
||||
"GLOBAL_ALPHA_RESET",
|
||||
"IRQ_ALL",
|
||||
}
|
||||
rtl_bit_names = {
|
||||
"COMMAND_START",
|
||||
"COMMAND_ABORT",
|
||||
"COMMAND_SOFT_RESET",
|
||||
"STATUS_BUSY",
|
||||
"STATUS_DRAINING",
|
||||
"STATUS_QUIESCED",
|
||||
"STATUS_DATA_READY",
|
||||
"STATUS_DONE",
|
||||
"STATUS_ABORTED",
|
||||
"STATUS_ERROR",
|
||||
"STATUS_RECOVERY_REQUIRED",
|
||||
"IRQ_DONE",
|
||||
"IRQ_ERROR",
|
||||
"IRQ_ABORT_DONE",
|
||||
"ERROR_STATUS_VALID",
|
||||
"CAPABILITY_FILL",
|
||||
"CAPABILITY_COPY",
|
||||
"CAPABILITY_CONVERT",
|
||||
"CAPABILITY_BLEND",
|
||||
"CAPABILITY_A8_MASK",
|
||||
"CAPABILITY_PRIVATE_DMA",
|
||||
"CAPABILITY_IRQ",
|
||||
"CAPABILITY_SNAPSHOT",
|
||||
"CAPABILITY_TWO_DIMENSIONAL_PITCH",
|
||||
"CAPABILITY_BYTE_EDGES",
|
||||
"CAPABILITY_INPLACE_BACKGROUND",
|
||||
}
|
||||
rtl_shift_names = {
|
||||
"ERROR_STATUS_CODE",
|
||||
"ERROR_STATUS_STAGE",
|
||||
"ERROR_STATUS_AXI_RESPONSE",
|
||||
"JOB_CONFIG_OPERATION",
|
||||
"GLOBAL_ALPHA_VALUE",
|
||||
"SIZE_WIDTH",
|
||||
"SIZE_HEIGHT",
|
||||
"FG_FORMAT_VALUE",
|
||||
"BG_FORMAT_VALUE",
|
||||
"DST_FORMAT_VALUE",
|
||||
"FORMAT_CAPABILITY_FOREGROUND",
|
||||
"FORMAT_CAPABILITY_BACKGROUND",
|
||||
"FORMAT_CAPABILITY_DESTINATION",
|
||||
}
|
||||
error_names = {
|
||||
"NONE",
|
||||
"INVALID_SIZE",
|
||||
"INVALID_FORMAT",
|
||||
"INVALID_PITCH",
|
||||
"INVALID_ALIGNMENT",
|
||||
"ADDRESS_OVERFLOW",
|
||||
"ADDRESS_RANGE",
|
||||
"OVERLAP",
|
||||
"AXI_READ",
|
||||
"AXI_WRITE",
|
||||
"AXI_PROTOCOL",
|
||||
"TIMEOUT",
|
||||
"EPOCH_LOST",
|
||||
"INTERNAL",
|
||||
}
|
||||
stage_names = {"NONE", "VALIDATE", "FOREGROUND", "BACKGROUND", "DESTINATION", "LIFECYCLE"}
|
||||
operation_names = {"FILL", "COPY", "CONVERT", "BLEND"}
|
||||
format_names = {"RGB565", "RGB888", "XRGB8888", "ARGB8888", "A8"}
|
||||
expected_rtl = (
|
||||
{f"APB4_GA2D__{name}" for name in OFFSETS}
|
||||
| {f"APB4_GA2D__{name}" for name in rtl_scalar_names}
|
||||
| {f"APB4_GA2D__{name}" for name in rtl_bit_names}
|
||||
| {f"APB4_GA2D__{name}" for name in rtl_shift_names}
|
||||
| {f"APB4_GA2D__ERROR_{name}" for name in error_names}
|
||||
| {f"APB4_GA2D__ERROR_STAGE_{name}" for name in stage_names}
|
||||
| {f"APB4_GA2D__OP_{name}" for name in operation_names}
|
||||
| {f"APB4_GA2D__FORMAT_{name}" for name in format_names}
|
||||
)
|
||||
expected_c = (
|
||||
{f"RS_GA2D_REG_{name}" for name in OFFSETS}
|
||||
| {
|
||||
"RS_GA2D_IP_ID_VALUE",
|
||||
"RS_GA2D_IP_VERSION_VALUE",
|
||||
"RS_GA2D_IP_VERSION_MAJOR_MASK",
|
||||
"RS_GA2D_IP_VERSION_MAJOR_1",
|
||||
"RS_GA2D_CAPABILITY_P3",
|
||||
"RS_GA2D_LIMITS_P3",
|
||||
"RS_GA2D_FORMAT_CAPABILITY_P3",
|
||||
"RS_GA2D_TIMEOUT_CYCLES_RESET",
|
||||
"RS_GA2D_GLOBAL_ALPHA_RESET",
|
||||
"RS_GA2D_COMMAND_START",
|
||||
"RS_GA2D_COMMAND_ABORT",
|
||||
"RS_GA2D_COMMAND_SOFT_RESET",
|
||||
"RS_GA2D_STATUS_BUSY",
|
||||
"RS_GA2D_STATUS_DRAINING",
|
||||
"RS_GA2D_STATUS_QUIESCED",
|
||||
"RS_GA2D_STATUS_DATA_READY",
|
||||
"RS_GA2D_STATUS_DONE",
|
||||
"RS_GA2D_STATUS_ABORTED",
|
||||
"RS_GA2D_STATUS_ERROR",
|
||||
"RS_GA2D_STATUS_RECOVERY_REQUIRED",
|
||||
"RS_GA2D_IRQ_DONE",
|
||||
"RS_GA2D_IRQ_ERROR",
|
||||
"RS_GA2D_IRQ_ABORT_DONE",
|
||||
"RS_GA2D_IRQ_ALL",
|
||||
"RS_GA2D_ERROR_STATUS_VALID",
|
||||
"RS_GA2D_ERROR_STATUS_CODE_SHIFT",
|
||||
"RS_GA2D_ERROR_STATUS_CODE_MASK",
|
||||
"RS_GA2D_ERROR_STATUS_STAGE_SHIFT",
|
||||
"RS_GA2D_ERROR_STATUS_STAGE_MASK",
|
||||
"RS_GA2D_ERROR_STATUS_AXI_RESPONSE_SHIFT",
|
||||
"RS_GA2D_ERROR_STATUS_AXI_RESPONSE_MASK",
|
||||
"RS_GA2D_JOB_CONFIG_OPERATION_SHIFT",
|
||||
"RS_GA2D_JOB_CONFIG_OPERATION_MASK",
|
||||
"RS_GA2D_GLOBAL_ALPHA_VALUE_SHIFT",
|
||||
"RS_GA2D_GLOBAL_ALPHA_VALUE_MASK",
|
||||
"RS_GA2D_SIZE_WIDTH_SHIFT",
|
||||
"RS_GA2D_SIZE_WIDTH_MASK",
|
||||
"RS_GA2D_SIZE_HEIGHT_SHIFT",
|
||||
"RS_GA2D_SIZE_HEIGHT_MASK",
|
||||
"RS_GA2D_FG_FORMAT_VALUE_SHIFT",
|
||||
"RS_GA2D_BG_FORMAT_VALUE_SHIFT",
|
||||
"RS_GA2D_DST_FORMAT_VALUE_SHIFT",
|
||||
"RS_GA2D_FORMAT_VALUE_MASK",
|
||||
"RS_GA2D_FORMAT_CAPABILITY_FOREGROUND_SHIFT",
|
||||
"RS_GA2D_FORMAT_CAPABILITY_BACKGROUND_SHIFT",
|
||||
"RS_GA2D_FORMAT_CAPABILITY_DESTINATION_SHIFT",
|
||||
"RS_GA2D_FORMAT_CAPABILITY_MASK",
|
||||
}
|
||||
| {f"RS_GA2D_CAPABILITY_{name}" for name in operation_names | {
|
||||
"A8_MASK",
|
||||
"PRIVATE_DMA",
|
||||
"IRQ",
|
||||
"SNAPSHOT",
|
||||
"TWO_DIMENSIONAL_PITCH",
|
||||
"BYTE_EDGES",
|
||||
"INPLACE_BACKGROUND",
|
||||
}}
|
||||
| {f"RS_GA2D_ERROR_CODE_{name}" for name in error_names}
|
||||
| {f"RS_GA2D_ERROR_STAGE_{name}" for name in stage_names}
|
||||
)
|
||||
|
||||
assert set(rtl) == expected_rtl
|
||||
assert set(c) == expected_c
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -45,14 +46,15 @@ def test_phase1_generates_64bit_vector_and_sdk_metadata(tmp_path: Path) -> None:
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 64" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 64'h00000000004EFBFC" in irq_config
|
||||
assert "s_irq[31] = s_apb4_periph_irq[23];" in irq_wiring
|
||||
assert "s_irq[32]" not in irq_wiring
|
||||
assert "irq_i[32] == 1'b0" in irq_sva
|
||||
assert "s_irq[32] = s_apb4_periph_irq[24];" in irq_wiring
|
||||
assert "irq_i[32] == apb4_periph_irq_i[24]" in irq_sva
|
||||
assert "irq_i[63] == 1'b0" in irq_sva
|
||||
assert "RS_SOC_IRQ_VECTOR_WIDTH UINT32_C(64)" in metadata
|
||||
assert "RS_SOC_EXTERNAL_IRQ_COUNT UINT32_C(62)" in metadata
|
||||
assert "RS_SOC_ALLOCATED_IRQ_COUNT UINT32_C(30)" in metadata
|
||||
assert "RS_SOC_ALLOCATED_IRQ_COUNT UINT32_C(31)" in metadata
|
||||
assert "RS_SOC_EXT_IRQ_APU UINT32_C(29)" in metadata
|
||||
assert "RS_SOC_IRQ_GA2D" not in metadata
|
||||
assert "RS_SOC_IRQ_GA2D UINT32_C(32)" in metadata
|
||||
assert "RS_SOC_EXT_IRQ_GA2D UINT32_C(30)" in metadata
|
||||
|
||||
|
||||
def test_phase1_supports_32bit_compatibility_metadata(tmp_path: Path) -> None:
|
||||
@@ -128,10 +130,11 @@ def test_phase1_wrapper_and_backend_contracts() -> None:
|
||||
assert "CSR_HAZARD3_MEIEA 0xbe0" in csr
|
||||
assert "CSR_HAZARD3_MEINEXT 0xbe4" in csr
|
||||
assert "CSR_HAZARD3_MEICONTEXT 0xbe5" in csr
|
||||
assert "{0U, 15U, 16U, 29U, 30U, 31U, 32U, 61U}" in firmware
|
||||
assert "static const uint32_t tested_ordinals[]" in firmware
|
||||
assert re.search(r"29U,\s*RS_SOC_EXT_IRQ_GA2D,\s*31U", firmware) is not None
|
||||
assert "rs_irq_register_external(62U" in firmware
|
||||
assert "rs_irq_set_external_priority(29U, UINT8_C(0))" in firmware
|
||||
assert "rs_irq_set_external_priority(30U, UINT8_C(1))" in firmware
|
||||
assert "rs_irq_set_external_priority(RS_SOC_EXT_IRQ_GA2D, UINT8_C(1))" in firmware
|
||||
assert "rs_irq_set_external_priority(31U, UINT8_C(2))" in firmware
|
||||
assert "rs_irq_set_external_priority(32U, UINT8_C(3))" in firmware
|
||||
assert "rs_irq_set_external_priority(15U, UINT8_C(3))" in firmware
|
||||
|
||||
@@ -125,6 +125,7 @@ def test_booter_prints_every_public_active_mmio_region() -> None:
|
||||
assert "DMA(8CH)" in mmio_function
|
||||
assert "DMA(6CH)" not in mmio_function
|
||||
assert "RS_SOC_APB4_GA_BASE" not in mmio_function
|
||||
assert "RS_SOC_APB4_GA2D_BASE" in mmio_function
|
||||
assert "RS_SOC_APB4_APU_BASE" in mmio_function
|
||||
|
||||
|
||||
@@ -178,6 +179,7 @@ def test_user_ip_is_always_emitted_for_the_fixed_platform(tmp_path: Path) -> Non
|
||||
assert "#define RS_SOC_APB4_CRYPTO_BASE UINT32_C(0x1000C000)" in header
|
||||
assert "#define RS_SOC_APB4_USB2_BASE UINT32_C(0x10016000)" in header
|
||||
assert "#define RS_SOC_APB4_APU_BASE UINT32_C(0x10013000)" in header
|
||||
assert "#define RS_SOC_APB4_GA2D_BASE UINT32_C(0x10012000)" in header
|
||||
|
||||
|
||||
def test_bootstrap_assembly_uses_the_generated_gpio_admin_base() -> None:
|
||||
|
||||
@@ -95,7 +95,8 @@ def test_application_results_keep_early_return_and_repeated_stage_values():
|
||||
("return", 1), ("test-fail", 1), ("test-fail", 2), ("test-fail", 3), ("test-pass", 0)]
|
||||
assert [r["id"] for r in smoke["stages"] if r["code"] == 12] == ["sram", "usb"]
|
||||
assert [r["id"] for r in smoke["stages"] if r["code"] == 13] == ["monitor-start", "monitor-check"]
|
||||
assert len(smoke["stages"]) == 18
|
||||
assert [r["id"] for r in smoke["stages"] if r["code"] == 15] == ["external-irq", "ga2d-irq"]
|
||||
assert len(smoke["stages"]) == 19
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mutation", ["omit", "duplicate-stage", "value", "scope", "trigger"])
|
||||
|
||||
+22
-10
@@ -80,7 +80,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
).read_text(encoding="utf-8")
|
||||
filelist = (tmp_path / "soc_topology.fl").read_text(encoding="utf-8")
|
||||
|
||||
assert interfaces.count("apb4_if u_") == 26
|
||||
assert interfaces.count("apb4_if u_") == 27
|
||||
assert "nmi_if" not in interfaces
|
||||
assert "soc_nmi" not in interfaces
|
||||
assert "assign s_psel_comb[17] = `SOC_ADDR_IS_APB4_I2C1(s_decode_addr);" in routes
|
||||
@@ -97,6 +97,8 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "assign s_psel_comb[25] = `SOC_ADDR_IS_HP_PLIC(s_decode_addr);" in routes
|
||||
assert "assign s_psel_comb[26] = `SOC_ADDR_IS_APB4_JPEG(s_decode_addr);" in routes
|
||||
assert "assign s_psel_comb[27] = `SOC_ADDR_IS_APB4_APU(s_decode_addr);" in routes
|
||||
assert "assign s_psel_comb[28] = `SOC_ADDR_IS_APB4_GA2D(s_decode_addr);" in routes
|
||||
assert "apb4_if u_ga2d_apb4_if (clk_i, rst_n_i);" in interfaces
|
||||
assert gpio.count("// GPIO") == 64
|
||||
assert "u_uart1_if" not in gpio
|
||||
assert "assign u_uart0_if.cts_n_i = u_gpio_if.di_i[0];" in gpio
|
||||
@@ -145,7 +147,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert ".usb2_axi4(u_usb2_axi4_if)" in apb_periph_fabric
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 64" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 64'h00000000004EFBFC" in irq_config
|
||||
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 24" in irq_config
|
||||
assert "`define SOC_IRQ_APB4_PERIPH_WIDTH 25" in irq_config
|
||||
assert "`define SOC_IRQ_APB4_SYSTEM_WIDTH 8" in irq_config
|
||||
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
|
||||
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
|
||||
@@ -160,6 +162,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "assign irq_o[19] = resource_irq_lp_i[1];" in rib_irq
|
||||
assert "assign irq_o[22] = resource_irq_lp_i[5];" in rib_irq
|
||||
assert "assign irq_o[23] = resource_irq_lp_i[6];" in rib_irq
|
||||
assert "assign irq_o[24] = resource_irq_lp_i[7];" in rib_irq
|
||||
assert "assign irq_o[0] = pwm.irq_o;" in apb_irq
|
||||
assert "assign irq_o[4] = s_rng_irq;" in apb_irq
|
||||
assert "assign irq_o[5] = s_ext_l_irq;" in apb_irq
|
||||
@@ -178,6 +181,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "s_irq[29] = s_apb4_system_irq[7];" in irq_wiring
|
||||
assert "s_irq[30] = s_apb4_periph_irq[22];" in irq_wiring
|
||||
assert "s_irq[31] = s_apb4_periph_irq[23];" in irq_wiring
|
||||
assert "s_irq[32] = s_apb4_periph_irq[24];" in irq_wiring
|
||||
assert "irq_i[10] == apb4_periph_irq_i[16]" in irq_sva
|
||||
assert "irq_i[15] == apb4_periph_irq_i[13]" in irq_sva
|
||||
assert "irq_i[20] == apb4_periph_irq_i[14]" in irq_sva
|
||||
@@ -187,6 +191,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "irq_i[24] == apb4_periph_irq_i[19]" in irq_sva
|
||||
assert "irq_i[30] == apb4_periph_irq_i[22]" in irq_sva
|
||||
assert "irq_i[31] == apb4_periph_irq_i[23]" in irq_sva
|
||||
assert "irq_i[32] == apb4_periph_irq_i[24]" in irq_sva
|
||||
assert "bind retrosoc soc_irq_topology_sva" in irq_sva
|
||||
assert ".clk_i(clk_lp_i)" in irq_sva
|
||||
assert ".rst_n_i(rst_lp_n_i)" in irq_sva
|
||||
@@ -203,7 +208,8 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "RS_SOC_IRQ_UART0 UINT32_C(2)" in irq_metadata
|
||||
assert "RS_SOC_EXT_IRQ_UART0 UINT32_C(0)" in irq_metadata
|
||||
assert "RS_SOC_IRQ_APU" in irq_metadata
|
||||
assert "RS_SOC_IRQ_GA2D" not in irq_metadata
|
||||
assert "RS_SOC_IRQ_GA2D UINT32_C(32)" in irq_metadata
|
||||
assert "RS_SOC_EXT_IRQ_GA2D UINT32_C(30)" in irq_metadata
|
||||
assert filelist.startswith("+incdir+")
|
||||
|
||||
|
||||
@@ -253,10 +259,11 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("jpeg", "apb4_periph", 22, 30, "resource_irq_lp_i[5]"),
|
||||
("resource_fault", "apb4_system", 7, 29, "s_resource_fault_irq"),
|
||||
("apu", "apb4_periph", 23, 31, "resource_irq_lp_i[6]"),
|
||||
("ga2d", "apb4_periph", 24, 32, "resource_irq_lp_i[7]"),
|
||||
]
|
||||
|
||||
|
||||
def test_ga2d_p2_topology_is_data_master_only() -> None:
|
||||
def test_ga2d_p3_topology_activates_the_shell_without_a_data_source() -> None:
|
||||
document = json.loads(TOPOLOGY.read_text(encoding="utf-8"))
|
||||
policies = document["data_master_policies"]
|
||||
|
||||
@@ -280,11 +287,12 @@ def test_ga2d_p2_topology_is_data_master_only() -> None:
|
||||
"allow_instruction": False,
|
||||
"require_noncacheable": True,
|
||||
}
|
||||
assert all(
|
||||
target["name"] != "ga2d"
|
||||
for target in document["apb4_periph_targets"] + document["apb4_system_targets"]
|
||||
)
|
||||
assert all("ga2d" not in interrupt["name"] for interrupt in document["interrupts"])
|
||||
assert document["apb4_periph_targets"][-1]["name"] == "ga2d"
|
||||
assert document["apb4_periph_targets"][-1]["slot"] == 28
|
||||
assert document["apb4_periph_targets"][-1]["region"] == "APB4_GA2D"
|
||||
assert document["interrupts"][-1]["name"] == "ga2d"
|
||||
assert document["interrupts"][-1]["group_bit"] == 24
|
||||
assert document["interrupts"][-1]["core_bit"] == 32
|
||||
|
||||
|
||||
def test_apu_p1_fixed_resource_and_hp_irq_allocations() -> None:
|
||||
@@ -296,11 +304,15 @@ def test_apu_p1_fixed_resource_and_hp_irq_allocations() -> None:
|
||||
)
|
||||
|
||||
assert "s_hp_plic_source[10] = resource_irq_hp_i[6];" in periph
|
||||
assert "s_apu_irq_raw, s_jpeg_irq_raw" in periph
|
||||
assert "s_hp_plic_source[11] = resource_irq_hp_i[7];" in periph
|
||||
assert "s_ga2d_irq_raw," in periph
|
||||
assert ".ResourceCount(9)" in system
|
||||
assert ".apu_owner_i (s_resource_owner[7])" in top
|
||||
assert ".apu_quiesce_i (s_resource_quiesce[7])" in top
|
||||
assert ".apu_reset_i (s_resource_reset[7])" in top
|
||||
compact_top = "".join(top.split())
|
||||
assert ".ga2d_quiesce_i(s_resource_quiesce[8])" in compact_top
|
||||
assert ".ga2d_reset_i(s_resource_reset[8])" in compact_top
|
||||
assert "RS_RESOURCE_APU = 7" in resource_header
|
||||
assert "RS_RESOURCE_COUNT = 9" in resource_header
|
||||
|
||||
|
||||
Reference in new issue
Block a user