mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add WS2812 support and related tests
- Replace onewire interface with ws2812 interface in retrosoc module. - Include ws2812_math.c in C test sources. - Add ws2812 header in test_runtime.c and implement ws2812 helper tests. - Update ribp_topology_tb and soc_irq_topology_tb to handle ws2812 interface. - Create ws2812_dma_tb and ws2812_tb for testing WS2812 DMA and waveform functionality. - Enhance test_script_tools.py to include ws2812 in formal filelists. - Modify test_soc_topology.py to ensure proper IRQ mapping for ws2812. - Introduce test_ws2812.py for WS2812 register, waveform, and streaming regression tests.
This commit is contained in:
46 files changed
+2635
-616
No files matched your search
@@ -233,7 +233,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-clean formal-doctor
|
||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-ws2812 formal-clean formal-doctor
|
||||
.NOTPARALLEL: setup
|
||||
|
||||
help:
|
||||
@@ -261,7 +261,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-user run SBY peripheral-control proofs' \
|
||||
' formal-sysctrl | formal-pll-rcu | formal-gpio-user | formal-ws2812 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' \
|
||||
|
||||
@@ -28,7 +28,7 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
||||
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with
|
||||
open-source CI coverage.
|
||||
- A memory-mapped peripheral subsystem with GPIO, UART, timers, PWM, I2C, I2S, PS2,
|
||||
1-Wire, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC
|
||||
WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC
|
||||
support. Available interfaces depend on the selected SoC configuration.
|
||||
- A standalone RISC-V runtime, HAL, board support, middleware, and `benchmark`, `bringup`,
|
||||
`coremark`, `debug`, and `shell` applications.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
#include <retrosoc/hal/i2s.h>
|
||||
#include <retrosoc/hal/lcd.h>
|
||||
#include <retrosoc/hal/onewire.h>
|
||||
#include <retrosoc/hal/ws2812.h>
|
||||
#include <retrosoc/hal/ps2.h>
|
||||
#include <retrosoc/hal/pwm.h>
|
||||
#include <retrosoc/hal/qspi.h>
|
||||
@@ -56,7 +56,7 @@ int main(void) {
|
||||
rs_shell_init();
|
||||
(void)rs_shell_register("app", "app info", true, rs_app_info_command);
|
||||
(void)rs_shell_register("arch", "archinfo test", true, ip_archinfo_test);
|
||||
(void)rs_shell_register("1wire", "1wire test", true, ip_1wire_test);
|
||||
(void)rs_shell_register("ws2812", "ws2812 test", true, ip_ws2812_test);
|
||||
(void)rs_shell_register("tim", "timer test", true, ip_tim_test);
|
||||
(void)rs_shell_register("gpio", "gpio test", true, ip_gpio_test);
|
||||
(void)rs_shell_register("pwm", "pwm test", true, ip_pwm_test);
|
||||
|
||||
@@ -88,14 +88,23 @@
|
||||
#define reg_i2s_txdata RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x14))
|
||||
#define reg_i2s_rxdata RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x18))
|
||||
#define reg_i2s_status RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x1C))
|
||||
// onewire
|
||||
#define reg_onewire_clkdiv RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x00))
|
||||
#define reg_onewire_zerocnt RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x04))
|
||||
#define reg_onewire_onecnt RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x08))
|
||||
#define reg_onewire_rstcnt RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x0C))
|
||||
#define reg_onewire_txdata RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x10))
|
||||
#define reg_onewire_ctrl RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x14))
|
||||
#define reg_onewire_status RS_SOC_REG32(RS_SOC_RIBP_ONEWIRE_BASE, UINT32_C(0x18))
|
||||
// ws2812
|
||||
#define reg_ws2812_bit_cycles RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x00))
|
||||
#define reg_ws2812_t0h_cycles RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x04))
|
||||
#define reg_ws2812_t1h_cycles RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x08))
|
||||
#define reg_ws2812_reset_cycles RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x0C))
|
||||
#define reg_ws2812_txdata RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x10))
|
||||
#define reg_ws2812_ctrl RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x14))
|
||||
#define reg_ws2812_status RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x18))
|
||||
#define reg_ws2812_frame_words RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x1C))
|
||||
#define reg_ws2812_fifo_level RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x20))
|
||||
#define reg_ws2812_fifo_watermark RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x24))
|
||||
#define reg_ws2812_remaining_words RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x28))
|
||||
#define reg_ws2812_error_status RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x2C))
|
||||
#define reg_ws2812_intr_state RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x30))
|
||||
#define reg_ws2812_intr_enable RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x34))
|
||||
#define reg_ws2812_intr_test RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x38))
|
||||
#define reg_ws2812_ip_info RS_SOC_REG32(RS_SOC_RIBP_WS2812_BASE, UINT32_C(0x3C))
|
||||
// xpi
|
||||
#define reg_xpi_cfgidx RS_SOC_REG32(RS_SOC_RIBP_XPI_BASE, UINT32_C(0x00))
|
||||
#define reg_xpi_accmd RS_SOC_REG32(RS_SOC_RIBP_XPI_BASE, UINT32_C(0x04))
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#ifndef RETROSOC_1WIRE_H
|
||||
#define RETROSOC_1WIRE_H
|
||||
|
||||
void ip_1wire_test(int argc, char **argv);
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef RETROSOC_HAL_WS2812_H
|
||||
#define RETROSOC_HAL_WS2812_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
#define RS_WS2812_DEFAULT_BIT_PERIOD_NS UINT32_C(1250)
|
||||
#define RS_WS2812_DEFAULT_T0H_NS UINT32_C(350)
|
||||
#define RS_WS2812_DEFAULT_T1H_NS UINT32_C(700)
|
||||
#define RS_WS2812_DEFAULT_RESET_NS UINT32_C(300000)
|
||||
|
||||
#define RS_WS2812_ERROR_CONFIG UINT32_C(0x01)
|
||||
#define RS_WS2812_ERROR_UNDERFLOW UINT32_C(0x02)
|
||||
#define RS_WS2812_ERROR_COMMAND UINT32_C(0x04)
|
||||
|
||||
#define RS_WS2812_INTR_DONE UINT32_C(0x01)
|
||||
#define RS_WS2812_INTR_FIFO_LOW UINT32_C(0x02)
|
||||
#define RS_WS2812_INTR_ERROR UINT32_C(0x04)
|
||||
#define RS_WS2812_INTR_ABORTED UINT32_C(0x08)
|
||||
#define RS_WS2812_INTR_ALL UINT32_C(0x0F)
|
||||
|
||||
typedef struct {
|
||||
uint32_t source_clock_hz;
|
||||
uint32_t bit_period_ns;
|
||||
uint32_t t0h_ns;
|
||||
uint32_t t1h_ns;
|
||||
uint32_t reset_ns;
|
||||
uint32_t fifo_watermark;
|
||||
} rs_ws2812_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t bit_cycles;
|
||||
uint16_t t0h_cycles;
|
||||
uint16_t t1h_cycles;
|
||||
uint32_t reset_cycles;
|
||||
} rs_ws2812_timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t fifo_level;
|
||||
uint32_t remaining_words;
|
||||
uint32_t error_status;
|
||||
uint32_t interrupt_state;
|
||||
bool busy;
|
||||
bool fifo_empty;
|
||||
bool fifo_full;
|
||||
bool config_valid;
|
||||
bool reset_active;
|
||||
} rs_ws2812_status_t;
|
||||
|
||||
uint32_t rs_ws2812_pack_grb(uint8_t red, uint8_t green, uint8_t blue);
|
||||
rs_status_t rs_ws2812_timing_from_ns(const rs_ws2812_config_t *config, rs_ws2812_timing_t *timing);
|
||||
rs_status_t rs_ws2812_init(const rs_ws2812_config_t *config);
|
||||
rs_status_t rs_ws2812_get_status(rs_ws2812_status_t *status);
|
||||
rs_status_t rs_ws2812_push(uint32_t pixel, rs_timeout_t timeout);
|
||||
rs_status_t rs_ws2812_start(uint32_t pixel_count);
|
||||
rs_status_t rs_ws2812_wait(rs_timeout_t timeout);
|
||||
rs_status_t rs_ws2812_abort(rs_timeout_t timeout);
|
||||
rs_status_t rs_ws2812_irq_enable(uint32_t mask);
|
||||
rs_status_t rs_ws2812_irq_ack(uint32_t mask);
|
||||
rs_status_t rs_ws2812_write(const uint32_t *pixels, size_t pixel_count, rs_timeout_t timeout);
|
||||
rs_status_t rs_ws2812_write_dma(const uint32_t *pixels, size_t pixel_count, rs_timeout_t timeout);
|
||||
void ip_ws2812_test(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/core/wait.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
#include <retrosoc/hal/onewire.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
|
||||
void ip_1wire_test(int argc, char **argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
printf("1-wire test\n");
|
||||
|
||||
reg_onewire_clkdiv = (uint8_t)(CPU_FREQ / 0.8); // 72M 90
|
||||
reg_onewire_zerocnt = (uint8_t)(CPU_FREQ / 3); // 72M 24
|
||||
reg_onewire_onecnt = (uint8_t)(CPU_FREQ / 1.6); // 72M 45
|
||||
reg_onewire_rstcnt = (uint8_t)(CPU_FREQ / 12); // 72M 6
|
||||
|
||||
for (uint32_t num = 0U; num < 6U; ++num) {
|
||||
for (uint32_t i = 0U; i < 256U; ++i) {
|
||||
// clear fifo
|
||||
reg_onewire_ctrl = (uint8_t)0b01;
|
||||
// write data(GRB888 format)
|
||||
reg_onewire_txdata = (uint32_t)i;
|
||||
reg_onewire_txdata = (uint32_t)(i << 8);
|
||||
reg_onewire_txdata = (uint32_t)(i << 16);
|
||||
reg_onewire_txdata = (uint32_t)((i << 8) | (i << 16));
|
||||
reg_onewire_ctrl = (uint8_t)0b10;
|
||||
if (rs_wait_value(®_onewire_status, 5U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("1-wire transfer timed out\n");
|
||||
return;
|
||||
}
|
||||
delay_ms(5);
|
||||
}
|
||||
}
|
||||
|
||||
reg_onewire_ctrl = (uint8_t)0b01;
|
||||
reg_onewire_txdata = (uint32_t)0;
|
||||
reg_onewire_txdata = (uint32_t)0;
|
||||
reg_onewire_txdata = (uint32_t)0;
|
||||
reg_onewire_txdata = (uint32_t)0;
|
||||
reg_onewire_ctrl = (uint8_t)0b10;
|
||||
printf("1-wire test done\n");
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/ws2812.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
|
||||
#define RS_WS2812_CTRL_START UINT32_C(0x01)
|
||||
#define RS_WS2812_CTRL_ABORT UINT32_C(0x02)
|
||||
#define RS_WS2812_CTRL_FIFO_FLUSH UINT32_C(0x04)
|
||||
#define RS_WS2812_STATUS_BUSY UINT32_C(0x01)
|
||||
#define RS_WS2812_STATUS_FIFO_EMPTY UINT32_C(0x02)
|
||||
#define RS_WS2812_STATUS_FIFO_FULL UINT32_C(0x04)
|
||||
#define RS_WS2812_STATUS_CONFIG_VALID UINT32_C(0x08)
|
||||
#define RS_WS2812_STATUS_RESET_ACTIVE UINT32_C(0x10)
|
||||
#define RS_WS2812_IP_FIFO_DEPTH_SHIFT 16U
|
||||
#define RS_WS2812_IP_FIFO_DEPTH_MASK UINT32_C(0xFF)
|
||||
#define RS_WS2812_PIXEL_MASK UINT32_C(0x00FFFFFF)
|
||||
#define RS_WS2812_DMA_SOFTWARE_MODE UINT32_C(0)
|
||||
#define RS_WS2812_GPIO_MASK (UINT32_C(1) << 2U)
|
||||
|
||||
static uint32_t rs_ws2812_fifo_depth(void) {
|
||||
return (reg_ws2812_ip_info >> RS_WS2812_IP_FIFO_DEPTH_SHIFT) & RS_WS2812_IP_FIFO_DEPTH_MASK;
|
||||
}
|
||||
|
||||
static rs_status_t rs_ws2812_prepare(const uint32_t *pixels, size_t pixel_count,
|
||||
size_t *preloaded) {
|
||||
uint32_t fifo_depth;
|
||||
size_t preload_count;
|
||||
|
||||
if ((pixels == NULL) || (pixel_count == 0U) || (pixel_count > UINT32_MAX) ||
|
||||
(preloaded == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
for (size_t index = 0U; index < pixel_count; ++index) {
|
||||
if ((pixels[index] & ~RS_WS2812_PIXEL_MASK) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
}
|
||||
if ((reg_ws2812_status & RS_WS2812_STATUS_BUSY) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
|
||||
fifo_depth = rs_ws2812_fifo_depth();
|
||||
if (fifo_depth == 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
reg_ws2812_ctrl = RS_WS2812_CTRL_FIFO_FLUSH;
|
||||
reg_ws2812_error_status =
|
||||
RS_WS2812_ERROR_CONFIG | RS_WS2812_ERROR_UNDERFLOW | RS_WS2812_ERROR_COMMAND;
|
||||
reg_ws2812_intr_state = RS_WS2812_INTR_ALL;
|
||||
preload_count = pixel_count < (size_t)fifo_depth ? pixel_count : (size_t)fifo_depth;
|
||||
for (size_t index = 0U; index < preload_count; ++index) {
|
||||
reg_ws2812_txdata = pixels[index];
|
||||
}
|
||||
*preloaded = preload_count;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_init(const rs_ws2812_config_t *config) {
|
||||
rs_ws2812_timing_t timing;
|
||||
uint32_t fifo_depth;
|
||||
|
||||
if (rs_ws2812_timing_from_ns(config, &timing) != RS_OK) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
fifo_depth = rs_ws2812_fifo_depth();
|
||||
if ((fifo_depth == 0U) || (config->fifo_watermark >= fifo_depth)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((reg_ws2812_status & RS_WS2812_STATUS_BUSY) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
|
||||
reg_ws2812_ctrl = RS_WS2812_CTRL_FIFO_FLUSH;
|
||||
reg_ws2812_error_status =
|
||||
RS_WS2812_ERROR_CONFIG | RS_WS2812_ERROR_UNDERFLOW | RS_WS2812_ERROR_COMMAND;
|
||||
reg_ws2812_intr_state = RS_WS2812_INTR_ALL;
|
||||
reg_ws2812_bit_cycles = timing.bit_cycles;
|
||||
reg_ws2812_t0h_cycles = timing.t0h_cycles;
|
||||
reg_ws2812_t1h_cycles = timing.t1h_cycles;
|
||||
reg_ws2812_reset_cycles = timing.reset_cycles;
|
||||
reg_ws2812_fifo_watermark = config->fifo_watermark;
|
||||
return ((reg_ws2812_status & RS_WS2812_STATUS_CONFIG_VALID) != 0U) ? RS_OK : RS_EIO;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_get_status(rs_ws2812_status_t *status) {
|
||||
uint32_t value;
|
||||
|
||||
if (status == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
value = reg_ws2812_status;
|
||||
status->fifo_level = reg_ws2812_fifo_level;
|
||||
status->remaining_words = reg_ws2812_remaining_words;
|
||||
status->error_status = reg_ws2812_error_status;
|
||||
status->interrupt_state = reg_ws2812_intr_state;
|
||||
status->busy = (value & RS_WS2812_STATUS_BUSY) != 0U;
|
||||
status->fifo_empty = (value & RS_WS2812_STATUS_FIFO_EMPTY) != 0U;
|
||||
status->fifo_full = (value & RS_WS2812_STATUS_FIFO_FULL) != 0U;
|
||||
status->config_valid = (value & RS_WS2812_STATUS_CONFIG_VALID) != 0U;
|
||||
status->reset_active = (value & RS_WS2812_STATUS_RESET_ACTIVE) != 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_push(uint32_t pixel, rs_timeout_t timeout) {
|
||||
uint32_t status;
|
||||
|
||||
if ((pixel & ~RS_WS2812_PIXEL_MASK) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
while (timeout-- != 0U) {
|
||||
status = reg_ws2812_status;
|
||||
if ((reg_ws2812_error_status & RS_WS2812_ERROR_UNDERFLOW) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
if ((status & RS_WS2812_STATUS_FIFO_FULL) == 0U) {
|
||||
reg_ws2812_txdata = pixel;
|
||||
return RS_OK;
|
||||
}
|
||||
if ((status & RS_WS2812_STATUS_BUSY) == 0U) {
|
||||
return RS_ENOSPC;
|
||||
}
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_start(uint32_t pixel_count) {
|
||||
if ((pixel_count == 0U) || ((reg_ws2812_status & RS_WS2812_STATUS_BUSY) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
reg_ws2812_frame_words = pixel_count;
|
||||
reg_ws2812_ctrl = RS_WS2812_CTRL_START;
|
||||
if ((reg_ws2812_error_status & (RS_WS2812_ERROR_CONFIG | RS_WS2812_ERROR_COMMAND)) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
return ((reg_ws2812_status & RS_WS2812_STATUS_BUSY) != 0U) ? RS_OK : RS_EIO;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_wait(rs_timeout_t timeout) {
|
||||
while (timeout-- != 0U) {
|
||||
const uint32_t interrupt_state = reg_ws2812_intr_state;
|
||||
if ((interrupt_state & RS_WS2812_INTR_ERROR) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
if ((interrupt_state & RS_WS2812_INTR_ABORTED) != 0U) {
|
||||
reg_ws2812_intr_state = RS_WS2812_INTR_ABORTED;
|
||||
return RS_EIO;
|
||||
}
|
||||
if ((interrupt_state & RS_WS2812_INTR_DONE) != 0U) {
|
||||
reg_ws2812_intr_state = RS_WS2812_INTR_DONE;
|
||||
return RS_OK;
|
||||
}
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_abort(rs_timeout_t timeout) {
|
||||
if ((reg_ws2812_status & RS_WS2812_STATUS_BUSY) == 0U) {
|
||||
return RS_OK;
|
||||
}
|
||||
reg_ws2812_ctrl = RS_WS2812_CTRL_ABORT;
|
||||
while (timeout-- != 0U) {
|
||||
if ((reg_ws2812_status & RS_WS2812_STATUS_BUSY) == 0U) {
|
||||
reg_ws2812_intr_state = RS_WS2812_INTR_ABORTED;
|
||||
return RS_OK;
|
||||
}
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_irq_enable(uint32_t mask) {
|
||||
if ((mask & ~RS_WS2812_INTR_ALL) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
reg_ws2812_intr_enable = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_irq_ack(uint32_t mask) {
|
||||
if ((mask & ~RS_WS2812_INTR_ALL) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
reg_ws2812_intr_state = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_write(const uint32_t *pixels, size_t pixel_count, rs_timeout_t timeout) {
|
||||
size_t preloaded;
|
||||
rs_status_t status;
|
||||
|
||||
status = rs_ws2812_prepare(pixels, pixel_count, &preloaded);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
status = rs_ws2812_start((uint32_t)pixel_count);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
for (size_t index = preloaded; index < pixel_count; ++index) {
|
||||
status = rs_ws2812_push(pixels[index], timeout);
|
||||
if (status != RS_OK) {
|
||||
(void)rs_ws2812_abort(timeout);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return rs_ws2812_wait(timeout);
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_write_dma(const uint32_t *pixels, size_t pixel_count, rs_timeout_t timeout) {
|
||||
size_t preloaded;
|
||||
size_t dma_words;
|
||||
rs_status_t status;
|
||||
|
||||
status = rs_ws2812_prepare(pixels, pixel_count, &preloaded);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
dma_words = pixel_count - preloaded;
|
||||
if (dma_words != 0U) {
|
||||
status = rs_dma_config(RS_WS2812_DMA_SOFTWARE_MODE, (uintptr_t)&pixels[preloaded], 1U,
|
||||
(uintptr_t)®_ws2812_txdata, 0U, (uint32_t)dma_words);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
status = rs_ws2812_start((uint32_t)pixel_count);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
if (dma_words != 0U) {
|
||||
status = rs_dma_start();
|
||||
if (status == RS_OK) {
|
||||
status = rs_dma_wait(timeout);
|
||||
}
|
||||
if (status != RS_OK) {
|
||||
(void)rs_ws2812_abort(timeout);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return rs_ws2812_wait(timeout);
|
||||
}
|
||||
|
||||
void ip_ws2812_test(int argc, char **argv) {
|
||||
const rs_ws2812_config_t config = {
|
||||
CPU_FREQ * UINT32_C(1000000), RS_WS2812_DEFAULT_BIT_PERIOD_NS, RS_WS2812_DEFAULT_T0H_NS,
|
||||
RS_WS2812_DEFAULT_T1H_NS, RS_WS2812_DEFAULT_RESET_NS, 4U,
|
||||
};
|
||||
const uint32_t pixels[] = {
|
||||
rs_ws2812_pack_grb(0x20U, 0x00U, 0x00U),
|
||||
rs_ws2812_pack_grb(0x00U, 0x20U, 0x00U),
|
||||
rs_ws2812_pack_grb(0x00U, 0x00U, 0x20U),
|
||||
rs_ws2812_pack_grb(0x10U, 0x10U, 0x10U),
|
||||
};
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
printf("ws2812 test\n");
|
||||
reg_gpio_user_sel &= ~RS_WS2812_GPIO_MASK;
|
||||
reg_gpio_pinmux |= RS_WS2812_GPIO_MASK;
|
||||
reg_gpio_iofcfg |= RS_WS2812_GPIO_MASK;
|
||||
if ((rs_ws2812_init(&config) != RS_OK) ||
|
||||
(rs_ws2812_write(pixels, sizeof(pixels) / sizeof(pixels[0]), RS_TIMEOUT_DEFAULT) !=
|
||||
RS_OK)) {
|
||||
printf("ws2812 transfer failed\n");
|
||||
return;
|
||||
}
|
||||
printf("ws2812 test passed\n");
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/hal/ws2812.h>
|
||||
|
||||
#define RS_NANOSECONDS_PER_SECOND UINT64_C(1000000000)
|
||||
|
||||
static rs_status_t rs_ws2812_cycles_nearest(uint32_t frequency_hz, uint32_t duration_ns,
|
||||
uint32_t maximum, uint32_t *cycles) {
|
||||
uint64_t product;
|
||||
uint64_t rounded;
|
||||
|
||||
if ((frequency_hz == 0U) || (duration_ns == 0U) || (cycles == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
product = (uint64_t)frequency_hz * (uint64_t)duration_ns;
|
||||
if (product > (UINT64_MAX - (RS_NANOSECONDS_PER_SECOND / 2U))) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
rounded = (product + (RS_NANOSECONDS_PER_SECOND / 2U)) / RS_NANOSECONDS_PER_SECOND;
|
||||
if ((rounded == 0U) || (rounded > maximum)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*cycles = (uint32_t)rounded;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static rs_status_t rs_ws2812_cycles_ceil(uint32_t frequency_hz, uint32_t duration_ns,
|
||||
uint32_t *cycles) {
|
||||
uint64_t product;
|
||||
uint64_t rounded;
|
||||
|
||||
if ((frequency_hz == 0U) || (duration_ns == 0U) || (cycles == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
product = (uint64_t)frequency_hz * (uint64_t)duration_ns;
|
||||
if (product > (UINT64_MAX - (RS_NANOSECONDS_PER_SECOND - 1U))) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
rounded = (product + (RS_NANOSECONDS_PER_SECOND - 1U)) / RS_NANOSECONDS_PER_SECOND;
|
||||
if ((rounded == 0U) || (rounded > UINT32_MAX)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*cycles = (uint32_t)rounded;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
uint32_t rs_ws2812_pack_grb(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
return ((uint32_t)green << 16U) | ((uint32_t)red << 8U) | (uint32_t)blue;
|
||||
}
|
||||
|
||||
rs_status_t rs_ws2812_timing_from_ns(const rs_ws2812_config_t *config, rs_ws2812_timing_t *timing) {
|
||||
uint32_t bit_cycles;
|
||||
uint32_t t0h_cycles;
|
||||
uint32_t t1h_cycles;
|
||||
uint32_t reset_cycles;
|
||||
|
||||
if ((config == NULL) || (timing == NULL) ||
|
||||
(rs_ws2812_cycles_nearest(config->source_clock_hz, config->bit_period_ns, UINT16_MAX,
|
||||
&bit_cycles) != RS_OK) ||
|
||||
(rs_ws2812_cycles_nearest(config->source_clock_hz, config->t0h_ns, UINT16_MAX,
|
||||
&t0h_cycles) != RS_OK) ||
|
||||
(rs_ws2812_cycles_nearest(config->source_clock_hz, config->t1h_ns, UINT16_MAX,
|
||||
&t1h_cycles) != RS_OK) ||
|
||||
(rs_ws2812_cycles_ceil(config->source_clock_hz, config->reset_ns, &reset_cycles) !=
|
||||
RS_OK) ||
|
||||
(t0h_cycles >= t1h_cycles) || (t1h_cycles >= bit_cycles)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
|
||||
timing->bit_cycles = (uint16_t)bit_cycles;
|
||||
timing->t0h_cycles = (uint16_t)t0h_cycles;
|
||||
timing->t1h_cycles = (uint16_t)t1h_cycles;
|
||||
timing->reset_cycles = reset_cycles;
|
||||
return RS_OK;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ void rs_app_info(void) {
|
||||
printf(" 1 x SPISD @%p\n", (void *)®_spisd_mode);
|
||||
printf(" 1 x I2C0 @%p\n", (void *)®_i2c0_clkdiv);
|
||||
printf(" 1 x I2S @%p\n", (void *)®_i2s_mode);
|
||||
printf(" 1 x ONEWIRE @%p\n", (void *)®_onewire_clkdiv);
|
||||
printf(" 1 x WS2812 @%p\n", (void *)®_ws2812_bit_cycles);
|
||||
printf(" 1 x XPI @%p\n", (void *)®_xpi_cfgidx);
|
||||
printf(" 1 x DMA @%p\n", (void *)®_dma_mode);
|
||||
printf(" 1 x SYSCTRL @%p\n", (void *)®_sysctrl_coresel);
|
||||
|
||||
@@ -23,6 +23,8 @@ the root README and subsystem guides.
|
||||
and its commercial reference points.
|
||||
- [rib-interconnect.md](rib-interconnect.md) defines the RIB v1 linear-burst
|
||||
contract, compatibility boundaries, target status, and verification.
|
||||
- [ws2812.md](ws2812.md) defines the WS2812 transmitter register ABI,
|
||||
timing, FIFO, interrupt, DMA, and integration contracts.
|
||||
- [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated
|
||||
pin-map workflow and SoC integration boundary.
|
||||
- [mini-soc-block-diagram.svg](mini-soc-block-diagram.svg) is the Mini SoC
|
||||
|
||||
+8
-5
@@ -130,14 +130,17 @@ Verilator regressions.
|
||||
|
||||
`make CONFIG=configs/ci/ihp130.mk formal` proves selected
|
||||
protocol invariants with SymbiYosys, Yosys, `sv2v`, and Bitwuzla. The current
|
||||
targets are `bus`, `rib_adapter`, `rib2apb`, `sysctrl`, `pll_rcu`, and
|
||||
`gpio_user`; each uses
|
||||
the SBY `prove` task for bounded model checking and k-induction, plus a
|
||||
`cover` task, at depth 20. `sysctrl` checks register side effects, sticky terminal-test status, PLL request
|
||||
targets are `bus`, `rib_adapter`, `rib2apb`, `sysctrl`, `pll_rcu`,
|
||||
`gpio_user`, and `ws2812`; each uses the SBY `prove` task for bounded model
|
||||
checking and k-induction, plus a `cover` task. The default depth is 20;
|
||||
`ws2812` uses depth 120 and a 120-second per-task limit to cover a complete
|
||||
serialized word and reset path. `sysctrl` checks register side effects, sticky terminal-test status, PLL request
|
||||
handling, and fault reporting. `pll_rcu` checks the clock-switch controller
|
||||
state machine. `gpio_user` checks fixed user-GPIO ownership, lock, handoff,
|
||||
and mux safety. `rib_adapter` checks both single-word compatibility adapters
|
||||
under backpressure. Direct Common utility proofs, including `spill_register`,
|
||||
under backpressure. `ws2812` checks RIBP response stability, FIFO bounds,
|
||||
waveform idle safety, sticky error and interrupt propagation, abort, and
|
||||
underflow preconditions. Direct Common utility proofs, including `spill_register`,
|
||||
are maintained in the Common repository.
|
||||
`FORMAL_DEPTH` and `FORMAL_TIMEOUT` set the proof bound and per-task
|
||||
wall-clock limit. Use `make CONFIG=<profile> formal-doctor` before a local
|
||||
|
||||
@@ -43,7 +43,7 @@ digraph mini_soc_block_diagram {
|
||||
];
|
||||
ext_io [
|
||||
fillcolor="#F3F4F6",
|
||||
label="External I/O and memory\nGPIO, UART0, XPI Flash, SDRAM, PSRAM\nSD card, I2C, I2S, DVP and serial I/O"
|
||||
label="External I/O and memory\nGPIO, UART0, XPI Flash, SDRAM, PSRAM\nSD card, I2C, I2S, DVP and WS2812"
|
||||
];
|
||||
ext_jtag [
|
||||
fillcolor="#F3F4F6",
|
||||
@@ -124,7 +124,11 @@ digraph mini_soc_block_diagram {
|
||||
];
|
||||
ribp_targets [
|
||||
fillcolor="#F9E1E7",
|
||||
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD, DVP\nGPIO, UART0, timers, I2C, I2S and 1-Wire"
|
||||
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nGPIO, UART0, timers, I2C and I2S"
|
||||
];
|
||||
ws2812 [
|
||||
fillcolor="#F9E1E7",
|
||||
label="WS2812 TX\n24-bit MSB-first serializer\n16-word FIFO, IRQ17, DMA-fed"
|
||||
];
|
||||
apb_targets [
|
||||
fillcolor="#E6F4EA",
|
||||
@@ -145,7 +149,7 @@ digraph mini_soc_block_diagram {
|
||||
{ rank=same; user_core; dma; }
|
||||
{ rank=same; fault; fabric; sram; }
|
||||
{ rank=same; ribp_adapter; apb_adapter; }
|
||||
{ rank=same; sysctrl; ribp_targets; apb_targets; }
|
||||
{ rank=same; sysctrl; ribp_targets; ws2812; apb_targets; }
|
||||
{ rank=same; gpio_bridge; irq; }
|
||||
|
||||
ext_clock -> rcu [label="clock / reset"];
|
||||
@@ -167,9 +171,13 @@ digraph mini_soc_block_diagram {
|
||||
fabric -> apb_adapter [label="RIB"];
|
||||
ribp_adapter -> sysctrl [label="RIBP"];
|
||||
ribp_adapter -> ribp_targets [label="RIBP"];
|
||||
ribp_adapter -> ws2812 [label="RIBP"];
|
||||
apb_adapter -> apb_targets [label="APB"];
|
||||
|
||||
ribp_targets -> gpio_bridge [label="GPIO alternate functions"];
|
||||
ws2812 -> gpio_bridge [label="GPIO2 ALT1"];
|
||||
dma -> ws2812 [label="TXDATA writes", style=dashed];
|
||||
ws2812 -> irq [label="IRQ17"];
|
||||
apb_targets -> gpio_bridge [label="user_gpio"];
|
||||
ribp_targets -> ext_io [dir=both, label="device interfaces"];
|
||||
gpio_bridge -> ext_io [dir=both, label="pad control"];
|
||||
|
||||
+176
-140
@@ -4,19 +4,19 @@
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: mini_soc_block_diagram Pages: 1 -->
|
||||
<svg width="1203pt" height="887pt"
|
||||
viewBox="0.00 0.00 1203.00 887.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="1315pt" height="887pt"
|
||||
viewBox="0.00 0.00 1315.00 887.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 883.48)">
|
||||
<title>mini_soc_block_diagram</title>
|
||||
<text text-anchor="middle" x="132" y="-861.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_asic</title>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 1175,-85 1175,-85 1181,-85 1187,-91 1187,-97 1187,-97 1187,-763.48 1187,-763.48 1187,-769.48 1181,-775.48 1175,-775.48 1175,-775.48 160,-775.48 160,-775.48 154,-775.48 148,-769.48 148,-763.48 148,-763.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 1287,-85 1287,-85 1293,-85 1299,-91 1299,-97 1299,-97 1299,-763.48 1299,-763.48 1299,-769.48 1293,-775.48 1287,-775.48 1287,-775.48 160,-775.48 160,-775.48 154,-775.48 148,-769.48 148,-763.48 148,-763.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<text text-anchor="middle" x="196.5" y="-760.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_soc</title>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 1157,-103 1157,-103 1163,-103 1169,-109 1169,-115 1169,-115 1169,-720.48 1169,-720.48 1169,-726.48 1163,-732.48 1157,-732.48 1157,-732.48 390,-732.48 390,-732.48 384,-732.48 378,-726.48 378,-720.48 378,-720.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 1269,-103 1269,-103 1275,-103 1281,-109 1281,-115 1281,-115 1281,-720.48 1281,-720.48 1281,-726.48 1275,-732.48 1269,-732.48 1269,-732.48 390,-732.48 390,-732.48 384,-732.48 378,-726.48 378,-720.48 378,-720.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<text text-anchor="middle" x="407.5" y="-718.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
|
||||
</g>
|
||||
<!-- ext_clock -->
|
||||
@@ -44,277 +44,313 @@
|
||||
<!-- ext_io -->
|
||||
<g id="node2" class="node">
|
||||
<title>ext_io</title>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M997,-45C997,-45 805,-45 805,-45 799,-45 793,-39 793,-33 793,-33 793,-12 793,-12 793,-6 799,0 805,0 805,0 997,0 997,0 1003,0 1009,-6 1009,-12 1009,-12 1009,-33 1009,-33 1009,-39 1003,-45 997,-45"/>
|
||||
<text text-anchor="middle" x="901" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
|
||||
<text text-anchor="middle" x="901" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
|
||||
<text text-anchor="middle" x="901" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and serial I/O</text>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M903,-45C903,-45 711,-45 711,-45 705,-45 699,-39 699,-33 699,-33 699,-12 699,-12 699,-6 705,0 711,0 711,0 903,0 903,0 909,0 915,-6 915,-12 915,-12 915,-33 915,-33 915,-39 909,-45 903,-45"/>
|
||||
<text text-anchor="middle" x="807" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
|
||||
<text text-anchor="middle" x="807" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
|
||||
<text text-anchor="middle" x="807" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
|
||||
</g>
|
||||
<!-- ext_jtag -->
|
||||
<g id="node3" class="node">
|
||||
<title>ext_jtag</title>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M546.5,-851.48C546.5,-851.48 415.5,-851.48 415.5,-851.48 409.5,-851.48 403.5,-845.48 403.5,-839.48 403.5,-839.48 403.5,-827.48 403.5,-827.48 403.5,-821.48 409.5,-815.48 415.5,-815.48 415.5,-815.48 546.5,-815.48 546.5,-815.48 552.5,-815.48 558.5,-821.48 558.5,-827.48 558.5,-827.48 558.5,-839.48 558.5,-839.48 558.5,-845.48 552.5,-851.48 546.5,-851.48"/>
|
||||
<text text-anchor="middle" x="481" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
|
||||
<text text-anchor="middle" x="481" y="-825.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M569.5,-851.48C569.5,-851.48 438.5,-851.48 438.5,-851.48 432.5,-851.48 426.5,-845.48 426.5,-839.48 426.5,-839.48 426.5,-827.48 426.5,-827.48 426.5,-821.48 432.5,-815.48 438.5,-815.48 438.5,-815.48 569.5,-815.48 569.5,-815.48 575.5,-815.48 581.5,-821.48 581.5,-827.48 581.5,-827.48 581.5,-839.48 581.5,-839.48 581.5,-845.48 575.5,-851.48 569.5,-851.48"/>
|
||||
<text text-anchor="middle" x="504" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
|
||||
<text text-anchor="middle" x="504" y="-825.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text>
|
||||
</g>
|
||||
<!-- jtag_dtm -->
|
||||
<g id="node6" class="node">
|
||||
<title>jtag_dtm</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M556,-669.98C556,-669.98 406,-669.98 406,-669.98 400,-669.98 394,-663.98 394,-657.98 394,-657.98 394,-645.98 394,-645.98 394,-639.98 400,-633.98 406,-633.98 406,-633.98 556,-633.98 556,-633.98 562,-633.98 568,-639.98 568,-645.98 568,-645.98 568,-657.98 568,-657.98 568,-663.98 562,-669.98 556,-669.98"/>
|
||||
<text text-anchor="middle" x="481" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
|
||||
<text text-anchor="middle" x="481" y="-643.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M579,-669.98C579,-669.98 429,-669.98 429,-669.98 423,-669.98 417,-663.98 417,-657.98 417,-657.98 417,-645.98 417,-645.98 417,-639.98 423,-633.98 429,-633.98 429,-633.98 579,-633.98 579,-633.98 585,-633.98 591,-639.98 591,-645.98 591,-645.98 591,-657.98 591,-657.98 591,-663.98 585,-669.98 579,-669.98"/>
|
||||
<text text-anchor="middle" x="504" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
|
||||
<text text-anchor="middle" x="504" y="-643.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
|
||||
</g>
|
||||
<!-- ext_jtag->jtag_dtm -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>ext_jtag->jtag_dtm</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M481,-815.27C481,-783.24 481,-714.39 481,-677.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="483.45,-677.14 481,-670.14 478.55,-677.14 483.45,-677.14"/>
|
||||
<text text-anchor="middle" x="501" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M504,-815.27C504,-783.24 504,-714.39 504,-677.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="506.45,-677.14 504,-670.14 501.55,-677.14 506.45,-677.14"/>
|
||||
<text text-anchor="middle" x="524" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
|
||||
</g>
|
||||
<!-- fabric -->
|
||||
<g id="node11" class="node">
|
||||
<title>fabric</title>
|
||||
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M774.66,-442.31C774.66,-442.31 706.98,-470.16 706.98,-470.16 701.43,-472.45 689.88,-474.73 683.88,-474.73 683.88,-474.73 528.12,-474.73 528.12,-474.73 522.12,-474.73 510.57,-472.45 505.02,-470.16 505.02,-470.16 437.34,-442.31 437.34,-442.31 431.79,-440.03 431.79,-435.46 437.34,-433.18 437.34,-433.18 505.02,-405.32 505.02,-405.32 510.57,-403.04 522.12,-400.76 528.12,-400.76 528.12,-400.76 683.88,-400.76 683.88,-400.76 689.88,-400.76 701.43,-403.04 706.98,-405.32 706.98,-405.32 774.66,-433.18 774.66,-433.18 780.21,-435.46 780.21,-440.03 774.66,-442.31"/>
|
||||
<text text-anchor="middle" x="606" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
|
||||
<text text-anchor="middle" x="606" y="-435.24" font-family="Arial" font-size="10.00" fill="#111827">3-master round-robin arbitration</text>
|
||||
<text text-anchor="middle" x="606" y="-424.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
|
||||
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M853.66,-442.31C853.66,-442.31 785.98,-470.16 785.98,-470.16 780.43,-472.45 768.88,-474.73 762.88,-474.73 762.88,-474.73 607.12,-474.73 607.12,-474.73 601.12,-474.73 589.57,-472.45 584.02,-470.16 584.02,-470.16 516.34,-442.31 516.34,-442.31 510.79,-440.03 510.79,-435.46 516.34,-433.18 516.34,-433.18 584.02,-405.32 584.02,-405.32 589.57,-403.04 601.12,-400.76 607.12,-400.76 607.12,-400.76 762.88,-400.76 762.88,-400.76 768.88,-400.76 780.43,-403.04 785.98,-405.32 785.98,-405.32 853.66,-433.18 853.66,-433.18 859.21,-435.46 859.21,-440.03 853.66,-442.31"/>
|
||||
<text text-anchor="middle" x="685" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
|
||||
<text text-anchor="middle" x="685" y="-435.24" font-family="Arial" font-size="10.00" fill="#111827">3-master round-robin arbitration</text>
|
||||
<text text-anchor="middle" x="685" y="-424.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
|
||||
</g>
|
||||
<!-- rcu->fabric -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>rcu->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M329.54,-529.48C377.9,-513.6 444.73,-491.67 500.57,-473.34"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="501.44,-475.64 507.33,-471.13 499.91,-470.98 501.44,-475.64"/>
|
||||
<text text-anchor="middle" x="459" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M344.67,-529.48C408.63,-512.43 498.81,-488.38 570.28,-469.33"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="571,-471.67 577.13,-467.5 569.74,-466.94 571,-471.67"/>
|
||||
<text text-anchor="middle" x="496" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
|
||||
</g>
|
||||
<!-- mgmt_core -->
|
||||
<g id="node5" class="node">
|
||||
<title>mgmt_core</title>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1141,-674.48C1141,-674.48 987,-674.48 987,-674.48 981,-674.48 975,-668.48 975,-662.48 975,-662.48 975,-641.48 975,-641.48 975,-635.48 981,-629.48 987,-629.48 987,-629.48 1141,-629.48 1141,-629.48 1147,-629.48 1153,-635.48 1153,-641.48 1153,-641.48 1153,-662.48 1153,-662.48 1153,-668.48 1147,-674.48 1141,-674.48"/>
|
||||
<text text-anchor="middle" x="1064" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
|
||||
<text text-anchor="middle" x="1064" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
|
||||
<text text-anchor="middle" x="1064" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1164,-674.48C1164,-674.48 1010,-674.48 1010,-674.48 1004,-674.48 998,-668.48 998,-662.48 998,-662.48 998,-641.48 998,-641.48 998,-635.48 1004,-629.48 1010,-629.48 1010,-629.48 1164,-629.48 1164,-629.48 1170,-629.48 1176,-635.48 1176,-641.48 1176,-641.48 1176,-662.48 1176,-662.48 1176,-668.48 1170,-674.48 1164,-674.48"/>
|
||||
<text text-anchor="middle" x="1087" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
|
||||
<text text-anchor="middle" x="1087" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
|
||||
<text text-anchor="middle" x="1087" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
|
||||
</g>
|
||||
<!-- mgmt_adapter -->
|
||||
<g id="node8" class="node">
|
||||
<title>mgmt_adapter</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M777.5,-569.98C777.5,-569.98 736.5,-569.98 736.5,-569.98 730.5,-569.98 724.5,-563.98 724.5,-557.98 724.5,-557.98 724.5,-545.98 724.5,-545.98 724.5,-539.98 730.5,-533.98 736.5,-533.98 736.5,-533.98 777.5,-533.98 777.5,-533.98 783.5,-533.98 789.5,-539.98 789.5,-545.98 789.5,-545.98 789.5,-557.98 789.5,-557.98 789.5,-563.98 783.5,-569.98 777.5,-569.98"/>
|
||||
<text text-anchor="middle" x="757" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M809.5,-569.98C809.5,-569.98 768.5,-569.98 768.5,-569.98 762.5,-569.98 756.5,-563.98 756.5,-557.98 756.5,-557.98 756.5,-545.98 756.5,-545.98 756.5,-539.98 762.5,-533.98 768.5,-533.98 768.5,-533.98 809.5,-533.98 809.5,-533.98 815.5,-533.98 821.5,-539.98 821.5,-545.98 821.5,-545.98 821.5,-557.98 821.5,-557.98 821.5,-563.98 815.5,-569.98 809.5,-569.98"/>
|
||||
<text text-anchor="middle" x="789" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
|
||||
</g>
|
||||
<!-- mgmt_core->mgmt_adapter -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>mgmt_core->mgmt_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M996.63,-629.48C935.43,-609.94 847.24,-581.79 796.67,-565.65"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="797.21,-563.25 789.79,-563.45 795.72,-567.92 797.21,-563.25"/>
|
||||
<text text-anchor="middle" x="928.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1021.6,-629.48C962.53,-610.05 877.54,-582.1 828.32,-565.92"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="829.04,-563.57 821.62,-563.71 827.51,-568.23 829.04,-563.57"/>
|
||||
<text text-anchor="middle" x="955.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- debug_module -->
|
||||
<g id="node7" class="node">
|
||||
<title>debug_module</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M817.5,-674.48C817.5,-674.48 696.5,-674.48 696.5,-674.48 690.5,-674.48 684.5,-668.48 684.5,-662.48 684.5,-662.48 684.5,-641.48 684.5,-641.48 684.5,-635.48 690.5,-629.48 696.5,-629.48 696.5,-629.48 817.5,-629.48 817.5,-629.48 823.5,-629.48 829.5,-635.48 829.5,-641.48 829.5,-641.48 829.5,-662.48 829.5,-662.48 829.5,-668.48 823.5,-674.48 817.5,-674.48"/>
|
||||
<text text-anchor="middle" x="757" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
|
||||
<text text-anchor="middle" x="757" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
|
||||
<text text-anchor="middle" x="757" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">management-hart-only reset</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M840.5,-674.48C840.5,-674.48 719.5,-674.48 719.5,-674.48 713.5,-674.48 707.5,-668.48 707.5,-662.48 707.5,-662.48 707.5,-641.48 707.5,-641.48 707.5,-635.48 713.5,-629.48 719.5,-629.48 719.5,-629.48 840.5,-629.48 840.5,-629.48 846.5,-629.48 852.5,-635.48 852.5,-641.48 852.5,-641.48 852.5,-662.48 852.5,-662.48 852.5,-668.48 846.5,-674.48 840.5,-674.48"/>
|
||||
<text text-anchor="middle" x="780" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
|
||||
<text text-anchor="middle" x="780" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
|
||||
<text text-anchor="middle" x="780" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">management-hart-only reset</text>
|
||||
</g>
|
||||
<!-- jtag_dtm->debug_module -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>jtag_dtm->debug_module</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M568.33,-651.98C603.12,-651.98 642.91,-651.98 676.95,-651.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="677.12,-654.43 684.12,-651.98 677.12,-649.53 677.12,-654.43"/>
|
||||
<text text-anchor="middle" x="626.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M591.33,-651.98C626.12,-651.98 665.91,-651.98 699.95,-651.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="700.12,-654.43 707.12,-651.98 700.12,-649.53 700.12,-654.43"/>
|
||||
<text text-anchor="middle" x="649.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
|
||||
</g>
|
||||
<!-- debug_module->mgmt_core -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>debug_module->mgmt_core</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M829.75,-651.98C870.99,-651.98 923.09,-651.98 967.69,-651.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="967.77,-654.43 974.77,-651.98 967.77,-649.53 967.77,-654.43"/>
|
||||
<text text-anchor="middle" x="902.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M852.75,-651.98C893.99,-651.98 946.09,-651.98 990.69,-651.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="990.77,-654.43 997.77,-651.98 990.77,-649.53 990.77,-654.43"/>
|
||||
<text text-anchor="middle" x="925.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
|
||||
</g>
|
||||
<!-- debug_module->mgmt_adapter -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>debug_module->mgmt_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M757,-629.24C757,-613.92 757,-593.4 757,-577.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="759.45,-577.12 757,-570.12 754.55,-577.12 759.45,-577.12"/>
|
||||
<text text-anchor="middle" x="795" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M782,-629.24C783.4,-613.92 785.29,-593.4 786.75,-577.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="789.23,-577.31 787.43,-570.12 784.35,-576.86 789.23,-577.31"/>
|
||||
<text text-anchor="middle" x="822" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
|
||||
</g>
|
||||
<!-- mgmt_adapter->fabric -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>mgmt_adapter->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M734.07,-533.94C714.43,-519.34 685.38,-497.75 659.9,-478.81"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="661.27,-476.77 654.19,-474.57 658.35,-480.71 661.27,-476.77"/>
|
||||
<text text-anchor="middle" x="702" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M773.2,-533.94C759.91,-519.59 740.34,-498.47 723.01,-479.77"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="724.75,-478.03 718.19,-474.57 721.15,-481.37 724.75,-478.03"/>
|
||||
<text text-anchor="middle" x="753" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- user_core -->
|
||||
<g id="node9" class="node">
|
||||
<title>user_core</title>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M680,-574.48C680,-574.48 604,-574.48 604,-574.48 598,-574.48 592,-568.48 592,-562.48 592,-562.48 592,-541.48 592,-541.48 592,-535.48 598,-529.48 604,-529.48 604,-529.48 680,-529.48 680,-529.48 686,-529.48 692,-535.48 692,-541.48 692,-541.48 692,-562.48 692,-562.48 692,-568.48 686,-574.48 680,-574.48"/>
|
||||
<text text-anchor="middle" x="642" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
|
||||
<text text-anchor="middle" x="642" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0-C5, one active</text>
|
||||
<text text-anchor="middle" x="642" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M717,-574.48C717,-574.48 641,-574.48 641,-574.48 635,-574.48 629,-568.48 629,-562.48 629,-562.48 629,-541.48 629,-541.48 629,-535.48 635,-529.48 641,-529.48 641,-529.48 717,-529.48 717,-529.48 723,-529.48 729,-535.48 729,-541.48 729,-541.48 729,-562.48 729,-562.48 729,-568.48 723,-574.48 717,-574.48"/>
|
||||
<text text-anchor="middle" x="679" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
|
||||
<text text-anchor="middle" x="679" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0-C5, one active</text>
|
||||
<text text-anchor="middle" x="679" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
|
||||
</g>
|
||||
<!-- user_core->fabric -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>user_core->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M635.06,-529.34C630.73,-515.85 625.01,-498.03 619.8,-481.75"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="622.07,-480.81 617.59,-474.89 617.4,-482.31 622.07,-480.81"/>
|
||||
<text text-anchor="middle" x="634" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M680.16,-529.34C680.87,-515.97 681.81,-498.34 682.68,-482.19"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="685.14,-482.01 683.07,-474.89 680.25,-481.75 685.14,-482.01"/>
|
||||
<text text-anchor="middle" x="688" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- dma -->
|
||||
<g id="node10" class="node">
|
||||
<title>dma</title>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M553,-569.98C553,-569.98 435,-569.98 435,-569.98 429,-569.98 423,-563.98 423,-557.98 423,-557.98 423,-545.98 423,-545.98 423,-539.98 429,-533.98 435,-533.98 435,-533.98 553,-533.98 553,-533.98 559,-533.98 565,-539.98 565,-545.98 565,-545.98 565,-557.98 565,-557.98 565,-563.98 559,-569.98 553,-569.98"/>
|
||||
<text text-anchor="middle" x="494" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
|
||||
<text text-anchor="middle" x="494" y="-543.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M570,-569.98C570,-569.98 452,-569.98 452,-569.98 446,-569.98 440,-563.98 440,-557.98 440,-557.98 440,-545.98 440,-545.98 440,-539.98 446,-533.98 452,-533.98 452,-533.98 570,-533.98 570,-533.98 576,-533.98 582,-539.98 582,-545.98 582,-545.98 582,-557.98 582,-557.98 582,-563.98 576,-569.98 570,-569.98"/>
|
||||
<text text-anchor="middle" x="511" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
|
||||
<text text-anchor="middle" x="511" y="-543.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
|
||||
</g>
|
||||
<!-- dma->fabric -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>dma->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M511.01,-533.94C525.33,-519.59 546.4,-498.47 565.06,-479.77"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="567.04,-481.25 570.25,-474.57 563.58,-477.79 567.04,-481.25"/>
|
||||
<text text-anchor="middle" x="553" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M537.43,-533.94C560.15,-519.28 593.81,-497.56 623.25,-478.57"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="624.91,-480.42 629.47,-474.57 622.26,-476.3 624.91,-480.42"/>
|
||||
<text text-anchor="middle" x="599" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- ws2812 -->
|
||||
<g id="node18" class="node">
|
||||
<title>ws2812</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M540,-255C540,-255 406,-255 406,-255 400,-255 394,-249 394,-243 394,-243 394,-222 394,-222 394,-216 400,-210 406,-210 406,-210 540,-210 540,-210 546,-210 552,-216 552,-222 552,-222 552,-243 552,-243 552,-249 546,-255 540,-255"/>
|
||||
<text text-anchor="middle" x="473" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
|
||||
<text text-anchor="middle" x="473" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24-bit MSB-first serializer</text>
|
||||
<text text-anchor="middle" x="473" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16-word FIFO, IRQ17, DMA-fed</text>
|
||||
</g>
|
||||
<!-- dma->ws2812 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>dma->ws2812</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M506.69,-533.63C501.08,-511.05 492,-474.48 492,-474.48 492,-474.48 480.31,-326.28 475.27,-262.32"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="477.71,-262.1 474.72,-255.31 472.83,-262.48 477.71,-262.1"/>
|
||||
<text text-anchor="middle" x="511.5" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
|
||||
</g>
|
||||
<!-- fault -->
|
||||
<g id="node12" class="node">
|
||||
<title>fault</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1109.5,-455.74C1109.5,-455.74 1000.5,-455.74 1000.5,-455.74 994.5,-455.74 988.5,-449.74 988.5,-443.74 988.5,-443.74 988.5,-431.74 988.5,-431.74 988.5,-425.74 994.5,-419.74 1000.5,-419.74 1000.5,-419.74 1109.5,-419.74 1109.5,-419.74 1115.5,-419.74 1121.5,-425.74 1121.5,-431.74 1121.5,-431.74 1121.5,-443.74 1121.5,-443.74 1121.5,-449.74 1115.5,-455.74 1109.5,-455.74"/>
|
||||
<text text-anchor="middle" x="1055" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
|
||||
<text text-anchor="middle" x="1055" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1065.5,-455.74C1065.5,-455.74 956.5,-455.74 956.5,-455.74 950.5,-455.74 944.5,-449.74 944.5,-443.74 944.5,-443.74 944.5,-431.74 944.5,-431.74 944.5,-425.74 950.5,-419.74 956.5,-419.74 956.5,-419.74 1065.5,-419.74 1065.5,-419.74 1071.5,-419.74 1077.5,-425.74 1077.5,-431.74 1077.5,-431.74 1077.5,-443.74 1077.5,-443.74 1077.5,-449.74 1071.5,-455.74 1065.5,-455.74"/>
|
||||
<text text-anchor="middle" x="1011" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
|
||||
<text text-anchor="middle" x="1011" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
|
||||
</g>
|
||||
<!-- fabric->fault -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>fabric->fault</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M728.45,-466.01C793.63,-481.05 860.5,-496.48 860.5,-496.48 860.5,-496.48 913.5,-496.48 913.5,-496.48 913.5,-496.48 975,-474.48 975,-474.48 975,-474.48 991.11,-467.08 1008.88,-458.93"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="728.71,-463.55 721.34,-464.36 727.61,-468.33 728.71,-463.55"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1010.13,-461.05 1015.47,-455.9 1008.08,-456.59 1010.13,-461.05"/>
|
||||
<text text-anchor="middle" x="887" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M871.98,-437.74C894.93,-437.74 917.24,-437.74 937.02,-437.74"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="871.69,-435.29 864.69,-437.74 871.69,-440.19 871.69,-435.29"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="937.19,-440.19 944.19,-437.74 937.19,-435.29 937.19,-440.19"/>
|
||||
<text text-anchor="middle" x="904.56" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
|
||||
</g>
|
||||
<!-- sram -->
|
||||
<g id="node13" class="node">
|
||||
<title>sram</title>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M949,-455.74C949,-455.74 851,-455.74 851,-455.74 845,-455.74 839,-449.74 839,-443.74 839,-443.74 839,-431.74 839,-431.74 839,-425.74 845,-419.74 851,-419.74 851,-419.74 949,-419.74 949,-419.74 955,-419.74 961,-425.74 961,-431.74 961,-431.74 961,-443.74 961,-443.74 961,-449.74 955,-455.74 949,-455.74"/>
|
||||
<text text-anchor="middle" x="900" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On-chip SRAM</text>
|
||||
<text text-anchor="middle" x="900" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1215,-455.74C1215,-455.74 1117,-455.74 1117,-455.74 1111,-455.74 1105,-449.74 1105,-443.74 1105,-443.74 1105,-431.74 1105,-431.74 1105,-425.74 1111,-419.74 1117,-419.74 1117,-419.74 1215,-419.74 1215,-419.74 1221,-419.74 1227,-425.74 1227,-431.74 1227,-431.74 1227,-443.74 1227,-443.74 1227,-449.74 1221,-455.74 1215,-455.74"/>
|
||||
<text text-anchor="middle" x="1166" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On-chip SRAM</text>
|
||||
<text text-anchor="middle" x="1166" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
|
||||
</g>
|
||||
<!-- fabric->sram -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>fabric->sram</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M785.91,-437.74C801.95,-437.74 817.44,-437.74 831.56,-437.74"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="831.81,-440.19 838.81,-437.74 831.81,-435.29 831.81,-440.19"/>
|
||||
<text text-anchor="middle" x="812.31" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M805.88,-462.06C886.21,-478.22 977,-496.48 977,-496.48 977,-496.48 991,-496.48 991,-496.48 991,-496.48 1091,-474.48 1091,-474.48 1091,-474.48 1105.84,-467.21 1122.32,-459.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1123.73,-461.18 1128.94,-455.9 1121.58,-456.78 1123.73,-461.18"/>
|
||||
<text text-anchor="middle" x="984" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- ribp_adapter -->
|
||||
<g id="node14" class="node">
|
||||
<title>ribp_adapter</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M764.5,-346C764.5,-346 723.5,-346 723.5,-346 717.5,-346 711.5,-340 711.5,-334 711.5,-334 711.5,-322 711.5,-322 711.5,-316 717.5,-310 723.5,-310 723.5,-310 764.5,-310 764.5,-310 770.5,-310 776.5,-316 776.5,-322 776.5,-322 776.5,-334 776.5,-334 776.5,-340 770.5,-346 764.5,-346"/>
|
||||
<text text-anchor="middle" x="744" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M708.5,-346C708.5,-346 667.5,-346 667.5,-346 661.5,-346 655.5,-340 655.5,-334 655.5,-334 655.5,-322 655.5,-322 655.5,-316 661.5,-310 667.5,-310 667.5,-310 708.5,-310 708.5,-310 714.5,-310 720.5,-316 720.5,-322 720.5,-322 720.5,-334 720.5,-334 720.5,-340 714.5,-346 708.5,-346"/>
|
||||
<text text-anchor="middle" x="688" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
|
||||
</g>
|
||||
<!-- fabric->ribp_adapter -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>fabric->ribp_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M651.95,-400.87C673.23,-384.26 697.8,-365.07 716.21,-350.7"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="718.19,-352.26 722.2,-346.02 715.17,-348.4 718.19,-352.26"/>
|
||||
<text text-anchor="middle" x="698" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M686,-400.87C686.43,-385.27 686.93,-367.39 687.32,-353.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="689.78,-353.09 687.53,-346.02 684.88,-352.95 689.78,-353.09"/>
|
||||
<text text-anchor="middle" x="693" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- apb_adapter -->
|
||||
<g id="node15" class="node">
|
||||
<title>apb_adapter</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M599,-346C599,-346 529,-346 529,-346 523,-346 517,-340 517,-334 517,-334 517,-322 517,-322 517,-316 523,-310 529,-310 529,-310 599,-310 599,-310 605,-310 611,-316 611,-322 611,-322 611,-334 611,-334 611,-340 605,-346 599,-346"/>
|
||||
<text text-anchor="middle" x="564" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
|
||||
<text text-anchor="middle" x="564" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M875,-346C875,-346 805,-346 805,-346 799,-346 793,-340 793,-334 793,-334 793,-322 793,-322 793,-316 799,-310 805,-310 805,-310 875,-310 875,-310 881,-310 887,-316 887,-322 887,-322 887,-334 887,-334 887,-340 881,-346 875,-346"/>
|
||||
<text text-anchor="middle" x="840" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
|
||||
<text text-anchor="middle" x="840" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
|
||||
</g>
|
||||
<!-- fabric->apb_adapter -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>fabric->apb_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M592.01,-400.87C585.82,-384.98 578.71,-366.73 573.2,-352.6"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="575.46,-351.65 570.64,-346.02 570.9,-353.43 575.46,-351.65"/>
|
||||
<text text-anchor="middle" x="589" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M736.61,-400.87C760.82,-384.04 788.83,-364.57 809.59,-350.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="811.16,-352.03 815.51,-346.02 808.37,-348.01 811.16,-352.03"/>
|
||||
<text text-anchor="middle" x="787" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- sysctrl -->
|
||||
<g id="node16" class="node">
|
||||
<title>sysctrl</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M825.5,-255C825.5,-255 662.5,-255 662.5,-255 656.5,-255 650.5,-249 650.5,-243 650.5,-243 650.5,-222 650.5,-222 650.5,-216 656.5,-210 662.5,-210 662.5,-210 825.5,-210 825.5,-210 831.5,-210 837.5,-216 837.5,-222 837.5,-222 837.5,-243 837.5,-243 837.5,-249 831.5,-255 825.5,-255"/>
|
||||
<text text-anchor="middle" x="744" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL and CLINT</text>
|
||||
<text text-anchor="middle" x="744" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user-core select/reset/bus enable</text>
|
||||
<text text-anchor="middle" x="744" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1010.5,-255C1010.5,-255 847.5,-255 847.5,-255 841.5,-255 835.5,-249 835.5,-243 835.5,-243 835.5,-222 835.5,-222 835.5,-216 841.5,-210 847.5,-210 847.5,-210 1010.5,-210 1010.5,-210 1016.5,-210 1022.5,-216 1022.5,-222 1022.5,-222 1022.5,-243 1022.5,-243 1022.5,-249 1016.5,-255 1010.5,-255"/>
|
||||
<text text-anchor="middle" x="929" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL and CLINT</text>
|
||||
<text text-anchor="middle" x="929" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user-core select/reset/bus enable</text>
|
||||
<text text-anchor="middle" x="929" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->sysctrl -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>ribp_adapter->sysctrl</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M744,-309.85C744,-296.62 744,-278.02 744,-262.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="746.45,-262.15 744,-255.15 741.55,-262.15 746.45,-262.15"/>
|
||||
<text text-anchor="middle" x="753.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M720.5,-314.39C757.85,-299.9 820,-275.79 866.75,-257.65"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="867.89,-259.84 873.53,-255.02 866.12,-255.27 867.89,-259.84"/>
|
||||
<text text-anchor="middle" x="817.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_targets -->
|
||||
<g id="node17" class="node">
|
||||
<title>ribp_targets</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1066,-255C1066,-255 876,-255 876,-255 870,-255 864,-249 864,-243 864,-243 864,-222 864,-222 864,-216 870,-210 876,-210 876,-210 1066,-210 1066,-210 1072,-210 1078,-216 1078,-222 1078,-222 1078,-243 1078,-243 1078,-249 1072,-255 1066,-255"/>
|
||||
<text text-anchor="middle" x="971" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
|
||||
<text text-anchor="middle" x="971" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI-SD, DVP</text>
|
||||
<text text-anchor="middle" x="971" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, timers, I2C, I2S and 1-Wire</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M796.5,-255C796.5,-255 591.5,-255 591.5,-255 585.5,-255 579.5,-249 579.5,-243 579.5,-243 579.5,-222 579.5,-222 579.5,-216 585.5,-210 591.5,-210 591.5,-210 796.5,-210 796.5,-210 802.5,-210 808.5,-216 808.5,-222 808.5,-222 808.5,-243 808.5,-243 808.5,-249 802.5,-255 796.5,-255"/>
|
||||
<text text-anchor="middle" x="694" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
|
||||
<text text-anchor="middle" x="694" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP</text>
|
||||
<text text-anchor="middle" x="694" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, timers, I2C and I2S</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->ribp_targets -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>ribp_adapter->ribp_targets</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M776.52,-313.6C811.74,-299.1 868.65,-275.66 911.84,-257.87"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="912.83,-260.11 918.37,-255.18 910.97,-255.58 912.83,-260.11"/>
|
||||
<text text-anchor="middle" x="866.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M689.1,-309.85C689.95,-296.62 691.14,-278.02 692.14,-262.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="694.61,-262.29 692.61,-255.15 689.72,-261.98 694.61,-262.29"/>
|
||||
<text text-anchor="middle" x="700.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->ws2812 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>ribp_adapter->ws2812</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M655.35,-312.8C622.03,-298.31 569.68,-275.54 529.6,-258.11"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="530.17,-255.69 522.77,-255.15 528.21,-260.18 530.17,-255.69"/>
|
||||
<text text-anchor="middle" x="602.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- apb_targets -->
|
||||
<g id="node18" class="node">
|
||||
<g id="node19" class="node">
|
||||
<title>apb_targets</title>
|
||||
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M611.5,-255C611.5,-255 420.5,-255 420.5,-255 414.5,-255 408.5,-249 408.5,-243 408.5,-243 408.5,-222 408.5,-222 408.5,-216 414.5,-210 420.5,-210 420.5,-210 611.5,-210 611.5,-210 617.5,-210 623.5,-216 623.5,-222 623.5,-222 623.5,-243 623.5,-243 623.5,-249 617.5,-255 611.5,-255"/>
|
||||
<text text-anchor="middle" x="516" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
|
||||
<text text-anchor="middle" x="516" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
|
||||
<text text-anchor="middle" x="516" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
|
||||
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M1252.5,-255C1252.5,-255 1061.5,-255 1061.5,-255 1055.5,-255 1049.5,-249 1049.5,-243 1049.5,-243 1049.5,-222 1049.5,-222 1049.5,-216 1055.5,-210 1061.5,-210 1061.5,-210 1252.5,-210 1252.5,-210 1258.5,-210 1264.5,-216 1264.5,-222 1264.5,-222 1264.5,-243 1264.5,-243 1264.5,-249 1258.5,-255 1252.5,-255"/>
|
||||
<text text-anchor="middle" x="1157" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
|
||||
<text text-anchor="middle" x="1157" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
|
||||
<text text-anchor="middle" x="1157" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
|
||||
</g>
|
||||
<!-- apb_adapter->apb_targets -->
|
||||
<g id="edge17" class="edge">
|
||||
<g id="edge18" class="edge">
|
||||
<title>apb_adapter->apb_targets</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M555.2,-309.85C548.28,-296.38 538.51,-277.34 530.45,-261.65"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="532.49,-260.26 527.11,-255.15 528.13,-262.5 532.49,-260.26"/>
|
||||
<text text-anchor="middle" x="550" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M887.12,-313.1C937.19,-298.33 1017.25,-274.72 1077.19,-257.04"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1078,-259.35 1084.02,-255.02 1076.62,-254.65 1078,-259.35"/>
|
||||
<text text-anchor="middle" x="1006" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
|
||||
</g>
|
||||
<!-- ribp_targets->ext_io -->
|
||||
<g id="edge20" class="edge">
|
||||
<g id="edge24" class="edge">
|
||||
<title>ribp_targets->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M963.24,-203.09C951.61,-160.49 931,-85 931,-85 931,-85 922.54,-67.66 914.6,-51.39"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="960.89,-203.78 965.1,-209.88 965.62,-202.49 960.89,-203.78"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="916.76,-50.23 911.49,-45.01 912.36,-52.38 916.76,-50.23"/>
|
||||
<text text-anchor="middle" x="979" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M780.98,-208.04C820.68,-197.33 859,-187 859,-187 859,-187 859,-178 859,-178 859,-178 837,-85 837,-85 837,-85 828.54,-67.66 820.6,-51.39"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="780.2,-205.71 774.08,-209.9 781.48,-210.44 780.2,-205.71"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="822.76,-50.23 817.49,-45.01 818.36,-52.38 822.76,-50.23"/>
|
||||
<text text-anchor="middle" x="883" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
|
||||
</g>
|
||||
<!-- gpio_bridge -->
|
||||
<g id="node19" class="node">
|
||||
<g id="node20" class="node">
|
||||
<title>gpio_bridge</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M905,-155C905,-155 757,-155 757,-155 751,-155 745,-149 745,-143 745,-143 745,-131 745,-131 745,-125 751,-119 757,-119 757,-119 905,-119 905,-119 911,-119 917,-125 917,-131 917,-131 917,-143 917,-143 917,-149 911,-155 905,-155"/>
|
||||
<text text-anchor="middle" x="831" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
|
||||
<text text-anchor="middle" x="831" y="-129" font-family="Arial" font-size="10.00" fill="#111827">software, alternate and user modes</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M811,-155C811,-155 663,-155 663,-155 657,-155 651,-149 651,-143 651,-143 651,-131 651,-131 651,-125 657,-119 663,-119 663,-119 811,-119 811,-119 817,-119 823,-125 823,-131 823,-131 823,-143 823,-143 823,-149 817,-155 811,-155"/>
|
||||
<text text-anchor="middle" x="737" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
|
||||
<text text-anchor="middle" x="737" y="-129" font-family="Arial" font-size="10.00" fill="#111827">software, alternate and user modes</text>
|
||||
</g>
|
||||
<!-- ribp_targets->gpio_bridge -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>ribp_targets->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M918.58,-209.9C891.06,-198.56 863,-187 863,-187 863,-187 854.45,-173.9 846.19,-161.25"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="848.07,-159.66 842.19,-155.14 843.97,-162.34 848.07,-159.66"/>
|
||||
<text text-anchor="middle" x="907" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text>
|
||||
</g>
|
||||
<!-- apb_targets->gpio_bridge -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>apb_targets->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M588.66,-209.93C642.48,-193.96 715.14,-172.39 766.82,-157.05"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="767.64,-159.36 773.65,-155.02 766.24,-154.67 767.64,-159.36"/>
|
||||
<text text-anchor="middle" x="710" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
|
||||
<title>ribp_targets->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M695.22,-209.74C696.05,-194.93 697,-178 697,-178 697,-178 705.52,-169.48 714.69,-160.31"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="716.59,-161.88 719.8,-155.2 713.12,-158.41 716.59,-161.88"/>
|
||||
<text text-anchor="middle" x="741" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text>
|
||||
</g>
|
||||
<!-- gpio_bridge->ext_io -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>gpio_bridge->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M845.43,-112.81C856.49,-95.04 871.79,-70.44 883.54,-51.56"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="843.25,-111.68 841.63,-118.91 847.41,-114.26 843.25,-111.68"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="885.76,-52.63 887.38,-45.39 881.6,-50.04 885.76,-52.63"/>
|
||||
<text text-anchor="middle" x="892" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
<!-- ws2812->gpio_bridge -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>ws2812->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M533.9,-209.93C578.56,-194.11 638.71,-172.81 681.94,-157.5"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="682.94,-159.74 688.73,-155.1 681.31,-155.12 682.94,-159.74"/>
|
||||
<text text-anchor="middle" x="642.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
|
||||
</g>
|
||||
<!-- irq -->
|
||||
<g id="node20" class="node">
|
||||
<g id="node21" class="node">
|
||||
<title>irq</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M659,-155C659,-155 453,-155 453,-155 447,-155 441,-149 441,-143 441,-143 441,-131 441,-131 441,-125 447,-119 453,-119 453,-119 659,-119 659,-119 665,-119 671,-125 671,-131 671,-131 671,-143 671,-143 671,-149 665,-155 659,-155"/>
|
||||
<text text-anchor="middle" x="556" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
|
||||
<text text-anchor="middle" x="556" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M612,-155C612,-155 406,-155 406,-155 400,-155 394,-149 394,-143 394,-143 394,-131 394,-131 394,-125 400,-119 406,-119 406,-119 612,-119 612,-119 618,-119 624,-125 624,-131 624,-131 624,-143 624,-143 624,-149 618,-155 612,-155"/>
|
||||
<text text-anchor="middle" x="509" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
|
||||
<text text-anchor="middle" x="509" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
|
||||
</g>
|
||||
<!-- ws2812->irq -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>ws2812->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M481.35,-209.81C486.85,-195.54 494.05,-176.83 499.73,-162.09"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="502.15,-162.62 502.38,-155.2 497.57,-160.86 502.15,-162.62"/>
|
||||
<text text-anchor="middle" x="505" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
|
||||
</g>
|
||||
<!-- apb_targets->gpio_bridge -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>apb_targets->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1060.38,-209.99C987.9,-193.86 889.69,-171.99 820.58,-156.61"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="820.93,-154.17 813.56,-155.04 819.86,-158.96 820.93,-154.17"/>
|
||||
<text text-anchor="middle" x="965" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
|
||||
</g>
|
||||
<!-- gpio_bridge->ext_io -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>gpio_bridge->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M751.43,-112.81C762.49,-95.04 777.79,-70.44 789.54,-51.56"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="749.25,-111.68 747.63,-118.91 753.41,-114.26 749.25,-111.68"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="791.76,-52.63 793.38,-45.39 787.6,-50.04 791.76,-52.63"/>
|
||||
<text text-anchor="middle" x="798" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
@@ -26,6 +26,19 @@ SoC wrappers use the existing clusterIP interfaces for protocol boundaries.
|
||||
`apb4_if_bridge` only adapts `apb4_pure_if` to `apb4_if`, and `gpio_pad_bridge`
|
||||
only exposes the pad-side subset of `gpio_if`; neither module contains state.
|
||||
|
||||
## WS2812 output
|
||||
|
||||
The single-channel WS2812 transmitter occupies RIBP address `0x10008000` and
|
||||
drives GPIO2 alternate function 1. Software must configure GPIO2 for ALT1
|
||||
before starting a frame. The transmitter interrupt is RIBP group bit 10 and
|
||||
management-core interrupt 17. The data pin is forced low while idle, during
|
||||
reset/latch time, after abort, and after underflow.
|
||||
|
||||
The RIBP TX FIFO is also a fixed-address target for the generic DMA engine.
|
||||
DMA remains a normal RIB master and receives RIBP backpressure when the FIFO
|
||||
is full; the transmitter does not own a private DMA request channel. See
|
||||
[ws2812.md](ws2812.md) for the register and transfer contract.
|
||||
|
||||
## Management JTAG
|
||||
|
||||
The fixed Hazard3 management core always exposes five ASIC pads:
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# WS2812 Transmitter
|
||||
|
||||
The Mini SoC WS2812 block is a single-channel, transmit-only peripheral for
|
||||
24-bit GRB LED words. It replaces the former generic one-wire block; it is not
|
||||
a Dallas/Maxim 1-Wire controller. The block has a strict RIBP register target,
|
||||
a 16-word FIFO, programmable symbol and reset timing, sticky interrupt and
|
||||
error state, and a GPIO alternate-function output.
|
||||
|
||||
## Integration
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| RIBP base address | `0x10008000` |
|
||||
| FIFO depth | 16 24-bit words |
|
||||
| Pixel order | GRB, bit 23 first |
|
||||
| GPIO route | GPIO2 alternate function 1 |
|
||||
| RIBP interrupt group | Bit 10 |
|
||||
| Management-core interrupt | 17 |
|
||||
| DMA target | Fixed address `TXDATA` |
|
||||
|
||||
`IP_INFO` reports the implemented data width, FIFO depth, and ABI version so
|
||||
software does not need to duplicate the configured FIFO depth. The current
|
||||
value is `0x18100100`: 24-bit data, 16 entries, ABI 1.0.
|
||||
|
||||
## Register ABI
|
||||
|
||||
All registers are 32 bits and naturally aligned. Unmapped, unaligned, and
|
||||
direction-invalid accesses complete with `resp_err`. `TXDATA` requires all
|
||||
four byte strobes; partial writes complete with `resp_err` and set the command
|
||||
error. Timing and frame registers support byte strobes unless noted below.
|
||||
|
||||
| Offset | Name | Access | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `0x00` | `BIT_CYCLES` | RW | Total system-clock cycles per serialized bit; implemented width is 16 bits. |
|
||||
| `0x04` | `T0H_CYCLES` | RW | High cycles for a zero bit; implemented width is 16 bits. |
|
||||
| `0x08` | `T1H_CYCLES` | RW | High cycles for a one bit; implemented width is 16 bits. |
|
||||
| `0x0C` | `RESET_CYCLES` | RW | Low cycles after a frame, abort, or underflow. |
|
||||
| `0x10` | `TXDATA` | WO | Push one 24-bit GRB word into the FIFO. Bits 31:24 must be zero in software. |
|
||||
| `0x14` | `CTRL` | WO | One-hot commands: bit 0 `START`, bit 1 `ABORT`, bit 2 `FIFO_FLUSH`. |
|
||||
| `0x18` | `STATUS` | RO | Bits 0:4 are `BUSY`, `FIFO_EMPTY`, `FIFO_FULL`, `CONFIG_VALID`, and `RESET_ACTIVE`. |
|
||||
| `0x1C` | `FRAME_WORDS` | RW | Exact number of FIFO words consumed by the next frame. |
|
||||
| `0x20` | `FIFO_LEVEL` | RO | Current FIFO occupancy. |
|
||||
| `0x24` | `FIFO_WATERMARK` | RW | Low-watermark threshold; valid values are 0 through 15. |
|
||||
| `0x28` | `REMAINING_WORDS` | RO | Frame words not yet completely serialized. |
|
||||
| `0x2C` | `ERROR_STATUS` | RW1C | Bits 0:2 are configuration, underflow, and command errors. |
|
||||
| `0x30` | `INTR_STATE` | RW1C | Bits 0:3 are done, FIFO-low, error, and aborted state. |
|
||||
| `0x34` | `INTR_ENABLE` | RW | Interrupt enable mask. |
|
||||
| `0x38` | `INTR_TEST` | WO | Write-one software interrupt test bits. |
|
||||
| `0x3C` | `IP_INFO` | RO | `{data_width, fifo_depth, abi_major, abi_minor}`. |
|
||||
|
||||
The external interrupt is the reduction OR of `INTR_STATE & INTR_ENABLE`.
|
||||
`ERROR_STATUS` and `INTR_STATE` are sticky until software writes one to clear
|
||||
the corresponding bit. `INTR_STATE.ERROR` reflects any newly observed error.
|
||||
`FIFO_LOW` is asserted while a frame still needs input and FIFO occupancy is
|
||||
at or below the programmed watermark.
|
||||
|
||||
## Timing contract
|
||||
|
||||
The active timing is captured on an accepted `START` command and cannot change
|
||||
mid-frame. A valid configuration satisfies:
|
||||
|
||||
```text
|
||||
0 < T0H_CYCLES < T1H_CYCLES < BIT_CYCLES
|
||||
RESET_CYCLES > 0
|
||||
```
|
||||
|
||||
For a source frequency `f` and duration in nanoseconds, the HAL rounds the bit
|
||||
and high durations to the nearest integer cycle. It rounds reset duration up,
|
||||
so the specified minimum reset/latch time is never shortened. The default HAL
|
||||
profile is a 1,250 ns bit, 350 ns zero-high, 700 ns one-high, and 300 us reset.
|
||||
Software must recompute and program the timing after changing the source clock.
|
||||
|
||||
## Transfer sequence
|
||||
|
||||
1. Configure GPIO2 for alternate function 1 and call `rs_ws2812_init()`.
|
||||
2. Clear old errors and interrupts, flush the idle FIFO, and enqueue initial
|
||||
24-bit GRB words.
|
||||
3. Program the exact nonzero `FRAME_WORDS` count and issue `START`.
|
||||
4. Refill `TXDATA` with the CPU or generic DMA before the FIFO empties.
|
||||
5. Wait for `DONE`; the output remains low for `RESET_CYCLES` before the frame
|
||||
is complete and the done state is raised.
|
||||
|
||||
When `TXDATA` is full during an active frame, RIBP applies backpressure until a
|
||||
FIFO entry becomes available. A full-FIFO write while idle is rejected instead
|
||||
of waiting indefinitely. Underflow aborts the frame, flushes queued data, sets
|
||||
the underflow and error state, and holds the output low for the configured
|
||||
reset interval. `ABORT` has the same output-safety behavior and additionally
|
||||
sets the aborted interrupt state. `FIFO_FLUSH` is accepted only while idle.
|
||||
|
||||
`rs_ws2812_write()` implements bounded CPU refill. `rs_ws2812_write_dma()`
|
||||
preloads the FIFO, programs the generic DMA for incrementing source and fixed
|
||||
`TXDATA` destination writes, then starts the frame and DMA. Both paths validate
|
||||
the complete pixel array before modifying peripheral state and use caller
|
||||
timeouts for all waits.
|
||||
|
||||
## Verification and current scope
|
||||
|
||||
The self-checking RTL test verifies exact zero/one pulse widths, MSB-first word
|
||||
order, frame length, reset low time, FIFO backpressure, watermark and done
|
||||
interrupts, invalid accesses, underflow, abort, and software interrupt test.
|
||||
The DMA integration test connects the production `dma_core` to `TXDATA` and
|
||||
checks fixed-destination writes, full-FIFO backpressure, completion, and the
|
||||
resulting serialized frame.
|
||||
The formal target proves bounded FIFO, RIBP response, idle-low output, and
|
||||
sticky event invariants and covers normal, underflow-precondition, and abort
|
||||
paths. Host C
|
||||
tests cover GRB packing and integer timing conversion. SoC topology tests lock
|
||||
the address, interrupt, and GPIO route.
|
||||
|
||||
The current delivery is deliberately one channel and 24-bit GRB. RGBW framing,
|
||||
parallel lanes, per-pixel brightness processing, and a dedicated DMA request
|
||||
line are outside this ABI and require a versioned extension rather than an
|
||||
incompatible register reinterpretation.
|
||||
@@ -5,7 +5,7 @@ module retrosoc_top (
|
||||
inout rst_n_i,
|
||||
inout ps2_clk_i,
|
||||
inout ps2_dat_i,
|
||||
output onewire_dat_o,
|
||||
output ws2812_dat_o,
|
||||
inout i2c_scl_io,
|
||||
inout i2c_sda_io,
|
||||
output pwm_2_o,
|
||||
|
||||
@@ -12,8 +12,8 @@ set_property -dict {PACKAGE_PIN AB11 IOSTANDARD LVCMOS18} [get_ports rst_n_i]
|
||||
# ps2
|
||||
set_property -dict {PACKAGE_PIN AB4 IOSTANDARD LVCMOS18} [get_ports ps2_clk_i]
|
||||
set_property -dict {PACKAGE_PIN AB5 IOSTANDARD LVCMOS18} [get_ports ps2_dat_i]
|
||||
#onewire
|
||||
set_property -dict {PACKAGE_PIN AB10 IOSTANDARD LVCMOS18} [get_ports onewire_dat_o]
|
||||
# ws2812
|
||||
set_property -dict {PACKAGE_PIN AB10 IOSTANDARD LVCMOS18} [get_ports ws2812_dat_o]
|
||||
# i2c1
|
||||
set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS18} [get_ports i2c_scl_io]
|
||||
set_property -dict {PACKAGE_PIN Y15 IOSTANDARD LVCMOS18} [get_ports i2c_sda_io]
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
// Copyright (c) 2023-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 ONEWIRE_DEF_SV
|
||||
`define ONEWIRE_DEF_SV
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_ONEWIRE_CLKDIV 8'h00
|
||||
`define RIBP_ONEWIRE_ZEROCNT 8'h04
|
||||
`define RIBP_ONEWIRE_ONECNT 8'h08
|
||||
`define RIBP_ONEWIRE_RSTCNT 8'h0C
|
||||
`define RIBP_ONEWIRE_TXDATA 8'h10
|
||||
`define RIBP_ONEWIRE_CTRL 8'h14
|
||||
`define RIBP_ONEWIRE_STATUS 8'h18
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
|
||||
interface onewire_if ();
|
||||
logic dat_o;
|
||||
|
||||
modport dut(output dat_o);
|
||||
endinterface
|
||||
|
||||
// generate 1250ns for ws2812x only
|
||||
module ribp_onewire (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
onewire_if.dut onewire
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
logic s_onewire_clkdiv_en;
|
||||
logic [7:0] s_onewire_clkdiv_d, s_onewire_clkdiv_q;
|
||||
logic s_onewire_zerocnt_en;
|
||||
logic [7:0] s_onewire_zerocnt_d, s_onewire_zerocnt_q;
|
||||
logic s_onewire_onecnt_en;
|
||||
logic [7:0] s_onewire_onecnt_d, s_onewire_onecnt_q;
|
||||
logic s_onewire_rstcnt_en;
|
||||
logic [7:0] s_onewire_rstcnt_d, s_onewire_rstcnt_q;
|
||||
logic [1:0] s_onewire_ctrl_d, s_onewire_ctrl_q;
|
||||
logic [2:0] s_onewire_status_d, s_onewire_status_q;
|
||||
// fifo
|
||||
logic s_tx_push_valid, s_tx_empty, s_tx_full;
|
||||
logic s_tx_pop_valid, s_tx_pop_ready;
|
||||
logic [23:0] s_tx_push_data, s_tx_pop_data;
|
||||
|
||||
logic s_done;
|
||||
|
||||
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && (|ribp.wstrb);
|
||||
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;
|
||||
|
||||
|
||||
assign s_onewire_clkdiv_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_CLKDIV;
|
||||
assign s_onewire_clkdiv_d = ribp.wdata[7:0];
|
||||
dffer #(8) u_onewire_clkdiv_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_onewire_clkdiv_en,
|
||||
s_onewire_clkdiv_d,
|
||||
s_onewire_clkdiv_q
|
||||
);
|
||||
|
||||
assign s_onewire_zerocnt_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_ZEROCNT;
|
||||
assign s_onewire_zerocnt_d = ribp.wdata[7:0];
|
||||
dffer #(8) u_onewire_zerocnt_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_onewire_zerocnt_en,
|
||||
s_onewire_zerocnt_d,
|
||||
s_onewire_zerocnt_q
|
||||
);
|
||||
|
||||
assign s_onewire_onecnt_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_ONECNT;
|
||||
assign s_onewire_onecnt_d = ribp.wdata[7:0];
|
||||
dffer #(8) u_onewire_onecnt_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_onewire_onecnt_en,
|
||||
s_onewire_onecnt_d,
|
||||
s_onewire_onecnt_q
|
||||
);
|
||||
|
||||
assign s_onewire_rstcnt_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_RSTCNT;
|
||||
assign s_onewire_rstcnt_d = ribp.wdata[7:0];
|
||||
dffer #(8) u_onewire_rstcnt_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_onewire_rstcnt_en,
|
||||
s_onewire_rstcnt_d,
|
||||
s_onewire_rstcnt_q
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_tx_push_valid = 1'b0;
|
||||
s_tx_push_data = '0;
|
||||
if (s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_TXDATA) begin
|
||||
s_tx_push_valid = 1'b1;
|
||||
if (ribp.wstrb[0]) s_tx_push_data[7:0] = ribp.wdata[7:0];
|
||||
if (ribp.wstrb[1]) s_tx_push_data[15:8] = ribp.wdata[15:8];
|
||||
if (ribp.wstrb[2]) s_tx_push_data[23:16] = ribp.wdata[23:16];
|
||||
end
|
||||
end
|
||||
|
||||
assign s_tx_pop_ready = ~s_tx_empty;
|
||||
fifo #(
|
||||
.DATA_WIDTH (24),
|
||||
.BUFFER_DEPTH(8)
|
||||
) u_tx_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(s_onewire_ctrl_q[0]),
|
||||
.push_i (s_tx_push_valid),
|
||||
.full_o (s_tx_full),
|
||||
.dat_i (s_tx_push_data),
|
||||
.pop_i (s_tx_pop_valid),
|
||||
.empty_o(s_tx_empty),
|
||||
.dat_o (s_tx_pop_data),
|
||||
.cnt_o ()
|
||||
);
|
||||
|
||||
|
||||
// [0] clear fifo [1] start
|
||||
always_comb begin
|
||||
if (s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_CTRL) begin
|
||||
s_onewire_ctrl_d = ribp.wdata[1:0];
|
||||
end else begin
|
||||
s_onewire_ctrl_d = '0;
|
||||
end
|
||||
end
|
||||
dffr #(2) u_onewire_ctrl_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_onewire_ctrl_d,
|
||||
s_onewire_ctrl_q
|
||||
);
|
||||
|
||||
|
||||
// [0] xfer done [1] fifo full, [2] fifo empty
|
||||
always_comb begin
|
||||
s_onewire_status_d = s_onewire_status_q;
|
||||
s_onewire_status_d[1] = s_tx_full;
|
||||
s_onewire_status_d[2] = s_tx_empty;
|
||||
if (s_done) begin
|
||||
s_onewire_status_d[0] = 1'b1;
|
||||
end else if (s_ribp_rd_hdshk && ribp.addr[7:0] == `RIBP_ONEWIRE_STATUS) begin
|
||||
s_onewire_status_d[0] = 1'b0;
|
||||
end
|
||||
end
|
||||
dffr #(3) u_onewire_status_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_onewire_status_d,
|
||||
s_onewire_status_q
|
||||
);
|
||||
|
||||
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q);
|
||||
dffr #(1) u_ribp_ready_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_ready_d,
|
||||
s_ribp_ready_q
|
||||
);
|
||||
|
||||
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
|
||||
always_comb begin
|
||||
s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_ONEWIRE_CLKDIV: s_ribp_rdata_d = {24'd0, s_onewire_clkdiv_q};
|
||||
`RIBP_ONEWIRE_ZEROCNT: s_ribp_rdata_d = {24'd0, s_onewire_zerocnt_q};
|
||||
`RIBP_ONEWIRE_ONECNT: s_ribp_rdata_d = {24'd0, s_onewire_onecnt_q};
|
||||
`RIBP_ONEWIRE_RSTCNT: s_ribp_rdata_d = {24'd0, s_onewire_rstcnt_q};
|
||||
`RIBP_ONEWIRE_STATUS: s_ribp_rdata_d = {29'd0, s_onewire_status_q};
|
||||
default: s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
endcase
|
||||
end
|
||||
dffer #(32) u_ribp_rdata_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_rdata_en,
|
||||
s_ribp_rdata_d,
|
||||
s_ribp_rdata_q
|
||||
);
|
||||
|
||||
onewire_core u_onewire_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.clkdiv_i (s_onewire_clkdiv_q),
|
||||
.zerocnt_i (s_onewire_zerocnt_q),
|
||||
.onecnt_i (s_onewire_onecnt_q),
|
||||
.rstcnt_i (s_onewire_rstcnt_q),
|
||||
.start_i (s_onewire_ctrl_q[1]),
|
||||
.data_req_o(s_tx_pop_valid),
|
||||
.data_rdy_i(s_tx_pop_ready),
|
||||
.data_i (s_tx_pop_data),
|
||||
.done_o (s_done),
|
||||
.onewire (onewire)
|
||||
);
|
||||
endmodule
|
||||
@@ -1,156 +0,0 @@
|
||||
// Copyright (c) 2023-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.
|
||||
|
||||
module onewire_core (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [7:0] clkdiv_i,
|
||||
input logic [7:0] zerocnt_i,
|
||||
input logic [7:0] onecnt_i,
|
||||
input logic [7:0] rstcnt_i,
|
||||
input logic start_i,
|
||||
output logic data_req_o,
|
||||
input logic data_rdy_i,
|
||||
input logic [23:0] data_i,
|
||||
output logic done_o,
|
||||
onewire_if.dut onewire
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
localparam FSM_IDLE = 2'd0;
|
||||
localparam FSM_XFER = 2'd1;
|
||||
localparam FSM_RST = 2'd2;
|
||||
|
||||
logic [1:0] s_fsm_d, s_fsm_q;
|
||||
logic s_clkdiv_cnt_en;
|
||||
logic [7:0] s_clkdiv_cnt_d, s_clkdiv_cnt_q;
|
||||
logic [7:0] s_rst_cnt_d, s_rst_cnt_q;
|
||||
logic [4:0] s_bit_cnt_d, s_bit_cnt_q;
|
||||
logic [23:0] s_xfer_data_d, s_xfer_data_q;
|
||||
logic s_done_d, s_done_q;
|
||||
|
||||
assign done_o = s_done_q;
|
||||
|
||||
always_comb begin
|
||||
s_fsm_d = s_fsm_q;
|
||||
s_clkdiv_cnt_d = s_clkdiv_cnt_q;
|
||||
s_bit_cnt_d = s_bit_cnt_q;
|
||||
s_rst_cnt_d = s_rst_cnt_q;
|
||||
s_xfer_data_d = s_xfer_data_q;
|
||||
s_done_d = s_done_q;
|
||||
data_req_o = '0;
|
||||
onewire.dat_o = '0;
|
||||
unique case (s_fsm_q)
|
||||
FSM_IDLE: begin
|
||||
s_done_d = 1'b0;
|
||||
if (start_i && data_rdy_i) begin
|
||||
data_req_o = 1'b1;
|
||||
s_xfer_data_d = data_i;
|
||||
s_fsm_d = FSM_XFER;
|
||||
end
|
||||
end
|
||||
FSM_XFER: begin
|
||||
// handle the data
|
||||
// xfer '1'
|
||||
if (s_xfer_data_q[23]) begin
|
||||
if (s_clkdiv_cnt_q <= onecnt_i) onewire.dat_o = 1'b1;
|
||||
else onewire.dat_o = 1'b0;
|
||||
end else begin
|
||||
if (s_clkdiv_cnt_q <= zerocnt_i) onewire.dat_o = 1'b1;
|
||||
else onewire.dat_o = 1'b0;
|
||||
end
|
||||
s_clkdiv_cnt_d = s_clkdiv_cnt_q + 1'b1;
|
||||
if (s_clkdiv_cnt_q == clkdiv_i) begin
|
||||
s_clkdiv_cnt_d = '0;
|
||||
s_xfer_data_d = {s_xfer_data_q[22:0], 1'b0};
|
||||
s_bit_cnt_d = s_bit_cnt_q + 1'b1;
|
||||
end
|
||||
|
||||
if (s_bit_cnt_q == 5'd23 && s_clkdiv_cnt_q == clkdiv_i) begin
|
||||
s_bit_cnt_d = '0;
|
||||
if (~data_rdy_i) begin
|
||||
s_fsm_d = FSM_RST;
|
||||
end else begin
|
||||
data_req_o = 1'b1;
|
||||
s_xfer_data_d = data_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
FSM_RST: begin
|
||||
if (s_rst_cnt_q == rstcnt_i) begin
|
||||
s_rst_cnt_d = '0;
|
||||
s_clkdiv_cnt_d = '0;
|
||||
s_fsm_d = FSM_IDLE;
|
||||
s_done_d = 1'b1;
|
||||
end else begin
|
||||
s_clkdiv_cnt_d = s_clkdiv_cnt_q + 1'b1;
|
||||
if (s_clkdiv_cnt_q == clkdiv_i) begin
|
||||
s_clkdiv_cnt_d = '0;
|
||||
s_rst_cnt_d = s_rst_cnt_q + 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
s_fsm_d = s_fsm_q;
|
||||
s_clkdiv_cnt_d = s_clkdiv_cnt_q;
|
||||
s_bit_cnt_d = s_bit_cnt_q;
|
||||
s_rst_cnt_d = s_rst_cnt_q;
|
||||
s_xfer_data_d = s_xfer_data_q;
|
||||
s_done_d = s_done_q;
|
||||
onewire.dat_o = '0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
dffr #(2) u_fsm_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_fsm_d,
|
||||
s_fsm_q
|
||||
);
|
||||
|
||||
assign s_clkdiv_cnt_en = s_fsm_q != FSM_IDLE;
|
||||
dffer #(8) u_clkdiv_cnt_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_clkdiv_cnt_en,
|
||||
s_clkdiv_cnt_d,
|
||||
s_clkdiv_cnt_q
|
||||
);
|
||||
|
||||
dffr #(1) u_done_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_done_d,
|
||||
s_done_q
|
||||
);
|
||||
|
||||
dffr #(5) u_bit_cnt_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_bit_cnt_d,
|
||||
s_bit_cnt_q
|
||||
);
|
||||
|
||||
dffr #(8) u_rst_cnt_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_rst_cnt_d,
|
||||
s_rst_cnt_q
|
||||
);
|
||||
|
||||
dffr #(24) u_xfer_data_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_xfer_data_d,
|
||||
s_xfer_data_q
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2023-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.
|
||||
|
||||
module ribp_ws2812 #(
|
||||
parameter int TX_FIFO_DEPTH = 16
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
ws2812_if.dut ws2812
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic [15:0] s_bit_cycles;
|
||||
logic [15:0] s_t0h_cycles;
|
||||
logic [15:0] s_t1h_cycles;
|
||||
logic [31:0] s_reset_cycles;
|
||||
logic [31:0] s_frame_words;
|
||||
logic s_start, s_abort;
|
||||
logic s_data_valid, s_data_pop;
|
||||
logic [23:0] s_data;
|
||||
logic s_fifo_flush;
|
||||
logic s_busy, s_reset_active;
|
||||
logic [31:0] s_remaining_words;
|
||||
logic s_done, s_underflow, s_aborted;
|
||||
logic s_irq, s_dat;
|
||||
|
||||
assign ws2812.dat_o = s_dat;
|
||||
assign ws2812.irq_o = s_irq;
|
||||
|
||||
ws2812_reg #(
|
||||
.TX_FIFO_DEPTH(TX_FIFO_DEPTH)
|
||||
) u_ws2812_reg (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (ribp),
|
||||
.bit_cycles_o (s_bit_cycles),
|
||||
.t0h_cycles_o (s_t0h_cycles),
|
||||
.t1h_cycles_o (s_t1h_cycles),
|
||||
.reset_cycles_o (s_reset_cycles),
|
||||
.frame_words_o (s_frame_words),
|
||||
.start_o (s_start),
|
||||
.abort_o (s_abort),
|
||||
.data_valid_o (s_data_valid),
|
||||
.data_o (s_data),
|
||||
.data_pop_i (s_data_pop),
|
||||
.core_fifo_flush_i (s_fifo_flush),
|
||||
.core_busy_i (s_busy),
|
||||
.core_reset_active_i (s_reset_active),
|
||||
.core_remaining_words_i(s_remaining_words),
|
||||
.core_done_i (s_done),
|
||||
.core_underflow_i (s_underflow),
|
||||
.core_aborted_i (s_aborted),
|
||||
.irq_o (s_irq)
|
||||
);
|
||||
|
||||
ws2812_core u_ws2812_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.bit_cycles_i (s_bit_cycles),
|
||||
.t0h_cycles_i (s_t0h_cycles),
|
||||
.t1h_cycles_i (s_t1h_cycles),
|
||||
.reset_cycles_i (s_reset_cycles),
|
||||
.frame_words_i (s_frame_words),
|
||||
.start_i (s_start),
|
||||
.abort_i (s_abort),
|
||||
.data_valid_i (s_data_valid),
|
||||
.data_i (s_data),
|
||||
.data_pop_o (s_data_pop),
|
||||
.fifo_flush_o (s_fifo_flush),
|
||||
.busy_o (s_busy),
|
||||
.reset_active_o (s_reset_active),
|
||||
.remaining_words_o(s_remaining_words),
|
||||
.done_o (s_done),
|
||||
.underflow_o (s_underflow),
|
||||
.aborted_o (s_aborted),
|
||||
.dat_o (s_dat)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright (c) 2023-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.
|
||||
|
||||
module ws2812_core (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [15:0] bit_cycles_i,
|
||||
input logic [15:0] t0h_cycles_i,
|
||||
input logic [15:0] t1h_cycles_i,
|
||||
input logic [31:0] reset_cycles_i,
|
||||
input logic [31:0] frame_words_i,
|
||||
input logic start_i,
|
||||
input logic abort_i,
|
||||
input logic data_valid_i,
|
||||
input logic [23:0] data_i,
|
||||
output logic data_pop_o,
|
||||
output logic fifo_flush_o,
|
||||
output logic busy_o,
|
||||
output logic reset_active_o,
|
||||
output logic [31:0] remaining_words_o,
|
||||
output logic done_o,
|
||||
output logic underflow_o,
|
||||
output logic aborted_o,
|
||||
output logic dat_o
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
WS_IDLE,
|
||||
WS_XFER,
|
||||
WS_RESET
|
||||
} ws_state_t;
|
||||
|
||||
ws_state_t s_state_d, s_state_q;
|
||||
logic [15:0] s_bit_cycles_d, s_bit_cycles_q;
|
||||
logic [15:0] s_t0h_cycles_d, s_t0h_cycles_q;
|
||||
logic [15:0] s_t1h_cycles_d, s_t1h_cycles_q;
|
||||
logic [31:0] s_reset_cycles_d, s_reset_cycles_q;
|
||||
logic [15:0] s_bit_cycle_d, s_bit_cycle_q;
|
||||
logic [4:0] s_bit_index_d, s_bit_index_q;
|
||||
logic [31:0] s_reset_cycle_d, s_reset_cycle_q;
|
||||
logic [31:0] s_remaining_words_d, s_remaining_words_q;
|
||||
logic [23:0] s_xfer_data_d, s_xfer_data_q;
|
||||
logic s_success_pending_d, s_success_pending_q;
|
||||
logic s_abort_pending_d, s_abort_pending_q;
|
||||
logic s_done_d, s_done_q;
|
||||
logic s_underflow_d, s_underflow_q;
|
||||
logic s_aborted_d, s_aborted_q;
|
||||
logic [15:0] s_high_cycles;
|
||||
|
||||
assign busy_o = s_state_q != WS_IDLE;
|
||||
assign reset_active_o = s_state_q == WS_RESET;
|
||||
assign remaining_words_o = s_remaining_words_q;
|
||||
assign done_o = s_done_q;
|
||||
assign underflow_o = s_underflow_q;
|
||||
assign aborted_o = s_aborted_q;
|
||||
assign s_high_cycles = s_xfer_data_q[23] ? s_t1h_cycles_q : s_t0h_cycles_q;
|
||||
|
||||
always_comb begin
|
||||
s_state_d = s_state_q;
|
||||
s_bit_cycles_d = s_bit_cycles_q;
|
||||
s_t0h_cycles_d = s_t0h_cycles_q;
|
||||
s_t1h_cycles_d = s_t1h_cycles_q;
|
||||
s_reset_cycles_d = s_reset_cycles_q;
|
||||
s_bit_cycle_d = s_bit_cycle_q;
|
||||
s_bit_index_d = s_bit_index_q;
|
||||
s_reset_cycle_d = s_reset_cycle_q;
|
||||
s_remaining_words_d = s_remaining_words_q;
|
||||
s_xfer_data_d = s_xfer_data_q;
|
||||
s_success_pending_d = s_success_pending_q;
|
||||
s_abort_pending_d = s_abort_pending_q;
|
||||
s_done_d = 1'b0;
|
||||
s_underflow_d = 1'b0;
|
||||
s_aborted_d = 1'b0;
|
||||
data_pop_o = 1'b0;
|
||||
fifo_flush_o = 1'b0;
|
||||
dat_o = 1'b0;
|
||||
|
||||
unique case (s_state_q)
|
||||
WS_IDLE: begin
|
||||
s_bit_cycle_d = '0;
|
||||
s_bit_index_d = '0;
|
||||
s_reset_cycle_d = '0;
|
||||
s_remaining_words_d = '0;
|
||||
s_success_pending_d = 1'b0;
|
||||
s_abort_pending_d = 1'b0;
|
||||
if (start_i) begin
|
||||
s_bit_cycles_d = bit_cycles_i;
|
||||
s_t0h_cycles_d = t0h_cycles_i;
|
||||
s_t1h_cycles_d = t1h_cycles_i;
|
||||
s_reset_cycles_d = reset_cycles_i;
|
||||
s_remaining_words_d = frame_words_i;
|
||||
s_xfer_data_d = data_i;
|
||||
data_pop_o = 1'b1;
|
||||
s_state_d = WS_XFER;
|
||||
end
|
||||
end
|
||||
|
||||
WS_XFER: begin
|
||||
dat_o = s_bit_cycle_q < s_high_cycles;
|
||||
if (abort_i) begin
|
||||
s_bit_cycle_d = '0;
|
||||
s_bit_index_d = '0;
|
||||
s_reset_cycle_d = '0;
|
||||
s_remaining_words_d = '0;
|
||||
s_success_pending_d = 1'b0;
|
||||
s_abort_pending_d = 1'b1;
|
||||
fifo_flush_o = 1'b1;
|
||||
s_state_d = WS_RESET;
|
||||
end else if (s_bit_cycle_q == (s_bit_cycles_q - 1'b1)) begin
|
||||
s_bit_cycle_d = '0;
|
||||
if (s_bit_index_q == 5'd23) begin
|
||||
s_bit_index_d = '0;
|
||||
if (s_remaining_words_q == 32'd1) begin
|
||||
s_remaining_words_d = '0;
|
||||
s_reset_cycle_d = '0;
|
||||
s_success_pending_d = 1'b1;
|
||||
s_state_d = WS_RESET;
|
||||
end else if (data_valid_i) begin
|
||||
s_remaining_words_d = s_remaining_words_q - 1'b1;
|
||||
s_xfer_data_d = data_i;
|
||||
data_pop_o = 1'b1;
|
||||
end else begin
|
||||
s_remaining_words_d = '0;
|
||||
s_reset_cycle_d = '0;
|
||||
s_success_pending_d = 1'b0;
|
||||
s_abort_pending_d = 1'b0;
|
||||
s_underflow_d = 1'b1;
|
||||
fifo_flush_o = 1'b1;
|
||||
s_state_d = WS_RESET;
|
||||
end
|
||||
end else begin
|
||||
s_bit_index_d = s_bit_index_q + 1'b1;
|
||||
s_xfer_data_d = {s_xfer_data_q[22:0], 1'b0};
|
||||
end
|
||||
end else begin
|
||||
s_bit_cycle_d = s_bit_cycle_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
WS_RESET: begin
|
||||
if (abort_i) begin
|
||||
s_reset_cycle_d = '0;
|
||||
s_success_pending_d = 1'b0;
|
||||
s_abort_pending_d = 1'b1;
|
||||
fifo_flush_o = 1'b1;
|
||||
end else if (s_reset_cycle_q == (s_reset_cycles_q - 1'b1)) begin
|
||||
s_reset_cycle_d = '0;
|
||||
s_state_d = WS_IDLE;
|
||||
if (s_abort_pending_q) begin
|
||||
s_aborted_d = 1'b1;
|
||||
end else if (s_success_pending_q) begin
|
||||
s_done_d = 1'b1;
|
||||
end
|
||||
s_success_pending_d = 1'b0;
|
||||
s_abort_pending_d = 1'b0;
|
||||
end else begin
|
||||
s_reset_cycle_d = s_reset_cycle_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
s_state_d = WS_IDLE;
|
||||
s_bit_cycle_d = '0;
|
||||
s_bit_index_d = '0;
|
||||
s_reset_cycle_d = '0;
|
||||
s_remaining_words_d = '0;
|
||||
s_success_pending_d = 1'b0;
|
||||
s_abort_pending_d = 1'b0;
|
||||
fifo_flush_o = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
dffercn #(
|
||||
.REG_TYPE (ws_state_t),
|
||||
.RESET_VAL(WS_IDLE)
|
||||
) u_state_dffercn (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (1'b1),
|
||||
.dat_i (s_state_d),
|
||||
.dat_o (s_state_q)
|
||||
);
|
||||
|
||||
dffr #(16) u_bit_cycles_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_bit_cycles_d,
|
||||
s_bit_cycles_q
|
||||
);
|
||||
dffr #(16) u_t0h_cycles_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_t0h_cycles_d,
|
||||
s_t0h_cycles_q
|
||||
);
|
||||
dffr #(16) u_t1h_cycles_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_t1h_cycles_d,
|
||||
s_t1h_cycles_q
|
||||
);
|
||||
dffr #(32) u_reset_cycles_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_reset_cycles_d,
|
||||
s_reset_cycles_q
|
||||
);
|
||||
dffr #(16) u_bit_cycle_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_bit_cycle_d,
|
||||
s_bit_cycle_q
|
||||
);
|
||||
dffr #(5) u_bit_index_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_bit_index_d,
|
||||
s_bit_index_q
|
||||
);
|
||||
dffr #(32) u_reset_cycle_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_reset_cycle_d,
|
||||
s_reset_cycle_q
|
||||
);
|
||||
dffr #(32) u_remaining_words_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_remaining_words_d,
|
||||
s_remaining_words_q
|
||||
);
|
||||
dffr #(24) u_xfer_data_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_xfer_data_d,
|
||||
s_xfer_data_q
|
||||
);
|
||||
dffr #(1) u_success_pending_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_success_pending_d,
|
||||
s_success_pending_q
|
||||
);
|
||||
dffr #(1) u_abort_pending_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_abort_pending_d,
|
||||
s_abort_pending_q
|
||||
);
|
||||
dffr #(1) u_done_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_done_d,
|
||||
s_done_q
|
||||
);
|
||||
dffr #(1) u_underflow_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_underflow_d,
|
||||
s_underflow_q
|
||||
);
|
||||
dffr #(1) u_aborted_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_aborted_d,
|
||||
s_aborted_q
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
`ifndef WS2812_DEFINE_SVH
|
||||
`define WS2812_DEFINE_SVH
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_WS2812_BIT_CYCLES 8'h00
|
||||
`define RIBP_WS2812_T0H_CYCLES 8'h04
|
||||
`define RIBP_WS2812_T1H_CYCLES 8'h08
|
||||
`define RIBP_WS2812_RESET_CYCLES 8'h0C
|
||||
`define RIBP_WS2812_TXDATA 8'h10
|
||||
`define RIBP_WS2812_CTRL 8'h14
|
||||
`define RIBP_WS2812_STATUS 8'h18
|
||||
`define RIBP_WS2812_FRAME_WORDS 8'h1C
|
||||
`define RIBP_WS2812_FIFO_LEVEL 8'h20
|
||||
`define RIBP_WS2812_FIFO_WATERMARK 8'h24
|
||||
`define RIBP_WS2812_REMAINING_WORDS 8'h28
|
||||
`define RIBP_WS2812_ERROR_STATUS 8'h2C
|
||||
`define RIBP_WS2812_INTR_STATE 8'h30
|
||||
`define RIBP_WS2812_INTR_ENABLE 8'h34
|
||||
`define RIBP_WS2812_INTR_TEST 8'h38
|
||||
`define RIBP_WS2812_IP_INFO 8'h3C
|
||||
|
||||
`define WS2812_CTRL_START 0
|
||||
`define WS2812_CTRL_ABORT 1
|
||||
`define WS2812_CTRL_FIFO_FLUSH 2
|
||||
|
||||
`define WS2812_STATUS_BUSY 0
|
||||
`define WS2812_STATUS_FIFO_EMPTY 1
|
||||
`define WS2812_STATUS_FIFO_FULL 2
|
||||
`define WS2812_STATUS_CONFIG_VALID 3
|
||||
`define WS2812_STATUS_RESET_ACTIVE 4
|
||||
|
||||
`define WS2812_ERROR_CONFIG 0
|
||||
`define WS2812_ERROR_UNDERFLOW 1
|
||||
`define WS2812_ERROR_COMMAND 2
|
||||
|
||||
`define WS2812_INTR_DONE 0
|
||||
`define WS2812_INTR_FIFO_LOW 1
|
||||
`define WS2812_INTR_ERROR 2
|
||||
`define WS2812_INTR_ABORTED 3
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2023-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.
|
||||
|
||||
interface ws2812_if ();
|
||||
logic dat_o;
|
||||
logic irq_o;
|
||||
|
||||
modport dut(output dat_o, output irq_o);
|
||||
endinterface
|
||||
@@ -0,0 +1,458 @@
|
||||
// Copyright (c) 2023-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 "ws2812_define.svh"
|
||||
|
||||
module ws2812_reg #(
|
||||
parameter int TX_FIFO_DEPTH = 16,
|
||||
parameter int TX_FIFO_LOG_DEPTH = $clog2(TX_FIFO_DEPTH)
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
output logic [15:0] bit_cycles_o,
|
||||
output logic [15:0] t0h_cycles_o,
|
||||
output logic [15:0] t1h_cycles_o,
|
||||
output logic [31:0] reset_cycles_o,
|
||||
output logic [31:0] frame_words_o,
|
||||
output logic start_o,
|
||||
output logic abort_o,
|
||||
output logic data_valid_o,
|
||||
output logic [23:0] data_o,
|
||||
input logic data_pop_i,
|
||||
input logic core_fifo_flush_i,
|
||||
input logic core_busy_i,
|
||||
input logic core_reset_active_i,
|
||||
input logic [31:0] core_remaining_words_i,
|
||||
input logic core_done_i,
|
||||
input logic core_underflow_i,
|
||||
input logic core_aborted_i,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
localparam logic [31:0] FIFO_WATERMARK_RESET = (TX_FIFO_DEPTH > 4) ? 32'd4 : TX_FIFO_DEPTH - 1;
|
||||
localparam logic [7:0] FIFO_DEPTH_INFO = TX_FIFO_DEPTH[7:0];
|
||||
localparam logic [31:0] IP_INFO = {8'd24, FIFO_DEPTH_INFO, 8'd1, 8'd0};
|
||||
|
||||
logic s_req;
|
||||
logic s_write;
|
||||
logic s_req_accept;
|
||||
logic s_access_error;
|
||||
logic s_ribp_ready_d, s_ribp_ready_q;
|
||||
logic s_ribp_resp_err_d, s_ribp_resp_err_q;
|
||||
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
|
||||
|
||||
logic s_bit_cycles_en;
|
||||
logic [15:0] s_bit_cycles_d, s_bit_cycles_q;
|
||||
logic s_t0h_cycles_en;
|
||||
logic [15:0] s_t0h_cycles_d, s_t0h_cycles_q;
|
||||
logic s_t1h_cycles_en;
|
||||
logic [15:0] s_t1h_cycles_d, s_t1h_cycles_q;
|
||||
logic s_reset_cycles_en;
|
||||
logic [31:0] s_reset_cycles_d, s_reset_cycles_q;
|
||||
logic s_frame_words_en;
|
||||
logic [31:0] s_frame_words_d, s_frame_words_q;
|
||||
logic s_fifo_watermark_en;
|
||||
logic [31:0] s_fifo_watermark_d, s_fifo_watermark_q;
|
||||
logic s_intr_enable_en;
|
||||
logic [3:0] s_intr_enable_d, s_intr_enable_q;
|
||||
|
||||
logic s_fifo_flush_cmd;
|
||||
logic s_tx_push;
|
||||
logic [23:0] s_tx_push_data;
|
||||
logic s_tx_empty, s_tx_full;
|
||||
logic [ 23:0] s_tx_pop_data;
|
||||
logic [TX_FIFO_LOG_DEPTH:0] s_tx_count;
|
||||
|
||||
logic [31:0] s_load_remaining_d, s_load_remaining_q;
|
||||
logic [2:0] s_error_status_d, s_error_status_q;
|
||||
logic [3:0] s_intr_state_d, s_intr_state_q;
|
||||
logic [ 2:0] s_error_clear;
|
||||
logic [ 3:0] s_intr_clear;
|
||||
logic [ 3:0] s_intr_test;
|
||||
logic s_config_error_event;
|
||||
logic s_command_error_event;
|
||||
logic s_fifo_low;
|
||||
logic s_config_valid;
|
||||
logic [31:0] s_status;
|
||||
logic [31:0] s_fifo_level;
|
||||
logic [31:0] s_watermark_write_value;
|
||||
|
||||
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;
|
||||
integer byte_index;
|
||||
begin
|
||||
merged = current;
|
||||
for (byte_index = 0; byte_index < 4; byte_index = byte_index + 1) begin
|
||||
if (strobe[byte_index]) begin
|
||||
merged[byte_index*8+:8] = value[byte_index*8+:8];
|
||||
end
|
||||
end
|
||||
return merged;
|
||||
end
|
||||
endfunction
|
||||
|
||||
assign s_req = ribp.valid && !s_ribp_ready_q;
|
||||
assign s_write = |ribp.wstrb;
|
||||
assign ribp.ready = s_ribp_ready_q;
|
||||
assign ribp.resp_err = s_ribp_resp_err_q;
|
||||
assign ribp.rdata = s_ribp_rdata_q;
|
||||
assign bit_cycles_o = s_bit_cycles_q;
|
||||
assign t0h_cycles_o = s_t0h_cycles_q;
|
||||
assign t1h_cycles_o = s_t1h_cycles_q;
|
||||
assign reset_cycles_o = s_reset_cycles_q;
|
||||
assign frame_words_o = s_frame_words_q;
|
||||
assign data_valid_o = !s_tx_empty;
|
||||
assign data_o = s_tx_pop_data;
|
||||
assign irq_o = |(s_intr_state_q & s_intr_enable_q);
|
||||
assign s_fifo_level = {{(31 - TX_FIFO_LOG_DEPTH) {1'b0}}, s_tx_count};
|
||||
assign s_watermark_write_value = merge_wstrb(s_fifo_watermark_q, ribp.wdata, ribp.wstrb);
|
||||
assign s_config_valid = (s_bit_cycles_q != 16'd0) &&
|
||||
(s_t0h_cycles_q != 16'd0) &&
|
||||
(s_t1h_cycles_q != 16'd0) &&
|
||||
(s_t0h_cycles_q < s_t1h_cycles_q) &&
|
||||
(s_t1h_cycles_q < s_bit_cycles_q) &&
|
||||
(s_reset_cycles_q != 32'd0);
|
||||
assign s_fifo_low = core_busy_i && (s_load_remaining_q != 32'd0) &&
|
||||
(s_fifo_level <= s_fifo_watermark_q);
|
||||
|
||||
always_comb begin
|
||||
s_status = '0;
|
||||
s_status[`WS2812_STATUS_BUSY] = core_busy_i;
|
||||
s_status[`WS2812_STATUS_FIFO_EMPTY] = s_tx_empty;
|
||||
s_status[`WS2812_STATUS_FIFO_FULL] = s_tx_full;
|
||||
s_status[`WS2812_STATUS_CONFIG_VALID] = s_config_valid;
|
||||
s_status[`WS2812_STATUS_RESET_ACTIVE] = core_reset_active_i;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_req_accept = s_req;
|
||||
s_access_error = 1'b0;
|
||||
s_bit_cycles_en = 1'b0;
|
||||
s_t0h_cycles_en = 1'b0;
|
||||
s_t1h_cycles_en = 1'b0;
|
||||
s_reset_cycles_en = 1'b0;
|
||||
s_frame_words_en = 1'b0;
|
||||
s_fifo_watermark_en = 1'b0;
|
||||
s_intr_enable_en = 1'b0;
|
||||
s_bit_cycles_d = s_bit_cycles_q;
|
||||
s_t0h_cycles_d = s_t0h_cycles_q;
|
||||
s_t1h_cycles_d = s_t1h_cycles_q;
|
||||
s_reset_cycles_d = s_reset_cycles_q;
|
||||
s_frame_words_d = s_frame_words_q;
|
||||
s_fifo_watermark_d = s_fifo_watermark_q;
|
||||
s_intr_enable_d = s_intr_enable_q;
|
||||
s_fifo_flush_cmd = 1'b0;
|
||||
s_tx_push = 1'b0;
|
||||
s_tx_push_data = ribp.wdata[23:0];
|
||||
start_o = 1'b0;
|
||||
abort_o = 1'b0;
|
||||
s_error_clear = '0;
|
||||
s_intr_clear = '0;
|
||||
s_intr_test = '0;
|
||||
s_config_error_event = 1'b0;
|
||||
s_command_error_event = 1'b0;
|
||||
s_ribp_rdata_d = '0;
|
||||
|
||||
if (s_req) begin
|
||||
if ((ribp.addr[11:8] != 4'd0) || (ribp.addr[1:0] != 2'b00)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else if (s_write) begin
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_WS2812_BIT_CYCLES: begin
|
||||
s_bit_cycles_en = 1'b1;
|
||||
s_bit_cycles_d = 16'(merge_wstrb({16'd0, s_bit_cycles_q}, ribp.wdata, ribp.wstrb));
|
||||
end
|
||||
`RIBP_WS2812_T0H_CYCLES: begin
|
||||
s_t0h_cycles_en = 1'b1;
|
||||
s_t0h_cycles_d = 16'(merge_wstrb({16'd0, s_t0h_cycles_q}, ribp.wdata, ribp.wstrb));
|
||||
end
|
||||
`RIBP_WS2812_T1H_CYCLES: begin
|
||||
s_t1h_cycles_en = 1'b1;
|
||||
s_t1h_cycles_d = 16'(merge_wstrb({16'd0, s_t1h_cycles_q}, ribp.wdata, ribp.wstrb));
|
||||
end
|
||||
`RIBP_WS2812_RESET_CYCLES: begin
|
||||
s_reset_cycles_en = 1'b1;
|
||||
s_reset_cycles_d = merge_wstrb(s_reset_cycles_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
`RIBP_WS2812_TXDATA: begin
|
||||
if (ribp.wstrb != 4'hF || (core_busy_i && (s_load_remaining_q == 32'd0))) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else if (s_tx_full && core_busy_i) begin
|
||||
s_req_accept = 1'b0;
|
||||
end else if (s_tx_full && !core_busy_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_tx_push = 1'b1;
|
||||
end
|
||||
end
|
||||
`RIBP_WS2812_CTRL: begin
|
||||
if (!ribp.wstrb[0]) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else begin
|
||||
unique case (ribp.wdata[2:0])
|
||||
3'b001: begin
|
||||
if (core_busy_i || (s_frame_words_q == 32'd0) || s_tx_empty ||
|
||||
(s_fifo_level > s_frame_words_q)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else if (!s_config_valid) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
start_o = 1'b1;
|
||||
end
|
||||
end
|
||||
3'b010: begin
|
||||
if (!core_busy_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else begin
|
||||
abort_o = 1'b1;
|
||||
end
|
||||
end
|
||||
3'b100: begin
|
||||
if (core_busy_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_fifo_flush_cmd = 1'b1;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
`RIBP_WS2812_FRAME_WORDS: begin
|
||||
s_frame_words_en = 1'b1;
|
||||
s_frame_words_d = merge_wstrb(s_frame_words_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
`RIBP_WS2812_FIFO_WATERMARK: begin
|
||||
if (s_watermark_write_value >= TX_FIFO_DEPTH) begin
|
||||
s_access_error = 1'b1;
|
||||
s_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_fifo_watermark_en = 1'b1;
|
||||
s_fifo_watermark_d = s_watermark_write_value;
|
||||
end
|
||||
end
|
||||
`RIBP_WS2812_ERROR_STATUS: begin
|
||||
if (!ribp.wstrb[0]) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_error_clear = ribp.wdata[2:0];
|
||||
end
|
||||
end
|
||||
`RIBP_WS2812_INTR_STATE: begin
|
||||
if (!ribp.wstrb[0]) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_intr_clear = ribp.wdata[3:0];
|
||||
end
|
||||
end
|
||||
`RIBP_WS2812_INTR_ENABLE: begin
|
||||
s_intr_enable_en = 1'b1;
|
||||
s_intr_enable_d = 4'(merge_wstrb({28'd0, s_intr_enable_q}, ribp.wdata, ribp.wstrb));
|
||||
end
|
||||
`RIBP_WS2812_INTR_TEST: begin
|
||||
if (!ribp.wstrb[0]) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_intr_test = ribp.wdata[3:0];
|
||||
end
|
||||
end
|
||||
default: s_access_error = 1'b1;
|
||||
endcase
|
||||
end else begin
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_WS2812_BIT_CYCLES: s_ribp_rdata_d = {16'd0, s_bit_cycles_q};
|
||||
`RIBP_WS2812_T0H_CYCLES: s_ribp_rdata_d = {16'd0, s_t0h_cycles_q};
|
||||
`RIBP_WS2812_T1H_CYCLES: s_ribp_rdata_d = {16'd0, s_t1h_cycles_q};
|
||||
`RIBP_WS2812_RESET_CYCLES: s_ribp_rdata_d = s_reset_cycles_q;
|
||||
`RIBP_WS2812_STATUS: s_ribp_rdata_d = s_status;
|
||||
`RIBP_WS2812_FRAME_WORDS: s_ribp_rdata_d = s_frame_words_q;
|
||||
`RIBP_WS2812_FIFO_LEVEL: s_ribp_rdata_d = s_fifo_level;
|
||||
`RIBP_WS2812_FIFO_WATERMARK: s_ribp_rdata_d = s_fifo_watermark_q;
|
||||
`RIBP_WS2812_REMAINING_WORDS: s_ribp_rdata_d = core_remaining_words_i;
|
||||
`RIBP_WS2812_ERROR_STATUS: s_ribp_rdata_d = {29'd0, s_error_status_q};
|
||||
`RIBP_WS2812_INTR_STATE: s_ribp_rdata_d = {28'd0, s_intr_state_q};
|
||||
`RIBP_WS2812_INTR_ENABLE: s_ribp_rdata_d = {28'd0, s_intr_enable_q};
|
||||
`RIBP_WS2812_IP_INFO: s_ribp_rdata_d = IP_INFO;
|
||||
default: begin
|
||||
s_ribp_rdata_d = '0;
|
||||
s_access_error = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign s_ribp_ready_d = s_req_accept;
|
||||
assign s_ribp_resp_err_d = s_access_error;
|
||||
|
||||
dffr #(1) u_ribp_ready_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_ready_d,
|
||||
s_ribp_ready_q
|
||||
);
|
||||
dffer #(1) u_ribp_resp_err_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_req_accept,
|
||||
s_ribp_resp_err_d,
|
||||
s_ribp_resp_err_q
|
||||
);
|
||||
dffer #(32) u_ribp_rdata_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_req_accept,
|
||||
s_ribp_rdata_d,
|
||||
s_ribp_rdata_q
|
||||
);
|
||||
|
||||
dffer #(16) u_bit_cycles_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_bit_cycles_en,
|
||||
s_bit_cycles_d,
|
||||
s_bit_cycles_q
|
||||
);
|
||||
dffer #(16) u_t0h_cycles_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_t0h_cycles_en,
|
||||
s_t0h_cycles_d,
|
||||
s_t0h_cycles_q
|
||||
);
|
||||
dffer #(16) u_t1h_cycles_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_t1h_cycles_en,
|
||||
s_t1h_cycles_d,
|
||||
s_t1h_cycles_q
|
||||
);
|
||||
dffer #(32) u_reset_cycles_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_reset_cycles_en,
|
||||
s_reset_cycles_d,
|
||||
s_reset_cycles_q
|
||||
);
|
||||
dffer #(32) u_frame_words_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_frame_words_en,
|
||||
s_frame_words_d,
|
||||
s_frame_words_q
|
||||
);
|
||||
dfferc #(
|
||||
.DATA_WIDTH(32),
|
||||
.RESET_VAL (FIFO_WATERMARK_RESET)
|
||||
) u_fifo_watermark_dfferc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_fifo_watermark_en),
|
||||
.dat_i (s_fifo_watermark_d),
|
||||
.dat_o (s_fifo_watermark_q)
|
||||
);
|
||||
dffer #(4) u_intr_enable_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_intr_enable_en,
|
||||
s_intr_enable_d,
|
||||
s_intr_enable_q
|
||||
);
|
||||
|
||||
fifo #(
|
||||
.DATA_WIDTH (24),
|
||||
.BUFFER_DEPTH (TX_FIFO_DEPTH),
|
||||
.LOG_BUFFER_DEPTH(TX_FIFO_LOG_DEPTH)
|
||||
) u_tx_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(s_fifo_flush_cmd || core_fifo_flush_i),
|
||||
.push_i (s_tx_push),
|
||||
.full_o (s_tx_full),
|
||||
.dat_i (s_tx_push_data),
|
||||
.pop_i (data_pop_i),
|
||||
.empty_o(s_tx_empty),
|
||||
.dat_o (s_tx_pop_data),
|
||||
.cnt_o (s_tx_count)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_load_remaining_d = s_load_remaining_q;
|
||||
if (start_o) begin
|
||||
s_load_remaining_d = s_frame_words_q - s_fifo_level;
|
||||
end else if (core_done_i || core_underflow_i || core_aborted_i) begin
|
||||
s_load_remaining_d = '0;
|
||||
end else if (s_tx_push && core_busy_i) begin
|
||||
s_load_remaining_d = s_load_remaining_q - 1'b1;
|
||||
end
|
||||
end
|
||||
dffr #(32) u_load_remaining_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_load_remaining_d,
|
||||
s_load_remaining_q
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_error_status_d = s_error_status_q & ~s_error_clear;
|
||||
if (s_config_error_event) begin
|
||||
s_error_status_d[`WS2812_ERROR_CONFIG] = 1'b1;
|
||||
end
|
||||
if (core_underflow_i) begin
|
||||
s_error_status_d[`WS2812_ERROR_UNDERFLOW] = 1'b1;
|
||||
end
|
||||
if (s_command_error_event) begin
|
||||
s_error_status_d[`WS2812_ERROR_COMMAND] = 1'b1;
|
||||
end
|
||||
end
|
||||
dffr #(3) u_error_status_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_error_status_d,
|
||||
s_error_status_q
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_intr_state_d = (s_intr_state_q & ~s_intr_clear) | s_intr_test;
|
||||
if (core_done_i) begin
|
||||
s_intr_state_d[`WS2812_INTR_DONE] = 1'b1;
|
||||
end
|
||||
if (s_fifo_low) begin
|
||||
s_intr_state_d[`WS2812_INTR_FIFO_LOW] = 1'b1;
|
||||
end
|
||||
if (s_config_error_event || s_command_error_event || core_underflow_i) begin
|
||||
s_intr_state_d[`WS2812_INTR_ERROR] = 1'b1;
|
||||
end
|
||||
if (core_aborted_i) begin
|
||||
s_intr_state_d[`WS2812_INTR_ABORTED] = 1'b1;
|
||||
end
|
||||
end
|
||||
dffr #(4) u_intr_state_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_intr_state_d,
|
||||
s_intr_state_q
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -43,7 +43,7 @@
|
||||
{"symbol": "RIBP_SPISD", "base": "0x10005000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "RIBP_I2C0", "base": "0x10006000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "RIBP_I2S", "base": "0x10007000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "RIBP_ONEWIRE", "base": "0x10008000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "RIBP_WS2812", "base": "0x10008000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "RIBP_XPI", "base": "0x10009000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
|
||||
{"symbol": "RIBP_DMA", "base": "0x1000A000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
|
||||
{"symbol": "RIBP_SYSCTRL", "base": "0x1000B000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
/ip/ribp/serial/i2s_send.sv
|
||||
/ip/ribp/serial/i2s_core.sv
|
||||
/ip/ribp/serial/i2s.sv
|
||||
/ip/ribp/serial/onewire_core.sv
|
||||
/ip/ribp/serial/onewire.sv
|
||||
/ip/ribp/serial/ws2812_if.sv
|
||||
/ip/ribp/serial/ws2812_reg.sv
|
||||
/ip/ribp/serial/ws2812_core.sv
|
||||
/ip/ribp/serial/ribp_ws2812.sv
|
||||
/ip/ribp/storage/xpi_reg.sv
|
||||
/ip/ribp/storage/xpi_mm.sv
|
||||
/ip/ribp/storage/xpi_clkgen.sv
|
||||
|
||||
@@ -19,6 +19,7 @@ from filelist import FileList, write_filelist # noqa: E402
|
||||
COMMON_RTL = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||
INTERCONNECT = ROOT / "rtl/ip/ribp/interconnect"
|
||||
PERIPHERAL = ROOT / "rtl/ip/ribp/peripheral"
|
||||
SERIAL = ROOT / "rtl/ip/ribp/serial"
|
||||
TOP = ROOT / "rtl/mini/top"
|
||||
|
||||
|
||||
@@ -87,6 +88,17 @@ def source_files(target: str) -> list[Path]:
|
||||
PERIPHERAL / "gpio.sv",
|
||||
SCRIPT_DIR / "gpio_user_formal.sv",
|
||||
]
|
||||
if target == "ws2812":
|
||||
return [
|
||||
COMMON_RTL / "interface/ribp_if.sv",
|
||||
COMMON_RTL / "utils/register.sv",
|
||||
COMMON_RTL / "utils/fifo.sv",
|
||||
SERIAL / "ws2812_if.sv",
|
||||
SERIAL / "ws2812_reg.sv",
|
||||
SERIAL / "ws2812_core.sv",
|
||||
SERIAL / "ribp_ws2812.sv",
|
||||
SCRIPT_DIR / "ws2812_formal.sv",
|
||||
]
|
||||
raise ValueError(f"unsupported formal target: {target}")
|
||||
|
||||
|
||||
@@ -109,6 +121,7 @@ def generate(
|
||||
COMMON_RTL / "utils",
|
||||
INTERCONNECT,
|
||||
PERIPHERAL,
|
||||
SERIAL,
|
||||
],
|
||||
files=source_files(target),
|
||||
).deduplicate()
|
||||
@@ -126,6 +139,7 @@ def parse_args() -> argparse.Namespace:
|
||||
"sysctrl",
|
||||
"pll_rcu",
|
||||
"gpio_user",
|
||||
"ws2812",
|
||||
),
|
||||
required=True,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module ws2812_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 dat,
|
||||
output logic irq,
|
||||
output logic busy,
|
||||
output logic reset_active,
|
||||
output logic start,
|
||||
output logic abort_cmd,
|
||||
output logic data_valid,
|
||||
output logic data_pop,
|
||||
output logic done,
|
||||
output logic underflow,
|
||||
output logic aborted,
|
||||
output logic [ 4:0] fifo_level,
|
||||
output logic [31:0] load_remaining,
|
||||
output logic [ 2:0] error_status,
|
||||
output logic [ 3:0] intr_state,
|
||||
output logic [ 3:0] intr_enable
|
||||
);
|
||||
|
||||
ribp_if rib ();
|
||||
ws2812_if ws2812 ();
|
||||
|
||||
(* anyseq *)logic f_rib_valid;
|
||||
(* anyseq *)logic [31:0] f_rib_addr;
|
||||
(* anyseq *)logic [31:0] f_rib_wdata;
|
||||
(* anyseq *)logic [ 3:0] f_rib_wstrb;
|
||||
|
||||
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 dat = ws2812.dat_o;
|
||||
assign irq = ws2812.irq_o;
|
||||
assign busy = u_dut.s_busy;
|
||||
assign reset_active = u_dut.s_reset_active;
|
||||
assign start = u_dut.s_start;
|
||||
assign abort_cmd = u_dut.s_abort;
|
||||
assign data_valid = u_dut.s_data_valid;
|
||||
assign data_pop = u_dut.s_data_pop;
|
||||
assign done = u_dut.s_done;
|
||||
assign underflow = u_dut.s_underflow;
|
||||
assign aborted = u_dut.s_aborted;
|
||||
assign fifo_level = u_dut.u_ws2812_reg.s_tx_count;
|
||||
assign load_remaining = u_dut.u_ws2812_reg.s_load_remaining_q;
|
||||
assign error_status = u_dut.u_ws2812_reg.s_error_status_q;
|
||||
assign intr_state = u_dut.u_ws2812_reg.s_intr_state_q;
|
||||
assign intr_enable = u_dut.u_ws2812_reg.s_intr_enable_q;
|
||||
|
||||
ribp_ws2812 u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (rib),
|
||||
.ws2812 (ws2812)
|
||||
);
|
||||
|
||||
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,100 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module ws2812_formal;
|
||||
|
||||
(* anyseq *) (* gclk *)reg clk_i;
|
||||
wire rst_n_i;
|
||||
wire f_past_valid;
|
||||
wire rib_valid;
|
||||
wire [31:0] rib_addr;
|
||||
wire [31:0] rib_wdata;
|
||||
wire [ 3:0] rib_wstrb;
|
||||
wire rib_ready;
|
||||
wire rib_resp_err;
|
||||
wire dat;
|
||||
wire irq;
|
||||
wire busy;
|
||||
wire reset_active;
|
||||
wire start;
|
||||
wire abort_cmd;
|
||||
wire data_valid;
|
||||
wire data_pop;
|
||||
wire done;
|
||||
wire underflow;
|
||||
wire aborted;
|
||||
wire [ 4:0] fifo_level;
|
||||
wire [31:0] load_remaining;
|
||||
wire [ 2:0] error_status;
|
||||
wire [ 3:0] intr_state;
|
||||
wire [ 3:0] intr_enable;
|
||||
|
||||
ws2812_formal_design u_design (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.f_past_valid (f_past_valid),
|
||||
.rib_valid (rib_valid),
|
||||
.rib_addr (rib_addr),
|
||||
.rib_wdata (rib_wdata),
|
||||
.rib_wstrb (rib_wstrb),
|
||||
.rib_ready (rib_ready),
|
||||
.rib_resp_err (rib_resp_err),
|
||||
.dat (dat),
|
||||
.irq (irq),
|
||||
.busy (busy),
|
||||
.reset_active (reset_active),
|
||||
.start (start),
|
||||
.abort_cmd (abort_cmd),
|
||||
.data_valid (data_valid),
|
||||
.data_pop (data_pop),
|
||||
.done (done),
|
||||
.underflow (underflow),
|
||||
.aborted (aborted),
|
||||
.fifo_level (fifo_level),
|
||||
.load_remaining(load_remaining),
|
||||
.error_status (error_status),
|
||||
.intr_state (intr_state),
|
||||
.intr_enable (intr_enable)
|
||||
);
|
||||
|
||||
always @(posedge clk_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));
|
||||
end
|
||||
|
||||
if (rst_n_i) begin
|
||||
assert (fifo_level <= 5'd16);
|
||||
assert (irq == |(intr_state & intr_enable));
|
||||
if (!busy || reset_active) begin
|
||||
assert (!dat);
|
||||
end
|
||||
if (data_pop) begin
|
||||
assert (data_valid);
|
||||
end
|
||||
if (f_past_valid && $past(rst_n_i && start)) begin
|
||||
assert (busy);
|
||||
end
|
||||
if (f_past_valid && $past(rst_n_i && done)) begin
|
||||
assert (intr_state[0]);
|
||||
end
|
||||
if (f_past_valid && $past(rst_n_i && underflow)) begin
|
||||
assert (error_status[1]);
|
||||
assert (intr_state[2]);
|
||||
end
|
||||
if (f_past_valid && $past(rst_n_i && aborted)) begin
|
||||
assert (intr_state[3]);
|
||||
end
|
||||
|
||||
cover (busy && dat);
|
||||
cover (reset_active);
|
||||
cover (busy && (load_remaining != 32'd0) && (fifo_level == 5'd0));
|
||||
cover (aborted);
|
||||
cover (irq);
|
||||
cover (rib_ready && rib_resp_err);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -44,6 +44,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
|
||||
("watchdog_reset", "apb", 4, 14, "u_wdg_if.rst_o"),
|
||||
("advanced_timer", "apb", 5, 15, "u_tmr_if.irq_o"),
|
||||
("reserved", "apb", 6, 16, "1'b0"),
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"gpio_pins": 32,
|
||||
"irq_vector_width": 32,
|
||||
"irq_groups": [
|
||||
{"name": "ribp", "width": 10, "top_signal": "s_ribp_irq"},
|
||||
{"name": "ribp", "width": 11, "top_signal": "s_ribp_irq"},
|
||||
{"name": "apb", "width": 7, "top_signal": "s_apb_irq"}
|
||||
],
|
||||
"interrupts": [
|
||||
@@ -23,7 +23,8 @@
|
||||
{"name": "rtc", "description": "APB RTC interrupt", "group": "apb", "group_bit": 3, "core_bit": 13, "signal": "u_rtc_if.irq_o"},
|
||||
{"name": "watchdog_reset", "description": "APB watchdog reset request", "group": "apb", "group_bit": 4, "core_bit": 14, "signal": "u_wdg_if.rst_o"},
|
||||
{"name": "advanced_timer", "description": "APB advanced timer interrupt", "group": "apb", "group_bit": 5, "core_bit": 15, "signal": "u_tmr_if.irq_o"},
|
||||
{"name": "reserved", "description": "Reserved interrupt slot", "group": "apb", "group_bit": 6, "core_bit": 16, "signal": "1'b0"}
|
||||
{"name": "reserved", "description": "Reserved interrupt slot", "group": "apb", "group_bit": 6, "core_bit": 16, "signal": "1'b0"},
|
||||
{"name": "ws2812", "description": "WS2812 transmitter interrupt", "group": "ribp", "group_bit": 10, "core_bit": 17, "signal": "ws2812.irq_o"}
|
||||
],
|
||||
"ribp_targets": [
|
||||
{"slot": 0, "name": "uart0", "interface": "u_uart_ribp_if", "regions": ["RIBP_UART0"]},
|
||||
@@ -34,7 +35,7 @@
|
||||
{"slot": 5, "name": "spisd", "interface": "u_spisd_ribp_if", "regions": ["RIBP_SPISD", "SPISD"]},
|
||||
{"slot": 6, "name": "i2c0", "interface": "u_i2c0_ribp_if", "regions": ["RIBP_I2C0"]},
|
||||
{"slot": 7, "name": "i2s", "interface": "u_i2s_ribp_if", "regions": ["RIBP_I2S"]},
|
||||
{"slot": 8, "name": "onewire", "interface": "u_onewire_ribp_if", "regions": ["RIBP_ONEWIRE"]},
|
||||
{"slot": 8, "name": "ws2812", "interface": "u_ws2812_ribp_if", "regions": ["RIBP_WS2812"]},
|
||||
{"slot": 9, "name": "xpi", "interface": "u_xpi_ribp_if", "regions": ["RIBP_XPI", "FLASH", "XPI"]},
|
||||
{"slot": 10, "name": "dma", "interface": "u_dma_ribp_if", "regions": ["RIBP_DMA"]},
|
||||
{"slot": 11, "name": "sysctrl", "interface": "u_sysctrl_ribp_if", "regions": ["RIBP_SYSCTRL"]},
|
||||
@@ -67,7 +68,7 @@
|
||||
"gpio_alt_functions": [
|
||||
{"pin": 0, "alt0": {"inputs": ["u_uart1_if.rx_i"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": ["u_ps2_if.ps2_clk_i"], "do": "1'b0", "oe": "1'b0"}},
|
||||
{"pin": 1, "alt0": {"inputs": [], "do": "u_uart1_if.tx_o", "oe": "1'b1"}, "alt1": {"inputs": ["u_ps2_if.ps2_dat_i"], "do": "1'b0", "oe": "1'b0"}},
|
||||
{"pin": 2, "alt0": {"inputs": ["s_tmr_capch"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": [], "do": "u_onewire_if.dat_o", "oe": "1'b1"}},
|
||||
{"pin": 2, "alt0": {"inputs": ["s_tmr_capch"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": [], "do": "u_ws2812_if.dat_o", "oe": "1'b1"}},
|
||||
{"pin": 3, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[0]", "oe": "1'b1"}, "alt1": {"inputs": ["u_i2c1_if.scl_i"], "do": "u_i2c1_if.scl_o", "oe": "u_i2c1_if.scl_oe_o"}},
|
||||
{"pin": 4, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[1]", "oe": "1'b1"}, "alt1": {"inputs": ["u_i2c1_if.sda_i"], "do": "u_i2c1_if.sda_o", "oe": "u_i2c1_if.sda_oe_o"}},
|
||||
{"pin": 5, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[2]", "oe": "1'b1"}, "alt1": {"inputs": [], "do": "clkdiv4_i", "oe": "1'b1"}},
|
||||
|
||||
+16
-6
@@ -5,8 +5,10 @@ FORMAL_SOLVER := bitwuzla
|
||||
FORMAL_SOLVER_DIR := $(FORMAL_DIR)/bin
|
||||
FORMAL_SOLVER_WRAPPER := $(FORMAL_SOLVER_DIR)/bitwuzla
|
||||
FORMAL_DEPTH ?= 20
|
||||
FORMAL_WS2812_DEPTH ?= 120
|
||||
FORMAL_TIMEOUT ?= 60
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user
|
||||
FORMAL_WS2812_TIMEOUT ?= 120
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user ws2812
|
||||
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
|
||||
@@ -22,6 +24,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(RTL_PATH)/formal/pll_rcu_formal_props.sv \
|
||||
$(RTL_PATH)/formal/gpio_user_formal.sv \
|
||||
$(RTL_PATH)/formal/gpio_user_formal_props.sv \
|
||||
$(RTL_PATH)/formal/ws2812_formal.sv \
|
||||
$(RTL_PATH)/formal/ws2812_formal_props.sv \
|
||||
$(RTL_PATH)/top/bus.sv \
|
||||
$(RTL_PATH)/top/rib_error_slave.sv \
|
||||
$(RTL_PATH)/top/rib_if.sv \
|
||||
@@ -33,6 +37,10 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/gpio.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/pll_ctrl_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/sysctrl.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ws2812_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ws2812_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ws2812_core.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ribp_ws2812.sv \
|
||||
$(RTL_PATH)/top/rcu.sv \
|
||||
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/ribp_if.sv \
|
||||
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/apb4_pure_if.sv \
|
||||
@@ -71,13 +79,13 @@ $(FORMAL_DIR)/%/prove.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_
|
||||
$(FORMAL_SBY_GENERATOR)
|
||||
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
|
||||
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
|
||||
--mode prove --depth $(FORMAL_DEPTH) --output $@
|
||||
--mode prove --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(FORMAL_DEPTH)) --output $@
|
||||
|
||||
$(FORMAL_DIR)/%/cover.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_props.sv \
|
||||
$(FORMAL_SBY_GENERATOR)
|
||||
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
|
||||
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
|
||||
--mode cover --depth $(FORMAL_DEPTH) --output $@
|
||||
--mode cover --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(FORMAL_DEPTH)) --output $@
|
||||
|
||||
$(FORMAL_SOLVER_WRAPPER): $(ROOT_PATH)/scripts/bitwuzla_smt2.py
|
||||
@mkdir -p $(@D)
|
||||
@@ -89,7 +97,7 @@ $(FORMAL_DIR)/%/prove.stamp: $(FORMAL_DIR)/%/prove.sby $(FORMAL_SOLVER_WRAPPER)
|
||||
--log $(@D)/prove.log --result $(@D)/result-prove.json \
|
||||
--env RETROSOC_BITWUZLA=$(FORMAL_BITWUZLA) \
|
||||
--env PATH=$(FORMAL_SOLVER_DIR):$(PATH) \
|
||||
-- timeout --foreground --kill-after=5s $(FORMAL_TIMEOUT)s $(FORMAL_SBY) \
|
||||
-- timeout --foreground --kill-after=5s $(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(FORMAL_TIMEOUT))s $(FORMAL_SBY) \
|
||||
-f -d $(@D)/prove $<
|
||||
@test "$$(awk '{print $$1}' $(@D)/prove/status)" = PASS
|
||||
@touch $@
|
||||
@@ -99,7 +107,7 @@ $(FORMAL_DIR)/%/cover.stamp: $(FORMAL_DIR)/%/cover.sby $(FORMAL_SOLVER_WRAPPER)
|
||||
--log $(@D)/cover.log --result $(@D)/result-cover.json \
|
||||
--env RETROSOC_BITWUZLA=$(FORMAL_BITWUZLA) \
|
||||
--env PATH=$(FORMAL_SOLVER_DIR):$(PATH) \
|
||||
-- timeout --foreground --kill-after=5s $(FORMAL_TIMEOUT)s $(FORMAL_SBY) \
|
||||
-- timeout --foreground --kill-after=5s $(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(FORMAL_TIMEOUT))s $(FORMAL_SBY) \
|
||||
-f -d $(@D)/cover $<
|
||||
@test "$$(awk '{print $$1}' $(@D)/cover/status)" = PASS
|
||||
@touch $@
|
||||
@@ -125,10 +133,12 @@ formal-pll-rcu: $(FORMAL_DIR)/pll_rcu/.stamp | manifest
|
||||
|
||||
formal-gpio-user: $(FORMAL_DIR)/gpio_user/.stamp | manifest
|
||||
|
||||
formal-ws2812: $(FORMAL_DIR)/ws2812/.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-user formal-doctor formal-clean
|
||||
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio-user formal-ws2812 formal-doctor formal-clean
|
||||
@@ -77,7 +77,8 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/hpuart.c \
|
||||
$(ROOT_PATH)/crt/src/hal/ps2.c \
|
||||
$(ROOT_PATH)/crt/src/hal/i2c.c \
|
||||
$(ROOT_PATH)/crt/src/hal/onewire.c \
|
||||
$(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/perf.c \
|
||||
$(ROOT_PATH)/crt/src/hal/lcd.c \
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
"jtag_tdo_o_pad": null,
|
||||
"gpio_0_io_pad": "ps2_clk_i",
|
||||
"gpio_1_io_pad": "ps2_dat_i",
|
||||
"gpio_2_io_pad": "onewire_dat_o",
|
||||
"gpio_2_io_pad": "ws2812_dat_o",
|
||||
"gpio_3_io_pad": "i2c_scl_io",
|
||||
"gpio_4_io_pad": "i2c_sda_io",
|
||||
"gpio_5_io_pad": "pwm_2_o",
|
||||
|
||||
@@ -26,7 +26,7 @@ module ip_ribp_wrapper (
|
||||
spi_if.dut spisd,
|
||||
i2c_if.dut i2c0,
|
||||
i2s_if.dut i2s,
|
||||
onewire_if.dut onewire,
|
||||
ws2812_if.dut ws2812,
|
||||
xpi_if.dut xpi,
|
||||
rib_if.master dma_rib,
|
||||
sysctrl_if.dut sysctrl,
|
||||
@@ -143,11 +143,11 @@ module ip_ribp_wrapper (
|
||||
.i2s (i2s)
|
||||
);
|
||||
|
||||
ribp_onewire u_rib_onewire (
|
||||
ribp_ws2812 u_rib_ws2812 (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (u_onewire_ribp_if),
|
||||
.onewire(onewire)
|
||||
.ribp (u_ws2812_ribp_if),
|
||||
.ws2812 (ws2812)
|
||||
);
|
||||
|
||||
ribp_xpi u_rib_xpi (
|
||||
|
||||
@@ -48,7 +48,7 @@ module retrosoc (
|
||||
spi_if u_spisd_if ();
|
||||
i2c_if u_i2c0_if ();
|
||||
i2s_if u_i2s_if ();
|
||||
onewire_if u_onewire_if ();
|
||||
ws2812_if u_ws2812_if ();
|
||||
sysctrl_if u_sysctrl_if ();
|
||||
dvp_if u_dvp_if ();
|
||||
sdio_if u_sdio_if ();
|
||||
@@ -173,7 +173,7 @@ core_wrapper u_core_wrapper (
|
||||
.spisd (u_spisd_if),
|
||||
.i2c0 (u_i2c0_if),
|
||||
.i2s (u_i2s_if),
|
||||
.onewire (u_onewire_if),
|
||||
.ws2812 (u_ws2812_if),
|
||||
.xpi (xpi),
|
||||
.sysctrl (u_sysctrl_if),
|
||||
.pll_ctrl (pll_ctrl),
|
||||
|
||||
@@ -20,6 +20,7 @@ TEST_SOURCES = (
|
||||
"crt/src/lib/printf.c",
|
||||
"crt/src/lib/stdlib.c",
|
||||
"crt/src/lib/string.c",
|
||||
"crt/src/hal/ws2812_math.c",
|
||||
"app/media/src/video_player.c",
|
||||
"app/media/src/wav_audio.c",
|
||||
"tests/c/test_runtime.c",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <retrosoc/core/wait.h>
|
||||
#include <retrosoc/hal/lcd.h>
|
||||
#include <retrosoc/hal/spisd.h>
|
||||
#include <retrosoc/hal/ws2812.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
#include <retrosoc/lib/stdlib.h>
|
||||
#include <retrosoc/lib/string.h>
|
||||
@@ -152,6 +153,39 @@ static int test_wait_helper(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_ws2812_helpers(void)
|
||||
{
|
||||
const rs_ws2812_config_t config = {
|
||||
72000000U,
|
||||
RS_WS2812_DEFAULT_BIT_PERIOD_NS,
|
||||
RS_WS2812_DEFAULT_T0H_NS,
|
||||
RS_WS2812_DEFAULT_T1H_NS,
|
||||
RS_WS2812_DEFAULT_RESET_NS,
|
||||
4U,
|
||||
};
|
||||
rs_ws2812_config_t invalid = config;
|
||||
rs_ws2812_timing_t timing;
|
||||
|
||||
if ((rs_ws2812_pack_grb(0x12U, 0x34U, 0x56U) != UINT32_C(0x341256)) ||
|
||||
(rs_ws2812_timing_from_ns(&config, &timing) != RS_OK) ||
|
||||
(timing.bit_cycles != 90U) || (timing.t0h_cycles != 25U) ||
|
||||
(timing.t1h_cycles != 50U) || (timing.reset_cycles != 21600U)) {
|
||||
return 1;
|
||||
}
|
||||
invalid.t0h_ns = invalid.t1h_ns;
|
||||
if ((rs_ws2812_timing_from_ns(&invalid, &timing) != RS_EINVAL) ||
|
||||
(rs_ws2812_timing_from_ns(NULL, &timing) != RS_EINVAL) ||
|
||||
(rs_ws2812_timing_from_ns(&config, NULL) != RS_EINVAL)) {
|
||||
return 2;
|
||||
}
|
||||
invalid = config;
|
||||
invalid.source_clock_hz = 1U;
|
||||
if (rs_ws2812_timing_from_ns(&invalid, &timing) != RS_EINVAL) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_wav_parser(void)
|
||||
{
|
||||
static const uint8_t wav[] = {
|
||||
@@ -200,6 +234,7 @@ int main(void)
|
||||
test_formatter(),
|
||||
test_compiler_helpers(),
|
||||
test_wait_helper(),
|
||||
test_ws2812_helpers(),
|
||||
test_wav_parser(),
|
||||
test_video_parser(),
|
||||
};
|
||||
|
||||
@@ -87,7 +87,7 @@ module ribp_topology_tb;
|
||||
u_spisd_ribp_if.ready = 1'b1;
|
||||
u_i2c0_ribp_if.ready = 1'b1;
|
||||
u_i2s_ribp_if.ready = 1'b1;
|
||||
u_onewire_ribp_if.ready = 1'b1;
|
||||
u_ws2812_ribp_if.ready = 1'b1;
|
||||
u_xpi_ribp_if.ready = 1'b1;
|
||||
u_dma_ribp_if.ready = 1'b1;
|
||||
u_sysctrl_ribp_if.ready = 1'b1;
|
||||
@@ -106,7 +106,7 @@ module ribp_topology_tb;
|
||||
u_spisd_ribp_if.rdata = 32'h5555_5555;
|
||||
u_i2c0_ribp_if.rdata = 32'h6666_6666;
|
||||
u_i2s_ribp_if.rdata = 32'h7777_7777;
|
||||
u_onewire_ribp_if.rdata = 32'h8888_8888;
|
||||
u_ws2812_ribp_if.rdata = 32'h8888_8888;
|
||||
u_xpi_ribp_if.rdata = 32'h9999_9999;
|
||||
u_dma_ribp_if.rdata = 32'hAAAA_AAAA;
|
||||
u_sysctrl_ribp_if.rdata = 32'hBBBB_BBBB;
|
||||
@@ -125,7 +125,7 @@ module ribp_topology_tb;
|
||||
u_spisd_ribp_if.resp_err = 1'b0;
|
||||
u_i2c0_ribp_if.resp_err = 1'b0;
|
||||
u_i2s_ribp_if.resp_err = 1'b0;
|
||||
u_onewire_ribp_if.resp_err = 1'b0;
|
||||
u_ws2812_ribp_if.resp_err = 1'b0;
|
||||
u_xpi_ribp_if.resp_err = 1'b0;
|
||||
u_dma_ribp_if.resp_err = 1'b0;
|
||||
u_sysctrl_ribp_if.resp_err = 1'b0;
|
||||
|
||||
@@ -23,13 +23,17 @@ module soc_irq_topology_tb;
|
||||
s_apb_irq = '0;
|
||||
expect_irq('0);
|
||||
|
||||
for (int bit_index = 0; bit_index < `SOC_IRQ_RIBP_WIDTH; bit_index++) begin
|
||||
for (int bit_index = 0; bit_index < 10; bit_index++) begin
|
||||
s_ribp_irq = '0;
|
||||
s_ribp_irq[bit_index] = 1'b1;
|
||||
s_apb_irq = '0;
|
||||
expect_irq(32'd1 << bit_index);
|
||||
end
|
||||
|
||||
s_ribp_irq = '0;
|
||||
s_ribp_irq[10] = 1'b1;
|
||||
expect_irq(32'd1 << 17);
|
||||
|
||||
for (int bit_index = 0; bit_index < `SOC_IRQ_APB_WIDTH; bit_index++) begin
|
||||
s_ribp_irq = '0;
|
||||
s_apb_irq = '0;
|
||||
@@ -37,8 +41,8 @@ module soc_irq_topology_tb;
|
||||
expect_irq(32'd1 << (10 + bit_index));
|
||||
end
|
||||
|
||||
if (s_irq[31:17] !== '0) begin
|
||||
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq[31:17]);
|
||||
if (s_irq[31:18] !== '0) begin
|
||||
$fatal(1, "unallocated core IRQ bits are not low: %h", s_irq[31:18]);
|
||||
end
|
||||
|
||||
$display("SoC topology IRQ routing test passed");
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "rib_defs.svh"
|
||||
`include "ws2812_define.svh"
|
||||
|
||||
module ws2812_dma_tb;
|
||||
localparam logic [31:0] SOURCE_BASE = 32'h4000_0000;
|
||||
localparam logic [31:0] WS2812_TXDATA = 32'h1000_8010;
|
||||
localparam int BIT_CYCLES = 4;
|
||||
localparam int T0H_CYCLES = 1;
|
||||
localparam int T1H_CYCLES = 3;
|
||||
localparam int RESET_CYCLES = 5;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
BUS_IDLE,
|
||||
BUS_READ_RESP,
|
||||
BUS_WRITE_DATA,
|
||||
BUS_WRITE_RESP
|
||||
} bus_state_t;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic dma_start = 1'b0;
|
||||
logic dma_done;
|
||||
logic dma_error;
|
||||
logic [ 2:0] dma_error_code;
|
||||
logic [31:0] dma_error_addr;
|
||||
logic [ 1:0] dma_fsm;
|
||||
logic host_active = 1'b1;
|
||||
logic host_valid = 1'b0;
|
||||
logic [31:0] host_addr = '0;
|
||||
logic [31:0] host_wdata = '0;
|
||||
logic [ 3:0] host_wstrb = '0;
|
||||
logic dma_ws_valid;
|
||||
bus_state_t bus_state_q = BUS_IDLE;
|
||||
logic [31:0] bus_addr_q = '0;
|
||||
integer dma_write_count = 0;
|
||||
integer dma_backpressure_cycles = 0;
|
||||
logic [23:0] pixels [0:5];
|
||||
integer observed_pixel = 0;
|
||||
integer observed_bit = 0;
|
||||
integer observed_cycle = 0;
|
||||
integer reset_low_cycles = 0;
|
||||
|
||||
dma_hw_trg_if hw_trg ();
|
||||
rib_if dma_rib ();
|
||||
ribp_if ws_ribp ();
|
||||
ws2812_if ws2812 ();
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
initial begin
|
||||
repeat (5000) @(posedge clk_i);
|
||||
$fatal(1, "WS2812 DMA integration test timeout");
|
||||
end
|
||||
|
||||
assign ws_ribp.valid = host_active ? host_valid : dma_ws_valid;
|
||||
assign ws_ribp.addr = host_active ? host_addr : bus_addr_q;
|
||||
assign ws_ribp.wdata = host_active ? host_wdata : dma_rib.wdata;
|
||||
assign ws_ribp.wstrb = host_active ? host_wstrb : dma_rib.wstrb;
|
||||
|
||||
assign dma_rib.cmd_ready = bus_state_q == BUS_IDLE;
|
||||
assign dma_rib.w_ready = (bus_state_q == BUS_WRITE_DATA) && ws_ribp.ready;
|
||||
assign dma_rib.rsp_valid = (bus_state_q == BUS_READ_RESP) || (bus_state_q == BUS_WRITE_RESP);
|
||||
assign dma_rib.rdata = pixels[bus_addr_q[4:2]];
|
||||
assign dma_rib.resp_err = 1'b0;
|
||||
assign dma_rib.resp_code = `RIB_RESP_OK;
|
||||
assign dma_rib.rsp_beat = 2'd0;
|
||||
assign dma_rib.rsp_last = 1'b1;
|
||||
assign dma_ws_valid = (bus_state_q == BUS_WRITE_DATA) && dma_rib.w_valid;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
bus_state_q <= BUS_IDLE;
|
||||
bus_addr_q <= '0;
|
||||
dma_write_count <= 0;
|
||||
dma_backpressure_cycles <= 0;
|
||||
end else begin
|
||||
if ((bus_state_q == BUS_WRITE_DATA) && dma_rib.w_valid && !dma_rib.w_ready) begin
|
||||
dma_backpressure_cycles <= dma_backpressure_cycles + 1;
|
||||
end
|
||||
unique case (bus_state_q)
|
||||
BUS_IDLE: begin
|
||||
if (dma_rib.cmd_valid && dma_rib.cmd_ready) begin
|
||||
bus_addr_q <= dma_rib.cmd_addr;
|
||||
if (dma_rib.cmd_len != `RIB_LEN_INCR1) begin
|
||||
$fatal(1, "fixed-destination WS2812 DMA transfer used a burst");
|
||||
end
|
||||
if (dma_rib.cmd_write) begin
|
||||
if (dma_rib.cmd_addr != WS2812_TXDATA) begin
|
||||
$fatal(1, "DMA wrote unexpected destination %h", dma_rib.cmd_addr);
|
||||
end
|
||||
bus_state_q <= BUS_WRITE_DATA;
|
||||
end else begin
|
||||
if ((dma_rib.cmd_addr < (SOURCE_BASE + 32'd4)) ||
|
||||
(dma_rib.cmd_addr > (SOURCE_BASE + 32'd20))) begin
|
||||
$fatal(1, "DMA read unexpected source %h", dma_rib.cmd_addr);
|
||||
end
|
||||
bus_state_q <= BUS_READ_RESP;
|
||||
end
|
||||
end
|
||||
end
|
||||
BUS_READ_RESP: begin
|
||||
if (dma_rib.rsp_valid && dma_rib.rsp_ready) begin
|
||||
bus_state_q <= BUS_IDLE;
|
||||
end
|
||||
end
|
||||
BUS_WRITE_DATA: begin
|
||||
if (dma_rib.w_valid && dma_rib.w_ready) begin
|
||||
if (!dma_rib.wlast) begin
|
||||
$fatal(1, "INCR1 WS2812 write did not assert wlast");
|
||||
end
|
||||
dma_write_count <= dma_write_count + 1;
|
||||
bus_state_q <= BUS_WRITE_RESP;
|
||||
end
|
||||
end
|
||||
BUS_WRITE_RESP: begin
|
||||
if (dma_rib.rsp_valid && dma_rib.rsp_ready) begin
|
||||
bus_state_q <= BUS_IDLE;
|
||||
end
|
||||
end
|
||||
default: bus_state_q <= BUS_IDLE;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
dma_core u_dma_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.mode_i (3'd0),
|
||||
.srcaddr_i (SOURCE_BASE + 32'd4),
|
||||
.srcincr_i (1'b1),
|
||||
.dstaddr_i (WS2812_TXDATA),
|
||||
.dstincr_i (1'b0),
|
||||
.xferlen_i (32'd5),
|
||||
.start_i (dma_start),
|
||||
.stop_i (1'b0),
|
||||
.reset_i (1'b0),
|
||||
.done_o (dma_done),
|
||||
.error_o (dma_error),
|
||||
.error_code_o(dma_error_code),
|
||||
.error_addr_o(dma_error_addr),
|
||||
.fsm_o (dma_fsm),
|
||||
.hw_trg (hw_trg),
|
||||
.rib (dma_rib)
|
||||
);
|
||||
|
||||
ribp_ws2812 #(
|
||||
.TX_FIFO_DEPTH(4)
|
||||
) u_ws2812 (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (ws_ribp),
|
||||
.ws2812 (ws2812)
|
||||
);
|
||||
|
||||
task automatic host_write(input logic [31:0] address, input logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
host_addr = address;
|
||||
host_wdata = data;
|
||||
host_wstrb = 4'hF;
|
||||
host_valid = 1'b1;
|
||||
while (!ws_ribp.ready) begin
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
if (ws_ribp.resp_err) begin
|
||||
$fatal(1, "host write %h failed", address);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
host_valid = 1'b0;
|
||||
host_wstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
#1;
|
||||
if (rst_n_i && u_ws2812.s_busy && !u_ws2812.s_reset_active) begin
|
||||
integer high_cycles;
|
||||
logic expected_data;
|
||||
high_cycles = pixels[observed_pixel][23-observed_bit] ? T1H_CYCLES : T0H_CYCLES;
|
||||
expected_data = observed_cycle < high_cycles;
|
||||
if (ws2812.dat_o !== expected_data) begin
|
||||
$fatal(1, "DMA waveform mismatch pixel=%0d bit=%0d cycle=%0d", observed_pixel,
|
||||
observed_bit, observed_cycle);
|
||||
end
|
||||
observed_cycle = observed_cycle + 1;
|
||||
if (observed_cycle == BIT_CYCLES) begin
|
||||
observed_cycle = 0;
|
||||
observed_bit = observed_bit + 1;
|
||||
if (observed_bit == 24) begin
|
||||
observed_bit = 0;
|
||||
observed_pixel = observed_pixel + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (rst_n_i && u_ws2812.s_reset_active) begin
|
||||
if (ws2812.dat_o !== 1'b0) begin
|
||||
$fatal(1, "DMA frame reset interval drove the output high");
|
||||
end
|
||||
reset_low_cycles = reset_low_cycles + 1;
|
||||
end
|
||||
if (dma_error) begin
|
||||
$fatal(1, "DMA failed code=%0d address=%h", dma_error_code, dma_error_addr);
|
||||
end
|
||||
end
|
||||
|
||||
initial begin
|
||||
pixels[0] = 24'h800001;
|
||||
pixels[1] = 24'h010203;
|
||||
pixels[2] = 24'hA5A5A5;
|
||||
pixels[3] = 24'h5A5A5A;
|
||||
pixels[4] = 24'hFFFFFF;
|
||||
pixels[5] = 24'h000000;
|
||||
hw_trg.i2s_tx_proc = 1'b0;
|
||||
hw_trg.i2s_rx_proc = 1'b0;
|
||||
hw_trg.qspi_tx_proc = 1'b0;
|
||||
hw_trg.qspi_rx_proc = 1'b0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
host_write(`RIBP_WS2812_BIT_CYCLES, BIT_CYCLES);
|
||||
host_write(`RIBP_WS2812_T0H_CYCLES, T0H_CYCLES);
|
||||
host_write(`RIBP_WS2812_T1H_CYCLES, T1H_CYCLES);
|
||||
host_write(`RIBP_WS2812_RESET_CYCLES, RESET_CYCLES);
|
||||
host_write(`RIBP_WS2812_FIFO_WATERMARK, 3);
|
||||
host_write(`RIBP_WS2812_INTR_ENABLE, 1);
|
||||
host_write(`RIBP_WS2812_TXDATA, pixels[0]);
|
||||
host_write(`RIBP_WS2812_FRAME_WORDS, 6);
|
||||
host_write(`RIBP_WS2812_CTRL, 1);
|
||||
|
||||
host_active = 1'b0;
|
||||
@(negedge clk_i);
|
||||
dma_start = 1'b1;
|
||||
@(negedge clk_i);
|
||||
dma_start = 1'b0;
|
||||
|
||||
wait (dma_done);
|
||||
wait (!u_ws2812.s_busy);
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (dma_write_count != 5) begin
|
||||
$fatal(1, "DMA completed %0d WS2812 writes, expected 5", dma_write_count);
|
||||
end
|
||||
if (dma_backpressure_cycles < 40) begin
|
||||
$fatal(1, "DMA did not observe full-FIFO backpressure: %0d cycles", dma_backpressure_cycles);
|
||||
end
|
||||
if ((observed_pixel != 6) || (reset_low_cycles < RESET_CYCLES) || !ws2812.irq_o) begin
|
||||
$fatal(1, "DMA frame did not complete pixels=%0d reset=%0d irq=%b", observed_pixel,
|
||||
reset_low_cycles, ws2812.irq_o);
|
||||
end
|
||||
|
||||
$display("WS2812 DMA backpressure integration test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,298 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "ws2812_define.svh"
|
||||
|
||||
module ws2812_tb;
|
||||
localparam int FIFO_DEPTH = 4;
|
||||
localparam int BIT_CYCLES = 4;
|
||||
localparam int T0H_CYCLES = 1;
|
||||
localparam int T1H_CYCLES = 3;
|
||||
localparam int RESET_CYCLES = 5;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
ribp_if ribp ();
|
||||
ws2812_if ws2812 ();
|
||||
|
||||
logic monitor_enable = 1'b0;
|
||||
logic [23:0] expected_pixels [0:7];
|
||||
integer expected_pixel_count = 0;
|
||||
integer observed_pixel = 0;
|
||||
integer observed_bit = 0;
|
||||
integer observed_cycle = 0;
|
||||
integer expected_bit_cycles = BIT_CYCLES;
|
||||
integer expected_t0h_cycles = T0H_CYCLES;
|
||||
integer expected_t1h_cycles = T1H_CYCLES;
|
||||
integer reset_low_cycles = 0;
|
||||
integer test_stage = 0;
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
initial begin
|
||||
repeat (10000) @(posedge clk_i);
|
||||
$fatal(1, "WS2812 test timeout at stage %0d state=%0d valid=%b ready=%b", test_stage,
|
||||
u_dut.u_ws2812_core.s_state_q, ribp.valid, ribp.ready);
|
||||
end
|
||||
|
||||
ribp_ws2812 #(
|
||||
.TX_FIFO_DEPTH(FIFO_DEPTH)
|
||||
) u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (ribp),
|
||||
.ws2812 (ws2812)
|
||||
);
|
||||
|
||||
task automatic ribp_write(input logic [31:0] address, input logic [31:0] data,
|
||||
input logic [3:0] strobe, input logic expected_error,
|
||||
output integer wait_cycles);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.addr = address;
|
||||
ribp.wdata = data;
|
||||
ribp.wstrb = strobe;
|
||||
ribp.valid = 1'b1;
|
||||
wait_cycles = 0;
|
||||
while (!ribp.ready) begin
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
wait_cycles = wait_cycles + 1;
|
||||
end
|
||||
if (ribp.resp_err !== expected_error) begin
|
||||
$fatal(1, "write %h error=%b expected=%b", address, ribp.resp_err, expected_error);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
ribp.wstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic ribp_read(input logic [31:0] address, input logic expected_error,
|
||||
output logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.addr = address;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
ribp.valid = 1'b1;
|
||||
while (!ribp.ready) begin
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
if (ribp.resp_err !== expected_error) begin
|
||||
$fatal(1, "read %h error=%b expected=%b", address, ribp.resp_err, expected_error);
|
||||
end
|
||||
data = ribp.rdata;
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic write_ok(input logic [31:0] address, input logic [31:0] data);
|
||||
integer ignored_wait;
|
||||
begin
|
||||
ribp_write(address, data, 4'hF, 1'b0, ignored_wait);
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic wait_until_idle;
|
||||
logic [31:0] status;
|
||||
begin
|
||||
status = 32'h1;
|
||||
while (status[`WS2812_STATUS_BUSY]) begin
|
||||
ribp_read(`RIBP_WS2812_STATUS, 1'b0, status);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic configure_timing;
|
||||
begin
|
||||
write_ok(`RIBP_WS2812_BIT_CYCLES, BIT_CYCLES);
|
||||
write_ok(`RIBP_WS2812_T0H_CYCLES, T0H_CYCLES);
|
||||
write_ok(`RIBP_WS2812_T1H_CYCLES, T1H_CYCLES);
|
||||
write_ok(`RIBP_WS2812_RESET_CYCLES, RESET_CYCLES);
|
||||
write_ok(`RIBP_WS2812_FIFO_WATERMARK, 3);
|
||||
write_ok(`RIBP_WS2812_INTR_ENABLE, 4'hF);
|
||||
end
|
||||
endtask
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
#1;
|
||||
if (!rst_n_i && ws2812.dat_o !== 1'b0) begin
|
||||
$fatal(1, "WS2812 output is not low during reset");
|
||||
end
|
||||
if (monitor_enable && u_dut.s_busy && !u_dut.s_reset_active) begin
|
||||
integer high_cycles;
|
||||
logic expected_data;
|
||||
high_cycles = expected_pixels[observed_pixel][23-observed_bit] ? expected_t1h_cycles :
|
||||
expected_t0h_cycles;
|
||||
expected_data = observed_cycle < high_cycles;
|
||||
if (ws2812.dat_o !== expected_data) begin
|
||||
$fatal(1, "waveform mismatch pixel=%0d bit=%0d cycle=%0d", observed_pixel, observed_bit,
|
||||
observed_cycle);
|
||||
end
|
||||
observed_cycle = observed_cycle + 1;
|
||||
if (observed_cycle == expected_bit_cycles) begin
|
||||
observed_cycle = 0;
|
||||
observed_bit = observed_bit + 1;
|
||||
if (observed_bit == 24) begin
|
||||
observed_bit = 0;
|
||||
observed_pixel = observed_pixel + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (monitor_enable && u_dut.s_reset_active) begin
|
||||
if (ws2812.dat_o !== 1'b0) begin
|
||||
$fatal(1, "WS2812 output is high during latch/reset");
|
||||
end
|
||||
reset_low_cycles = reset_low_cycles + 1;
|
||||
end
|
||||
end
|
||||
|
||||
task automatic begin_monitor(input integer pixel_count);
|
||||
begin
|
||||
observed_pixel = 0;
|
||||
observed_bit = 0;
|
||||
observed_cycle = 0;
|
||||
reset_low_cycles = 0;
|
||||
expected_pixel_count = pixel_count;
|
||||
monitor_enable = 1'b1;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic end_monitor(input logic expect_complete_frame);
|
||||
begin
|
||||
monitor_enable = 1'b0;
|
||||
if (expect_complete_frame && observed_pixel != expected_pixel_count) begin
|
||||
$fatal(1, "observed %0d pixels, expected %0d", observed_pixel, expected_pixel_count);
|
||||
end
|
||||
if (reset_low_cycles < RESET_CYCLES) begin
|
||||
$fatal(1, "latch/reset low interval was only %0d cycles", reset_low_cycles);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
logic [31:0] value;
|
||||
integer wait_cycles;
|
||||
|
||||
ribp.valid = 1'b0;
|
||||
ribp.addr = '0;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
test_stage = 1;
|
||||
ribp_read(`RIBP_WS2812_IP_INFO, 1'b0, value);
|
||||
if (value !== 32'h1804_0100) begin
|
||||
$fatal(1, "unexpected IP_INFO %h", value);
|
||||
end
|
||||
ribp_read(`RIBP_WS2812_STATUS, 1'b0, value);
|
||||
if (value[`WS2812_STATUS_CONFIG_VALID] || !value[`WS2812_STATUS_FIFO_EMPTY]) begin
|
||||
$fatal(1, "unexpected reset status %h", value);
|
||||
end
|
||||
ribp_read(`RIBP_WS2812_CTRL, 1'b1, value);
|
||||
ribp_write(8'h02, 32'd1, 4'hF, 1'b1, wait_cycles);
|
||||
ribp_read(32'h00000100, 1'b1, value);
|
||||
ribp_write(`RIBP_WS2812_TXDATA, 24'h112233, 4'h7, 1'b1, wait_cycles);
|
||||
write_ok(`RIBP_WS2812_TXDATA, 24'h112233);
|
||||
write_ok(`RIBP_WS2812_FRAME_WORDS, 1);
|
||||
ribp_write(`RIBP_WS2812_CTRL, 32'h1, 4'hF, 1'b1, wait_cycles);
|
||||
ribp_read(`RIBP_WS2812_ERROR_STATUS, 1'b0, value);
|
||||
if (!value[`WS2812_ERROR_CONFIG]) begin
|
||||
$fatal(1, "invalid timing did not set CONFIG error");
|
||||
end
|
||||
write_ok(`RIBP_WS2812_ERROR_STATUS, 32'h7);
|
||||
write_ok(`RIBP_WS2812_CTRL, 32'h4);
|
||||
|
||||
configure_timing();
|
||||
ribp_read(`RIBP_WS2812_STATUS, 1'b0, value);
|
||||
if (!value[`WS2812_STATUS_CONFIG_VALID]) begin
|
||||
$fatal(1, "legal timing was not accepted");
|
||||
end
|
||||
|
||||
test_stage = 2;
|
||||
for (integer index = 0; index < FIFO_DEPTH; index = index + 1) begin
|
||||
write_ok(`RIBP_WS2812_TXDATA, index);
|
||||
end
|
||||
ribp_write(`RIBP_WS2812_TXDATA, 32'h55, 4'hF, 1'b1, wait_cycles);
|
||||
write_ok(`RIBP_WS2812_CTRL, 32'h4);
|
||||
write_ok(`RIBP_WS2812_ERROR_STATUS, 32'h7);
|
||||
write_ok(`RIBP_WS2812_INTR_STATE, 32'hF);
|
||||
|
||||
test_stage = 3;
|
||||
expected_pixels[0] = 24'h800001;
|
||||
expected_pixels[1] = 24'h010203;
|
||||
expected_pixels[2] = 24'hA5A5A5;
|
||||
expected_pixels[3] = 24'h5A5A5A;
|
||||
expected_pixels[4] = 24'hFFFFFF;
|
||||
expected_pixels[5] = 24'h000000;
|
||||
for (integer index = 0; index < FIFO_DEPTH; index = index + 1) begin
|
||||
write_ok(`RIBP_WS2812_TXDATA, expected_pixels[index]);
|
||||
end
|
||||
write_ok(`RIBP_WS2812_FRAME_WORDS, 6);
|
||||
begin_monitor(6);
|
||||
write_ok(`RIBP_WS2812_CTRL, 32'h1);
|
||||
write_ok(`RIBP_WS2812_TXDATA, expected_pixels[4]);
|
||||
ribp_write(`RIBP_WS2812_TXDATA, expected_pixels[5], 4'hF, 1'b0, wait_cycles);
|
||||
if (wait_cycles < (BIT_CYCLES * 20)) begin
|
||||
$fatal(1, "full FIFO write was not backpressured: %0d cycles", wait_cycles);
|
||||
end
|
||||
wait_until_idle();
|
||||
end_monitor(1'b1);
|
||||
ribp_read(`RIBP_WS2812_INTR_STATE, 1'b0, value);
|
||||
if ((value & 32'h3) != 32'h3 || !ws2812.irq_o) begin
|
||||
$fatal(1, "done/low-watermark interrupt missing: %h", value);
|
||||
end
|
||||
write_ok(`RIBP_WS2812_INTR_STATE, 32'hF);
|
||||
if (ws2812.irq_o) begin
|
||||
$fatal(1, "IRQ did not clear");
|
||||
end
|
||||
|
||||
test_stage = 4;
|
||||
expected_pixels[0] = 24'h123456;
|
||||
write_ok(`RIBP_WS2812_TXDATA, expected_pixels[0]);
|
||||
write_ok(`RIBP_WS2812_FRAME_WORDS, 2);
|
||||
begin_monitor(1);
|
||||
write_ok(`RIBP_WS2812_CTRL, 32'h1);
|
||||
wait_until_idle();
|
||||
end_monitor(1'b1);
|
||||
ribp_read(`RIBP_WS2812_ERROR_STATUS, 1'b0, value);
|
||||
if (!value[`WS2812_ERROR_UNDERFLOW]) begin
|
||||
$fatal(1, "underflow was not reported");
|
||||
end
|
||||
ribp_read(`RIBP_WS2812_FIFO_LEVEL, 1'b0, value);
|
||||
if (value != 0) begin
|
||||
$fatal(1, "underflow did not flush FIFO");
|
||||
end
|
||||
write_ok(`RIBP_WS2812_ERROR_STATUS, 32'h7);
|
||||
write_ok(`RIBP_WS2812_INTR_STATE, 32'hF);
|
||||
|
||||
test_stage = 5;
|
||||
expected_pixels[0] = 24'hABCDEF;
|
||||
expected_pixels[1] = 24'h765432;
|
||||
write_ok(`RIBP_WS2812_TXDATA, expected_pixels[0]);
|
||||
write_ok(`RIBP_WS2812_TXDATA, expected_pixels[1]);
|
||||
write_ok(`RIBP_WS2812_FRAME_WORDS, 2);
|
||||
begin_monitor(2);
|
||||
write_ok(`RIBP_WS2812_CTRL, 32'h1);
|
||||
repeat (8) @(posedge clk_i);
|
||||
write_ok(`RIBP_WS2812_CTRL, 32'h2);
|
||||
wait_until_idle();
|
||||
end_monitor(1'b0);
|
||||
ribp_read(`RIBP_WS2812_INTR_STATE, 1'b0, value);
|
||||
if (!value[`WS2812_INTR_ABORTED]) begin
|
||||
$fatal(1, "abort completion was not reported");
|
||||
end
|
||||
|
||||
write_ok(`RIBP_WS2812_INTR_TEST, 32'h1);
|
||||
if (!ws2812.irq_o) begin
|
||||
$fatal(1, "interrupt test did not assert IRQ");
|
||||
end
|
||||
write_ok(`RIBP_WS2812_INTR_STATE, 32'hF);
|
||||
|
||||
$display("WS2812 register, waveform, streaming, and error test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -204,6 +204,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
sysctrl_filelist = tmp_path / "sysctrl.fl"
|
||||
pll_rcu_filelist = tmp_path / "pll_rcu.fl"
|
||||
gpio_user_filelist = tmp_path / "gpio_user.fl"
|
||||
ws2812_filelist = tmp_path / "ws2812.fl"
|
||||
assert generate_formal_filelist("bus", bus_filelist, memory_map, topology, user_extensions)
|
||||
assert generate_formal_filelist(
|
||||
"rib_adapter", rib_adapter_filelist, memory_map, topology, user_extensions
|
||||
@@ -220,6 +221,9 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
assert generate_formal_filelist(
|
||||
"gpio_user", gpio_user_filelist, memory_map, topology, user_extensions
|
||||
)
|
||||
assert generate_formal_filelist(
|
||||
"ws2812", ws2812_filelist, memory_map, topology, user_extensions
|
||||
)
|
||||
|
||||
bus = parse_filelists([bus_filelist], require_files=False)
|
||||
rib_adapter = parse_filelists([rib_adapter_filelist], require_files=False)
|
||||
@@ -227,6 +231,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
sysctrl = parse_filelists([sysctrl_filelist], require_files=False)
|
||||
pll_rcu = parse_filelists([pll_rcu_filelist], require_files=False)
|
||||
gpio_user = parse_filelists([gpio_user_filelist], require_files=False)
|
||||
ws2812 = parse_filelists([ws2812_filelist], require_files=False)
|
||||
assert "+define+SV_ASSRT_DISABLE" in bus.defines
|
||||
assert ROOT / "rtl/mini/top/bus.sv" in bus.files
|
||||
assert ROOT / "rtl/mini/top/rib_if.sv" in bus.files
|
||||
@@ -246,6 +251,9 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/gpio.sv" in gpio_user.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv" in gpio_user.files
|
||||
assert ROOT / "rtl/mini/formal/gpio_user_formal.sv" in gpio_user.files
|
||||
assert ROOT / "rtl/ip/ribp/serial/ribp_ws2812.sv" in ws2812.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv" in ws2812.files
|
||||
assert ROOT / "rtl/mini/formal/ws2812_formal.sv" in ws2812.files
|
||||
|
||||
|
||||
def test_sysctrl_formal_properties_use_exported_user_core_shape() -> None:
|
||||
@@ -291,7 +299,7 @@ def test_fatfs_release_script_uses_the_locked_archive_contract() -> None:
|
||||
|
||||
|
||||
def test_formal_result_summary_requires_every_passing_step(tmp_path: Path) -> None:
|
||||
proofs = ("bus", "rib2apb", "sysctrl", "pll_rcu", "gpio_user")
|
||||
proofs = ("bus", "rib2apb", "sysctrl", "pll_rcu", "gpio_user", "ws2812")
|
||||
for proof in proofs:
|
||||
directory = tmp_path / proof
|
||||
directory.mkdir()
|
||||
@@ -320,6 +328,8 @@ def test_formal_result_summary_requires_every_passing_step(tmp_path: Path) -> No
|
||||
f"pll_rcu={tmp_path / 'pll_rcu'}",
|
||||
"--proof",
|
||||
f"gpio_user={tmp_path / 'gpio_user'}",
|
||||
"--proof",
|
||||
f"ws2812={tmp_path / 'ws2812'}",
|
||||
)
|
||||
result = json.loads(output.read_text(encoding="utf-8"))
|
||||
assert result["status"] == "passed"
|
||||
|
||||
@@ -83,6 +83,7 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert "assign u_sdio_ribp_if.valid = 1'b0;" in routes
|
||||
assert gpio.count("// GPIO") == 64
|
||||
assert "assign u_uart1_if.rx_i = u_gpio_if.di_i[0];" in gpio
|
||||
assert "assign u_gpio_if.alt1_do_i[2] = u_ws2812_if.dat_o;" in gpio
|
||||
assert "assign u_gpio_if.alt1_do_i[22] = u_psram_if.nss_o[0];" in gpio
|
||||
assert apb_interfaces.count("apb4_if u_") == 10
|
||||
assert "apb4_pure_if u_archinfo_apb_pure_if ();" in apb_interfaces
|
||||
@@ -96,9 +97,10 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert ".apb_rib(u_apb_rib_if)" in bus_fabric
|
||||
assert ".rib(u_rib_if)" in bus_fabric
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 10" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 11" in irq_config
|
||||
assert "`define SOC_IRQ_APB_WIDTH 7" in irq_config
|
||||
assert "assign irq_o[0] = u_clint_if.sfr_irq_o;" in rib_irq
|
||||
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
|
||||
assert "assign irq_o[5] = u_tmr_if.irq_o;" in apb_irq
|
||||
assert "s_irq[16] = s_apb_irq[6];" in irq_wiring
|
||||
assert "irq_i[31] == 1'b0" in irq_sva
|
||||
@@ -119,7 +121,7 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
)
|
||||
for interrupt in document["interrupts"]
|
||||
]
|
||||
assert mappings[:17] == [
|
||||
assert mappings[:18] == [
|
||||
("clint_software", "ribp", 0, 0, "u_clint_if.sfr_irq_o"),
|
||||
("clint_timer", "ribp", 1, 1, "u_clint_if.tmr_irq_o"),
|
||||
("uart0", "ribp", 2, 2, "uart.irq_o"),
|
||||
@@ -137,8 +139,9 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("watchdog_reset", "apb", 4, 14, "u_wdg_if.rst_o"),
|
||||
("advanced_timer", "apb", 5, 15, "u_tmr_if.irq_o"),
|
||||
("reserved", "apb", 6, 16, "1'b0"),
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
]
|
||||
assert all(mapping[3] >= 17 for mapping in mappings[17:])
|
||||
assert all(mapping[3] >= 18 for mapping in mappings[18:])
|
||||
|
||||
|
||||
def test_topology_always_adds_the_user_apb_target(tmp_path: Path) -> None:
|
||||
@@ -249,7 +252,7 @@ def test_topology_rejects_invalid_irq_groups_and_bindings(tmp_path: Path) -> Non
|
||||
assert "core interrupt bit 0 is duplicated" in result.stderr
|
||||
|
||||
document = json.loads(TOPOLOGY.read_text(encoding="utf-8"))
|
||||
document["interrupts"].pop()
|
||||
document["interrupts"].pop(16)
|
||||
result = validate(write_invalid_topology(tmp_path, document))
|
||||
assert result.returncode != 0
|
||||
assert "interrupt group apb does not cover every group bit" in result.stderr
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
"""WS2812 register, waveform, and streaming regression tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_ws2812_register_waveform_streaming_and_errors(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"
|
||||
serial = ROOT / "rtl/ip/ribp/serial"
|
||||
source_list = tmp_path / "ws2812.fl"
|
||||
source_list.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
f"+incdir+{common}",
|
||||
f"+incdir+{common / 'interface'}",
|
||||
f"+incdir+{common / 'utils'}",
|
||||
f"+incdir+{serial}",
|
||||
str(common / "interface/ribp_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(common / "utils/fifo.sv"),
|
||||
str(serial / "ws2812_if.sv"),
|
||||
str(serial / "ws2812_reg.sv"),
|
||||
str(serial / "ws2812_core.sv"),
|
||||
str(serial / "ribp_ws2812.sv"),
|
||||
str(ROOT / "tests/rtl/ws2812_tb.sv"),
|
||||
"",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
converted = tmp_path / "ws2812_tb.v"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
||||
"-f",
|
||||
str(source_list),
|
||||
"--output",
|
||||
str(converted),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
simulation = tmp_path / "ws2812_tb"
|
||||
subprocess.run(
|
||||
[iverilog, "-g2012", "-s", "ws2812_tb", "-o", str(simulation), str(converted)],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
assert "WS2812 register, waveform, streaming, and error test passed" in result.stdout
|
||||
|
||||
|
||||
def test_ws2812_accepts_dma_fixed_destination_backpressure(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or vvp is None:
|
||||
return
|
||||
|
||||
memory_map = tmp_path / "memory_map"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(ROOT / "rtl/mini/address_map/generate_memory_map.py"),
|
||||
"--map",
|
||||
str(ROOT / "rtl/mini/address_map/memory_map.json"),
|
||||
"--output-dir",
|
||||
str(memory_map),
|
||||
"--have-sram-if",
|
||||
"NO",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||
serial = ROOT / "rtl/ip/ribp/serial"
|
||||
source_list = tmp_path / "ws2812_dma.fl"
|
||||
source_list.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
f"+incdir+{memory_map / 'rtl'}",
|
||||
f"+incdir+{common}",
|
||||
f"+incdir+{common / 'interface'}",
|
||||
f"+incdir+{common / 'utils'}",
|
||||
f"+incdir+{ROOT / 'rtl/mini/top'}",
|
||||
f"+incdir+{serial}",
|
||||
str(common / "interface/ribp_if.sv"),
|
||||
str(ROOT / "rtl/mini/top/rib_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(common / "utils/fifo.sv"),
|
||||
str(ROOT / "rtl/ip/ribp/peripheral/dma.sv"),
|
||||
str(ROOT / "rtl/ip/ribp/peripheral/dma_core.sv"),
|
||||
str(serial / "ws2812_if.sv"),
|
||||
str(serial / "ws2812_reg.sv"),
|
||||
str(serial / "ws2812_core.sv"),
|
||||
str(serial / "ribp_ws2812.sv"),
|
||||
str(ROOT / "tests/rtl/ws2812_dma_tb.sv"),
|
||||
"",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
converted = tmp_path / "ws2812_dma_tb.v"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
||||
"-f",
|
||||
str(source_list),
|
||||
"--output",
|
||||
str(converted),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
simulation = tmp_path / "ws2812_dma_tb"
|
||||
subprocess.run(
|
||||
[iverilog, "-g2012", "-s", "ws2812_dma_tb", "-o", str(simulation), str(converted)],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
assert "WS2812 DMA backpressure integration test passed" in result.stdout
|
||||
Reference in new issue
Block a user