mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add DVP (Digital Video Processor) support and related formal verification
- Modified dma_core to accommodate a wider data width for FIFO operations. - Updated filelists to include new DVP source files and formal verification files. - Introduced formal verification modules for DVP functionality. - Enhanced clock and reset domain configurations for DVP integration. - Added DVP interrupt handling in the IRQ topology. - Implemented a testbench for DVP to validate register access and frame processing. - Updated software build scripts to include DVP-related source files. - Adjusted the system topology to reflect the new DVP interrupt and IRQ mapping.
This commit is contained in:
31 files changed
+1617
-332
No files matched your search
@@ -262,7 +262,7 @@ endif
|
||||
benchmark-report coremark-report \
|
||||
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
|
||||
check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
|
||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clean formal-doctor
|
||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-dvp formal-clean formal-doctor
|
||||
.NOTPARALLEL: setup
|
||||
|
||||
help:
|
||||
@@ -290,7 +290,7 @@ help:
|
||||
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
|
||||
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
|
||||
' formal | formal-bus | formal-rib-adapter | formal-rib2apb run SBY protocol proofs' \
|
||||
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-i2c | formal-timer | formal-clint run peripheral proofs' \
|
||||
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-i2c | formal-timer | formal-clint | formal-dvp run peripheral proofs' \
|
||||
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
|
||||
' benchmark-report run the memory/DMA profile and write meta/performance.json' \
|
||||
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
|
||||
|
||||
@@ -183,11 +183,6 @@
|
||||
// sdram
|
||||
#define reg_sdram_clkdiv RS_SOC_REG32(RS_SOC_RIBP_SDRAM_BASE, UINT32_C(0x00))
|
||||
#define reg_sdram_cfg RS_SOC_REG32(RS_SOC_RIBP_SDRAM_BASE, UINT32_C(0x04))
|
||||
// dvp
|
||||
#define reg_dvp_recven RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x00))
|
||||
#define reg_dvp_rxdata RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x04))
|
||||
#define reg_dvp_status RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x08))
|
||||
#define reg_dvp_stream_ctrl RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x0C))
|
||||
#define reg_user_ip_reg0 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x00))
|
||||
#define reg_user_ip_reg1 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x04))
|
||||
#define reg_user_ip_reg2 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x08))
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef RETROSOC_HAL_DVP_H
|
||||
#define RETROSOC_HAL_DVP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
#define RS_DVP_INTERRUPT_FRAME_START UINT32_C(0x00000001)
|
||||
#define RS_DVP_INTERRUPT_LINE_DONE UINT32_C(0x00000002)
|
||||
#define RS_DVP_INTERRUPT_FRAME_DONE UINT32_C(0x00000004)
|
||||
#define RS_DVP_INTERRUPT_OVERFLOW UINT32_C(0x00000008)
|
||||
#define RS_DVP_INTERRUPT_SYNC_ERROR UINT32_C(0x00000010)
|
||||
#define RS_DVP_INTERRUPT_CONFIG UINT32_C(0x00000020)
|
||||
#define RS_DVP_INTERRUPT_ABORTED UINT32_C(0x00000040)
|
||||
#define RS_DVP_INTERRUPT_ALL UINT32_C(0x0000007F)
|
||||
|
||||
#define RS_DVP_ERROR_OVERFLOW UINT32_C(0x00000001)
|
||||
#define RS_DVP_ERROR_SYNC UINT32_C(0x00000002)
|
||||
#define RS_DVP_ERROR_SIZE UINT32_C(0x00000004)
|
||||
#define RS_DVP_ERROR_PARTIAL UINT32_C(0x00000008)
|
||||
#define RS_DVP_ERROR_CONFIG UINT32_C(0x00000010)
|
||||
#define RS_DVP_ERROR_ABORT UINT32_C(0x00000020)
|
||||
|
||||
typedef enum {
|
||||
RS_DVP_FORMAT_RGB565 = 0,
|
||||
RS_DVP_FORMAT_YUV422 = 1,
|
||||
} rs_dvp_format_t;
|
||||
|
||||
typedef struct {
|
||||
rs_dvp_format_t format;
|
||||
uint16_t frame_width;
|
||||
uint16_t frame_height;
|
||||
uint16_t crop_x;
|
||||
uint16_t crop_y;
|
||||
uint16_t crop_width;
|
||||
uint16_t crop_height;
|
||||
bool crop_enable;
|
||||
bool snapshot;
|
||||
bool stream_enable;
|
||||
bool byte_swap;
|
||||
bool pixel_swap;
|
||||
bool vsync_active_low;
|
||||
bool href_active_low;
|
||||
bool pclk_falling;
|
||||
} rs_dvp_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t frame_count;
|
||||
uint32_t line_count;
|
||||
uint32_t pixel_count;
|
||||
uint32_t word_count;
|
||||
uint32_t drop_count;
|
||||
uint32_t error_status;
|
||||
uint32_t interrupt_state;
|
||||
bool active;
|
||||
} rs_dvp_status_t;
|
||||
|
||||
rs_status_t rs_dvp_probe(uint32_t *version, uint32_t *capability);
|
||||
rs_status_t rs_dvp_configure(const rs_dvp_config_t *config);
|
||||
rs_status_t rs_dvp_start(void);
|
||||
rs_status_t rs_dvp_abort(void);
|
||||
rs_status_t rs_dvp_flush(void);
|
||||
rs_status_t rs_dvp_get_status(rs_dvp_status_t *status);
|
||||
rs_status_t rs_dvp_interrupt_enable(uint32_t mask);
|
||||
rs_status_t rs_dvp_interrupt_clear(uint32_t mask);
|
||||
rs_status_t rs_dvp_interrupt_test(uint32_t mask);
|
||||
rs_status_t rs_dvp_capture_dma(uintptr_t destination, uint32_t word_capacity, rs_timeout_t timeout);
|
||||
void ip_dvp_test(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,182 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/dvp.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
|
||||
#define RS_DVP_CTRL_OFFSET UINT32_C(0x000)
|
||||
#define RS_DVP_RXDATA_OFFSET UINT32_C(0x004)
|
||||
#define RS_DVP_STATUS_OFFSET UINT32_C(0x008)
|
||||
#define RS_DVP_STREAM_CTRL_OFFSET UINT32_C(0x00C)
|
||||
#define RS_DVP_FORMAT_OFFSET UINT32_C(0x010)
|
||||
#define RS_DVP_SYNC_CFG_OFFSET UINT32_C(0x014)
|
||||
#define RS_DVP_FRAME_SIZE_OFFSET UINT32_C(0x018)
|
||||
#define RS_DVP_CROP_START_OFFSET UINT32_C(0x01C)
|
||||
#define RS_DVP_CROP_SIZE_OFFSET UINT32_C(0x020)
|
||||
#define RS_DVP_FRAME_COUNT_OFFSET UINT32_C(0x024)
|
||||
#define RS_DVP_LINE_COUNT_OFFSET UINT32_C(0x028)
|
||||
#define RS_DVP_PIXEL_COUNT_OFFSET UINT32_C(0x02C)
|
||||
#define RS_DVP_WORD_COUNT_OFFSET UINT32_C(0x030)
|
||||
#define RS_DVP_DROP_COUNT_OFFSET UINT32_C(0x034)
|
||||
#define RS_DVP_ERROR_STATUS_OFFSET UINT32_C(0x038)
|
||||
#define RS_DVP_INTR_STATE_OFFSET UINT32_C(0x03C)
|
||||
#define RS_DVP_INTR_ENABLE_OFFSET UINT32_C(0x040)
|
||||
#define RS_DVP_INTR_STATUS_OFFSET UINT32_C(0x044)
|
||||
#define RS_DVP_INTR_TEST_OFFSET UINT32_C(0x048)
|
||||
#define RS_DVP_COMMAND_OFFSET UINT32_C(0x04C)
|
||||
#define RS_DVP_VERSION_OFFSET UINT32_C(0x0F8)
|
||||
#define RS_DVP_CAPABILITY_OFFSET UINT32_C(0x0FC)
|
||||
|
||||
#define RS_DVP_CTRL_ENABLE_MASK UINT32_C(0x00000001)
|
||||
#define RS_DVP_CTRL_SNAPSHOT_MASK UINT32_C(0x00000002)
|
||||
#define RS_DVP_CTRL_CROP_MASK UINT32_C(0x00000004)
|
||||
#define RS_DVP_COMMAND_ABORT_MASK UINT32_C(0x00000001)
|
||||
#define RS_DVP_COMMAND_FLUSH_MASK UINT32_C(0x00000002)
|
||||
#define RS_DVP_STATUS_ACTIVE_MASK UINT32_C(0x00000001)
|
||||
#define RS_DVP_STATUS_ERROR_MASK UINT32_C(0x00000040)
|
||||
|
||||
static volatile uint32_t *rs_dvp_register(uint32_t offset) {
|
||||
return (volatile uint32_t *)(RS_SOC_RIBP_DVP_BASE + (uintptr_t)offset);
|
||||
}
|
||||
|
||||
static bool rs_dvp_config_valid(const rs_dvp_config_t *config) {
|
||||
if ((config == NULL) || ((uint32_t)config->format > (uint32_t)RS_DVP_FORMAT_YUV422) ||
|
||||
(config->frame_width == 0U) || (config->frame_height == 0U)) {
|
||||
return false;
|
||||
}
|
||||
if (config->crop_enable &&
|
||||
((config->crop_width == 0U) || (config->crop_height == 0U) ||
|
||||
((uint32_t)config->crop_x + config->crop_width > config->frame_width) ||
|
||||
((uint32_t)config->crop_y + config->crop_height > config->frame_height))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_probe(uint32_t *version, uint32_t *capability) {
|
||||
if ((version == NULL) || (capability == NULL))
|
||||
return RS_EINVAL;
|
||||
*version = *rs_dvp_register(RS_DVP_VERSION_OFFSET);
|
||||
*capability = *rs_dvp_register(RS_DVP_CAPABILITY_OFFSET);
|
||||
return (*version == UINT32_C(0x00020000)) ? RS_OK : RS_EIO;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_configure(const rs_dvp_config_t *config) {
|
||||
uint32_t format;
|
||||
uint32_t sync;
|
||||
uint32_t control;
|
||||
|
||||
if (!rs_dvp_config_valid(config))
|
||||
return RS_EINVAL;
|
||||
(void)rs_dvp_abort();
|
||||
format = (uint32_t)config->format;
|
||||
if (config->byte_swap)
|
||||
format |= UINT32_C(0x00000004);
|
||||
if (config->pixel_swap)
|
||||
format |= UINT32_C(0x00000008);
|
||||
sync = (config->vsync_active_low ? 1U : 0U) | (config->href_active_low ? 2U : 0U) |
|
||||
(config->pclk_falling ? 4U : 0U);
|
||||
control = (config->snapshot ? RS_DVP_CTRL_SNAPSHOT_MASK : 0U) |
|
||||
(config->crop_enable ? RS_DVP_CTRL_CROP_MASK : 0U);
|
||||
*rs_dvp_register(RS_DVP_FORMAT_OFFSET) = format;
|
||||
*rs_dvp_register(RS_DVP_SYNC_CFG_OFFSET) = sync;
|
||||
*rs_dvp_register(RS_DVP_FRAME_SIZE_OFFSET) =
|
||||
((uint32_t)config->frame_height << 16) | config->frame_width;
|
||||
*rs_dvp_register(RS_DVP_CROP_START_OFFSET) = ((uint32_t)config->crop_y << 16) | config->crop_x;
|
||||
*rs_dvp_register(RS_DVP_CROP_SIZE_OFFSET) =
|
||||
((uint32_t)config->crop_height << 16) | config->crop_width;
|
||||
*rs_dvp_register(RS_DVP_STREAM_CTRL_OFFSET) = config->stream_enable ? 1U : 0U;
|
||||
*rs_dvp_register(RS_DVP_ERROR_STATUS_OFFSET) = RS_DVP_ERROR_OVERFLOW | RS_DVP_ERROR_SYNC |
|
||||
RS_DVP_ERROR_SIZE | RS_DVP_ERROR_PARTIAL |
|
||||
RS_DVP_ERROR_CONFIG | RS_DVP_ERROR_ABORT;
|
||||
*rs_dvp_register(RS_DVP_INTR_STATE_OFFSET) = RS_DVP_INTERRUPT_ALL;
|
||||
*rs_dvp_register(RS_DVP_CTRL_OFFSET) = control;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_start(void) {
|
||||
*rs_dvp_register(RS_DVP_CTRL_OFFSET) |= RS_DVP_CTRL_ENABLE_MASK;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_abort(void) {
|
||||
*rs_dvp_register(RS_DVP_COMMAND_OFFSET) = RS_DVP_COMMAND_ABORT_MASK;
|
||||
*rs_dvp_register(RS_DVP_CTRL_OFFSET) &= ~RS_DVP_CTRL_ENABLE_MASK;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_flush(void) {
|
||||
*rs_dvp_register(RS_DVP_COMMAND_OFFSET) = RS_DVP_COMMAND_FLUSH_MASK;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_get_status(rs_dvp_status_t *status) {
|
||||
if (status == NULL)
|
||||
return RS_EINVAL;
|
||||
status->status = *rs_dvp_register(RS_DVP_STATUS_OFFSET);
|
||||
status->active = (status->status & RS_DVP_STATUS_ACTIVE_MASK) != 0U;
|
||||
status->frame_count = *rs_dvp_register(RS_DVP_FRAME_COUNT_OFFSET);
|
||||
status->line_count = *rs_dvp_register(RS_DVP_LINE_COUNT_OFFSET);
|
||||
status->pixel_count = *rs_dvp_register(RS_DVP_PIXEL_COUNT_OFFSET);
|
||||
status->word_count = *rs_dvp_register(RS_DVP_WORD_COUNT_OFFSET);
|
||||
status->drop_count = *rs_dvp_register(RS_DVP_DROP_COUNT_OFFSET);
|
||||
status->error_status = *rs_dvp_register(RS_DVP_ERROR_STATUS_OFFSET);
|
||||
status->interrupt_state = *rs_dvp_register(RS_DVP_INTR_STATE_OFFSET);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_interrupt_enable(uint32_t mask) {
|
||||
if ((mask & ~RS_DVP_INTERRUPT_ALL) != 0U)
|
||||
return RS_EINVAL;
|
||||
*rs_dvp_register(RS_DVP_INTR_ENABLE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_interrupt_clear(uint32_t mask) {
|
||||
if ((mask & ~RS_DVP_INTERRUPT_ALL) != 0U)
|
||||
return RS_EINVAL;
|
||||
*rs_dvp_register(RS_DVP_INTR_STATE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_interrupt_test(uint32_t mask) {
|
||||
if ((mask & ~RS_DVP_INTERRUPT_ALL) != 0U)
|
||||
return RS_EINVAL;
|
||||
*rs_dvp_register(RS_DVP_INTR_TEST_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_dvp_capture_dma(uintptr_t destination, uint32_t word_capacity,
|
||||
rs_timeout_t timeout) {
|
||||
rs_dvp_status_t status;
|
||||
if ((destination == 0U) || (word_capacity == 0U))
|
||||
return RS_EINVAL;
|
||||
if ((rs_dma_config(RS_DMA_MODE_DVP_RX, RS_SOC_RIBP_DVP_BASE, 0U, destination, 1U,
|
||||
word_capacity) != RS_OK) ||
|
||||
(rs_dma_start() != RS_OK) || (rs_dvp_start() != RS_OK)) {
|
||||
return RS_EIO;
|
||||
}
|
||||
while (timeout-- != 0U) {
|
||||
if (rs_dvp_get_status(&status) != RS_OK)
|
||||
return RS_EIO;
|
||||
if ((status.error_status != 0U) ||
|
||||
((status.interrupt_state & RS_DVP_INTERRUPT_FRAME_DONE) != 0U)) {
|
||||
(void)rs_dvp_abort();
|
||||
return (status.error_status == 0U) && (rs_dma_wait(timeout) == RS_OK) ? RS_OK : RS_EIO;
|
||||
}
|
||||
}
|
||||
(void)rs_dvp_abort();
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
void ip_dvp_test(void) {
|
||||
uint32_t version;
|
||||
uint32_t capability;
|
||||
printf("dvp test\n");
|
||||
if (rs_dvp_probe(&version, &capability) == RS_OK) {
|
||||
printf("dvp v%lx capability %lx\n", (unsigned long)version, (unsigned long)capability);
|
||||
} else {
|
||||
printf("dvp probe failed\n");
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,8 @@ void rs_app_info(void) {
|
||||
printf(" 1 x CLINT @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_CLINT_BASE);
|
||||
printf(" 1 x SDRAM @%p\n", (void *)®_sdram_clkdiv);
|
||||
printf(" 1 x DVP @%p\n", (void *)®_dvp_recven);
|
||||
printf(" 1 x DVP @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_DVP_BASE);
|
||||
printf(" 1 x I2C1 @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_I2C1_BASE);
|
||||
printf(" 1 x ARCHINFO @%p\n",
|
||||
|
||||
@@ -9,6 +9,7 @@ verification documentation for self-owned retroSoC peripheral IP.
|
||||
- [gpio.md](gpio.md) defines the dual-window GPIO controller.
|
||||
- [uart.md](uart.md) defines the RIBP UART V3 controller.
|
||||
- [i2c.md](i2c.md) defines the dual RIBP I2C V2 controllers.
|
||||
- [dvp.md](dvp.md) defines the RIBP DVP V2 capture controller.
|
||||
|
||||
The corresponding RTL and HAL implementations remain the executable sources
|
||||
of truth. Update the affected document whenever an IP interface or register ABI
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
# RIBP DVP V2
|
||||
|
||||
The DVP V2 block captures an 8-bit parallel camera stream and presents the
|
||||
captured pixels through an AXI4-Stream source. RIBP is used for configuration,
|
||||
status, statistics, error reporting, and interrupts. The existing DMA engine
|
||||
can transfer the AXI4-Stream payload into AXI4 memory using DVP receive mode.
|
||||
The input path supports RGB565 and YUV422 byte formats, programmable VSYNC
|
||||
and HREF polarity, selectable PCLK sampling edge, snapshot and continuous
|
||||
capture, and rectangular cropping.
|
||||
|
||||
## Integration
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| RIBP base address | `0x1000E000` |
|
||||
| RIBP interrupt group bit | 13 |
|
||||
| Management-core interrupt | 15 |
|
||||
| Input interface | 8-bit parallel data, PCLK, HREF, VSYNC |
|
||||
| AXI4-Stream data width | 32 bits |
|
||||
| AXI4-Stream frame markers | `TUSER[0]` SOF, `TLAST` EOL |
|
||||
| DMA mode | 11 DVP RX |
|
||||
| ABI version | `0x00020000` |
|
||||
|
||||
The pixel clock is buffered and can be inverted before the pixel-domain reset
|
||||
synchronizer. Configuration and frame statistics cross between the system and
|
||||
pixel domains through the common `cdc_2phase` primitive. Captured payloads use
|
||||
the common `cdc_fifo_warm_flush` primitive and carry
|
||||
`{TUSER, TLAST, TKEEP, TSTRB, TDATA}`. FIFO overflow drops the active frame,
|
||||
sets an error flag, and requires software to discard the affected DMA buffer.
|
||||
|
||||
## Register ABI
|
||||
|
||||
All registers are 32 bits and naturally aligned. Unmapped, unaligned, and
|
||||
direction-invalid accesses complete with `resp_err`. Configuration writes are
|
||||
rejected while capture is active. Frame dimensions must be non-zero; invalid
|
||||
format or crop values set the configuration error path and do not start a
|
||||
valid capture. RW registers support byte strobes.
|
||||
|
||||
| Offset | Name | Access | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `0x000` | `CTRL` | RW | Enable, snapshot, and crop-enable controls. |
|
||||
| `0x004` | `RXDATA` | RO/pop | PIO receive word when AXI4-Stream output is disabled. |
|
||||
| `0x008` | `STATUS` | RO | Active, FIFO, stream, and error state. |
|
||||
| `0x00C` | `STREAM_CTRL` | RW | Enable AXI4-Stream output. |
|
||||
| `0x010` | `FORMAT` | RW | RGB565/YUV422 selection and byte/pixel swap controls. |
|
||||
| `0x014` | `SYNC_CFG` | RW | VSYNC, HREF, and PCLK polarity controls. |
|
||||
| `0x018` | `FRAME_SIZE` | RW | Frame width in bits 15:0 and height in bits 31:16. |
|
||||
| `0x01C` | `CROP_START` | RW | Crop X coordinate in bits 15:0 and Y coordinate in bits 31:16. |
|
||||
| `0x020` | `CROP_SIZE` | RW | Crop width in bits 15:0 and height in bits 31:16. |
|
||||
| `0x024` | `FRAME_COUNT` | RO | Completed frame count. |
|
||||
| `0x028` | `LINE_COUNT` | RO | Completed line count from the last frame. |
|
||||
| `0x02C` | `PIXEL_COUNT` | RO | Captured pixel count from the last frame. |
|
||||
| `0x030` | `WORD_COUNT` | RO | AXI4-Stream word count from the last frame. |
|
||||
| `0x034` | `DROP_COUNT` | RO | Number of dropped words caused by overflow. |
|
||||
| `0x038` | `ERROR_STATUS` | RW1C | Sticky overflow, sync, size, partial, config, and abort errors. |
|
||||
| `0x03C` | `INTR_STATE` | RW1C | Sticky frame, line, overflow, configuration, and abort events. |
|
||||
| `0x040` | `INTR_ENABLE` | RW | Interrupt enable mask. |
|
||||
| `0x044` | `INTR_STATUS` | RO | `INTR_STATE & INTR_ENABLE`. |
|
||||
| `0x048` | `INTR_TEST` | WO | Write-one software interrupt injection. |
|
||||
| `0x04C` | `COMMAND` | WO | Abort and FIFO flush commands. |
|
||||
| `0x0F8` | `IP_VERSION` | RO | ABI version, currently `0x00020000` (2.0). |
|
||||
| `0x0FC` | `CAPABILITY` | RO | Implemented format, crop, statistics, interrupt, and stream features. |
|
||||
|
||||
`CTRL` bit 0 enables capture, bit 1 selects snapshot mode, and bit 2 enables
|
||||
cropping. `STREAM_CTRL` bit 0 enables AXI4-Stream output; when it is clear,
|
||||
software can consume captured words through `RXDATA`. `FORMAT` values `0` and
|
||||
`1` select RGB565 and YUV422 respectively. Values above `1` are invalid.
|
||||
`FORMAT` bits 2 and 3 control byte and pixel ordering. `SYNC_CFG` bits 0, 1,
|
||||
and 2 select active-low VSYNC, active-low HREF, and falling-edge PCLK.
|
||||
|
||||
The seven interrupt bits are frame start, line done, frame done, overflow,
|
||||
synchronization error, configuration error, and aborted capture. Error and
|
||||
interrupt state are write-one-to-clear. Hardware events have priority over a
|
||||
simultaneous software clear so that an event cannot be lost. The external
|
||||
interrupt is the reduction OR of `INTR_STATE & INTR_ENABLE`.
|
||||
|
||||
The RTL ABI constants are maintained directly in
|
||||
`rtl/ip/ribp/multimedia/dvp_define.svh`. Matching HAL offsets and masks are
|
||||
maintained directly in `crt/src/hal/dvp.c`. Changes to either definition must
|
||||
update the other definition, this document, and the RTL/software tests in the
|
||||
same change.
|
||||
|
||||
## AXI4-Stream and Capture Semantics
|
||||
|
||||
Two 8-bit input samples are packed into one 32-bit stream word. The first
|
||||
pixel occupies `TDATA[15:0]` and the second pixel occupies `TDATA[31:16]`.
|
||||
`TUSER[0]` is asserted on the first word of a frame, and `TLAST` is asserted
|
||||
on the last word of each line. `TID` and `TDEST` are tied to zero.
|
||||
|
||||
For an even number of pixels, `TKEEP` and `TSTRB` are `4'b1111`. For an odd
|
||||
number of pixels, the final word of each line uses `4'b0011` and the unused
|
||||
upper half of `TDATA` is zero. AXI4-Stream `TVALID` remains asserted and the
|
||||
payload remains stable while `TREADY` is low. The FIFO backpressures the pixel
|
||||
domain; an inability to accept a word during an active frame records an
|
||||
overflow and terminates that frame.
|
||||
|
||||
VSYNC rising after polarity normalization starts a frame. HREF qualifies
|
||||
pixel sampling and its falling edge completes a line. Snapshot mode stops
|
||||
after the next completed frame; continuous mode resets line and pixel counters
|
||||
and captures the next frame. Crop coordinates are applied in the normalized
|
||||
frame coordinate space, and a crop must fit within the configured frame size.
|
||||
|
||||
The PIO path and AXI4-Stream path are mutually exclusive at the output:
|
||||
`RXDATA` pops a word only while stream output is disabled. The DMA HAL uses a
|
||||
single-frame transfer length; descriptor rings, double buffering, and frame
|
||||
metadata chaining are not part of the current ABI.
|
||||
|
||||
## DMA and Software Contract
|
||||
|
||||
DMA mode 11 treats each AXI4-Stream word as one 32-bit memory write and uses
|
||||
the stream `TKEEP` value for the final partial word. Software should configure
|
||||
the frame and crop dimensions, clear stale error and interrupt state, program
|
||||
the DMA destination and capacity, enable stream output, and then start DVP
|
||||
capture. A frame that reports overflow, synchronization, partial, or abort
|
||||
errors must not be consumed by software.
|
||||
|
||||
The public HAL exposes structured configuration, bounded status polling,
|
||||
command and interrupt control, capability discovery, and a convenience API
|
||||
for one-frame DMA capture. Applications should use `rs_dvp_configure()`,
|
||||
`rs_dma_config()`, `rs_dvp_start()`, and `rs_dvp_capture_dma()` rather than
|
||||
accessing the registers directly.
|
||||
|
||||
## Verification and Current Scope
|
||||
|
||||
The self-checking RTL test covers the versioned ABI, invalid RIBP accesses,
|
||||
configuration writes, RGB565 packing, SOF/EOL framing, even and odd line
|
||||
widths, AXI4-Stream output, frame statistics, and interrupt state handling.
|
||||
The SBY target proves RIBP response behavior, request/response progress,
|
||||
interrupt composition, and normal/error coverage for the register shell.
|
||||
Host tests compile and execute the DVP directed test, while the IHP130
|
||||
regression exercises behavior simulation, synthesis, netlist simulation, and
|
||||
STA integration.
|
||||
|
||||
The current ABI does not include a native DVP AXI4 memory master, outstanding
|
||||
AXI transactions, frame descriptor rings, line stride configuration, JPEG or
|
||||
other compressed formats, external sync metadata, or multiple camera clocks.
|
||||
Those features require a versioned ABI extension and explicit SoC routing;
|
||||
existing register fields must not be repurposed for them.
|
||||
@@ -164,7 +164,7 @@ digraph mini_soc_block_diagram {
|
||||
];
|
||||
stream_io [
|
||||
fillcolor="#FFF3C9",
|
||||
label="AXI4-Stream data endpoints\nI2S TX/RX and DVP RX\nRIBP configuration with PIO fallback"
|
||||
label="AXI4-Stream data endpoints\nI2S TX/RX and DVP RX\nSOF/EOL/TKEEP framing"
|
||||
];
|
||||
uart0 [
|
||||
fillcolor="#F9E1E7",
|
||||
|
||||
@@ -4,24 +4,24 @@
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: mini_soc_block_diagram Pages: 1 -->
|
||||
<svg width="4505pt" height="963pt"
|
||||
viewBox="0.00 0.00 4505.00 963.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="4467pt" height="963pt"
|
||||
viewBox="0.00 0.00 4467.00 963.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 959.48)">
|
||||
<title>mini_soc_block_diagram</title>
|
||||
<text text-anchor="middle" x="132" y="-937.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_rtl_ownership</title>
|
||||
<path fill="transparent" stroke="#cbd5e1" stroke-dasharray="5,2" d="M3182,-821.48C3182,-821.48 3837,-821.48 3837,-821.48 3843,-821.48 3849,-827.48 3849,-833.48 3849,-833.48 3849,-907.48 3849,-907.48 3849,-913.48 3843,-919.48 3837,-919.48 3837,-919.48 3182,-919.48 3182,-919.48 3176,-919.48 3170,-913.48 3170,-907.48 3170,-907.48 3170,-833.48 3170,-833.48 3170,-827.48 3176,-821.48 3182,-821.48"/>
|
||||
<text text-anchor="middle" x="3259.5" y="-907.48" font-family="Arial" font-size="10.00" fill="#334155">RTL ownership and validation profiles</text>
|
||||
<path fill="transparent" stroke="#cbd5e1" stroke-dasharray="5,2" d="M3163,-821.48C3163,-821.48 3818,-821.48 3818,-821.48 3824,-821.48 3830,-827.48 3830,-833.48 3830,-833.48 3830,-907.48 3830,-907.48 3830,-913.48 3824,-919.48 3818,-919.48 3818,-919.48 3163,-919.48 3163,-919.48 3157,-919.48 3151,-913.48 3151,-907.48 3151,-907.48 3151,-833.48 3151,-833.48 3151,-827.48 3157,-821.48 3163,-821.48"/>
|
||||
<text text-anchor="middle" x="3240.5" y="-907.48" font-family="Arial" font-size="10.00" fill="#334155">RTL ownership and validation profiles</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_asic</title>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 4477,-85 4477,-85 4483,-85 4489,-91 4489,-97 4489,-97 4489,-781.48 4489,-781.48 4489,-787.48 4483,-793.48 4477,-793.48 4477,-793.48 160,-793.48 160,-793.48 154,-793.48 148,-787.48 148,-781.48 148,-781.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 4439,-85 4439,-85 4445,-85 4451,-91 4451,-97 4451,-97 4451,-781.48 4451,-781.48 4451,-787.48 4445,-793.48 4439,-793.48 4439,-793.48 160,-793.48 160,-793.48 154,-793.48 148,-787.48 148,-781.48 148,-781.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<text text-anchor="middle" x="196.5" y="-778.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text>
|
||||
</g>
|
||||
<g id="clust3" class="cluster">
|
||||
<title>cluster_soc</title>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 4459,-103 4459,-103 4465,-103 4471,-109 4471,-115 4471,-115 4471,-738.48 4471,-738.48 4471,-744.48 4465,-750.48 4459,-750.48 4459,-750.48 390,-750.48 390,-750.48 384,-750.48 378,-744.48 378,-738.48 378,-738.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 4421,-103 4421,-103 4427,-103 4433,-109 4433,-115 4433,-115 4433,-738.48 4433,-738.48 4433,-744.48 4427,-750.48 4421,-750.48 4421,-750.48 390,-750.48 390,-750.48 384,-750.48 378,-744.48 378,-738.48 378,-738.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<text text-anchor="middle" x="407.5" y="-736.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
|
||||
</g>
|
||||
<!-- ext_clock -->
|
||||
@@ -78,30 +78,30 @@
|
||||
<!-- rtl_owned -->
|
||||
<g id="node4" class="node">
|
||||
<title>rtl_owned</title>
|
||||
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M3825,-869.48C3825,-869.48 3713,-869.48 3713,-869.48 3707,-869.48 3701,-863.48 3701,-857.48 3701,-857.48 3701,-845.48 3701,-845.48 3701,-839.48 3707,-833.48 3713,-833.48 3713,-833.48 3825,-833.48 3825,-833.48 3831,-833.48 3837,-839.48 3837,-845.48 3837,-845.48 3837,-857.48 3837,-857.48 3837,-863.48 3831,-869.48 3825,-869.48"/>
|
||||
<text text-anchor="middle" x="3769" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">Self-owned RTL</text>
|
||||
<text text-anchor="middle" x="3769" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">Verible format + strict style</text>
|
||||
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M3806,-869.48C3806,-869.48 3694,-869.48 3694,-869.48 3688,-869.48 3682,-863.48 3682,-857.48 3682,-857.48 3682,-845.48 3682,-845.48 3682,-839.48 3688,-833.48 3694,-833.48 3694,-833.48 3806,-833.48 3806,-833.48 3812,-833.48 3818,-839.48 3818,-845.48 3818,-845.48 3818,-857.48 3818,-857.48 3818,-863.48 3812,-869.48 3806,-869.48"/>
|
||||
<text text-anchor="middle" x="3750" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">Self-owned RTL</text>
|
||||
<text text-anchor="middle" x="3750" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">Verible format + strict style</text>
|
||||
</g>
|
||||
<!-- rtl_verif -->
|
||||
<g id="node5" class="node">
|
||||
<title>rtl_verif</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M3661.5,-869.48C3661.5,-869.48 3574.5,-869.48 3574.5,-869.48 3568.5,-869.48 3562.5,-863.48 3562.5,-857.48 3562.5,-857.48 3562.5,-845.48 3562.5,-845.48 3562.5,-839.48 3568.5,-833.48 3574.5,-833.48 3574.5,-833.48 3661.5,-833.48 3661.5,-833.48 3667.5,-833.48 3673.5,-839.48 3673.5,-845.48 3673.5,-845.48 3673.5,-857.48 3673.5,-857.48 3673.5,-863.48 3667.5,-869.48 3661.5,-869.48"/>
|
||||
<text text-anchor="middle" x="3618" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">Formal and DV RTL</text>
|
||||
<text text-anchor="middle" x="3618" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">verification lint profile</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M3642.5,-869.48C3642.5,-869.48 3555.5,-869.48 3555.5,-869.48 3549.5,-869.48 3543.5,-863.48 3543.5,-857.48 3543.5,-857.48 3543.5,-845.48 3543.5,-845.48 3543.5,-839.48 3549.5,-833.48 3555.5,-833.48 3555.5,-833.48 3642.5,-833.48 3642.5,-833.48 3648.5,-833.48 3654.5,-839.48 3654.5,-845.48 3654.5,-845.48 3654.5,-857.48 3654.5,-857.48 3654.5,-863.48 3648.5,-869.48 3642.5,-869.48"/>
|
||||
<text text-anchor="middle" x="3599" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">Formal and DV RTL</text>
|
||||
<text text-anchor="middle" x="3599" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">verification lint profile</text>
|
||||
</g>
|
||||
<!-- rtl_tech -->
|
||||
<g id="node6" class="node">
|
||||
<title>rtl_tech</title>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M3523.5,-869.48C3523.5,-869.48 3396.5,-869.48 3396.5,-869.48 3390.5,-869.48 3384.5,-863.48 3384.5,-857.48 3384.5,-857.48 3384.5,-845.48 3384.5,-845.48 3384.5,-839.48 3390.5,-833.48 3396.5,-833.48 3396.5,-833.48 3523.5,-833.48 3523.5,-833.48 3529.5,-833.48 3535.5,-839.48 3535.5,-845.48 3535.5,-845.48 3535.5,-857.48 3535.5,-857.48 3535.5,-863.48 3529.5,-869.48 3523.5,-869.48"/>
|
||||
<text text-anchor="middle" x="3460" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">PDK and technology wrappers</text>
|
||||
<text text-anchor="middle" x="3460" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">compile/elaboration profile</text>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M3504.5,-869.48C3504.5,-869.48 3377.5,-869.48 3377.5,-869.48 3371.5,-869.48 3365.5,-863.48 3365.5,-857.48 3365.5,-857.48 3365.5,-845.48 3365.5,-845.48 3365.5,-839.48 3371.5,-833.48 3377.5,-833.48 3377.5,-833.48 3504.5,-833.48 3504.5,-833.48 3510.5,-833.48 3516.5,-839.48 3516.5,-845.48 3516.5,-845.48 3516.5,-857.48 3516.5,-857.48 3516.5,-863.48 3510.5,-869.48 3504.5,-869.48"/>
|
||||
<text text-anchor="middle" x="3441" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">PDK and technology wrappers</text>
|
||||
<text text-anchor="middle" x="3441" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">compile/elaboration profile</text>
|
||||
</g>
|
||||
<!-- rtl_generated -->
|
||||
<g id="node7" class="node">
|
||||
<title>rtl_generated</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M3345.5,-869.48C3345.5,-869.48 3194.5,-869.48 3194.5,-869.48 3188.5,-869.48 3182.5,-863.48 3182.5,-857.48 3182.5,-857.48 3182.5,-845.48 3182.5,-845.48 3182.5,-839.48 3188.5,-833.48 3194.5,-833.48 3194.5,-833.48 3345.5,-833.48 3345.5,-833.48 3351.5,-833.48 3357.5,-839.48 3357.5,-845.48 3357.5,-845.48 3357.5,-857.48 3357.5,-857.48 3357.5,-863.48 3351.5,-869.48 3345.5,-869.48"/>
|
||||
<text text-anchor="middle" x="3270" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">Generated and managed RTL</text>
|
||||
<text text-anchor="middle" x="3270" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">locked source and regeneration flow</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M3326.5,-869.48C3326.5,-869.48 3175.5,-869.48 3175.5,-869.48 3169.5,-869.48 3163.5,-863.48 3163.5,-857.48 3163.5,-857.48 3163.5,-845.48 3163.5,-845.48 3163.5,-839.48 3169.5,-833.48 3175.5,-833.48 3175.5,-833.48 3326.5,-833.48 3326.5,-833.48 3332.5,-833.48 3338.5,-839.48 3338.5,-845.48 3338.5,-845.48 3338.5,-857.48 3338.5,-857.48 3338.5,-863.48 3332.5,-869.48 3326.5,-869.48"/>
|
||||
<text text-anchor="middle" x="3251" y="-854.48" font-family="Arial" font-size="10.00" fill="#111827">Generated and managed RTL</text>
|
||||
<text text-anchor="middle" x="3251" y="-843.48" font-family="Arial" font-size="10.00" fill="#111827">locked source and regeneration flow</text>
|
||||
</g>
|
||||
<!-- fabric -->
|
||||
<g id="node15" class="node">
|
||||
@@ -268,18 +268,18 @@
|
||||
<!-- stream_io -->
|
||||
<g id="node24" class="node">
|
||||
<title>stream_io</title>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M4442.5,-255C4442.5,-255 4287.5,-255 4287.5,-255 4281.5,-255 4275.5,-249 4275.5,-243 4275.5,-243 4275.5,-222 4275.5,-222 4275.5,-216 4281.5,-210 4287.5,-210 4287.5,-210 4442.5,-210 4442.5,-210 4448.5,-210 4454.5,-216 4454.5,-222 4454.5,-222 4454.5,-243 4454.5,-243 4454.5,-249 4448.5,-255 4442.5,-255"/>
|
||||
<text text-anchor="middle" x="4365" y="-241" font-family="Arial" font-size="10.00" fill="#111827">AXI4-Stream data endpoints</text>
|
||||
<text text-anchor="middle" x="4365" y="-230" font-family="Arial" font-size="10.00" fill="#111827">I2S TX/RX and DVP RX</text>
|
||||
<text text-anchor="middle" x="4365" y="-219" font-family="Arial" font-size="10.00" fill="#111827">RIBP configuration with PIO fallback</text>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M4405,-255C4405,-255 4287,-255 4287,-255 4281,-255 4275,-249 4275,-243 4275,-243 4275,-222 4275,-222 4275,-216 4281,-210 4287,-210 4287,-210 4405,-210 4405,-210 4411,-210 4417,-216 4417,-222 4417,-222 4417,-243 4417,-243 4417,-249 4411,-255 4405,-255"/>
|
||||
<text text-anchor="middle" x="4346" y="-241" font-family="Arial" font-size="10.00" fill="#111827">AXI4-Stream data endpoints</text>
|
||||
<text text-anchor="middle" x="4346" y="-230" font-family="Arial" font-size="10.00" fill="#111827">I2S TX/RX and DVP RX</text>
|
||||
<text text-anchor="middle" x="4346" y="-219" font-family="Arial" font-size="10.00" fill="#111827">SOF/EOL/TKEEP framing</text>
|
||||
</g>
|
||||
<!-- dma->stream_io -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>dma->stream_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1916.58,-564.04C2167.25,-550.79 2835,-515.48 2835,-515.48 2835,-515.48 3342,-492.48 3342,-492.48 3342,-492.48 4021.7,-320.41 4273.03,-256.78"/>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1916.58,-564.04C2167.25,-550.79 2835,-515.48 2835,-515.48 2835,-515.48 3342,-492.48 3342,-492.48 3342,-492.48 4031.56,-314.61 4267.75,-253.69"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1916.14,-561.61 1909.28,-564.42 1916.4,-566.5 1916.14,-561.61"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4273.79,-259.12 4279.98,-255.02 4272.59,-254.37 4273.79,-259.12"/>
|
||||
<text text-anchor="middle" x="3770.5" y="-389.6" font-family="Arial" font-size="8.00" fill="#374151">AXI4-Stream</text>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4268.43,-256.04 4274.6,-251.92 4267.21,-251.29 4268.43,-256.04"/>
|
||||
<text text-anchor="middle" x="3763.5" y="-389.6" font-family="Arial" font-size="8.00" fill="#374151">AXI4-Stream</text>
|
||||
</g>
|
||||
<!-- uart0 -->
|
||||
<g id="node25" class="node">
|
||||
@@ -605,8 +605,8 @@
|
||||
<!-- ribp_targets->stream_io -->
|
||||
<g id="edge62" class="edge">
|
||||
<title>ribp_targets->stream_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M2141,-250.5C2155.7,-253.15 2166,-255 2166,-255 2166,-255 2931.5,-287 2931.5,-287 2931.5,-287 2998.5,-287 2998.5,-287 2998.5,-287 4262,-255 4262,-255 4262,-255 4264.39,-254.48 4268.43,-253.59"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4269.15,-255.95 4275.47,-252.06 4268.1,-251.16 4269.15,-255.95"/>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M2141,-250.5C2155.7,-253.15 2166,-255 2166,-255 2166,-255 2931.5,-287 2931.5,-287 2931.5,-287 2998.5,-287 2998.5,-287 2998.5,-287 4262,-255 4262,-255 4262,-255 4264.19,-254.41 4267.86,-253.43"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4268.63,-255.76 4274.76,-251.58 4267.36,-251.03 4268.63,-255.76"/>
|
||||
<text text-anchor="middle" x="2965" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP configuration</text>
|
||||
</g>
|
||||
<!-- ribp_targets->gpio_controller -->
|
||||
@@ -627,10 +627,10 @@
|
||||
<!-- stream_io->ext_io -->
|
||||
<g id="edge64" class="edge">
|
||||
<title>stream_io->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M4314.21,-206.7C4228.65,-164.91 4065,-85 4065,-85 4065,-85 3955.01,-63.86 3863.99,-46.37"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4313.37,-209.01 4320.73,-209.88 4315.52,-204.61 4313.37,-209.01"/>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M4297.94,-206.45C4217.67,-164.59 4065,-85 4065,-85 4065,-85 3955.01,-63.86 3863.99,-46.37"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4297.2,-208.82 4304.54,-209.88 4299.46,-204.47 4297.2,-208.82"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="3864.26,-43.92 3856.92,-45.01 3863.33,-48.74 3864.26,-43.92"/>
|
||||
<text text-anchor="middle" x="4236" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">I2S / DVP signals</text>
|
||||
<text text-anchor="middle" x="4227" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">I2S / DVP signals</text>
|
||||
</g>
|
||||
<!-- uart0->ext_io -->
|
||||
<g id="edge65" class="edge">
|
||||
|
||||
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
+258
-164
@@ -1,25 +1,9 @@
|
||||
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
// You may obtain a copy of Mulan PSL v2 at:
|
||||
// http://license.coscl.org.cn/MulanPSL2
|
||||
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
`ifndef RIBP_DVP_DEF_SV
|
||||
`define RIBP_DVP_DEF_SV
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_DVP_RECVEN 8'h00
|
||||
`define RIBP_DVP_RXDATA 8'h04
|
||||
`define RIBP_DVP_STATUS 8'h08
|
||||
`define RIBP_DVP_STREAM_CTRL 8'h0C
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
`include "dvp_define.svh"
|
||||
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
interface dvp_if ();
|
||||
logic pclk_i;
|
||||
logic href_i;
|
||||
@@ -28,178 +12,288 @@ interface dvp_if ();
|
||||
|
||||
modport dut(input pclk_i, input href_i, input vsync_i, input dat_i);
|
||||
endinterface
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
|
||||
module ribp_dvp (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
axi4_stream_if.source rx_axis,
|
||||
dvp_if.dut dvp
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
axi4_stream_if.source rx_axis,
|
||||
dvp_if.dut dvp,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
// ribp
|
||||
logic s_ribp_wr_hdshk, s_ribp_rd_hdshk;
|
||||
logic s_ribp_ready_d, s_ribp_ready_q;
|
||||
logic s_ribp_rdata_en;
|
||||
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
|
||||
// register
|
||||
logic s_dvp_recven_en;
|
||||
logic s_dvp_recven_d, s_dvp_recven_q;
|
||||
logic s_dvp_stat_d, s_dvp_stat_q;
|
||||
logic s_dvp_stream_en;
|
||||
logic s_dvp_stream_d, s_dvp_stream_q;
|
||||
// dvp clk
|
||||
logic s_dvp_pclk_buf;
|
||||
logic s_dvp_pclk_rst_n_sync;
|
||||
logic s_dvp_recven_pclk_q;
|
||||
// rx fifo
|
||||
logic s_rx_push_valid, s_rx_full, s_rx_empty;
|
||||
logic s_rx_pop_valid, s_rx_pop_ready;
|
||||
logic [31:0] s_rx_push_data, s_rx_pop_data;
|
||||
logic [7:0] s_rx_elem_num;
|
||||
localparam int DVP_PAYLOAD_WIDTH = 42;
|
||||
|
||||
// ribp
|
||||
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && ribp.wstrb[0];
|
||||
assign s_ribp_rd_hdshk = ribp.valid && (~s_ribp_ready_q) && (~(|ribp.wstrb));
|
||||
assign ribp.ready = s_ribp_ready_q;
|
||||
assign ribp.resp_err = 1'b0;
|
||||
assign ribp.rdata = s_ribp_rdata_q;
|
||||
logic [ 127:0] s_config_sys;
|
||||
logic s_cfg_v_sys;
|
||||
logic s_cfg_rdy_sys;
|
||||
logic [ 127:0] s_cfg_pclk_q;
|
||||
logic s_cfg_v_pclk;
|
||||
logic s_cfg_rdy_pclk;
|
||||
logic [ 1:0] s_cmd_sys;
|
||||
logic [ 1:0] s_cmd_pclk;
|
||||
logic s_cmd_v_pclk;
|
||||
logic s_cmd_rdy_pclk;
|
||||
logic s_cmd_rdy_sys;
|
||||
logic s_cmd_v_sys;
|
||||
logic [ 1:0] s_cmd_core;
|
||||
logic s_cmd_abort_sys;
|
||||
logic s_cmd_flush_sys;
|
||||
|
||||
logic s_pclk_inv;
|
||||
logic s_pclk_buf;
|
||||
logic s_pclk_rst_n;
|
||||
logic s_pclk_sel;
|
||||
logic s_pclk_falling;
|
||||
logic s_active;
|
||||
logic s_stream_en;
|
||||
logic s_fifo_src_ready;
|
||||
logic s_fifo_dst_valid;
|
||||
logic [DVP_PAYLOAD_WIDTH-1:0] s_fifo_dst_data;
|
||||
logic s_fifo_dst_ready;
|
||||
logic s_fifo_src_clear;
|
||||
logic s_fifo_src_clear_busy;
|
||||
logic s_fifo_dst_clear_busy;
|
||||
logic [ 31:0] s_fifo_rx_data;
|
||||
logic s_rx_pop;
|
||||
logic s_fifo_full_sys;
|
||||
logic s_fifo_empty_sys;
|
||||
logic s_frm_start_tgl;
|
||||
logic s_line_done_tgl;
|
||||
logic s_frm_done_tgl;
|
||||
logic s_err_tgl;
|
||||
logic s_frame_start_event;
|
||||
logic s_line_done_event;
|
||||
logic s_frame_done_event;
|
||||
logic s_err_evt;
|
||||
logic [ 5:0] s_err_flags_pclk;
|
||||
logic [ 5:0] s_err_flags_sys;
|
||||
logic [ 127:0] s_frm_stats_pclk;
|
||||
logic s_frm_stats_v_pclk;
|
||||
logic s_frm_stats_rdy_pclk;
|
||||
logic [ 127:0] s_frm_stats_sys;
|
||||
logic s_frm_stats_v_sys;
|
||||
|
||||
assign s_dvp_recven_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DVP_RECVEN;
|
||||
assign s_dvp_recven_d = ribp.wdata[0];
|
||||
dffer #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_dvp_recven_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dvp_recven_en),
|
||||
.dat_i (s_dvp_recven_d),
|
||||
.dat_o (s_dvp_recven_q)
|
||||
);
|
||||
assign s_cmd_sys = {s_cmd_flush_sys, s_cmd_abort_sys};
|
||||
// Commands are consumed in the pixel domain as soon as they cross the CDC.
|
||||
assign s_cmd_rdy_pclk = !s_fifo_src_clear_busy;
|
||||
assign s_pclk_falling = s_config_sys[106];
|
||||
assign s_fifo_src_clear = s_cmd_pclk[`DVP_COMMAND_FLUSH] || s_cmd_pclk[`DVP_COMMAND_ABORT];
|
||||
assign s_fifo_dst_ready = !s_fifo_dst_clear_busy && (s_stream_en ? rx_axis.tready : s_rx_pop);
|
||||
assign s_fifo_rx_data = s_fifo_dst_data[31:0];
|
||||
assign s_fifo_empty_sys = !s_fifo_dst_valid;
|
||||
|
||||
assign s_dvp_stream_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DVP_STREAM_CTRL;
|
||||
assign s_dvp_stream_d = ribp.wdata[0];
|
||||
dffer #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_dvp_stream_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dvp_stream_en),
|
||||
.dat_i (s_dvp_stream_d),
|
||||
.dat_o (s_dvp_stream_q)
|
||||
);
|
||||
|
||||
assign s_dvp_stat_d = s_rx_empty;
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_dvp_status_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dvp_stat_d),
|
||||
.dat_o (s_dvp_stat_q)
|
||||
);
|
||||
|
||||
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_ribp_ready_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_ribp_ready_d),
|
||||
.dat_o (s_ribp_ready_q)
|
||||
);
|
||||
|
||||
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
|
||||
always_comb begin
|
||||
s_rx_pop_valid = s_dvp_stream_q && rx_axis.tvalid && rx_axis.tready;
|
||||
s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_DVP_RECVEN: s_ribp_rdata_d = {31'd0, s_dvp_recven_q};
|
||||
`RIBP_DVP_RXDATA: begin
|
||||
if (s_ribp_rd_hdshk && !s_dvp_stream_q) begin
|
||||
s_rx_pop_valid = 1'b1;
|
||||
if (!s_rx_empty) s_ribp_rdata_d = s_rx_pop_data;
|
||||
else s_ribp_rdata_d = '0;
|
||||
end
|
||||
end
|
||||
`RIBP_DVP_STATUS: s_ribp_rdata_d = {31'd0, s_dvp_stat_q};
|
||||
`RIBP_DVP_STREAM_CTRL: s_ribp_rdata_d = {31'd0, s_dvp_stream_q};
|
||||
default: s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
endcase
|
||||
end
|
||||
dffer #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_ribp_rdata_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_ribp_rdata_en),
|
||||
.dat_i (s_ribp_rdata_d),
|
||||
.dat_o (s_ribp_rdata_q)
|
||||
);
|
||||
|
||||
assign rx_axis.tdata = s_rx_pop_data;
|
||||
assign rx_axis.tkeep = '1;
|
||||
assign rx_axis.tstrb = '1;
|
||||
assign rx_axis.tlast = 1'b0;
|
||||
assign rx_axis.tid = '0;
|
||||
assign rx_axis.tdest = '0;
|
||||
assign rx_axis.tuser = '0;
|
||||
assign rx_axis.tvalid = s_dvp_stream_q && !s_rx_empty;
|
||||
|
||||
|
||||
// clk buffer
|
||||
tc_clk_buf u_dvp_pclk_clk_buf (
|
||||
.clk_i(dvp.pclk_i),
|
||||
.clk_o(s_dvp_pclk_buf)
|
||||
.clk_o(s_pclk_buf)
|
||||
);
|
||||
tc_clk_inv u_dvp_pclk_inv (
|
||||
.clk_i(s_pclk_buf),
|
||||
.clk_o(s_pclk_inv)
|
||||
);
|
||||
tc_clk_mux2 u_dvp_pclk_mux (
|
||||
.clk0_i (s_pclk_buf),
|
||||
.clk1_i (s_pclk_inv),
|
||||
.clk_sel_i(s_pclk_falling),
|
||||
.clk_o (s_pclk_sel)
|
||||
);
|
||||
|
||||
rst_sync #(
|
||||
.STAGE(5)
|
||||
) u_dvp_pclk_rst_sync (
|
||||
.clk_i (s_dvp_pclk_buf),
|
||||
.clk_i (s_pclk_sel),
|
||||
.rst_n_i(rst_n_i),
|
||||
.rst_n_o(s_dvp_pclk_rst_n_sync)
|
||||
.rst_n_o(s_pclk_rst_n)
|
||||
);
|
||||
|
||||
// The software enable is stable while a frame is captured, but it originates
|
||||
// in the system domain and must be synchronized before it gates DVP writes.
|
||||
dvp_reg u_dvp_reg (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (ribp),
|
||||
.active_i (s_active),
|
||||
.fifo_empty_i (s_fifo_empty_sys),
|
||||
.fifo_full_i (s_fifo_full_sys),
|
||||
.rx_data_i (s_fifo_rx_data),
|
||||
.frame_start_i (s_frame_start_event),
|
||||
.line_done_i (s_line_done_event),
|
||||
.frame_done_i (s_frame_done_event),
|
||||
.error_event_i (s_err_evt),
|
||||
.error_flags_i (s_err_flags_sys),
|
||||
.frame_stats_i (s_frm_stats_sys),
|
||||
.frame_stats_valid_i(s_frm_stats_v_sys),
|
||||
.config_o (s_config_sys),
|
||||
.config_valid_o (s_cfg_v_sys),
|
||||
.config_ready_i (s_cfg_rdy_sys),
|
||||
.command_abort_o (s_cmd_abort_sys),
|
||||
.command_flush_o (s_cmd_flush_sys),
|
||||
.command_valid_o (s_cmd_v_sys),
|
||||
.command_ready_i (s_cmd_rdy_sys),
|
||||
.rx_pop_o (s_rx_pop),
|
||||
.stream_enable_o (s_stream_en),
|
||||
.irq_o (irq_o)
|
||||
);
|
||||
|
||||
cdc_2phase #(
|
||||
.DATA_WIDTH(128)
|
||||
) u_dvp_config_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
.src_rst_n_i(rst_n_i),
|
||||
.src_data_i (s_config_sys),
|
||||
.src_valid_i(s_cfg_v_sys),
|
||||
.src_ready_o(s_cfg_rdy_sys),
|
||||
.dst_clk_i (s_pclk_sel),
|
||||
.dst_rst_n_i(s_pclk_rst_n),
|
||||
.dst_data_o (s_cfg_pclk_q),
|
||||
.dst_valid_o(s_cfg_v_pclk),
|
||||
.dst_ready_i(s_cfg_rdy_pclk)
|
||||
);
|
||||
|
||||
cdc_2phase #(
|
||||
.DATA_WIDTH(2)
|
||||
) u_dvp_command_cdc (
|
||||
.src_clk_i (clk_i),
|
||||
.src_rst_n_i(rst_n_i),
|
||||
.src_data_i (s_cmd_sys),
|
||||
.src_valid_i(s_cmd_v_sys),
|
||||
.src_ready_o(s_cmd_rdy_sys),
|
||||
.dst_clk_i (s_pclk_sel),
|
||||
.dst_rst_n_i(s_pclk_rst_n),
|
||||
.dst_data_o (s_cmd_pclk),
|
||||
.dst_valid_o(s_cmd_v_pclk),
|
||||
.dst_ready_i(s_cmd_rdy_pclk)
|
||||
);
|
||||
|
||||
cdc_fifo_warm_flush #(
|
||||
.DATA_WIDTH (DVP_PAYLOAD_WIDTH),
|
||||
.BUFFER_DEPTH(128)
|
||||
) u_dvp_payload_fifo (
|
||||
.src_clk_i (s_pclk_sel),
|
||||
.src_rst_n_i (s_pclk_rst_n),
|
||||
.src_clear_i (s_fifo_src_clear),
|
||||
.src_clear_busy_o(s_fifo_src_clear_busy),
|
||||
.src_data_i (s_core_push_data),
|
||||
.src_valid_i (s_core_push_valid),
|
||||
.src_ready_o (s_fifo_src_ready),
|
||||
.dst_clk_i (clk_i),
|
||||
.dst_rst_n_i (rst_n_i),
|
||||
.dst_clear_busy_o(s_fifo_dst_clear_busy),
|
||||
.dst_data_o (s_fifo_dst_data),
|
||||
.dst_valid_o (s_fifo_dst_valid),
|
||||
.dst_ready_i (s_fifo_dst_ready)
|
||||
);
|
||||
logic [DVP_PAYLOAD_WIDTH-1:0] s_core_push_data;
|
||||
logic s_core_push_valid;
|
||||
assign s_cmd_core = s_cmd_v_pclk ? s_cmd_pclk : 2'b00;
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(1)
|
||||
) u_dvp_recven_cdc_sync (
|
||||
.clk_i (s_dvp_pclk_buf),
|
||||
.rst_n_i(s_dvp_pclk_rst_n_sync),
|
||||
.dat_i (s_dvp_recven_q),
|
||||
.dat_o (s_dvp_recven_pclk_q)
|
||||
) u_fifo_full_sync (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (!s_fifo_src_ready),
|
||||
.dat_o (s_fifo_full_sys)
|
||||
);
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(6)
|
||||
) u_error_flags_sync (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_err_flags_pclk),
|
||||
.dat_o (s_err_flags_sys)
|
||||
);
|
||||
|
||||
async_fifo #(
|
||||
.DATA_WIDTH (32),
|
||||
.DEPTH_POWER(7)
|
||||
) u_rx_async_fifo (
|
||||
.wr_clk_i (s_dvp_pclk_buf),
|
||||
.wr_rst_n_i(s_dvp_pclk_rst_n_sync),
|
||||
.wr_en_i (s_rx_push_valid & s_dvp_recven_pclk_q),
|
||||
.wr_data_i (s_rx_push_data),
|
||||
.wr_full_o (s_rx_full),
|
||||
.rd_clk_i (clk_i),
|
||||
.rd_rst_n_i(rst_n_i),
|
||||
.rd_en_i (s_rx_pop_valid),
|
||||
.rd_data_o (s_rx_pop_data),
|
||||
.rd_empty_o(s_rx_empty),
|
||||
.elem_num_o(s_rx_elem_num)
|
||||
/* verilator lint_off PINCONNECTEMPTY */
|
||||
edge_det #(
|
||||
.STAGE(2)
|
||||
) u_frame_start_event (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_frm_start_tgl),
|
||||
.dat_o (),
|
||||
.re_o (s_frame_start_event),
|
||||
.fe_o ()
|
||||
);
|
||||
edge_det #(
|
||||
.STAGE(2)
|
||||
) u_line_done_event (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_line_done_tgl),
|
||||
.dat_o (),
|
||||
.re_o (s_line_done_event),
|
||||
.fe_o ()
|
||||
);
|
||||
edge_det #(
|
||||
.STAGE(2)
|
||||
) u_frame_done_event (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_frm_done_tgl),
|
||||
.dat_o (),
|
||||
.re_o (s_frame_done_event),
|
||||
.fe_o ()
|
||||
);
|
||||
edge_det #(
|
||||
.STAGE(2)
|
||||
) u_error_event (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_err_tgl),
|
||||
.dat_o (),
|
||||
.re_o (s_err_evt),
|
||||
.fe_o ()
|
||||
);
|
||||
/* verilator lint_on PINCONNECTEMPTY */
|
||||
|
||||
cdc_2phase #(
|
||||
.DATA_WIDTH(128)
|
||||
) u_dvp_stats_cdc (
|
||||
.src_clk_i (s_pclk_sel),
|
||||
.src_rst_n_i(s_pclk_rst_n),
|
||||
.src_data_i (s_frm_stats_pclk),
|
||||
.src_valid_i(s_frm_stats_v_pclk),
|
||||
.src_ready_o(s_frm_stats_rdy_pclk),
|
||||
.dst_clk_i (clk_i),
|
||||
.dst_rst_n_i(rst_n_i),
|
||||
.dst_data_o (s_frm_stats_sys),
|
||||
.dst_valid_o(s_frm_stats_v_sys),
|
||||
.dst_ready_i(1'b1)
|
||||
);
|
||||
|
||||
assign rx_axis.tdata = s_fifo_dst_data[31:0];
|
||||
assign rx_axis.tkeep = s_fifo_dst_data[39:36];
|
||||
assign rx_axis.tstrb = s_fifo_dst_data[35:32];
|
||||
assign rx_axis.tlast = s_fifo_dst_data[40];
|
||||
assign rx_axis.tid = '0;
|
||||
assign rx_axis.tdest = '0;
|
||||
assign rx_axis.tuser = s_fifo_dst_data[41];
|
||||
assign rx_axis.tvalid = s_stream_en && s_fifo_dst_valid;
|
||||
|
||||
dvp_core u_dvp_core (
|
||||
.clk_i (s_dvp_pclk_buf),
|
||||
.rst_n_i (s_dvp_pclk_rst_n_sync),
|
||||
.dvp_href_i (dvp.href_i),
|
||||
.dvp_vsync_i(dvp.vsync_i),
|
||||
.dvp_dat_i (dvp.dat_i),
|
||||
.wr_en_o (s_rx_push_valid),
|
||||
.rgb_dat_o (s_rx_push_data)
|
||||
.clk_i (s_pclk_sel),
|
||||
.rst_n_i (s_pclk_rst_n),
|
||||
.config_i (s_cfg_pclk_q),
|
||||
.config_valid_i (s_cfg_v_pclk),
|
||||
.command_i (s_cmd_core),
|
||||
.config_ready_o (s_cfg_rdy_pclk),
|
||||
.push_ready_i (s_fifo_src_ready),
|
||||
.push_valid_o (s_core_push_valid),
|
||||
.push_data_o (s_core_push_data),
|
||||
.active_o (s_active),
|
||||
.frame_start_toggle_o(s_frm_start_tgl),
|
||||
.line_done_toggle_o (s_line_done_tgl),
|
||||
.frame_done_toggle_o (s_frm_done_tgl),
|
||||
.error_toggle_o (s_err_tgl),
|
||||
.error_flags_o (s_err_flags_pclk),
|
||||
.frame_stats_o (s_frm_stats_pclk),
|
||||
.frame_stats_valid_o (s_frm_stats_v_pclk),
|
||||
.frame_stats_ready_i (s_frm_stats_rdy_pclk),
|
||||
.href_i (dvp.href_i),
|
||||
.vsync_i (dvp.vsync_i),
|
||||
.dat_i (dvp.dat_i)
|
||||
);
|
||||
endmodule
|
||||
+237
-106
@@ -1,120 +1,251 @@
|
||||
|
||||
|
||||
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
// You may obtain a copy of Mulan PSL v2 at:
|
||||
// http://license.coscl.org.cn/MulanPSL2
|
||||
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
`include "dvp_define.svh"
|
||||
|
||||
module dvp_core (
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic dvp_href_i,
|
||||
input logic dvp_vsync_i,
|
||||
input logic [ 7:0] dvp_dat_i,
|
||||
output logic wr_en_o,
|
||||
output logic [31:0] rgb_dat_o
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
/* verilator lint_off UNUSEDSIGNAL */
|
||||
input logic [127:0] config_i,
|
||||
/* verilator lint_on UNUSEDSIGNAL */
|
||||
input logic config_valid_i,
|
||||
input logic [ 1:0] command_i,
|
||||
output logic config_ready_o,
|
||||
input logic push_ready_i,
|
||||
output logic push_valid_o,
|
||||
output logic [ 41:0] push_data_o,
|
||||
output logic active_o,
|
||||
output logic frame_start_toggle_o,
|
||||
output logic line_done_toggle_o,
|
||||
output logic frame_done_toggle_o,
|
||||
output logic error_toggle_o,
|
||||
output logic [ 5:0] error_flags_o,
|
||||
output logic [127:0] frame_stats_o,
|
||||
output logic frame_stats_valid_o,
|
||||
input logic frame_stats_ready_i,
|
||||
input logic href_i,
|
||||
input logic vsync_i,
|
||||
input logic [ 7:0] dat_i
|
||||
// verilog_format: on
|
||||
);
|
||||
logic s_en;
|
||||
logic s_snap;
|
||||
logic s_crop_en;
|
||||
logic s_byte_swap;
|
||||
logic [ 1:0] s_format;
|
||||
logic s_pixel_swap;
|
||||
logic [15:0] s_frm_width;
|
||||
logic [15:0] s_frm_height;
|
||||
logic [15:0] s_crop_x;
|
||||
logic [15:0] s_crop_y;
|
||||
logic [15:0] s_crop_width;
|
||||
logic [15:0] s_crop_height;
|
||||
logic s_vsync_low;
|
||||
logic s_href_low;
|
||||
|
||||
// localparam FRAME_WAIT = 4'd3; // for sim
|
||||
localparam FRAME_WAIT = 4'd12;
|
||||
logic s_vsync_q;
|
||||
logic s_href_q;
|
||||
logic s_frm_active_q;
|
||||
logic [15:0] s_line_q;
|
||||
logic [15:0] s_pixel_q;
|
||||
logic s_byte_phase_q;
|
||||
logic s_word_phase_q;
|
||||
logic [ 7:0] s_first_byte_q;
|
||||
logic [15:0] s_word_q;
|
||||
logic [31:0] s_frm_seq_q;
|
||||
logic [31:0] s_pixel_total_q;
|
||||
logic [15:0] s_word_total_q;
|
||||
logic [31:0] s_drop_count_q;
|
||||
logic [ 5:0] s_err_flags_q;
|
||||
logic s_out_valid_q;
|
||||
logic [41:0] s_out_data_q;
|
||||
logic s_stat_pending_q;
|
||||
logic s_first_word_q;
|
||||
|
||||
logic s_vsync_active;
|
||||
logic s_href_active;
|
||||
logic s_vsync_rise;
|
||||
logic s_href_fall;
|
||||
logic s_crop_line;
|
||||
logic s_crop_pixel;
|
||||
logic s_last_pixel;
|
||||
logic [15:0] s_pixel_word;
|
||||
|
||||
logic s_dvp_vsync_re;
|
||||
logic s_frame_cnt_en;
|
||||
logic [3:0] s_frame_cnt_d, s_frame_cnt_q;
|
||||
logic s_frame_valid_en;
|
||||
logic s_frame_valid_d, s_frame_valid_q;
|
||||
logic [1:0] s_pix_cnt_d, s_pix_cnt_q;
|
||||
logic s_rgb_flag_d, s_rgb_flag_q;
|
||||
logic s_rgb_data_en;
|
||||
logic [31:0] s_rgb_data_d, s_rgb_data_q;
|
||||
assign s_vsync_active = s_vsync_low ? !vsync_i : vsync_i;
|
||||
assign s_href_active = s_href_low ? !href_i : href_i;
|
||||
assign s_vsync_rise = s_vsync_active && !s_vsync_q;
|
||||
assign s_href_fall = s_href_q && !s_href_active;
|
||||
assign s_crop_line = !s_crop_en ||
|
||||
((s_line_q >= s_crop_y) &&
|
||||
(s_line_q < (s_crop_y + s_crop_height)));
|
||||
assign s_crop_pixel = !s_crop_en ||
|
||||
((s_pixel_q >= s_crop_x) &&
|
||||
(s_pixel_q < (s_crop_x + s_crop_width)));
|
||||
assign s_last_pixel = s_crop_en ?
|
||||
(s_pixel_q + 16'd1 >= s_crop_x + s_crop_width) :
|
||||
(s_pixel_q + 16'd1 >= s_frm_width);
|
||||
assign s_pixel_word = s_pixel_swap ?
|
||||
{s_byte_swap ? dat_i : s_first_byte_q,
|
||||
s_byte_swap ? s_first_byte_q : dat_i} :
|
||||
(s_byte_swap ? {dat_i, s_first_byte_q} :
|
||||
{s_first_byte_q, dat_i});
|
||||
|
||||
assign config_ready_o = !s_stat_pending_q;
|
||||
assign push_valid_o = s_out_valid_q;
|
||||
assign push_data_o = s_out_data_q;
|
||||
assign active_o = s_frm_active_q;
|
||||
|
||||
assign wr_en_o = s_frame_valid_q & s_rgb_flag_q;
|
||||
assign rgb_dat_o = s_rgb_data_q;
|
||||
|
||||
|
||||
edge_det_sync_re #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_dvp_vsync_edge_det_sync_re (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (dvp_vsync_i),
|
||||
.re_o (s_dvp_vsync_re)
|
||||
);
|
||||
|
||||
|
||||
assign s_frame_cnt_en = (s_frame_cnt_q < FRAME_WAIT) && s_dvp_vsync_re;
|
||||
assign s_frame_cnt_d = s_frame_cnt_q + 4'd1;
|
||||
dffer #(
|
||||
.DATA_WIDTH(4)
|
||||
) u_frame_cnt_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_frame_cnt_en),
|
||||
.dat_i (s_frame_cnt_d),
|
||||
.dat_o (s_frame_cnt_q)
|
||||
);
|
||||
|
||||
|
||||
assign s_frame_valid_en = (s_frame_cnt_q == FRAME_WAIT) && s_dvp_vsync_re;
|
||||
assign s_frame_valid_d = 1'b1;
|
||||
dffer #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_frame_valid_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_frame_valid_en),
|
||||
.dat_i (s_frame_valid_d),
|
||||
.dat_o (s_frame_valid_q)
|
||||
);
|
||||
|
||||
|
||||
assign s_pix_cnt_d = dvp_href_i ? s_pix_cnt_q + 2'd1 : '0;
|
||||
dffr #(
|
||||
.DATA_WIDTH(2)
|
||||
) u_pix_cnt_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_pix_cnt_d),
|
||||
.dat_o (s_pix_cnt_q)
|
||||
);
|
||||
|
||||
|
||||
assign s_rgb_flag_d = s_pix_cnt_q == 2'd3;
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_rgb_flag_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_rgb_flag_d),
|
||||
.dat_o (s_rgb_flag_q)
|
||||
);
|
||||
|
||||
|
||||
assign s_rgb_data_en = dvp_href_i;
|
||||
always_comb begin
|
||||
s_rgb_data_d = s_rgb_data_q;
|
||||
if (s_pix_cnt_q == 2'd0) s_rgb_data_d[15:8] = dvp_dat_i;
|
||||
else if (s_pix_cnt_q == 2'd1) s_rgb_data_d[7:0] = dvp_dat_i;
|
||||
else if (s_pix_cnt_q == 2'd2) s_rgb_data_d[31:24] = dvp_dat_i;
|
||||
else if (s_pix_cnt_q == 2'd3) s_rgb_data_d[23:16] = dvp_dat_i;
|
||||
s_en = config_i[96];
|
||||
s_snap = config_i[97];
|
||||
s_crop_en = config_i[98];
|
||||
s_byte_swap = config_i[102];
|
||||
s_vsync_low = config_i[104];
|
||||
s_href_low = config_i[105];
|
||||
s_frm_width = config_i[15:0];
|
||||
s_frm_height = config_i[31:16];
|
||||
s_crop_x = config_i[47:32];
|
||||
s_crop_y = config_i[63:48];
|
||||
s_crop_width = config_i[79:64];
|
||||
s_crop_height = config_i[95:80];
|
||||
s_format = config_i[101:100];
|
||||
s_pixel_swap = config_i[103];
|
||||
end
|
||||
dffer #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_rgb_data_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_rgb_data_en),
|
||||
.dat_i (s_rgb_data_d),
|
||||
.dat_o (s_rgb_data_q)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_vsync_q <= 1'b0;
|
||||
s_href_q <= 1'b0;
|
||||
s_frm_active_q <= 1'b0;
|
||||
s_line_q <= '0;
|
||||
s_pixel_q <= '0;
|
||||
s_byte_phase_q <= 1'b0;
|
||||
s_word_phase_q <= 1'b0;
|
||||
s_first_byte_q <= '0;
|
||||
s_word_q <= '0;
|
||||
s_frm_seq_q <= '0;
|
||||
s_pixel_total_q <= '0;
|
||||
s_word_total_q <= '0;
|
||||
s_drop_count_q <= '0;
|
||||
s_err_flags_q <= '0;
|
||||
s_out_valid_q <= 1'b0;
|
||||
s_out_data_q <= '0;
|
||||
s_stat_pending_q <= 1'b0;
|
||||
s_first_word_q <= 1'b0;
|
||||
frame_start_toggle_o <= 1'b0;
|
||||
line_done_toggle_o <= 1'b0;
|
||||
frame_done_toggle_o <= 1'b0;
|
||||
error_toggle_o <= 1'b0;
|
||||
frame_stats_o <= '0;
|
||||
frame_stats_valid_o <= 1'b0;
|
||||
end else begin
|
||||
s_vsync_q <= s_vsync_active;
|
||||
s_href_q <= s_href_active;
|
||||
frame_stats_valid_o <= 1'b0;
|
||||
|
||||
if (s_out_valid_q && push_ready_i) s_out_valid_q <= 1'b0;
|
||||
if (s_stat_pending_q && frame_stats_ready_i) begin
|
||||
s_stat_pending_q <= 1'b0;
|
||||
frame_stats_valid_o <= 1'b1;
|
||||
end
|
||||
|
||||
if (config_valid_i && !s_frm_active_q) begin
|
||||
if ((s_frm_width == 0) || (s_frm_height == 0) || (s_format > 2'd1) ||
|
||||
(s_crop_en && ((s_crop_width == 0) || (s_crop_height == 0)))) begin
|
||||
s_err_flags_q[`DVP_ERROR_CONFIG] <= 1'b1;
|
||||
error_toggle_o <= ~error_toggle_o;
|
||||
end
|
||||
if (!s_en) s_frm_active_q <= 1'b0;
|
||||
end
|
||||
if (command_i[`DVP_COMMAND_ABORT]) begin
|
||||
s_frm_active_q <= 1'b0;
|
||||
s_err_flags_q[`DVP_ERROR_ABORT] <= 1'b1;
|
||||
error_toggle_o <= ~error_toggle_o;
|
||||
end
|
||||
if (command_i[`DVP_COMMAND_FLUSH]) begin
|
||||
s_out_valid_q <= 1'b0;
|
||||
s_byte_phase_q <= 1'b0;
|
||||
s_word_phase_q <= 1'b0;
|
||||
end
|
||||
|
||||
if (s_en && s_vsync_rise) begin
|
||||
if (s_frm_active_q) begin
|
||||
frame_done_toggle_o <= ~frame_done_toggle_o;
|
||||
frame_stats_o <= {
|
||||
s_drop_count_q, s_word_total_q, s_pixel_total_q, s_line_q, s_frm_seq_q + 1'b1
|
||||
};
|
||||
s_stat_pending_q <= 1'b1;
|
||||
s_frm_seq_q <= s_frm_seq_q + 1'b1;
|
||||
if (s_snap) begin
|
||||
s_frm_active_q <= 1'b0;
|
||||
end else begin
|
||||
s_line_q <= '0;
|
||||
s_pixel_q <= '0;
|
||||
s_pixel_total_q <= '0;
|
||||
s_word_total_q <= '0;
|
||||
end
|
||||
end else begin
|
||||
s_frm_active_q <= 1'b1;
|
||||
frame_start_toggle_o <= ~frame_start_toggle_o;
|
||||
s_first_word_q <= 1'b1;
|
||||
s_line_q <= '0;
|
||||
s_pixel_q <= '0;
|
||||
s_pixel_total_q <= '0;
|
||||
s_word_total_q <= '0;
|
||||
end
|
||||
end
|
||||
|
||||
if (s_frm_active_q && s_href_active) begin
|
||||
if (!s_byte_phase_q) begin
|
||||
s_first_byte_q <= dat_i;
|
||||
s_byte_phase_q <= 1'b1;
|
||||
end else begin
|
||||
if (s_crop_line && s_crop_pixel) begin
|
||||
if (!s_word_phase_q) begin
|
||||
s_word_q <= s_pixel_word;
|
||||
s_word_phase_q <= 1'b1;
|
||||
end else if (!s_out_valid_q || push_ready_i) begin
|
||||
s_out_data_q <= {
|
||||
s_first_word_q, s_last_pixel, 4'b1111, 4'b1111, s_pixel_word, s_word_q
|
||||
};
|
||||
s_out_valid_q <= 1'b1;
|
||||
s_first_word_q <= 1'b0;
|
||||
s_word_phase_q <= 1'b0;
|
||||
s_word_total_q <= s_word_total_q + 1'b1;
|
||||
end else begin
|
||||
s_err_flags_q[`DVP_ERROR_OVERFLOW] <= 1'b1;
|
||||
s_drop_count_q <= s_drop_count_q + 1'b1;
|
||||
error_toggle_o <= ~error_toggle_o;
|
||||
s_frm_active_q <= 1'b0;
|
||||
end
|
||||
s_pixel_total_q <= s_pixel_total_q + 1'b1;
|
||||
end
|
||||
s_byte_phase_q <= 1'b0;
|
||||
s_pixel_q <= s_pixel_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (s_frm_active_q && s_href_fall) begin
|
||||
line_done_toggle_o <= ~line_done_toggle_o;
|
||||
s_line_q <= s_line_q + 1'b1;
|
||||
s_pixel_q <= '0;
|
||||
s_byte_phase_q <= 1'b0;
|
||||
if (s_word_phase_q && (!s_out_valid_q || push_ready_i)) begin
|
||||
s_out_data_q <= {s_first_word_q, 1'b1, 4'b0011, 4'b0011, 16'd0, s_word_q[15:0]};
|
||||
s_out_valid_q <= 1'b1;
|
||||
s_first_word_q <= 1'b0;
|
||||
s_word_phase_q <= 1'b0;
|
||||
s_word_total_q <= s_word_total_q + 1'b1;
|
||||
end else if (s_word_phase_q) begin
|
||||
s_err_flags_q[`DVP_ERROR_OVERFLOW] <= 1'b1;
|
||||
error_toggle_o <= ~error_toggle_o;
|
||||
s_frm_active_q <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign error_flags_o = s_err_flags_q;
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`ifndef RIBP_DVP_DEFINE_SVH
|
||||
`define RIBP_DVP_DEFINE_SVH
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_DVP_CTRL 12'h000
|
||||
`define RIBP_DVP_RXDATA 12'h004
|
||||
`define RIBP_DVP_STATUS 12'h008
|
||||
`define RIBP_DVP_STREAM_CTRL 12'h00C
|
||||
`define RIBP_DVP_FORMAT 12'h010
|
||||
`define RIBP_DVP_SYNC_CFG 12'h014
|
||||
`define RIBP_DVP_FRAME_SIZE 12'h018
|
||||
`define RIBP_DVP_CROP_START 12'h01C
|
||||
`define RIBP_DVP_CROP_SIZE 12'h020
|
||||
`define RIBP_DVP_FRAME_COUNT 12'h024
|
||||
`define RIBP_DVP_LINE_COUNT 12'h028
|
||||
`define RIBP_DVP_PIXEL_COUNT 12'h02C
|
||||
`define RIBP_DVP_WORD_COUNT 12'h030
|
||||
`define RIBP_DVP_DROP_COUNT 12'h034
|
||||
`define RIBP_DVP_ERROR_STATUS 12'h038
|
||||
`define RIBP_DVP_INTR_STATE 12'h03C
|
||||
`define RIBP_DVP_INTR_ENABLE 12'h040
|
||||
`define RIBP_DVP_INTR_STATUS 12'h044
|
||||
`define RIBP_DVP_INTR_TEST 12'h048
|
||||
`define RIBP_DVP_COMMAND 12'h04C
|
||||
`define RIBP_DVP_IP_VERSION 12'h0F8
|
||||
`define RIBP_DVP_CAPABILITY 12'h0FC
|
||||
|
||||
`define DVP_CTRL_ENABLE 0
|
||||
`define DVP_CTRL_SNAPSHOT 1
|
||||
`define DVP_CTRL_CROP_ENABLE 2
|
||||
`define DVP_STREAM_ENABLE 0
|
||||
`define DVP_FORMAT_SELECT 1:0
|
||||
`define DVP_FORMAT_BYTE_SWAP 2
|
||||
`define DVP_FORMAT_PIXEL_SWAP 3
|
||||
`define DVP_SYNC_VSYNC_LOW 0
|
||||
`define DVP_SYNC_HREF_LOW 1
|
||||
`define DVP_SYNC_PCLK_FALLING 2
|
||||
|
||||
`define DVP_INTR_FRAME_START 0
|
||||
`define DVP_INTR_LINE_DONE 1
|
||||
`define DVP_INTR_FRAME_DONE 2
|
||||
`define DVP_INTR_OVERFLOW 3
|
||||
`define DVP_INTR_SYNC_ERROR 4
|
||||
`define DVP_INTR_CONFIG_ERROR 5
|
||||
`define DVP_INTR_ABORTED 6
|
||||
`define DVP_INTR_ALL 7'h7F
|
||||
|
||||
`define DVP_ERROR_OVERFLOW 0
|
||||
`define DVP_ERROR_SYNC 1
|
||||
`define DVP_ERROR_SIZE 2
|
||||
`define DVP_ERROR_PARTIAL 3
|
||||
`define DVP_ERROR_CONFIG 4
|
||||
`define DVP_ERROR_ABORT 5
|
||||
`define DVP_ERROR_ALL 6'h3F
|
||||
|
||||
`define DVP_COMMAND_ABORT 0
|
||||
`define DVP_COMMAND_FLUSH 1
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
@@ -0,0 +1,310 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`include "dvp_define.svh"
|
||||
|
||||
module dvp_reg (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
input logic active_i,
|
||||
input logic fifo_empty_i,
|
||||
input logic fifo_full_i,
|
||||
input logic [31:0] rx_data_i,
|
||||
input logic frame_start_i,
|
||||
input logic line_done_i,
|
||||
input logic frame_done_i,
|
||||
input logic error_event_i,
|
||||
input logic [ 5:0] error_flags_i,
|
||||
input logic [127:0] frame_stats_i,
|
||||
input logic frame_stats_valid_i,
|
||||
output logic [127:0] config_o,
|
||||
output logic config_valid_o,
|
||||
output logic command_abort_o,
|
||||
output logic command_flush_o,
|
||||
output logic command_valid_o,
|
||||
input logic command_ready_i,
|
||||
output logic rx_pop_o,
|
||||
input logic config_ready_i,
|
||||
output logic stream_enable_o,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
localparam logic [31:0] IP_VERSION = 32'h0002_0000;
|
||||
localparam logic [31:0] CAPABILITY = 32'h0000_3F7F;
|
||||
localparam logic [31:0] CTRL_MASK = 32'h0000_0007;
|
||||
localparam logic [31:0] STREAM_MASK = 32'h0000_0001;
|
||||
localparam logic [31:0] FORMAT_MASK = 32'h0000_000F;
|
||||
localparam logic [31:0] SYNC_MASK = 32'h0000_0007;
|
||||
|
||||
logic s_req;
|
||||
logic s_write;
|
||||
logic s_accept;
|
||||
logic [11:0] s_offset;
|
||||
logic s_aligned;
|
||||
logic s_access_err;
|
||||
logic s_ready_q;
|
||||
logic s_resp_err_d, s_resp_err_q;
|
||||
logic [31:0] s_rdata_d, s_rdata_q;
|
||||
logic [31:0] s_ctrl_d, s_ctrl_q;
|
||||
logic [31:0] s_stream_d, s_stream_q;
|
||||
logic [31:0] s_format_d, s_format_q;
|
||||
logic [31:0] s_sync_d, s_sync_q;
|
||||
logic [31:0] s_frame_size_d, s_frame_size_q;
|
||||
logic [31:0] s_crop_start_d, s_crop_start_q;
|
||||
logic [31:0] s_crop_size_d, s_crop_size_q;
|
||||
logic [5:0] s_error_q;
|
||||
logic [6:0] s_intr_state_q;
|
||||
logic [6:0] s_intr_enable_q;
|
||||
logic [31:0] s_frame_count_q, s_line_count_q;
|
||||
logic [31:0] s_pixel_count_q, s_word_count_q, s_drop_count_q;
|
||||
logic [31:0] s_config_seq_d, s_config_seq_q;
|
||||
logic [31:0] s_config_sent_q;
|
||||
logic [ 1:0] s_command_q;
|
||||
|
||||
function automatic logic [31:0] merge_wstrb(input logic [31:0] current, input logic [31:0] value,
|
||||
input logic [3:0] strobe);
|
||||
logic [31:0] merged;
|
||||
begin
|
||||
merged = current;
|
||||
for (int index = 0; index < 4; index++) begin
|
||||
if (strobe[index]) merged[index*8+:8] = value[index*8+:8];
|
||||
end
|
||||
return merged;
|
||||
end
|
||||
endfunction
|
||||
|
||||
assign s_req = ribp.valid && !s_ready_q;
|
||||
assign s_write = |ribp.wstrb;
|
||||
assign s_accept = s_req;
|
||||
assign s_offset = ribp.addr[11:0];
|
||||
assign s_aligned = ribp.addr[1:0] == 2'b00;
|
||||
assign ribp.ready = s_ready_q;
|
||||
assign ribp.rdata = s_rdata_q;
|
||||
assign ribp.resp_err = s_resp_err_q;
|
||||
assign stream_enable_o = s_stream_q[`DVP_STREAM_ENABLE];
|
||||
always_comb begin
|
||||
config_o = '0;
|
||||
config_o[15:0] = s_frame_size_q[15:0];
|
||||
config_o[31:16] = s_frame_size_q[31:16];
|
||||
config_o[47:32] = s_crop_start_q[15:0];
|
||||
config_o[63:48] = s_crop_start_q[31:16];
|
||||
config_o[79:64] = s_crop_size_q[15:0];
|
||||
config_o[95:80] = s_crop_size_q[31:16];
|
||||
config_o[96] = s_ctrl_q[`DVP_CTRL_ENABLE];
|
||||
config_o[97] = s_ctrl_q[`DVP_CTRL_SNAPSHOT];
|
||||
config_o[98] = s_ctrl_q[`DVP_CTRL_CROP_ENABLE];
|
||||
config_o[99] = s_stream_q[`DVP_STREAM_ENABLE];
|
||||
config_o[103:100] = s_format_q[3:0];
|
||||
config_o[106:104] = s_sync_q[2:0];
|
||||
end
|
||||
assign config_valid_o = s_config_seq_q != s_config_sent_q;
|
||||
assign rx_pop_o = s_accept && !s_write && !stream_enable_o && (s_offset == `RIBP_DVP_RXDATA);
|
||||
assign irq_o = |(s_intr_state_q & s_intr_enable_q);
|
||||
|
||||
always_comb begin
|
||||
s_access_err = !s_aligned;
|
||||
s_rdata_d = 32'd0;
|
||||
if (s_aligned) begin
|
||||
unique case (s_offset)
|
||||
`RIBP_DVP_CTRL: s_rdata_d = s_ctrl_q;
|
||||
`RIBP_DVP_RXDATA: s_rdata_d = rx_data_i;
|
||||
`RIBP_DVP_STATUS:
|
||||
s_rdata_d = {
|
||||
26'd0, s_error_q != 0, stream_enable_o, !fifo_full_i, fifo_empty_i, active_i, s_ctrl_q[0]
|
||||
};
|
||||
`RIBP_DVP_STREAM_CTRL: s_rdata_d = s_stream_q;
|
||||
`RIBP_DVP_FORMAT: s_rdata_d = s_format_q;
|
||||
`RIBP_DVP_SYNC_CFG: s_rdata_d = s_sync_q;
|
||||
`RIBP_DVP_FRAME_SIZE: s_rdata_d = s_frame_size_q;
|
||||
`RIBP_DVP_CROP_START: s_rdata_d = s_crop_start_q;
|
||||
`RIBP_DVP_CROP_SIZE: s_rdata_d = s_crop_size_q;
|
||||
`RIBP_DVP_FRAME_COUNT: s_rdata_d = s_frame_count_q;
|
||||
`RIBP_DVP_LINE_COUNT: s_rdata_d = s_line_count_q;
|
||||
`RIBP_DVP_PIXEL_COUNT: s_rdata_d = s_pixel_count_q;
|
||||
`RIBP_DVP_WORD_COUNT: s_rdata_d = s_word_count_q;
|
||||
`RIBP_DVP_DROP_COUNT: s_rdata_d = s_drop_count_q;
|
||||
`RIBP_DVP_ERROR_STATUS: s_rdata_d = {26'd0, s_error_q};
|
||||
`RIBP_DVP_INTR_STATE: s_rdata_d = {25'd0, s_intr_state_q};
|
||||
`RIBP_DVP_INTR_ENABLE: s_rdata_d = {25'd0, s_intr_enable_q};
|
||||
`RIBP_DVP_INTR_STATUS: s_rdata_d = {25'd0, s_intr_state_q & s_intr_enable_q};
|
||||
`RIBP_DVP_INTR_TEST: s_access_err = !s_write;
|
||||
`RIBP_DVP_IP_VERSION: s_rdata_d = IP_VERSION;
|
||||
`RIBP_DVP_CAPABILITY: s_rdata_d = CAPABILITY;
|
||||
`RIBP_DVP_COMMAND: s_access_err = !s_write;
|
||||
default: s_access_err = 1'b1;
|
||||
endcase
|
||||
end
|
||||
if (s_accept && s_write && active_i &&
|
||||
((s_offset == `RIBP_DVP_CTRL) || (s_offset == `RIBP_DVP_STREAM_CTRL) ||
|
||||
(s_offset == `RIBP_DVP_FORMAT) || (s_offset == `RIBP_DVP_SYNC_CFG) ||
|
||||
(s_offset == `RIBP_DVP_FRAME_SIZE) || (s_offset == `RIBP_DVP_CROP_START) ||
|
||||
(s_offset == `RIBP_DVP_CROP_SIZE))) begin
|
||||
s_access_err = 1'b1;
|
||||
end
|
||||
if (s_accept && s_write && (s_offset == `RIBP_DVP_FRAME_SIZE) &&
|
||||
((ribp.wdata[15:0] == 0) || (ribp.wdata[31:16] == 0))) begin
|
||||
s_access_err = 1'b1;
|
||||
end
|
||||
s_resp_err_d = s_accept && s_access_err;
|
||||
end
|
||||
|
||||
assign command_valid_o = |s_command_q;
|
||||
assign command_abort_o = s_command_q[`DVP_COMMAND_ABORT];
|
||||
assign command_flush_o = s_command_q[`DVP_COMMAND_FLUSH];
|
||||
|
||||
always_comb begin
|
||||
s_ctrl_d = s_ctrl_q;
|
||||
s_stream_d = s_stream_q;
|
||||
s_format_d = s_format_q;
|
||||
s_sync_d = s_sync_q;
|
||||
s_frame_size_d = s_frame_size_q;
|
||||
s_crop_start_d = s_crop_start_q;
|
||||
s_crop_size_d = s_crop_size_q;
|
||||
s_config_seq_d = s_config_seq_q;
|
||||
if (s_accept && s_write && !s_access_err) begin
|
||||
unique case (s_offset)
|
||||
`RIBP_DVP_CTRL: begin
|
||||
s_ctrl_d = merge_wstrb(s_ctrl_q, ribp.wdata, ribp.wstrb) & CTRL_MASK;
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
`RIBP_DVP_STREAM_CTRL: begin
|
||||
s_stream_d = merge_wstrb(s_stream_q, ribp.wdata, ribp.wstrb) & STREAM_MASK;
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
`RIBP_DVP_FORMAT: begin
|
||||
s_format_d = merge_wstrb(s_format_q, ribp.wdata, ribp.wstrb) & FORMAT_MASK;
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
`RIBP_DVP_SYNC_CFG: begin
|
||||
s_sync_d = merge_wstrb(s_sync_q, ribp.wdata, ribp.wstrb) & SYNC_MASK;
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
`RIBP_DVP_FRAME_SIZE: begin
|
||||
s_frame_size_d = merge_wstrb(s_frame_size_q, ribp.wdata, ribp.wstrb);
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
`RIBP_DVP_CROP_START: begin
|
||||
s_crop_start_d = merge_wstrb(s_crop_start_q, ribp.wdata, ribp.wstrb);
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
`RIBP_DVP_CROP_SIZE: begin
|
||||
s_crop_size_d = merge_wstrb(s_crop_size_q, ribp.wdata, ribp.wstrb);
|
||||
s_config_seq_d = s_config_seq_q + 1'b1;
|
||||
end
|
||||
default: begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
dffr #(32) u_ctrl_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_ctrl_d),
|
||||
.dat_o (s_ctrl_q)
|
||||
);
|
||||
dffr #(32) u_stream_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_stream_d),
|
||||
.dat_o (s_stream_q)
|
||||
);
|
||||
dffr #(32) u_format_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_format_d),
|
||||
.dat_o (s_format_q)
|
||||
);
|
||||
dffr #(32) u_sync_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_sync_d),
|
||||
.dat_o (s_sync_q)
|
||||
);
|
||||
dffr #(32) u_frame_size_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_frame_size_d),
|
||||
.dat_o (s_frame_size_q)
|
||||
);
|
||||
dffr #(32) u_crop_start_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_crop_start_d),
|
||||
.dat_o (s_crop_start_q)
|
||||
);
|
||||
dffr #(32) u_crop_size_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_crop_size_d),
|
||||
.dat_o (s_crop_size_q)
|
||||
);
|
||||
dffr #(32) u_config_seq_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_config_seq_d),
|
||||
.dat_o (s_config_seq_q)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
s_config_sent_q <= '0;
|
||||
s_command_q <= '0;
|
||||
s_error_q <= '0;
|
||||
s_intr_state_q <= '0;
|
||||
s_intr_enable_q <= '0;
|
||||
s_frame_count_q <= '0;
|
||||
s_line_count_q <= '0;
|
||||
s_pixel_count_q <= '0;
|
||||
s_word_count_q <= '0;
|
||||
s_drop_count_q <= '0;
|
||||
end else begin
|
||||
if (config_valid_o && config_ready_i) s_config_sent_q <= s_config_seq_q;
|
||||
if (command_valid_o && command_ready_i) s_command_q <= '0;
|
||||
if (s_accept && s_write && !s_access_err && (s_offset == `RIBP_DVP_COMMAND)) begin
|
||||
s_command_q <= s_command_q | ribp.wdata[1:0];
|
||||
end
|
||||
s_error_q <= (s_error_q | error_flags_i) & ~((s_accept && s_write && (s_offset == `RIBP_DVP_ERROR_STATUS)) ? ribp.wdata[5:0] : 6'd0);
|
||||
if (frame_start_i) s_intr_state_q[`DVP_INTR_FRAME_START] <= 1'b1;
|
||||
if (line_done_i) s_intr_state_q[`DVP_INTR_LINE_DONE] <= 1'b1;
|
||||
if (frame_done_i) s_intr_state_q[`DVP_INTR_FRAME_DONE] <= 1'b1;
|
||||
if (error_event_i) s_intr_state_q[`DVP_INTR_OVERFLOW] <= 1'b1;
|
||||
if (s_accept && s_write && (s_offset == `RIBP_DVP_INTR_STATE))
|
||||
s_intr_state_q <= s_intr_state_q & ~ribp.wdata[6:0];
|
||||
if (s_accept && s_write && (s_offset == `RIBP_DVP_INTR_ENABLE))
|
||||
s_intr_enable_q <= ribp.wdata[6:0];
|
||||
if (s_accept && s_write && (s_offset == `RIBP_DVP_INTR_TEST))
|
||||
s_intr_state_q <= s_intr_state_q | ribp.wdata[6:0];
|
||||
if (frame_stats_valid_i) begin
|
||||
s_frame_count_q <= frame_stats_i[31:0];
|
||||
s_line_count_q <= {16'd0, frame_stats_i[47:32]};
|
||||
s_pixel_count_q <= frame_stats_i[79:48];
|
||||
s_word_count_q <= {16'd0, frame_stats_i[95:80]};
|
||||
s_drop_count_q <= frame_stats_i[127:96];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dffr #(1) u_ready_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (ribp.valid && !s_ready_q),
|
||||
.dat_o (s_ready_q)
|
||||
);
|
||||
dffer #(32) u_rdata_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_accept && !s_write),
|
||||
.dat_i (s_rdata_d),
|
||||
.dat_o (s_rdata_q)
|
||||
);
|
||||
dffer #(1) u_resp_err_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_accept),
|
||||
.dat_i (s_resp_err_d),
|
||||
.dat_o (s_resp_err_q)
|
||||
);
|
||||
endmodule
|
||||
@@ -74,7 +74,7 @@ module dma_core (
|
||||
logic s_fifo_flush, s_fifo_push, s_fifo_pop;
|
||||
logic s_fifo_full, s_fifo_empty;
|
||||
logic [ 2:0] s_fifo_count;
|
||||
logic [31:0] s_fifo_rdata;
|
||||
logic [35:0] s_fifo_rdata;
|
||||
logic s_rsp_err;
|
||||
logic s_i2s_tx_stream;
|
||||
logic s_i2s_rx_stream;
|
||||
@@ -99,7 +99,7 @@ module dma_core (
|
||||
assign s_i2s_rx_stream = mode_i == HWT_I2S_RX_TRG;
|
||||
assign s_dvp_rx_stream = mode_i == HWT_DVP_RX_TRG;
|
||||
|
||||
assign i2s_tx_axis.tdata = s_fifo_rdata;
|
||||
assign i2s_tx_axis.tdata = s_fifo_rdata[31:0];
|
||||
assign i2s_tx_axis.tkeep = '1;
|
||||
assign i2s_tx_axis.tstrb = '1;
|
||||
assign i2s_tx_axis.tlast = (s_xfer_cnt_q + 1'b1) >= xferlen_i;
|
||||
@@ -148,8 +148,8 @@ module dma_core (
|
||||
assign rib.cmd_len = s_chunk_len;
|
||||
assign rib.w_valid = (s_fsm_q == FSM_WR_DATA) && !s_i2s_tx_stream &&
|
||||
~s_fifo_empty && (s_fifo_count != 3'd0);
|
||||
assign rib.wdata = s_fifo_rdata;
|
||||
assign rib.wstrb = '1;
|
||||
assign rib.wdata = s_fifo_rdata[31:0];
|
||||
assign rib.wstrb = s_dvp_rx_stream ? s_fifo_rdata[35:32] : '1;
|
||||
assign rib.wlast = s_wr_beat_q == s_chunk_len;
|
||||
assign rib.rsp_ready = (s_fsm_q == FSM_RD_RESP) && !(s_i2s_rx_stream || s_dvp_rx_stream) ?
|
||||
(~s_fifo_full && (s_fifo_count != 3'd4)) :
|
||||
@@ -166,7 +166,7 @@ module dma_core (
|
||||
assign s_fifo_pop = s_i2s_tx_stream ? s_stream_tx_hdshk : ((s_fsm_q == FSM_WR_DATA) && s_w_hdshk);
|
||||
|
||||
fifo #(
|
||||
.DATA_WIDTH (32),
|
||||
.DATA_WIDTH (36),
|
||||
.BUFFER_DEPTH(4)
|
||||
) u_data_fifo (
|
||||
.clk_i(clk_i),
|
||||
@@ -174,7 +174,9 @@ module dma_core (
|
||||
.flush_i(s_fifo_flush),
|
||||
.push_i(s_fifo_push),
|
||||
.full_o(s_fifo_full),
|
||||
.dat_i(s_i2s_rx_stream ? i2s_rx_axis.tdata : s_dvp_rx_stream ? dvp_rx_axis.tdata : rib.rdata),
|
||||
.dat_i(s_i2s_rx_stream ? {4'b1111, i2s_rx_axis.tdata} :
|
||||
s_dvp_rx_stream ? {dvp_rx_axis.tkeep, dvp_rx_axis.tdata} :
|
||||
{4'b1111, rib.rdata}),
|
||||
.pop_i(s_fifo_pop),
|
||||
.empty_o(s_fifo_empty),
|
||||
.dat_o(s_fifo_rdata),
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
/clusterip/common/rtl/utils/spill_register.sv
|
||||
/clusterip/common/rtl/stream/round_robin_arbiter.sv
|
||||
/clusterip/common/rtl/utils/lfsr.sv
|
||||
/clusterip/common/rtl/utils/bin2gray.sv
|
||||
/clusterip/common/rtl/utils/gray2bin.sv
|
||||
/clusterip/common/rtl/utils/edge_det.sv
|
||||
/clusterip/common/rtl/cdc/cdc_sync.sv
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
/ip/ribp/memory/sdram_reg.sv
|
||||
/ip/ribp/memory/sdram_core.sv
|
||||
/ip/ribp/memory/sdram.sv
|
||||
/ip/ribp/multimedia/dvp_define.svh
|
||||
/ip/ribp/multimedia/dvp_core.sv
|
||||
/ip/ribp/multimedia/dvp_reg.sv
|
||||
/ip/ribp/multimedia/dvp.sv
|
||||
/ip/ribp/peripheral/timer_core.sv
|
||||
/ip/ribp/peripheral/timer_reg.sv
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module dvp_formal_design (
|
||||
input logic clk_i,
|
||||
output logic rst_n_i,
|
||||
output logic f_past_valid,
|
||||
output logic rib_valid,
|
||||
output logic [31:0] rib_addr,
|
||||
output logic [31:0] rib_wdata,
|
||||
output logic [3:0] rib_wstrb,
|
||||
output logic rib_ready,
|
||||
output logic rib_resp_err,
|
||||
output logic [6:0] intr_state,
|
||||
output logic [6:0] intr_enable,
|
||||
output logic irq
|
||||
);
|
||||
ribp_if rib ();
|
||||
(* anyseq *) logic f_rib_valid;
|
||||
(* anyseq *) logic [31:0] f_rib_addr, f_rib_wdata;
|
||||
(* anyseq *) logic [3:0] f_rib_wstrb;
|
||||
(* anyseq *) logic f_active, f_fifo_empty, f_fifo_full;
|
||||
(* anyseq *) logic [5:0] f_error_flags;
|
||||
(* anyseq *) logic [127:0] f_frame_stats;
|
||||
(* anyseq *) logic f_frame_stats_valid;
|
||||
assign rib.valid = f_rib_valid; assign rib.addr = f_rib_addr;
|
||||
assign rib.wdata = f_rib_wdata; assign rib.wstrb = f_rib_wstrb;
|
||||
assign rib_valid = rib.valid; assign rib_addr = rib.addr; assign rib_wdata = rib.wdata;
|
||||
assign rib_wstrb = rib.wstrb; assign rib_ready = rib.ready; assign rib_resp_err = rib.resp_err;
|
||||
assign intr_state = u_dut.s_intr_state_q;
|
||||
assign intr_enable = u_dut.s_intr_enable_q;
|
||||
dvp_reg u_dut (
|
||||
.clk_i(clk_i), .rst_n_i(rst_n_i), .ribp(rib), .active_i(f_active),
|
||||
.fifo_empty_i(f_fifo_empty), .fifo_full_i(f_fifo_full), .rx_data_i(32'd0),
|
||||
.frame_start_i(1'b0), .line_done_i(1'b0), .frame_done_i(1'b0),
|
||||
.error_event_i(|f_error_flags), .error_flags_i(f_error_flags),
|
||||
.frame_stats_i(f_frame_stats), .frame_stats_valid_i(f_frame_stats_valid),
|
||||
.config_o(), .config_valid_o(), .config_ready_i(1'b1),
|
||||
.command_abort_o(), .command_flush_o(), .command_valid_o(), .command_ready_i(1'b1),
|
||||
.rx_pop_o(), .stream_enable_o(), .irq_o(irq)
|
||||
);
|
||||
initial begin rst_n_i = 1'b0; f_past_valid = 1'b0; end
|
||||
always_ff @(posedge clk_i) begin rst_n_i <= 1'b1; f_past_valid <= 1'b1; end
|
||||
endmodule
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module dvp_formal;
|
||||
(* anyseq *) (* gclk *) reg clk_i;
|
||||
wire rst_n_i, f_past_valid, rib_valid, rib_ready, rib_resp_err, irq;
|
||||
wire [31:0] rib_addr, rib_wdata; wire [3:0] rib_wstrb;
|
||||
wire [6:0] intr_state, intr_enable;
|
||||
dvp_formal_design u_design (.*);
|
||||
always @(posedge clk_i) begin
|
||||
if (rst_n_i) begin
|
||||
if (f_past_valid && $past(rst_n_i && rib_valid && !rib_ready)) begin
|
||||
assume (rib_valid); assume (rib_addr == $past(rib_addr));
|
||||
assume (rib_wdata == $past(rib_wdata)); assume (rib_wstrb == $past(rib_wstrb));
|
||||
assert (rib_ready);
|
||||
end
|
||||
assert (irq == ((intr_state & intr_enable) != 0));
|
||||
cover (rib_resp_err); cover (irq);
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
@@ -160,6 +160,13 @@ def source_files(target: str) -> list[Path]:
|
||||
PERIPHERAL / "ribp_clint.sv",
|
||||
SCRIPT_DIR / "clint_formal.sv",
|
||||
]
|
||||
if target == "dvp":
|
||||
return [
|
||||
COMMON_RTL / "interface/ribp_if.sv", COMMON_RTL / "utils/register.sv",
|
||||
ROOT / "rtl/ip/ribp/multimedia/dvp_define.svh",
|
||||
ROOT / "rtl/ip/ribp/multimedia/dvp_reg.sv",
|
||||
SCRIPT_DIR / "dvp_formal.sv",
|
||||
]
|
||||
raise ValueError(f"unsupported formal target: {target}")
|
||||
|
||||
|
||||
@@ -205,6 +212,7 @@ def parse_args() -> argparse.Namespace:
|
||||
"i2c",
|
||||
"timer",
|
||||
"clint",
|
||||
"dvp",
|
||||
),
|
||||
required=True,
|
||||
)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
},
|
||||
{
|
||||
"name": "dvp",
|
||||
"clock": "s_dvp_pclk_buf",
|
||||
"clock": "s_pclk_sel",
|
||||
"reset": "s_dvp_pclk_rst_n_sync",
|
||||
"reset_source": "rst_n_i",
|
||||
"reset_primitive": "rst_sync",
|
||||
@@ -107,17 +107,17 @@
|
||||
"name": "dvp_enable",
|
||||
"source": "system",
|
||||
"destination": "dvp",
|
||||
"primitive": "cdc_sync",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/ip/ribp/multimedia/dvp.sv",
|
||||
"instance": "u_dvp_recven_cdc_sync"
|
||||
"instance": "u_dvp_config_cdc"
|
||||
},
|
||||
{
|
||||
"name": "dvp_fifo",
|
||||
"source": "dvp",
|
||||
"destination": "system",
|
||||
"primitive": "async_fifo",
|
||||
"primitive": "cdc_fifo_warm_flush",
|
||||
"path": "rtl/ip/ribp/multimedia/dvp.sv",
|
||||
"instance": "u_rx_async_fifo"
|
||||
"instance": "u_dvp_payload_fifo"
|
||||
},
|
||||
{
|
||||
"name": "rtc_command",
|
||||
|
||||
@@ -39,6 +39,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "ribp", 11, 18, "gpio.irq_o"),
|
||||
("i2c1", "ribp", 12, 19, "i2c1.irq_o"),
|
||||
("dvp", "ribp", 13, 15, "s_dvp_irq"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"gpio_pins": 32,
|
||||
"irq_vector_width": 32,
|
||||
"irq_groups": [
|
||||
{"name": "ribp", "width": 13, "top_signal": "s_ribp_irq"},
|
||||
{"name": "ribp", "width": 14, "top_signal": "s_ribp_irq"},
|
||||
{"name": "apb", "width": 5, "top_signal": "s_apb_irq"}
|
||||
],
|
||||
"interrupts": [
|
||||
@@ -24,7 +24,8 @@
|
||||
{"name": "rng", "description": "APB RNG data/error interrupt", "group": "apb", "group_bit": 4, "core_bit": 16, "signal": "s_rng_irq", "user_visible": false},
|
||||
{"name": "ws2812", "description": "WS2812 transmitter interrupt", "group": "ribp", "group_bit": 10, "core_bit": 17, "signal": "ws2812.irq_o"},
|
||||
{"name": "gpio", "description": "RIBP GPIO combined interrupt", "group": "ribp", "group_bit": 11, "core_bit": 18, "signal": "gpio.irq_o"},
|
||||
{"name": "i2c1", "description": "RIBP I2C1 interrupt", "group": "ribp", "group_bit": 12, "core_bit": 19, "signal": "i2c1.irq_o"}
|
||||
{"name": "i2c1", "description": "RIBP I2C1 interrupt", "group": "ribp", "group_bit": 12, "core_bit": 19, "signal": "i2c1.irq_o"},
|
||||
{"name": "dvp", "description": "RIBP DVP capture interrupt", "group": "ribp", "group_bit": 13, "core_bit": 15, "signal": "s_dvp_irq"}
|
||||
],
|
||||
"wake_sources": [
|
||||
{"name": "rtc", "signal": "u_rtc_if.wake_o", "observer": "sysctrl.rtc_wake_i", "retained": false}
|
||||
|
||||
+10
-2
@@ -11,7 +11,7 @@ FORMAL_CLINT_DEPTH ?= 32
|
||||
FORMAL_TIMEOUT ?= 60
|
||||
FORMAL_WS2812_TIMEOUT ?= 120
|
||||
FORMAL_I2C_TIMEOUT ?= 300
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart i2c timer clint
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart i2c timer clint dvp
|
||||
FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py
|
||||
FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py
|
||||
FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py
|
||||
@@ -37,6 +37,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(RTL_PATH)/formal/timer_formal_props.sv \
|
||||
$(RTL_PATH)/formal/clint_formal.sv \
|
||||
$(RTL_PATH)/formal/clint_formal_props.sv \
|
||||
$(RTL_PATH)/formal/dvp_formal.sv \
|
||||
$(RTL_PATH)/formal/dvp_formal_props.sv \
|
||||
$(RTL_PATH)/top/bus.sv \
|
||||
$(RTL_PATH)/top/rib_error_slave.sv \
|
||||
$(RTL_PATH)/top/rib_if.sv \
|
||||
@@ -78,6 +80,10 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/clint_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/clint_core.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/ribp_clint.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/multimedia/dvp_define.svh \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/multimedia/dvp_core.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/multimedia/dvp_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/multimedia/dvp.sv \
|
||||
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/clkrst/counter.sv \
|
||||
$(RTL_PATH)/top/rcu.sv \
|
||||
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/ribp_if.sv \
|
||||
@@ -182,10 +188,12 @@ formal-timer: $(FORMAL_DIR)/timer/.stamp | manifest
|
||||
|
||||
formal-clint: $(FORMAL_DIR)/clint/.stamp | manifest
|
||||
|
||||
formal-dvp: $(FORMAL_DIR)/dvp/.stamp | manifest
|
||||
|
||||
formal-doctor:
|
||||
$(MAKE) FORMAL=YES SIMU=IVERILOG SYNTH=YOSYS STA=NONE doctor
|
||||
|
||||
formal-clean:
|
||||
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
|
||||
|
||||
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clint formal-doctor formal-clean
|
||||
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clint formal-dvp formal-doctor formal-clean
|
||||
@@ -94,6 +94,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/ws2812_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/ws2812.c \
|
||||
$(ROOT_PATH)/crt/src/hal/dma.c \
|
||||
$(ROOT_PATH)/crt/src/hal/dvp.c \
|
||||
$(ROOT_PATH)/crt/src/hal/perf.c \
|
||||
$(ROOT_PATH)/crt/src/hal/lcd.c \
|
||||
$(ROOT_PATH)/crt/src/hal/psram.c \
|
||||
|
||||
@@ -82,6 +82,7 @@ module ip_ribp_wrapper (
|
||||
logic s_dma_i2c1_tx_stall, s_dma_i2c1_rx_stall;
|
||||
logic s_dma_xfer_done;
|
||||
logic s_tim0_irq, s_tim1_irq;
|
||||
logic s_dvp_irq;
|
||||
|
||||
`ifdef PDK_GF180
|
||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
||||
@@ -333,7 +334,8 @@ module ip_ribp_wrapper (
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (u_dvp_ribp_if),
|
||||
.rx_axis(u_dvp_rx_axis_if),
|
||||
.dvp (dvp)
|
||||
.dvp (dvp),
|
||||
.irq_o (s_dvp_irq)
|
||||
);
|
||||
|
||||
ribp_sdio u_rib_sdio (
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
// waiver at the SoC integration boundary without modifying the dependency.
|
||||
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
/* verilator lint_off SYNCASYNCNET */
|
||||
`include "cdc_fifo.sv"
|
||||
`include "async_reqack.sv"
|
||||
`include "cdc_warm_flush.sv"
|
||||
/* verilator lint_on SYNCASYNCNET */
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
@@ -16,6 +16,7 @@ CDC_PRIMITIVES = {
|
||||
"async_reqack",
|
||||
"cdc_2phase",
|
||||
"cdc_sync",
|
||||
"cdc_fifo_warm_flush",
|
||||
"edge_det",
|
||||
"hazard3_apb_async_bridge",
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module dvp_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic pclk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic href_i = 1'b0;
|
||||
logic vsync_i = 1'b0;
|
||||
logic [ 7:0] dat_i = 8'd0;
|
||||
logic [31:0] ribp_rdata;
|
||||
logic irq_o;
|
||||
ribp_if ribp ();
|
||||
axi4_stream_if #(
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.DEST_WIDTH(1),
|
||||
.USER_WIDTH(1)
|
||||
) axis (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
dvp_if dvp ();
|
||||
|
||||
assign dvp.pclk_i = pclk_i;
|
||||
assign dvp.href_i = href_i;
|
||||
assign dvp.vsync_i = vsync_i;
|
||||
assign dvp.dat_i = dat_i;
|
||||
assign axis.tready = 1'b1;
|
||||
always #5 clk_i = ~clk_i;
|
||||
always #10 pclk_i = ~pclk_i;
|
||||
|
||||
ribp_dvp u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (ribp),
|
||||
.rx_axis(axis),
|
||||
.dvp (dvp),
|
||||
.irq_o (irq_o)
|
||||
);
|
||||
|
||||
task automatic write(input logic [31:0] address, input logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b1;
|
||||
ribp.addr = address;
|
||||
ribp.wdata = data;
|
||||
ribp.wstrb = 4'hf;
|
||||
do @(negedge clk_i); while (!ribp.ready);
|
||||
if (ribp.resp_err) $fatal(1, "unexpected write error at %h", address);
|
||||
ribp.valid = 1'b0;
|
||||
ribp.wstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic read(input logic [31:0] address, output logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b1;
|
||||
ribp.addr = address;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
do @(negedge clk_i); while (!ribp.ready);
|
||||
data = ribp.rdata;
|
||||
ribp.valid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic frame(input int lines, input int pixels);
|
||||
begin
|
||||
vsync_i = 1'b1;
|
||||
repeat (3) @(posedge pclk_i);
|
||||
vsync_i = 1'b0;
|
||||
repeat (2) @(posedge pclk_i);
|
||||
for (int line = 0; line < lines; line++) begin
|
||||
href_i = 1'b1;
|
||||
for (int index = 0; index < pixels * 2; index++) begin
|
||||
dat_i = index + line * 8;
|
||||
@(posedge pclk_i);
|
||||
end
|
||||
href_i = 1'b0;
|
||||
repeat (2) @(posedge pclk_i);
|
||||
end
|
||||
vsync_i = 1'b1;
|
||||
repeat (3) @(posedge pclk_i);
|
||||
vsync_i = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic check_frame(input int lines, input int pixels, input int expected_beats);
|
||||
begin
|
||||
beats = 0;
|
||||
frame(lines, pixels);
|
||||
repeat (80) @(posedge clk_i);
|
||||
if (beats != expected_beats)
|
||||
$fatal(1, "unexpected AXI beat count=%0d expected=%0d", beats, expected_beats);
|
||||
end
|
||||
endtask
|
||||
|
||||
logic [31:0] value;
|
||||
int beats;
|
||||
always @(posedge clk_i) begin
|
||||
if (axis.tvalid && axis.tready) begin
|
||||
beats = beats + 1;
|
||||
if (beats == 1 && !axis.tuser[0]) $fatal(1, "SOF missing");
|
||||
if ((beats == 2 || beats == 4) && !axis.tlast) $fatal(1, "EOL missing");
|
||||
end
|
||||
end
|
||||
initial begin
|
||||
ribp.valid = 1'b0;
|
||||
ribp.addr = '0;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
repeat (4) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
read(32'h0000_00f8, value);
|
||||
if (value != 32'h0002_0000) $fatal(1, "bad DVP version %h", value);
|
||||
read(32'h0000_0100, value);
|
||||
if (!ribp.resp_err) $fatal(1, "invalid DVP access was accepted");
|
||||
write(32'h0000_0018, {16'd2, 16'd4});
|
||||
write(32'h0000_000c, 32'd1);
|
||||
write(32'h0000_0000, 32'd3);
|
||||
repeat (50) @(posedge pclk_i);
|
||||
check_frame(2, 4, 4);
|
||||
read(32'h0000_0024, value);
|
||||
if (value == 0)
|
||||
$fatal(1, "frame count/beats invalid count=%h beats=%0d", value, beats);
|
||||
write(32'h0000_0018, {16'd2, 16'd3});
|
||||
check_frame(1, 3, 2);
|
||||
write(32'h0000_0048, 32'h0000_0004);
|
||||
read(32'h0000_003c, value);
|
||||
if (ribp.resp_err) $fatal(1, "DVP interrupt read failed");
|
||||
$display("RIBP DVP V2 capture test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -33,7 +33,10 @@ module soc_irq_topology_tb;
|
||||
for (int bit_index = 10; bit_index < `SOC_IRQ_RIBP_WIDTH; bit_index++) begin
|
||||
s_ribp_irq = '0;
|
||||
s_ribp_irq[bit_index] = 1'b1;
|
||||
expect_irq(32'd1 << (bit_index + 7));
|
||||
case (bit_index)
|
||||
13: expect_irq(32'd1 << 15);
|
||||
default: expect_irq(32'd1 << (bit_index + 7));
|
||||
endcase
|
||||
end
|
||||
|
||||
for (int bit_index = 0; bit_index < `SOC_IRQ_APB_WIDTH; bit_index++) begin
|
||||
@@ -52,8 +55,8 @@ module soc_irq_topology_tb;
|
||||
|
||||
s_apb_irq = '0;
|
||||
expect_irq('0);
|
||||
if (s_irq[10] !== 1'b0 || s_irq[15] !== 1'b0) begin
|
||||
$fatal(1, "removed core IRQ bits are not low: IRQ10=%b IRQ15=%b", s_irq[10], s_irq[15]);
|
||||
if (s_irq[10] !== 1'b0) begin
|
||||
$fatal(1, "removed core IRQ bit is not low: IRQ10=%b", s_irq[10]);
|
||||
end
|
||||
if (s_irq[31:18] !== '0) begin
|
||||
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq[31:18]);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
"""RIBP DVP V2 register, CDC, framing, and packing regression."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_dvp_capture_framing(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or vvp is None:
|
||||
return
|
||||
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||
ip = ROOT / "rtl/ip/ribp/multimedia"
|
||||
defines = [
|
||||
"+define+PDK_BEHAV",
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
]
|
||||
source = [
|
||||
"+incdir+" + str(common),
|
||||
"+incdir+" + str(common / "interface"),
|
||||
"+incdir+" + str(common / "utils"),
|
||||
"+incdir+" + str(common / "cdc"),
|
||||
"+incdir+" + str(common / "clkrst"),
|
||||
"+incdir+" + str(ip),
|
||||
str(common / "interface/ribp_if.sv"),
|
||||
str(common / "interface/axi4_stream_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(common / "utils/xchecker.sv"),
|
||||
str(common / "utils/bin2gray.sv"),
|
||||
str(common / "utils/gray2bin.sv"),
|
||||
str(common / "utils/spill_register.sv"),
|
||||
str(common / "cdc/cdc_sync.sv"),
|
||||
str(common / "cdc/cdc_rst_ctrlr.sv"),
|
||||
str(common / "cdc/async_reqack.sv"),
|
||||
str(common / "cdc/cdc_fifo.sv"),
|
||||
str(common / "cdc/cdc_2phase.sv"),
|
||||
str(common / "cdc/cdc_warm_flush.sv"),
|
||||
str(common / "utils/edge_det.sv"),
|
||||
str(common / "clkrst/rst_sync.sv"),
|
||||
str(ROOT / "rtl/tech/tc_clk.sv"),
|
||||
str(ip / "dvp_core.sv"),
|
||||
str(ip / "dvp_reg.sv"),
|
||||
str(ip / "dvp.sv"),
|
||||
str(ROOT / "tests/rtl/dvp_tb.sv"),
|
||||
]
|
||||
source_list = tmp_path / "dvp.fl"
|
||||
source_list.write_text("\n".join([*defines, *source, ""]), encoding="utf-8")
|
||||
converted = tmp_path / "dvp.v"
|
||||
subprocess.run(
|
||||
[sys.executable, str(ROOT / "rtl/mini/script/convt_sv2v.py"), "-f", str(source_list), "--output", str(converted)],
|
||||
check=True,
|
||||
)
|
||||
simulation = tmp_path / "dvp_tb"
|
||||
subprocess.run([iverilog, "-g2012", "-s", "dvp_tb", "-o", str(simulation), str(converted)], check=True)
|
||||
result = subprocess.run([vvp, str(simulation)], check=True, capture_output=True, text=True)
|
||||
assert "RIBP DVP V2 capture test passed" in result.stdout
|
||||
@@ -113,20 +113,21 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert ".cfg_axi4(u_cfg_axi4_if)" in bus_fabric
|
||||
assert ".apb_axi4(u_apb_axi4_if)" in bus_fabric
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 32'h000E7BFC" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 13" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 32'h000EFBFC" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 14" in irq_config
|
||||
assert "`define SOC_IRQ_APB_WIDTH 5" 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
|
||||
assert "assign irq_o[11] = gpio.irq_o;" in rib_irq
|
||||
assert "assign irq_o[12] = i2c1.irq_o;" in rib_irq
|
||||
assert "assign irq_o[13] = s_dvp_irq;" 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 "s_irq[10]" not in irq_wiring
|
||||
assert "s_irq[15]" not in irq_wiring
|
||||
assert "s_irq[15] = s_ribp_irq[13];" in irq_wiring
|
||||
assert "s_irq[16] = s_apb_irq[4];" in irq_wiring
|
||||
assert "irq_i[10] == 1'b0" in irq_sva
|
||||
assert "irq_i[15] == 1'b0" in irq_sva
|
||||
assert "irq_i[15] == ribp_irq_i[13]" in irq_sva
|
||||
assert "irq_i[31] == 1'b0" in irq_sva
|
||||
assert "bind retrosoc soc_irq_topology_sva" in irq_sva
|
||||
assert filelist.startswith("+incdir+")
|
||||
@@ -164,6 +165,7 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "ribp", 11, 18, "gpio.irq_o"),
|
||||
("i2c1", "ribp", 12, 19, "i2c1.irq_o"),
|
||||
("dvp", "ribp", 13, 15, "s_dvp_irq"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user