feat: add UART V2 support with formal verification and test cases

- Updated filelist to include new UART source files.
- Enhanced formal file generation script to support UART target.
- Introduced formal verification module and properties for UART.
- Modified makefiles to include UART in formal targets and source files.
- Added UART-related source files to software build.
- Updated top-level wrapper to integrate UART DMA signals.
- Implemented UART testbench for comprehensive testing of functionality.
- Created Python test script for UART V2 register, FIFO, and interrupt tests.
- Added UART helper functions in C test runtime.
- Updated DMA error testbench to handle UART signals.
- Ensured WS2812 DMA testbench accommodates UART signals.
This commit is contained in:
maksyuki committed 2026-08-08 23:10:56 +08:00
1 parent d517ce0fea
commit 0130825057
44 files changed
+2591 -446

No files matched your search

+2 -2
View File
@@ -252,7 +252,7 @@ endif
benchmark-report coremark-report \
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-timer formal-clean formal-doctor
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-timer formal-clean formal-doctor
.NOTPARALLEL: setup
help:
@@ -280,7 +280,7 @@ help:
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
' formal | formal-bus | formal-rib-adapter | formal-rib2apb run SBY protocol proofs' \
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-timer | formal-clint run peripheral proofs' \
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-timer | formal-clint 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' \
+3 -1
View File
@@ -227,7 +227,9 @@ int main(void) {
uint64_t cycle_start;
uint64_t cycles;
uart0_init(CPU_FREQ, UART_BPS);
if (rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) != RS_OK) {
rs_test_finish(RS_TEST_FAILED, 5U);
}
rs_benchmark_puts("retroSoC: A Customized ASIC for Retro Stuff\n");
if (!rs_benchmark_memory("sram", sram, RS_BENCHMARK_SRAM_SEED)) {
+3 -1
View File
@@ -5,7 +5,9 @@
#include <retrosoc/service/test.h>
int main(void) {
uart0_init(CPU_FREQ, UART_BPS);
if (rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) != RS_OK) {
return 1;
}
rs_app_info();
ip_archinfo_test(0, 0);
rs_test_finish(RS_TEST_PASSED, 0U);
+36 -2
View File
@@ -136,8 +136,42 @@ static bool rs_ci_smoke_gpio_v2(void) {
return rs_gpio_write(31U, false) == RS_OK;
}
static bool rs_ci_smoke_uart_v2(void) {
const rs_uart_config_t config = {
.source_clock_hz = CPU_FREQ * UINT32_C(1000000),
.baud_rate = UART_BPS,
.data_bits = 8U,
.stop_bits = 1U,
.parity = RS_UART_PARITY_NONE,
.tx_watermark = 16U,
.rx_watermark = 1U,
.rx_timeout_bits = 32U,
.tx_enable = true,
.rx_enable = true,
.loopback_enable = true,
};
const uint8_t transmitted = UINT8_C(0xA5);
rs_uart_rx_data_t received;
if ((RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0xF8)) != UINT32_C(0x00020000)) ||
(RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0xFC)) != UINT32_C(0x00FF4040)) ||
(rs_uart_configure(&config, RS_TIMEOUT_DEFAULT) != RS_OK) ||
(rs_uart_write(&transmitted, 1U, RS_TIMEOUT_DEFAULT) != RS_OK) ||
(rs_uart_read(&received, 1U, RS_TIMEOUT_DEFAULT) != RS_OK) ||
(received.data != transmitted) || (received.errors != 0U)) {
return false;
}
return rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) == RS_OK;
}
int main(void) {
uart0_init(CPU_FREQ, UART_BPS);
if (rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) != RS_OK) {
rs_test_finish(RS_TEST_FAILED, 6U);
}
if (!rs_ci_smoke_uart_v2()) {
rs_test_finish(RS_TEST_FAILED, 7U);
}
if (!rs_ci_smoke_archinfo_matches_reset_values()) {
rs_test_finish(RS_TEST_FAILED, 1U);
@@ -159,7 +193,7 @@ int main(void) {
rs_test_finish(RS_TEST_FAILED, 5U);
}
printf("ci_smoke: archinfo, CLINT, timer, and GPIO tests passed\n");
printf("ci_smoke: UART, archinfo, CLINT, timer, and GPIO tests passed\n");
rs_test_finish(RS_TEST_PASSED, 0U);
return 0;
}
+3 -1
View File
@@ -19,7 +19,9 @@ int main(void) {
int result;
uint32_t cycles;
uart0_init(CPU_FREQ, UART_BPS);
if (rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) != RS_OK) {
rs_test_finish(RS_TEST_FAILED, 2U);
}
result = core_main();
cycles = (uint32_t)get_time();
printf("COREMARK_RESULT mode=%s qualified=%u memory=sram iterations=%u cycles=%u cpu_hz=%u\n",
+3 -1
View File
@@ -29,7 +29,9 @@ static void rs_app_info_command(int argc, char **argv) {
}
int main(void) {
uart0_init(CPU_FREQ, UART_BPS);
if (rs_uart_init(CPU_FREQ * UINT32_C(1000000), UART_BPS) != RS_OK) {
return 1;
}
rs_booter();
if (rs_i2c0_init((uint8_t)(CPU_FREQ / 2 - 1)) != RS_OK) {
return 1;
+10 -5
View File
@@ -3,10 +3,15 @@
.global _start
_start:
UART_INIT:
lui a4, 0x10001
# li a5, 625 # 72M 115200bps
li a5, 78 # 72M 921600ps
li a4, RS_SOC_RIBP_UART0_BASE
li a5, 78 # 72 MHz / 921600 baud = 78.125 clocks
sw a5, 0(a4)
li a5, 32
sw a5, 4(a4)
li a5, 3 # 8 data bits, no parity, one stop bit
sw a5, 8(a4)
li a5, 3 # Enable TX and RX
sw a5, 12(a4)
HELLO_INIT:
la s0, msg_hello
li a0, 72
@@ -169,8 +174,8 @@ END:
j END
PUTC:
lui a4, 0x10001
sw a0, 4(a4)
li a4, RS_SOC_RIBP_UART0_BASE
sw a0, 16(a4)
ret
.section .data
-3
View File
@@ -31,9 +31,6 @@
#define RS_SOC_REG32(base, offset) (*(volatile uint32_t *)(uintptr_t)((base) + (offset)))
// uart0
#define reg_uart0_clkdiv RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0x00))
#define reg_uart0_data RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0x04))
// psram
#define reg_psram_wait RS_SOC_REG32(RS_SOC_RIBP_PSRAM_BASE, UINT32_C(0x00))
#define reg_psram_chd RS_SOC_REG32(RS_SOC_RIBP_PSRAM_BASE, UINT32_C(0x04))
+8
View File
@@ -10,6 +10,14 @@ typedef struct {
uintptr_t address;
} rs_dma_error_t;
#define RS_DMA_MODE_SOFTWARE UINT32_C(0)
#define RS_DMA_MODE_I2S_TX UINT32_C(1)
#define RS_DMA_MODE_I2S_RX UINT32_C(2)
#define RS_DMA_MODE_QSPI_TX UINT32_C(3)
#define RS_DMA_MODE_QSPI_RX UINT32_C(4)
#define RS_DMA_MODE_UART_TX UINT32_C(5)
#define RS_DMA_MODE_UART_RX UINT32_C(6)
rs_status_t rs_dma_config(uint32_t mode, uintptr_t source, uint32_t source_increment,
uintptr_t destination, uint32_t destination_increment,
uint32_t transfer_words);
+71 -4
View File
@@ -1,9 +1,76 @@
#ifndef RETROSOC_HAL_UART_H
#define RETROSOC_HAL_UART_H
#ifndef RETROSOC_UART_H
#define RETROSOC_UART_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
void uart0_init(uint32_t freq, uint32_t bps);
#include <retrosoc/core/status.h>
#define RS_UART_ERROR_PARITY UINT32_C(0x01)
#define RS_UART_ERROR_FRAME UINT32_C(0x02)
#define RS_UART_ERROR_BREAK UINT32_C(0x04)
#define RS_UART_ERROR_NOISE UINT32_C(0x08)
#define RS_UART_INTR_RX_WATERMARK UINT32_C(0x01)
#define RS_UART_INTR_RX_TIMEOUT UINT32_C(0x02)
#define RS_UART_INTR_TX_WATERMARK UINT32_C(0x04)
#define RS_UART_INTR_TX_DONE UINT32_C(0x08)
#define RS_UART_INTR_RX_ERROR UINT32_C(0x10)
#define RS_UART_INTR_BREAK UINT32_C(0x20)
#define RS_UART_INTR_ALL UINT32_C(0x3F)
typedef enum {
RS_UART_PARITY_NONE = 0,
RS_UART_PARITY_EVEN = 1,
RS_UART_PARITY_ODD = 2,
} rs_uart_parity_t;
typedef struct {
uint32_t source_clock_hz;
uint32_t baud_rate;
uint8_t data_bits;
uint8_t stop_bits;
rs_uart_parity_t parity;
uint8_t tx_watermark;
uint8_t rx_watermark;
uint16_t rx_timeout_bits;
bool tx_enable;
bool rx_enable;
bool loopback_enable;
} rs_uart_config_t;
typedef struct {
uint32_t baud_integer;
uint32_t baud_fraction;
} rs_uart_timing_t;
typedef struct {
uint8_t data;
uint8_t errors;
} rs_uart_rx_data_t;
typedef struct {
uint32_t flags;
uint32_t tx_level;
uint32_t rx_level;
uint32_t errors;
uint32_t interrupt_state;
} rs_uart_status_t;
rs_status_t rs_uart_timing_calculate(uint32_t source_clock_hz, uint32_t baud_rate,
rs_uart_timing_t *timing);
rs_status_t rs_uart_init(uint32_t source_clock_hz, uint32_t baud_rate);
rs_status_t rs_uart_configure(const rs_uart_config_t *config, rs_timeout_t timeout);
rs_status_t rs_uart_write(const uint8_t *data, size_t length, rs_timeout_t timeout);
rs_status_t rs_uart_read(rs_uart_rx_data_t *data, size_t length, rs_timeout_t timeout);
rs_status_t rs_uart_flush(bool flush_tx, bool flush_rx, rs_timeout_t timeout);
rs_status_t rs_uart_get_status(rs_uart_status_t *status);
rs_status_t rs_uart_irq_enable(uint32_t mask);
rs_status_t rs_uart_irq_ack(uint32_t mask);
rs_status_t rs_uart_irq_test(uint32_t mask);
rs_status_t rs_uart_write_dma(const uint32_t *words, size_t count, rs_timeout_t timeout);
rs_status_t rs_uart_read_dma(uint32_t *words, size_t count, rs_timeout_t timeout);
void putch(char ch);
#endif
+2 -2
View File
@@ -6,8 +6,8 @@
rs_status_t rs_dma_config(uint32_t mode, uintptr_t source, uint32_t source_increment,
uintptr_t destination, uint32_t destination_increment,
uint32_t transfer_words) {
if ((mode > 4U) || (source == 0U) || (destination == 0U) || (transfer_words == 0U) ||
(source_increment > 1U) || (destination_increment > 1U)) {
if ((mode > RS_DMA_MODE_UART_RX) || (source == 0U) || (destination == 0U) ||
(transfer_words == 0U) || (source_increment > 1U) || (destination_increment > 1U)) {
return RS_EINVAL;
}
+263 -7
View File
@@ -1,14 +1,270 @@
#include <limits.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/dma.h>
#include <retrosoc/hal/uart.h>
void uart0_init(uint32_t freq, uint32_t bps) {
reg_uart0_clkdiv = (uint32_t)(freq * 1000000 / bps);
#define RS_UART_REG(offset) RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, (offset))
#define RS_UART_BAUD_INT RS_UART_REG(UINT32_C(0x00))
#define RS_UART_BAUD_FRAC RS_UART_REG(UINT32_C(0x04))
#define RS_UART_LINE_CTRL RS_UART_REG(UINT32_C(0x08))
#define RS_UART_CTRL RS_UART_REG(UINT32_C(0x0C))
#define RS_UART_TXDATA RS_UART_REG(UINT32_C(0x10))
#define RS_UART_RXDATA RS_UART_REG(UINT32_C(0x14))
#define RS_UART_STATUS RS_UART_REG(UINT32_C(0x18))
#define RS_UART_FIFO_LEVEL RS_UART_REG(UINT32_C(0x1C))
#define RS_UART_FIFO_CTRL RS_UART_REG(UINT32_C(0x20))
#define RS_UART_TX_WATERMARK RS_UART_REG(UINT32_C(0x24))
#define RS_UART_RX_WATERMARK RS_UART_REG(UINT32_C(0x28))
#define RS_UART_RX_TIMEOUT RS_UART_REG(UINT32_C(0x2C))
#define RS_UART_ERROR_STATUS RS_UART_REG(UINT32_C(0x30))
#define RS_UART_INTR_STATE RS_UART_REG(UINT32_C(0x34))
#define RS_UART_INTR_ENABLE RS_UART_REG(UINT32_C(0x38))
#define RS_UART_INTR_TEST RS_UART_REG(UINT32_C(0x40))
#define RS_UART_DMA_CTRL RS_UART_REG(UINT32_C(0x44))
#define RS_UART_CTRL_TX_ENABLE UINT32_C(0x01)
#define RS_UART_CTRL_RX_ENABLE UINT32_C(0x02)
#define RS_UART_CTRL_LOOPBACK UINT32_C(0x04)
#define RS_UART_STATUS_TX_BUSY UINT32_C(0x04)
#define RS_UART_STATUS_RX_BUSY UINT32_C(0x08)
#define RS_UART_STATUS_TX_FULL UINT32_C(0x20)
#define RS_UART_STATUS_RX_EMPTY UINT32_C(0x40)
#define RS_UART_STATUS_CONFIG_VALID UINT32_C(0x100)
#define RS_UART_FIFO_TX_FLUSH UINT32_C(0x01)
#define RS_UART_FIFO_RX_FLUSH UINT32_C(0x02)
#define RS_UART_ERROR_ALL UINT32_C(0x7F)
#define RS_UART_DMA_TX_ENABLE UINT32_C(0x01)
#define RS_UART_DMA_RX_ENABLE UINT32_C(0x02)
static uint32_t rs_uart_control_from_config(const rs_uart_config_t *config) {
uint32_t control = 0U;
if (config->tx_enable) {
control |= RS_UART_CTRL_TX_ENABLE;
}
if (config->rx_enable) {
control |= RS_UART_CTRL_RX_ENABLE;
}
if (config->loopback_enable) {
control |= RS_UART_CTRL_LOOPBACK;
}
return control;
}
static bool rs_uart_config_valid(const rs_uart_config_t *config) {
return (config != NULL) && (config->data_bits >= 5U) && (config->data_bits <= 8U) &&
((config->stop_bits == 1U) || (config->stop_bits == 2U)) &&
(config->parity <= RS_UART_PARITY_ODD) && (config->tx_watermark < 64U) &&
(config->rx_watermark > 0U) && (config->rx_watermark <= 64U);
}
rs_status_t rs_uart_configure(const rs_uart_config_t *config, rs_timeout_t timeout) {
rs_uart_timing_t timing;
uint32_t line_control;
if (!rs_uart_config_valid(config) ||
(rs_uart_timing_calculate(config->source_clock_hz, config->baud_rate, &timing) != RS_OK)) {
return RS_EINVAL;
}
RS_UART_CTRL = 0U;
while (((RS_UART_STATUS & (RS_UART_STATUS_TX_BUSY | RS_UART_STATUS_RX_BUSY)) != 0U) &&
(timeout != 0U)) {
timeout--;
}
if ((RS_UART_STATUS & (RS_UART_STATUS_TX_BUSY | RS_UART_STATUS_RX_BUSY)) != 0U) {
return RS_ETIMEOUT;
}
RS_UART_FIFO_CTRL = RS_UART_FIFO_TX_FLUSH | RS_UART_FIFO_RX_FLUSH;
RS_UART_ERROR_STATUS = RS_UART_ERROR_ALL;
RS_UART_INTR_STATE = RS_UART_INTR_ALL;
RS_UART_BAUD_INT = timing.baud_integer;
RS_UART_BAUD_FRAC = timing.baud_fraction;
line_control = ((uint32_t)config->data_bits - 5U) | (((uint32_t)config->stop_bits - 1U) << 2U) |
((uint32_t)config->parity << 3U);
RS_UART_LINE_CTRL = line_control;
RS_UART_TX_WATERMARK = config->tx_watermark;
RS_UART_RX_WATERMARK = config->rx_watermark;
RS_UART_RX_TIMEOUT = config->rx_timeout_bits;
RS_UART_DMA_CTRL = 0U;
RS_UART_CTRL = rs_uart_control_from_config(config);
return ((RS_UART_STATUS & RS_UART_STATUS_CONFIG_VALID) != 0U) ? RS_OK : RS_EIO;
}
rs_status_t rs_uart_init(uint32_t source_clock_hz, uint32_t baud_rate) {
const rs_uart_config_t config = {
.source_clock_hz = source_clock_hz,
.baud_rate = baud_rate,
.data_bits = 8U,
.stop_bits = 1U,
.parity = RS_UART_PARITY_NONE,
.tx_watermark = 16U,
.rx_watermark = 32U,
.rx_timeout_bits = 32U,
.tx_enable = true,
.rx_enable = true,
.loopback_enable = false,
};
return rs_uart_configure(&config, RS_TIMEOUT_DEFAULT);
}
rs_status_t rs_uart_write(const uint8_t *data, size_t length, rs_timeout_t timeout) {
size_t index;
if ((data == NULL) && (length != 0U)) {
return RS_EINVAL;
}
for (index = 0U; index < length; index++) {
while ((RS_UART_STATUS & RS_UART_STATUS_TX_FULL) != 0U) {
if (timeout == 0U) {
return RS_ETIMEOUT;
}
timeout--;
}
RS_UART_TXDATA = data[index];
}
return RS_OK;
}
rs_status_t rs_uart_read(rs_uart_rx_data_t *data, size_t length, rs_timeout_t timeout) {
size_t index;
if ((data == NULL) && (length != 0U)) {
return RS_EINVAL;
}
for (index = 0U; index < length; index++) {
uint32_t value;
while ((RS_UART_STATUS & RS_UART_STATUS_RX_EMPTY) != 0U) {
if (timeout == 0U) {
return RS_ETIMEOUT;
}
timeout--;
}
value = RS_UART_RXDATA;
data[index].data = (uint8_t)value;
data[index].errors = (uint8_t)((value >> 8U) & UINT32_C(0x0F));
}
return RS_OK;
}
rs_status_t rs_uart_flush(bool flush_tx, bool flush_rx, rs_timeout_t timeout) {
const uint32_t old_control = RS_UART_CTRL;
uint32_t control = old_control;
uint32_t command = 0U;
if (!flush_tx && !flush_rx) {
return RS_EINVAL;
}
if (flush_tx) {
control &= ~RS_UART_CTRL_TX_ENABLE;
command |= RS_UART_FIFO_TX_FLUSH;
}
if (flush_rx) {
control &= ~RS_UART_CTRL_RX_ENABLE;
command |= RS_UART_FIFO_RX_FLUSH;
}
RS_UART_CTRL = control;
while (((RS_UART_STATUS & (RS_UART_STATUS_TX_BUSY | RS_UART_STATUS_RX_BUSY)) != 0U) &&
(timeout != 0U)) {
timeout--;
}
if ((RS_UART_STATUS & (RS_UART_STATUS_TX_BUSY | RS_UART_STATUS_RX_BUSY)) != 0U) {
return RS_ETIMEOUT;
}
RS_UART_FIFO_CTRL = command;
RS_UART_CTRL = old_control;
return RS_OK;
}
rs_status_t rs_uart_get_status(rs_uart_status_t *status) {
uint32_t levels;
if (status == NULL) {
return RS_EINVAL;
}
levels = RS_UART_FIFO_LEVEL;
status->flags = RS_UART_STATUS;
status->tx_level = levels & UINT32_C(0x7F);
status->rx_level = (levels >> 16U) & UINT32_C(0x7F);
status->errors = RS_UART_ERROR_STATUS;
status->interrupt_state = RS_UART_INTR_STATE;
return RS_OK;
}
rs_status_t rs_uart_irq_enable(uint32_t mask) {
if ((mask & ~RS_UART_INTR_ALL) != 0U) {
return RS_EINVAL;
}
RS_UART_INTR_ENABLE = mask;
return RS_OK;
}
rs_status_t rs_uart_irq_ack(uint32_t mask) {
if ((mask == 0U) || ((mask & ~RS_UART_INTR_ALL) != 0U)) {
return RS_EINVAL;
}
RS_UART_INTR_STATE = mask;
return RS_OK;
}
rs_status_t rs_uart_irq_test(uint32_t mask) {
if ((mask == 0U) || ((mask & ~RS_UART_INTR_ALL) != 0U)) {
return RS_EINVAL;
}
RS_UART_INTR_TEST = mask;
return RS_OK;
}
rs_status_t rs_uart_write_dma(const uint32_t *words, size_t count, rs_timeout_t timeout) {
size_t index;
rs_status_t status;
if ((words == NULL) || (count == 0U) || (count > UINT32_MAX)) {
return RS_EINVAL;
}
for (index = 0U; index < count; index++) {
if ((words[index] & UINT32_C(0xFFFFFF00)) != 0U) {
return RS_EINVAL;
}
}
RS_UART_DMA_CTRL = RS_UART_DMA_TX_ENABLE;
status = rs_dma_config(RS_DMA_MODE_UART_TX, (uintptr_t)words, 1U,
RS_SOC_RIBP_UART0_BASE + UINT32_C(0x10), 0U, (uint32_t)count);
if (status == RS_OK) {
status = rs_dma_start();
}
if (status == RS_OK) {
status = rs_dma_wait(timeout);
}
RS_UART_DMA_CTRL = 0U;
return status;
}
rs_status_t rs_uart_read_dma(uint32_t *words, size_t count, rs_timeout_t timeout) {
rs_status_t status;
if ((words == NULL) || (count == 0U) || (count > UINT32_MAX)) {
return RS_EINVAL;
}
RS_UART_DMA_CTRL = RS_UART_DMA_RX_ENABLE;
status = rs_dma_config(RS_DMA_MODE_UART_RX, RS_SOC_RIBP_UART0_BASE + UINT32_C(0x14), 0U,
(uintptr_t)words, 1U, (uint32_t)count);
if (status == RS_OK) {
status = rs_dma_start();
}
if (status == RS_OK) {
status = rs_dma_wait(timeout);
}
RS_UART_DMA_CTRL = 0U;
return status;
}
void putch(char ch) {
// while (((reg_uart1_lsr & 0x100) >> 8) == 1)
// ;
// reg_uart1_trx = (uint32_t)ch;
reg_uart0_data = ch;
const uint8_t value = (uint8_t)ch;
(void)rs_uart_write(&value, 1U, RS_TIMEOUT_DEFAULT);
}
+24
View File
@@ -0,0 +1,24 @@
#include <limits.h>
#include <retrosoc/hal/uart.h>
rs_status_t rs_uart_timing_calculate(uint32_t source_clock_hz, uint32_t baud_rate,
rs_uart_timing_t *timing) {
uint64_t scaled_period;
if ((source_clock_hz == 0U) || (baud_rate == 0U) || (timing == NULL)) {
return RS_EINVAL;
}
scaled_period =
(((uint64_t)source_clock_hz * UINT64_C(256)) + ((uint64_t)baud_rate / UINT64_C(2))) /
(uint64_t)baud_rate;
if ((scaled_period < UINT64_C(4096)) ||
(scaled_period > ((UINT64_C(0xFFFFFF) * UINT64_C(256)) + UINT64_C(255)))) {
return RS_EINVAL;
}
timing->baud_integer = (uint32_t)(scaled_period >> 8U);
timing->baud_fraction = (uint32_t)(scaled_period & UINT64_C(0xFF));
return RS_OK;
}
+9 -4
View File
@@ -1,17 +1,22 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/core/status.h>
#include <retrosoc/hal/uart.h>
#include <retrosoc/lib/console.h>
void putchar(char c) {
if (c == '\n') {
reg_uart0_data = '\r';
putch('\r');
}
reg_uart0_data = c;
putch(c);
}
char getchar(void) {
return reg_uart0_data;
rs_uart_rx_data_t data;
while (rs_uart_read(&data, 1U, RS_TIMEOUT_DEFAULT) != RS_OK) {
}
return (char)data.data;
}
void print(const char *p) {
+2 -1
View File
@@ -97,7 +97,8 @@ void rs_app_info(void) {
printf("Memory Map IO Device:\n");
printf(" 1 x GPIO(32PIN) @%p\n",
(void *)(uintptr_t)RS_SOC_RIBP_GPIO_ADMIN_BASE);
printf(" 1 x UART0 @%p\n", (void *)&reg_uart0_clkdiv);
printf(" 1 x UART0 @%p\n",
(void *)(uintptr_t)RS_SOC_RIBP_UART0_BASE);
printf(" 2 x TIMER(0,1) @%p,%p\n",
(void *)(uintptr_t)RS_SOC_RIBP_TIM0_BASE, (void *)(uintptr_t)RS_SOC_RIBP_TIM1_BASE);
printf(" 1 x PSRAM @%p\n", (void *)&reg_psram_wait);
+2
View File
@@ -28,6 +28,8 @@ the root README and subsystem guides.
timebase, RV32 access rules, interrupt behavior, and verification contract.
- [ip/gpio.md](ip/gpio.md) defines the GPIO V2 dual-window ABI, pad ownership,
filtering, interrupts, PDK capabilities, HAL, and verification contract.
- [ip/uart.md](ip/uart.md) defines the UART V2 framing, FIFO, error, interrupt,
DMA, HAL, and verification 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
+3 -2
View File
@@ -131,7 +131,7 @@ 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`, `gpio`,
and `ws2812`; each uses the SBY `prove` task for bounded model
`ws2812`, `uart`, `timer`, and `clint`; 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
@@ -141,7 +141,8 @@ ownership, locks, handoff, open-drain safety, and mux behavior. `rib_adapter`
checks both single-word compatibility adapters
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`,
underflow preconditions. `uart` checks FIFO bounds, interrupt composition,
DMA gating, and idle/break line safety. 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
+1
View File
@@ -7,6 +7,7 @@ verification documentation for self-owned retroSoC peripheral IP.
- [ws2812.md](ws2812.md) defines the WS2812 transmitter.
- [clint.md](clint.md) defines the management-hart software and timer interrupt block.
- [gpio.md](gpio.md) defines the dual-window GPIO controller.
- [uart.md](uart.md) defines the RIBP UART V2 controller.
The corresponding RTL and HAL implementations remain the executable sources
of truth. Update the affected document whenever an IP interface or register ABI
+110
View File
@@ -0,0 +1,110 @@
# RIBP UART V2
UART0 is the Mini SoC management console and a general-purpose full-duplex
serial port. UART V2 provides independent 64-byte transmit and receive FIFOs,
fractional baud-rate generation, configurable framing, receive diagnostics,
watermark and timeout interrupts, internal loopback, break generation, and
generic-DMA request pacing.
## Integration
| Property | Value |
| --- | --- |
| RIBP base address | `0x10001000` |
| TX/RX FIFO depth | 64 entries each |
| RIBP interrupt group bit | 2 |
| Management-core interrupt | 2 |
| DMA modes | 5 UART TX, 6 UART RX |
| External signals | `uart0_tx`, `uart0_rx` |
UART0 and the generic DMA share the SoC clock domain. The existing `uart_if`
continues to own the physical RX, TX, and IRQ signals; DMA readiness is a
separate internal connection. APB UART1 is independent and is not affected by
this ABI.
## Register ABI
All registers are 32-bit and naturally aligned. Unmapped, unaligned,
direction-invalid, reserved-field, and semantically illegal accesses complete
with `resp_err`. RW registers support byte strobes. Command and data registers
require the low byte lane; selected upper lanes must contain zero.
| Offset | Name | Access | Description |
| --- | --- | --- | --- |
| `0x000` | `BAUD_INT` | RW | Integer clocks per serial bit, 24 bits; minimum 16. |
| `0x004` | `BAUD_FRAC` | RW | Fractional clocks per bit in units of 1/256. |
| `0x008` | `LINE_CTRL` | RW | Data width, stop count, and parity. |
| `0x00C` | `CTRL` | RW | TX/RX enable, internal loopback, and TX break. |
| `0x010` | `TXDATA` | WO | Push one character from bits 7:0. |
| `0x014` | `RXDATA` | RO/pop | Character plus parity, frame, break, and noise flags. |
| `0x018` | `STATUS` | RO | Enable, activity, FIFO, configuration, break, and DMA state. |
| `0x01C` | `FIFO_LEVEL` | RO | TX count at bits 6:0 and RX count at bits 22:16. |
| `0x020` | `FIFO_CTRL` | WO | Bits 0/1 flush the disabled, idle TX/RX FIFO. |
| `0x024` | `TX_WATERMARK` | RW | Low-water threshold, 0 through 63; reset value 16. |
| `0x028` | `RX_WATERMARK` | RW | High-water threshold, 1 through 64; reset value 32. |
| `0x02C` | `RX_TIMEOUT_BITS` | RW | Idle bit periods before timeout; zero disables, reset value 32. |
| `0x030` | `ERROR_STATUS` | RW1C | Overrun, parity, frame, break, noise, config, command. |
| `0x034` | `INTR_STATE` | RW1C | RX water/timeout, TX water/done, RX error, break. |
| `0x038` | `INTR_ENABLE` | RW | Interrupt enable mask. |
| `0x03C` | `INTR_STATUS` | RO | `INTR_STATE & INTR_ENABLE`. |
| `0x040` | `INTR_TEST` | WO | Write-one interrupt injection. |
| `0x044` | `DMA_CTRL` | RW | TX and RX DMA request enables. |
| `0x0F8` | `IP_VERSION` | RO | `0x00020000`, ABI 2.0. |
| `0x0FC` | `CAPABILITY` | RO | `0x00FF4040`, depths and implemented features. |
`LINE_CTRL.DATA_BITS` values 0 through 3 select 5 through 8 bits. Bit 2
selects two stop bits. Bits 4:3 select none, even, or odd parity; value 3 is
reserved. `CTRL` bits 0 through 3 are TX enable, RX enable, loopback, and TX
break.
`RXDATA[7:0]` is the character. Bits 8 through 11 report parity error, frame
error, break, and inconsistent majority samples. A full RX FIFO drops the new
character and sets global overrun. An empty `RXDATA` read returns `resp_err`.
## Timing and transfer behavior
The programmed bit period is `BAUD_INT + BAUD_FRAC / 256`. A phase accumulator
generates a 16-times sample clock without accumulating whole-bit rounding
error. RX synchronizes the pad and votes three samples around each bit center;
mixed samples set the character noise flag. Start bits are confirmed before
data collection, and invalid starts return directly to idle.
Baud and line format can change only while TX/RX are disabled and both state
machines are idle. Clearing TX enable prevents a new character from starting
but lets the current frame finish; clearing RX enable aborts a partial frame.
TX break is accepted only while the transmitter is idle. FIFO contents are
preserved by enable changes and are discarded only by an accepted flush.
A full `TXDATA` write applies RIBP backpressure while the enabled transmitter
can make progress. A full write while disabled is rejected, avoiding an
unbounded bus wait. TX-done is raised when a transmitted character leaves both
the serializer and FIFO empty. Watermark conditions reassert their interrupt
state while the condition remains true, even after a software clear.
## DMA and software contract
The DMA transfers one 32-bit word per character. UART TX mode uses an
incrementing memory source and fixed `TXDATA` destination; bits 31:8 must be
zero. UART RX mode uses fixed `RXDATA` source and an incrementing memory
destination; bits 11:8 retain per-character errors. RX overrun remains global
because the dropped character cannot carry metadata.
The public HAL exposes structured configuration, bounded CPU reads/writes,
status and interrupt control, FIFO flush, and UART-paced DMA transfers.
`rs_uart_timing_calculate()` uses 64-bit arithmetic and nearest rounding.
`putch()` remains the internal formatted-output sink, while applications use
`rs_uart_init()` or `rs_uart_configure()` instead of raw registers.
## Verification and current scope
The self-checking RTL test covers the versioned ABI, access errors, FIFO depth,
8N1 loopback, external frame errors, W1C interrupt behavior, and DMA request
gating. The SBY target proves FIFO bounds, IRQ composition, disabled-DMA
gating, and TX idle/break levels, and covers bus error, TX/RX activity, error,
and IRQ paths. Host tests cover exact fractional timing and invalid ranges;
the CI smoke firmware verifies capability registers and loopback through the
public HAL.
Hardware RTS/CTS, IrDA, RS485 direction control, automatic baud detection, and
low-power wakeup are outside UART V2. Adding one requires a versioned ABI and,
where applicable, explicit pad and clock/reset integration.
+10 -2
View File
@@ -128,7 +128,11 @@ digraph mini_soc_block_diagram {
];
ribp_targets [
fillcolor="#F9E1E7",
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nUART0, I2C and I2S"
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nI2C and I2S"
];
uart0 [
fillcolor="#F9E1E7",
label="UART0 V2\n64-byte TX/RX FIFOs, fractional baud\nframing/errors, IRQ2, DMA-paced"
];
gpio_controller [
fillcolor="#F9E1E7",
@@ -161,7 +165,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; clint; ribp_targets; gpio_controller; timers; ws2812; apb_targets; }
{ rank=same; sysctrl; clint; ribp_targets; uart0; gpio_controller; timers; ws2812; apb_targets; }
{ rank=same; gpio_bridge; irq; }
ext_clock -> rcu [label="clock / reset"];
@@ -186,6 +190,7 @@ digraph mini_soc_block_diagram {
ribp_adapter -> sysctrl [label="RIBP"];
ribp_adapter -> clint [label="RIBP"];
ribp_adapter -> ribp_targets [label="RIBP"];
ribp_adapter -> uart0 [label="RIBP"];
ribp_adapter -> gpio_controller [label="RIBP\nuser/admin"];
ribp_adapter -> timers [label="RIBP"];
ribp_adapter -> ws2812 [label="RIBP"];
@@ -199,7 +204,10 @@ digraph mini_soc_block_diagram {
ws2812 -> gpio_bridge [label="GPIO2 ALT1"];
dma -> ws2812 [label="TXDATA writes", style=dashed];
ws2812 -> irq [label="IRQ17"];
dma -> uart0 [label="TX/RX data", style=dashed];
uart0 -> irq [label="IRQ2"];
apb_targets -> gpio_controller [label="user_gpio"];
ribp_targets -> ext_io [dir=both, label="device interfaces"];
uart0 -> ext_io [dir=both, label="UART pads"];
gpio_bridge -> ext_io [dir=both, label="pad control"];
}
+241 -204
View File
@@ -4,19 +4,19 @@
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: mini_soc_block_diagram Pages: 1 -->
<svg width="1986pt" height="896pt"
viewBox="0.00 0.00 1986.00 896.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="2197pt" height="896pt"
viewBox="0.00 0.00 2197.00 896.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 892.48)">
<title>mini_soc_block_diagram</title>
<text text-anchor="middle" x="132" y="-870.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 1958,-85 1958,-85 1964,-85 1970,-91 1970,-97 1970,-97 1970,-772.48 1970,-772.48 1970,-778.48 1964,-784.48 1958,-784.48 1958,-784.48 160,-784.48 160,-784.48 154,-784.48 148,-778.48 148,-772.48 148,-772.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 2169,-85 2169,-85 2175,-85 2181,-91 2181,-97 2181,-97 2181,-772.48 2181,-772.48 2181,-778.48 2175,-784.48 2169,-784.48 2169,-784.48 160,-784.48 160,-784.48 154,-784.48 148,-778.48 148,-772.48 148,-772.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
<text text-anchor="middle" x="196.5" y="-769.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 1940,-103 1940,-103 1946,-103 1952,-109 1952,-115 1952,-115 1952,-729.48 1952,-729.48 1952,-735.48 1946,-741.48 1940,-741.48 1940,-741.48 390,-741.48 390,-741.48 384,-741.48 378,-735.48 378,-729.48 378,-729.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 2151,-103 2151,-103 2157,-103 2163,-109 2163,-115 2163,-115 2163,-729.48 2163,-729.48 2163,-735.48 2157,-741.48 2151,-741.48 2151,-741.48 390,-741.48 390,-741.48 384,-741.48 378,-735.48 378,-729.48 378,-729.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
<text text-anchor="middle" x="407.5" y="-727.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
</g>
<!-- ext_clock -->
@@ -44,401 +44,438 @@
<!-- ext_io -->
<g id="node2" class="node">
<title>ext_io</title>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M1063,-45C1063,-45 871,-45 871,-45 865,-45 859,-39 859,-33 859,-33 859,-12 859,-12 859,-6 865,0 871,0 871,0 1063,0 1063,0 1069,0 1075,-6 1075,-12 1075,-12 1075,-33 1075,-33 1075,-39 1069,-45 1063,-45"/>
<text text-anchor="middle" x="967" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
<text text-anchor="middle" x="967" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
<text text-anchor="middle" x="967" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M1678,-45C1678,-45 1486,-45 1486,-45 1480,-45 1474,-39 1474,-33 1474,-33 1474,-12 1474,-12 1474,-6 1480,0 1486,0 1486,0 1678,0 1678,0 1684,0 1690,-6 1690,-12 1690,-12 1690,-33 1690,-33 1690,-39 1684,-45 1678,-45"/>
<text text-anchor="middle" x="1582" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
<text text-anchor="middle" x="1582" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
<text text-anchor="middle" x="1582" 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="M1078.5,-860.48C1078.5,-860.48 947.5,-860.48 947.5,-860.48 941.5,-860.48 935.5,-854.48 935.5,-848.48 935.5,-848.48 935.5,-836.48 935.5,-836.48 935.5,-830.48 941.5,-824.48 947.5,-824.48 947.5,-824.48 1078.5,-824.48 1078.5,-824.48 1084.5,-824.48 1090.5,-830.48 1090.5,-836.48 1090.5,-836.48 1090.5,-848.48 1090.5,-848.48 1090.5,-854.48 1084.5,-860.48 1078.5,-860.48"/>
<text text-anchor="middle" x="1013" y="-845.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
<text text-anchor="middle" x="1013" y="-834.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="M777.5,-860.48C777.5,-860.48 646.5,-860.48 646.5,-860.48 640.5,-860.48 634.5,-854.48 634.5,-848.48 634.5,-848.48 634.5,-836.48 634.5,-836.48 634.5,-830.48 640.5,-824.48 646.5,-824.48 646.5,-824.48 777.5,-824.48 777.5,-824.48 783.5,-824.48 789.5,-830.48 789.5,-836.48 789.5,-836.48 789.5,-848.48 789.5,-848.48 789.5,-854.48 783.5,-860.48 777.5,-860.48"/>
<text text-anchor="middle" x="712" y="-845.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
<text text-anchor="middle" x="712" y="-834.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="M1088,-678.98C1088,-678.98 938,-678.98 938,-678.98 932,-678.98 926,-672.98 926,-666.98 926,-666.98 926,-654.98 926,-654.98 926,-648.98 932,-642.98 938,-642.98 938,-642.98 1088,-642.98 1088,-642.98 1094,-642.98 1100,-648.98 1100,-654.98 1100,-654.98 1100,-666.98 1100,-666.98 1100,-672.98 1094,-678.98 1088,-678.98"/>
<text text-anchor="middle" x="1013" y="-663.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
<text text-anchor="middle" x="1013" y="-652.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="M787,-678.98C787,-678.98 637,-678.98 637,-678.98 631,-678.98 625,-672.98 625,-666.98 625,-666.98 625,-654.98 625,-654.98 625,-648.98 631,-642.98 637,-642.98 637,-642.98 787,-642.98 787,-642.98 793,-642.98 799,-648.98 799,-654.98 799,-654.98 799,-666.98 799,-666.98 799,-672.98 793,-678.98 787,-678.98"/>
<text text-anchor="middle" x="712" y="-663.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
<text text-anchor="middle" x="712" y="-652.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
</g>
<!-- ext_jtag&#45;&gt;jtag_dtm -->
<g id="edge2" class="edge">
<title>ext_jtag&#45;&gt;jtag_dtm</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1013,-824.27C1013,-792.24 1013,-723.39 1013,-686.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1015.45,-686.14 1013,-679.14 1010.55,-686.14 1015.45,-686.14"/>
<text text-anchor="middle" x="1033" y="-795.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M712,-824.27C712,-792.24 712,-723.39 712,-686.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="714.45,-686.14 712,-679.14 709.55,-686.14 714.45,-686.14"/>
<text text-anchor="middle" x="732" y="-795.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="M1086.66,-451.31C1086.66,-451.31 1018.98,-479.16 1018.98,-479.16 1013.43,-481.45 1001.88,-483.73 995.88,-483.73 995.88,-483.73 840.12,-483.73 840.12,-483.73 834.12,-483.73 822.57,-481.45 817.02,-479.16 817.02,-479.16 749.34,-451.31 749.34,-451.31 743.79,-449.03 743.79,-444.46 749.34,-442.18 749.34,-442.18 817.02,-414.32 817.02,-414.32 822.57,-412.04 834.12,-409.76 840.12,-409.76 840.12,-409.76 995.88,-409.76 995.88,-409.76 1001.88,-409.76 1013.43,-412.04 1018.98,-414.32 1018.98,-414.32 1086.66,-442.18 1086.66,-442.18 1092.21,-444.46 1092.21,-449.03 1086.66,-451.31"/>
<text text-anchor="middle" x="918" y="-455.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
<text text-anchor="middle" x="918" y="-444.24" font-family="Arial" font-size="10.00" fill="#111827">3&#45;master round&#45;robin arbitration</text>
<text text-anchor="middle" x="918" y="-433.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="M1083.66,-451.31C1083.66,-451.31 1015.98,-479.16 1015.98,-479.16 1010.43,-481.45 998.88,-483.73 992.88,-483.73 992.88,-483.73 837.12,-483.73 837.12,-483.73 831.12,-483.73 819.57,-481.45 814.02,-479.16 814.02,-479.16 746.34,-451.31 746.34,-451.31 740.79,-449.03 740.79,-444.46 746.34,-442.18 746.34,-442.18 814.02,-414.32 814.02,-414.32 819.57,-412.04 831.12,-409.76 837.12,-409.76 837.12,-409.76 992.88,-409.76 992.88,-409.76 998.88,-409.76 1010.43,-412.04 1015.98,-414.32 1015.98,-414.32 1083.66,-442.18 1083.66,-442.18 1089.21,-444.46 1089.21,-449.03 1083.66,-451.31"/>
<text text-anchor="middle" x="915" y="-455.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
<text text-anchor="middle" x="915" y="-444.24" font-family="Arial" font-size="10.00" fill="#111827">3&#45;master round&#45;robin arbitration</text>
<text text-anchor="middle" x="915" y="-433.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
</g>
<!-- rcu&#45;&gt;fabric -->
<g id="edge3" class="edge">
<title>rcu&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M362.03,-540.47C368.2,-539.24 372,-538.48 372,-538.48 372,-538.48 734,-483.48 734,-483.48 734,-483.48 758.75,-478.68 790.1,-472.59"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="790.92,-474.92 797.32,-471.18 789.98,-470.11 790.92,-474.92"/>
<text text-anchor="middle" x="609" y="-509.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="M362.03,-540.47C368.2,-539.24 372,-538.48 372,-538.48 372,-538.48 731,-483.48 731,-483.48 731,-483.48 755.75,-478.68 787.1,-472.59"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="787.92,-474.92 794.32,-471.18 786.98,-470.11 787.92,-474.92"/>
<text text-anchor="middle" x="607" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
</g>
<!-- clint -->
<g id="node17" class="node">
<title>clint</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M527.5,-255C527.5,-255 406.5,-255 406.5,-255 400.5,-255 394.5,-249 394.5,-243 394.5,-243 394.5,-222 394.5,-222 394.5,-216 400.5,-210 406.5,-210 406.5,-210 527.5,-210 527.5,-210 533.5,-210 539.5,-216 539.5,-222 539.5,-222 539.5,-243 539.5,-243 539.5,-249 533.5,-255 527.5,-255"/>
<text text-anchor="middle" x="467" y="-241" font-family="Arial" font-size="10.00" fill="#111827">CLINT</text>
<text text-anchor="middle" x="467" y="-230" font-family="Arial" font-size="10.00" fill="#111827">standard 64 KiB register map</text>
<text text-anchor="middle" x="467" y="-219" font-family="Arial" font-size="10.00" fill="#111827">mtime, mtimecmp and MSIP</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M769.5,-255C769.5,-255 648.5,-255 648.5,-255 642.5,-255 636.5,-249 636.5,-243 636.5,-243 636.5,-222 636.5,-222 636.5,-216 642.5,-210 648.5,-210 648.5,-210 769.5,-210 769.5,-210 775.5,-210 781.5,-216 781.5,-222 781.5,-222 781.5,-243 781.5,-243 781.5,-249 775.5,-255 769.5,-255"/>
<text text-anchor="middle" x="709" y="-241" font-family="Arial" font-size="10.00" fill="#111827">CLINT</text>
<text text-anchor="middle" x="709" y="-230" font-family="Arial" font-size="10.00" fill="#111827">standard 64 KiB register map</text>
<text text-anchor="middle" x="709" y="-219" font-family="Arial" font-size="10.00" fill="#111827">mtime, mtimecmp and MSIP</text>
</g>
<!-- rcu&#45;&gt;clint -->
<g id="edge8" class="edge">
<title>rcu&#45;&gt;clint</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M277.48,-538.31C313.09,-481.03 409.7,-325.66 449.5,-261.65"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="451.78,-262.62 453.4,-255.38 447.62,-260.03 451.78,-262.62"/>
<text text-anchor="middle" x="392.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">1 MHz tick</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M286.04,-538.33C353.25,-472.3 551,-278 551,-278 551,-278 590.26,-266.94 629.65,-255.85"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="630.4,-258.18 636.47,-253.93 629.07,-253.47 630.4,-258.18"/>
<text text-anchor="middle" x="464.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">1 MHz tick</text>
</g>
<!-- mgmt_core -->
<g id="node5" class="node">
<title>mgmt_core</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1293,-683.48C1293,-683.48 1139,-683.48 1139,-683.48 1133,-683.48 1127,-677.48 1127,-671.48 1127,-671.48 1127,-650.48 1127,-650.48 1127,-644.48 1133,-638.48 1139,-638.48 1139,-638.48 1293,-638.48 1293,-638.48 1299,-638.48 1305,-644.48 1305,-650.48 1305,-650.48 1305,-671.48 1305,-671.48 1305,-677.48 1299,-683.48 1293,-683.48"/>
<text text-anchor="middle" x="1216" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
<text text-anchor="middle" x="1216" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
<text text-anchor="middle" x="1216" y="-647.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="M992,-683.48C992,-683.48 838,-683.48 838,-683.48 832,-683.48 826,-677.48 826,-671.48 826,-671.48 826,-650.48 826,-650.48 826,-644.48 832,-638.48 838,-638.48 838,-638.48 992,-638.48 992,-638.48 998,-638.48 1004,-644.48 1004,-650.48 1004,-650.48 1004,-671.48 1004,-671.48 1004,-677.48 998,-683.48 992,-683.48"/>
<text text-anchor="middle" x="915" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
<text text-anchor="middle" x="915" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
<text text-anchor="middle" x="915" y="-647.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="M1236.5,-578.98C1236.5,-578.98 1195.5,-578.98 1195.5,-578.98 1189.5,-578.98 1183.5,-572.98 1183.5,-566.98 1183.5,-566.98 1183.5,-554.98 1183.5,-554.98 1183.5,-548.98 1189.5,-542.98 1195.5,-542.98 1195.5,-542.98 1236.5,-542.98 1236.5,-542.98 1242.5,-542.98 1248.5,-548.98 1248.5,-554.98 1248.5,-554.98 1248.5,-566.98 1248.5,-566.98 1248.5,-572.98 1242.5,-578.98 1236.5,-578.98"/>
<text text-anchor="middle" x="1216" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M935.5,-578.98C935.5,-578.98 894.5,-578.98 894.5,-578.98 888.5,-578.98 882.5,-572.98 882.5,-566.98 882.5,-566.98 882.5,-554.98 882.5,-554.98 882.5,-548.98 888.5,-542.98 894.5,-542.98 894.5,-542.98 935.5,-542.98 935.5,-542.98 941.5,-542.98 947.5,-548.98 947.5,-554.98 947.5,-554.98 947.5,-566.98 947.5,-566.98 947.5,-572.98 941.5,-578.98 935.5,-578.98"/>
<text text-anchor="middle" x="915" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
</g>
<!-- mgmt_core&#45;&gt;mgmt_adapter -->
<g id="edge9" class="edge">
<title>mgmt_core&#45;&gt;mgmt_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1216,-638.24C1216,-622.92 1216,-602.4 1216,-586.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1218.45,-586.12 1216,-579.12 1213.55,-586.12 1218.45,-586.12"/>
<text text-anchor="middle" x="1225.5" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M915,-638.24C915,-622.92 915,-602.4 915,-586.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="917.45,-586.12 915,-579.12 912.55,-586.12 917.45,-586.12"/>
<text text-anchor="middle" x="924.5" y="-609.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="M1583.5,-683.48C1583.5,-683.48 1462.5,-683.48 1462.5,-683.48 1456.5,-683.48 1450.5,-677.48 1450.5,-671.48 1450.5,-671.48 1450.5,-650.48 1450.5,-650.48 1450.5,-644.48 1456.5,-638.48 1462.5,-638.48 1462.5,-638.48 1583.5,-638.48 1583.5,-638.48 1589.5,-638.48 1595.5,-644.48 1595.5,-650.48 1595.5,-650.48 1595.5,-671.48 1595.5,-671.48 1595.5,-677.48 1589.5,-683.48 1583.5,-683.48"/>
<text text-anchor="middle" x="1523" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
<text text-anchor="middle" x="1523" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
<text text-anchor="middle" x="1523" y="-647.48" font-family="Arial" font-size="10.00" fill="#111827">management&#45;hart&#45;only reset</text>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1282.5,-683.48C1282.5,-683.48 1161.5,-683.48 1161.5,-683.48 1155.5,-683.48 1149.5,-677.48 1149.5,-671.48 1149.5,-671.48 1149.5,-650.48 1149.5,-650.48 1149.5,-644.48 1155.5,-638.48 1161.5,-638.48 1161.5,-638.48 1282.5,-638.48 1282.5,-638.48 1288.5,-638.48 1294.5,-644.48 1294.5,-650.48 1294.5,-650.48 1294.5,-671.48 1294.5,-671.48 1294.5,-677.48 1288.5,-683.48 1282.5,-683.48"/>
<text text-anchor="middle" x="1222" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
<text text-anchor="middle" x="1222" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
<text text-anchor="middle" x="1222" y="-647.48" font-family="Arial" font-size="10.00" fill="#111827">management&#45;hart&#45;only reset</text>
</g>
<!-- jtag_dtm&#45;&gt;debug_module -->
<g id="edge4" class="edge">
<title>jtag_dtm&#45;&gt;debug_module</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1031.06,-679.13C1060.11,-708.33 1114,-762.48 1114,-762.48 1114,-762.48 1319,-762.48 1319,-762.48 1319,-762.48 1410.81,-716.8 1471.25,-686.73"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1472.55,-688.82 1477.73,-683.51 1470.37,-684.44 1472.55,-688.82"/>
<text text-anchor="middle" x="1275" y="-795.08" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M730.06,-679.13C759.11,-708.33 813,-762.48 813,-762.48 813,-762.48 1018,-762.48 1018,-762.48 1018,-762.48 1109.81,-716.8 1170.25,-686.73"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1171.55,-688.82 1176.73,-683.51 1169.37,-684.44 1171.55,-688.82"/>
<text text-anchor="middle" x="974" y="-795.08" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
</g>
<!-- debug_module&#45;&gt;mgmt_core -->
<g id="edge5" class="edge">
<title>debug_module&#45;&gt;mgmt_core</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1450.11,-660.98C1408.89,-660.98 1356.84,-660.98 1312.29,-660.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1312.21,-658.53 1305.21,-660.98 1312.21,-663.43 1312.21,-658.53"/>
<text text-anchor="middle" x="1377.75" y="-666.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="M1149.11,-660.98C1107.89,-660.98 1055.84,-660.98 1011.29,-660.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1011.21,-658.53 1004.21,-660.98 1011.21,-663.43 1011.21,-658.53"/>
<text text-anchor="middle" x="1076.75" y="-666.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
</g>
<!-- debug_module&#45;&gt;mgmt_adapter -->
<g id="edge6" class="edge">
<title>debug_module&#45;&gt;mgmt_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1450.23,-638.57C1373.31,-615.94 1263,-583.48 1263,-583.48 1263,-583.48 1259.87,-582.05 1255.22,-579.93"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1256.03,-577.6 1248.64,-576.92 1253.99,-582.06 1256.03,-577.6"/>
<text text-anchor="middle" x="1407" y="-609.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="M1149.23,-638.57C1072.31,-615.94 962,-583.48 962,-583.48 962,-583.48 958.87,-582.05 954.22,-579.93"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="955.03,-577.6 947.64,-576.92 952.99,-582.06 955.03,-577.6"/>
<text text-anchor="middle" x="1106" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
</g>
<!-- timers -->
<g id="node20" class="node">
<g id="node21" class="node">
<title>timers</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1681.5,-255C1681.5,-255 1500.5,-255 1500.5,-255 1494.5,-255 1488.5,-249 1488.5,-243 1488.5,-243 1488.5,-222 1488.5,-222 1488.5,-216 1494.5,-210 1500.5,-210 1500.5,-210 1681.5,-210 1681.5,-210 1687.5,-210 1693.5,-216 1693.5,-222 1693.5,-222 1693.5,-243 1693.5,-243 1693.5,-249 1687.5,-255 1681.5,-255"/>
<text text-anchor="middle" x="1591" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
<text text-anchor="middle" x="1591" y="-230" font-family="Arial" font-size="10.00" fill="#111827">32&#45;bit counter, 16&#45;bit prescaler</text>
<text text-anchor="middle" x="1591" y="-219" font-family="Arial" font-size="10.00" fill="#111827">periodic / one&#45;shot, compare, debug freeze</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1923.5,-255C1923.5,-255 1742.5,-255 1742.5,-255 1736.5,-255 1730.5,-249 1730.5,-243 1730.5,-243 1730.5,-222 1730.5,-222 1730.5,-216 1736.5,-210 1742.5,-210 1742.5,-210 1923.5,-210 1923.5,-210 1929.5,-210 1935.5,-216 1935.5,-222 1935.5,-222 1935.5,-243 1935.5,-243 1935.5,-249 1929.5,-255 1923.5,-255"/>
<text text-anchor="middle" x="1833" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
<text text-anchor="middle" x="1833" y="-230" font-family="Arial" font-size="10.00" fill="#111827">32&#45;bit counter, 16&#45;bit prescaler</text>
<text text-anchor="middle" x="1833" y="-219" font-family="Arial" font-size="10.00" fill="#111827">periodic / one&#45;shot, compare, debug freeze</text>
</g>
<!-- debug_module&#45;&gt;timers -->
<g id="edge7" class="edge">
<title>debug_module&#45;&gt;timers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1530.32,-638.24C1540.05,-609.36 1556,-561.98 1556,-561.98 1556,-561.98 1556,-561.98 1556,-336 1556,-336 1570.96,-292.2 1581.31,-261.86"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1583.63,-262.65 1583.58,-255.24 1579,-261.07 1583.63,-262.65"/>
<text text-anchor="middle" x="1567" y="-444.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1294.55,-648.31C1456.04,-622.32 1831,-561.98 1831,-561.98 1831,-561.98 1831,-561.98 1831,-336 1831,-336 1831.85,-292.57 1832.44,-262.25"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1834.89,-262.28 1832.58,-255.24 1829.99,-262.19 1834.89,-262.28"/>
<text text-anchor="middle" x="1842" y="-444.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
</g>
<!-- mgmt_adapter&#45;&gt;fabric -->
<g id="edge10" class="edge">
<title>mgmt_adapter&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1197.65,-542.76C1180.99,-527.12 1159,-506.48 1159,-506.48 1159,-506.48 1097.55,-491.51 1036.71,-476.68"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1037.06,-474.24 1029.68,-474.96 1035.9,-479 1037.06,-474.24"/>
<text text-anchor="middle" x="1175" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M915,-542.94C915,-529.08 915,-508.91 915,-490.69"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="917.45,-490.57 915,-483.57 912.55,-490.57 917.45,-490.57"/>
<text text-anchor="middle" x="922" y="-509.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="M1364,-583.48C1364,-583.48 1288,-583.48 1288,-583.48 1282,-583.48 1276,-577.48 1276,-571.48 1276,-571.48 1276,-550.48 1276,-550.48 1276,-544.48 1282,-538.48 1288,-538.48 1288,-538.48 1364,-538.48 1364,-538.48 1370,-538.48 1376,-544.48 1376,-550.48 1376,-550.48 1376,-571.48 1376,-571.48 1376,-577.48 1370,-583.48 1364,-583.48"/>
<text text-anchor="middle" x="1326" y="-569.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="1326" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text>
<text text-anchor="middle" x="1326" y="-547.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1063,-583.48C1063,-583.48 987,-583.48 987,-583.48 981,-583.48 975,-577.48 975,-571.48 975,-571.48 975,-550.48 975,-550.48 975,-544.48 981,-538.48 987,-538.48 987,-538.48 1063,-538.48 1063,-538.48 1069,-538.48 1075,-544.48 1075,-550.48 1075,-550.48 1075,-571.48 1075,-571.48 1075,-577.48 1069,-583.48 1063,-583.48"/>
<text text-anchor="middle" x="1025" y="-569.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="1025" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text>
<text text-anchor="middle" x="1025" y="-547.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
</g>
<!-- user_core&#45;&gt;fabric -->
<g id="edge11" class="edge">
<title>user_core&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1275.79,-540.52C1236.33,-525.22 1188,-506.48 1188,-506.48 1188,-506.48 1112.22,-490 1040.95,-474.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1041.43,-472.09 1034.07,-473 1040.39,-476.88 1041.43,-472.09"/>
<text text-anchor="middle" x="1218" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1003.79,-538.34C990.1,-524.37 971.85,-505.75 955.45,-489.02"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="957.08,-487.18 950.43,-483.89 953.58,-490.61 957.08,-487.18"/>
<text text-anchor="middle" x="986" y="-509.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="M957,-578.98C957,-578.98 839,-578.98 839,-578.98 833,-578.98 827,-572.98 827,-566.98 827,-566.98 827,-554.98 827,-554.98 827,-548.98 833,-542.98 839,-542.98 839,-542.98 957,-542.98 957,-542.98 963,-542.98 969,-548.98 969,-554.98 969,-554.98 969,-566.98 969,-566.98 969,-572.98 963,-578.98 957,-578.98"/>
<text text-anchor="middle" x="898" y="-563.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
<text text-anchor="middle" x="898" y="-552.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="M1544,-578.98C1544,-578.98 1426,-578.98 1426,-578.98 1420,-578.98 1414,-572.98 1414,-566.98 1414,-566.98 1414,-554.98 1414,-554.98 1414,-548.98 1420,-542.98 1426,-542.98 1426,-542.98 1544,-542.98 1544,-542.98 1550,-542.98 1556,-548.98 1556,-554.98 1556,-554.98 1556,-566.98 1556,-566.98 1556,-572.98 1550,-578.98 1544,-578.98"/>
<text text-anchor="middle" x="1485" y="-563.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
<text text-anchor="middle" x="1485" y="-552.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
</g>
<!-- dma&#45;&gt;fabric -->
<g id="edge12" class="edge">
<title>dma&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M969,-546.87C1040.09,-533.75 1139,-515.48 1139,-515.48 1139,-515.48 1139,-506.48 1139,-506.48 1139,-506.48 1086.59,-492.55 1032.81,-478.26"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1033.3,-475.86 1025.91,-476.43 1032.05,-480.59 1033.3,-475.86"/>
<text text-anchor="middle" x="1146" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1413.75,-545.15C1337.69,-529.32 1228,-506.48 1228,-506.48 1228,-506.48 1130.17,-488.12 1043.89,-471.93"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1044.24,-469.51 1036.91,-470.62 1043.34,-474.32 1044.24,-469.51"/>
<text text-anchor="middle" x="1278" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- uart0 -->
<g id="node19" class="node">
<title>uart0</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M2135,-255C2135,-255 1975,-255 1975,-255 1969,-255 1963,-249 1963,-243 1963,-243 1963,-222 1963,-222 1963,-216 1969,-210 1975,-210 1975,-210 2135,-210 2135,-210 2141,-210 2147,-216 2147,-222 2147,-222 2147,-243 2147,-243 2147,-249 2141,-255 2135,-255"/>
<text text-anchor="middle" x="2055" y="-241" font-family="Arial" font-size="10.00" fill="#111827">UART0 V2</text>
<text text-anchor="middle" x="2055" y="-230" font-family="Arial" font-size="10.00" fill="#111827">64&#45;byte TX/RX FIFOs, fractional baud</text>
<text text-anchor="middle" x="2055" y="-219" font-family="Arial" font-size="10.00" fill="#111827">framing/errors, IRQ2, DMA&#45;paced</text>
</g>
<!-- dma&#45;&gt;uart0 -->
<g id="edge33" class="edge">
<title>dma&#45;&gt;uart0</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1512.85,-542.86C1586.53,-497.56 1781,-378 1781,-378 1781,-378 1929.1,-299.9 2007.53,-258.53"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2008.93,-260.57 2013.98,-255.13 2006.64,-256.23 2008.93,-260.57"/>
<text text-anchor="middle" x="1802.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">TX/RX data</text>
</g>
<!-- ws2812 -->
<g id="node21" class="node">
<g id="node22" class="node">
<title>ws2812</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M713,-255C713,-255 579,-255 579,-255 573,-255 567,-249 567,-243 567,-243 567,-222 567,-222 567,-216 573,-210 579,-210 579,-210 713,-210 713,-210 719,-210 725,-216 725,-222 725,-222 725,-243 725,-243 725,-249 719,-255 713,-255"/>
<text text-anchor="middle" x="646" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
<text text-anchor="middle" x="646" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24&#45;bit MSB&#45;first serializer</text>
<text text-anchor="middle" x="646" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16&#45;word FIFO, IRQ17, DMA&#45;fed</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1478,-255C1478,-255 1344,-255 1344,-255 1338,-255 1332,-249 1332,-243 1332,-243 1332,-222 1332,-222 1332,-216 1338,-210 1344,-210 1344,-210 1478,-210 1478,-210 1484,-210 1490,-216 1490,-222 1490,-222 1490,-243 1490,-243 1490,-249 1484,-255 1478,-255"/>
<text text-anchor="middle" x="1411" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
<text text-anchor="middle" x="1411" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24&#45;bit MSB&#45;first serializer</text>
<text text-anchor="middle" x="1411" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16&#45;word FIFO, IRQ17, DMA&#45;fed</text>
</g>
<!-- dma&#45;&gt;ws2812 -->
<g id="edge30" class="edge">
<g id="edge31" class="edge">
<title>dma&#45;&gt;ws2812</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M859.18,-542.82C808.17,-520.26 725,-483.48 725,-483.48 725,-483.48 689,-278 689,-278 689,-278 681.11,-269.83 672.08,-260.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="673.62,-258.56 667,-255.23 670.1,-261.96 673.62,-258.56"/>
<text text-anchor="middle" x="734.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1484.69,-542.77C1483.61,-481.55 1480,-278 1480,-278 1480,-278 1466.13,-269.06 1450.83,-259.19"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1451.9,-256.96 1444.69,-255.23 1449.25,-261.08 1451.9,-256.96"/>
<text text-anchor="middle" x="1508.5" y="-380.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="M1298.5,-464.74C1298.5,-464.74 1189.5,-464.74 1189.5,-464.74 1183.5,-464.74 1177.5,-458.74 1177.5,-452.74 1177.5,-452.74 1177.5,-440.74 1177.5,-440.74 1177.5,-434.74 1183.5,-428.74 1189.5,-428.74 1189.5,-428.74 1298.5,-428.74 1298.5,-428.74 1304.5,-428.74 1310.5,-434.74 1310.5,-440.74 1310.5,-440.74 1310.5,-452.74 1310.5,-452.74 1310.5,-458.74 1304.5,-464.74 1298.5,-464.74"/>
<text text-anchor="middle" x="1244" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
<text text-anchor="middle" x="1244" y="-438.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="M1295.5,-464.74C1295.5,-464.74 1186.5,-464.74 1186.5,-464.74 1180.5,-464.74 1174.5,-458.74 1174.5,-452.74 1174.5,-452.74 1174.5,-440.74 1174.5,-440.74 1174.5,-434.74 1180.5,-428.74 1186.5,-428.74 1186.5,-428.74 1295.5,-428.74 1295.5,-428.74 1301.5,-428.74 1307.5,-434.74 1307.5,-440.74 1307.5,-440.74 1307.5,-452.74 1307.5,-452.74 1307.5,-458.74 1301.5,-464.74 1295.5,-464.74"/>
<text text-anchor="middle" x="1241" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
<text text-anchor="middle" x="1241" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
</g>
<!-- fabric&#45;&gt;fault -->
<g id="edge13" class="edge">
<title>fabric&#45;&gt;fault</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1104.98,-446.74C1127.93,-446.74 1150.24,-446.74 1170.02,-446.74"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1104.69,-444.29 1097.69,-446.74 1104.69,-449.19 1104.69,-444.29"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1170.19,-449.19 1177.19,-446.74 1170.19,-444.29 1170.19,-449.19"/>
<text text-anchor="middle" x="1137.56" y="-452.34" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1101.98,-446.74C1124.93,-446.74 1147.24,-446.74 1167.02,-446.74"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1101.69,-444.29 1094.69,-446.74 1101.69,-449.19 1101.69,-444.29"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1167.19,-449.19 1174.19,-446.74 1167.19,-444.29 1167.19,-449.19"/>
<text text-anchor="middle" x="1134.56" y="-452.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="M1448,-464.74C1448,-464.74 1350,-464.74 1350,-464.74 1344,-464.74 1338,-458.74 1338,-452.74 1338,-452.74 1338,-440.74 1338,-440.74 1338,-434.74 1344,-428.74 1350,-428.74 1350,-428.74 1448,-428.74 1448,-428.74 1454,-428.74 1460,-434.74 1460,-440.74 1460,-440.74 1460,-452.74 1460,-452.74 1460,-458.74 1454,-464.74 1448,-464.74"/>
<text text-anchor="middle" x="1399" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">On&#45;chip SRAM</text>
<text text-anchor="middle" x="1399" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1445,-464.74C1445,-464.74 1347,-464.74 1347,-464.74 1341,-464.74 1335,-458.74 1335,-452.74 1335,-452.74 1335,-440.74 1335,-440.74 1335,-434.74 1341,-428.74 1347,-428.74 1347,-428.74 1445,-428.74 1445,-428.74 1451,-428.74 1457,-434.74 1457,-440.74 1457,-440.74 1457,-452.74 1457,-452.74 1457,-458.74 1451,-464.74 1445,-464.74"/>
<text text-anchor="middle" x="1396" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">On&#45;chip SRAM</text>
<text text-anchor="middle" x="1396" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
</g>
<!-- fabric&#45;&gt;sram -->
<g id="edge14" class="edge">
<title>fabric&#45;&gt;sram</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1024.32,-477.06C1074.69,-491.42 1124,-505.48 1124,-505.48 1124,-505.48 1138,-505.48 1138,-505.48 1138,-505.48 1324,-483.48 1324,-483.48 1324,-483.48 1338.84,-476.21 1355.32,-468.14"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1356.73,-470.18 1361.94,-464.9 1354.58,-465.78 1356.73,-470.18"/>
<text text-anchor="middle" x="1131" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1036.29,-471.06C1116.9,-487.22 1208,-505.48 1208,-505.48 1208,-505.48 1222,-505.48 1222,-505.48 1222,-505.48 1321,-483.48 1321,-483.48 1321,-483.48 1335.84,-476.21 1352.32,-468.14"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1353.73,-470.18 1358.94,-464.9 1351.58,-465.78 1353.73,-470.18"/>
<text text-anchor="middle" x="1215" y="-509.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="M938.5,-355C938.5,-355 897.5,-355 897.5,-355 891.5,-355 885.5,-349 885.5,-343 885.5,-343 885.5,-331 885.5,-331 885.5,-325 891.5,-319 897.5,-319 897.5,-319 938.5,-319 938.5,-319 944.5,-319 950.5,-325 950.5,-331 950.5,-331 950.5,-343 950.5,-343 950.5,-349 944.5,-355 938.5,-355"/>
<text text-anchor="middle" x="918" y="-334.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1253.5,-355C1253.5,-355 1212.5,-355 1212.5,-355 1206.5,-355 1200.5,-349 1200.5,-343 1200.5,-343 1200.5,-331 1200.5,-331 1200.5,-325 1206.5,-319 1212.5,-319 1212.5,-319 1253.5,-319 1253.5,-319 1259.5,-319 1265.5,-325 1265.5,-331 1265.5,-331 1265.5,-343 1265.5,-343 1265.5,-349 1259.5,-355 1253.5,-355"/>
<text text-anchor="middle" x="1233" y="-334.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
</g>
<!-- fabric&#45;&gt;ribp_adapter -->
<g id="edge15" class="edge">
<title>fabric&#45;&gt;ribp_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M918,-409.87C918,-394.27 918,-376.39 918,-362.38"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="920.45,-362.02 918,-355.02 915.55,-362.02 920.45,-362.02"/>
<text text-anchor="middle" x="925" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1012.57,-412.68C1073.53,-392.03 1148.71,-366.56 1193.65,-351.33"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1194.49,-353.64 1200.33,-349.07 1192.91,-349 1194.49,-353.64"/>
<text text-anchor="middle" x="1118" y="-380.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="M1395,-355C1395,-355 1325,-355 1325,-355 1319,-355 1313,-349 1313,-343 1313,-343 1313,-331 1313,-331 1313,-325 1319,-319 1325,-319 1325,-319 1395,-319 1395,-319 1401,-319 1407,-325 1407,-331 1407,-331 1407,-343 1407,-343 1407,-349 1401,-355 1395,-355"/>
<text text-anchor="middle" x="1360" y="-340" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
<text text-anchor="middle" x="1360" y="-329" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M662,-355C662,-355 592,-355 592,-355 586,-355 580,-349 580,-343 580,-343 580,-331 580,-331 580,-325 586,-319 592,-319 592,-319 662,-319 662,-319 668,-319 674,-325 674,-331 674,-331 674,-343 674,-343 674,-349 668,-355 662,-355"/>
<text text-anchor="middle" x="627" y="-340" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
<text text-anchor="middle" x="627" y="-329" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
</g>
<!-- fabric&#45;&gt;apb_adapter -->
<g id="edge16" class="edge">
<title>fabric&#45;&gt;apb_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1029.54,-418.55C1117.93,-397.01 1237.57,-367.84 1306,-351.16"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1306.64,-353.53 1312.86,-349.49 1305.48,-348.77 1306.64,-353.53"/>
<text text-anchor="middle" x="1198" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M846.72,-409.89C815.78,-393.64 786,-378 786,-378 786,-378 727.32,-363.24 681.26,-351.65"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="681.66,-349.22 674.27,-349.89 680.47,-353.98 681.66,-349.22"/>
<text text-anchor="middle" x="808" y="-380.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="M1449.5,-255C1449.5,-255 1286.5,-255 1286.5,-255 1280.5,-255 1274.5,-249 1274.5,-243 1274.5,-243 1274.5,-222 1274.5,-222 1274.5,-216 1280.5,-210 1286.5,-210 1286.5,-210 1449.5,-210 1449.5,-210 1455.5,-210 1461.5,-216 1461.5,-222 1461.5,-222 1461.5,-243 1461.5,-243 1461.5,-249 1455.5,-255 1449.5,-255"/>
<text text-anchor="middle" x="1368" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
<text text-anchor="middle" x="1368" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user&#45;core select/reset/bus enable</text>
<text text-anchor="middle" x="1368" 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="M1691.5,-255C1691.5,-255 1528.5,-255 1528.5,-255 1522.5,-255 1516.5,-249 1516.5,-243 1516.5,-243 1516.5,-222 1516.5,-222 1516.5,-216 1522.5,-210 1528.5,-210 1528.5,-210 1691.5,-210 1691.5,-210 1697.5,-210 1703.5,-216 1703.5,-222 1703.5,-222 1703.5,-243 1703.5,-243 1703.5,-249 1697.5,-255 1691.5,-255"/>
<text text-anchor="middle" x="1610" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
<text text-anchor="middle" x="1610" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user&#45;core select/reset/bus enable</text>
<text text-anchor="middle" x="1610" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
</g>
<!-- ribp_adapter&#45;&gt;sysctrl -->
<g id="edge17" class="edge">
<title>ribp_adapter&#45;&gt;sysctrl</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M950.67,-331.33C1024.53,-320.78 1198,-296 1198,-296 1198,-296 1254.85,-275.1 1302.8,-257.47"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1303.77,-259.72 1309.5,-255.01 1302.08,-255.12 1303.77,-259.72"/>
<text text-anchor="middle" x="1252.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1265.56,-320C1300.48,-302.83 1351,-278 1351,-278 1351,-278 1504,-255 1504,-255 1504,-255 1505.94,-254.61 1509.28,-253.93"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1509.79,-256.33 1516.16,-252.53 1508.81,-251.52 1509.79,-256.33"/>
<text text-anchor="middle" x="1360.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_adapter&#45;&gt;clint -->
<g id="edge18" class="edge">
<title>ribp_adapter&#45;&gt;clint</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M885.32,-320.57C883.27,-319.6 882,-319 882,-319 882,-319 740,-296 740,-296 740,-296 708,-278 708,-278 708,-278 554,-255 554,-255 554,-255 551.14,-254.29 546.46,-253.14"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="547.02,-250.75 539.63,-251.45 545.84,-255.51 547.02,-250.75"/>
<text text-anchor="middle" x="749.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1200.18,-333.65C1080.57,-325.07 675,-296 675,-296 675,-296 675,-278 675,-278 675,-278 681.01,-270.13 687.98,-261.01"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="690.1,-262.28 692.4,-255.23 686.2,-259.3 690.1,-262.28"/>
<text text-anchor="middle" x="684.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_targets -->
<g id="node18" class="node">
<title>ribp_targets</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1235.5,-255C1235.5,-255 1030.5,-255 1030.5,-255 1024.5,-255 1018.5,-249 1018.5,-243 1018.5,-243 1018.5,-222 1018.5,-222 1018.5,-216 1024.5,-210 1030.5,-210 1030.5,-210 1235.5,-210 1235.5,-210 1241.5,-210 1247.5,-216 1247.5,-222 1247.5,-222 1247.5,-243 1247.5,-243 1247.5,-249 1241.5,-255 1235.5,-255"/>
<text text-anchor="middle" x="1133" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
<text text-anchor="middle" x="1133" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI&#45;SD and DVP</text>
<text text-anchor="middle" x="1133" y="-219" font-family="Arial" font-size="10.00" fill="#111827">UART0, I2C and I2S</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1292.5,-255C1292.5,-255 1087.5,-255 1087.5,-255 1081.5,-255 1075.5,-249 1075.5,-243 1075.5,-243 1075.5,-222 1075.5,-222 1075.5,-216 1081.5,-210 1087.5,-210 1087.5,-210 1292.5,-210 1292.5,-210 1298.5,-210 1304.5,-216 1304.5,-222 1304.5,-222 1304.5,-243 1304.5,-243 1304.5,-249 1298.5,-255 1292.5,-255"/>
<text text-anchor="middle" x="1190" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
<text text-anchor="middle" x="1190" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI&#45;SD and DVP</text>
<text text-anchor="middle" x="1190" y="-219" font-family="Arial" font-size="10.00" fill="#111827">I2C and I2S</text>
</g>
<!-- ribp_adapter&#45;&gt;ribp_targets -->
<g id="edge19" class="edge">
<title>ribp_adapter&#45;&gt;ribp_targets</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M950.65,-320.43C985.33,-303.9 1040.64,-277.53 1081.26,-258.17"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1082.38,-260.35 1087.65,-255.12 1080.28,-255.92 1082.38,-260.35"/>
<text text-anchor="middle" x="1047.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1225.71,-318.61C1219.18,-303.05 1209.48,-279.94 1201.84,-261.72"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1204.1,-260.77 1199.13,-255.26 1199.58,-262.66 1204.1,-260.77"/>
<text text-anchor="middle" x="1224.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_adapter&#45;&gt;uart0 -->
<g id="edge20" class="edge">
<title>ribp_adapter&#45;&gt;uart0</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1265.81,-331C1358.23,-316.94 1614,-278 1614,-278 1614,-278 1949,-255 1949,-255 1949,-255 1951.57,-254.48 1955.91,-253.6"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1956.48,-255.98 1962.86,-252.19 1955.51,-251.18 1956.48,-255.98"/>
<text text-anchor="middle" x="1623.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- gpio_controller -->
<g id="node19" class="node">
<g id="node20" class="node">
<title>gpio_controller</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M914,-255C914,-255 764,-255 764,-255 758,-255 752,-249 752,-243 752,-243 752,-222 752,-222 752,-216 758,-210 764,-210 764,-210 914,-210 914,-210 920,-210 926,-216 926,-222 926,-222 926,-243 926,-243 926,-249 920,-255 914,-255"/>
<text text-anchor="middle" x="839" y="-241" font-family="Arial" font-size="10.00" fill="#111827">GPIO V2</text>
<text text-anchor="middle" x="839" y="-230" font-family="Arial" font-size="10.00" fill="#111827">user + management RIBP windows</text>
<text text-anchor="middle" x="839" y="-219" font-family="Arial" font-size="10.00" fill="#111827">atomic I/O, filter, locks, IRQ18</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M971,-255C971,-255 821,-255 821,-255 815,-255 809,-249 809,-243 809,-243 809,-222 809,-222 809,-216 815,-210 821,-210 821,-210 971,-210 971,-210 977,-210 983,-216 983,-222 983,-222 983,-243 983,-243 983,-249 977,-255 971,-255"/>
<text text-anchor="middle" x="896" y="-241" font-family="Arial" font-size="10.00" fill="#111827">GPIO V2</text>
<text text-anchor="middle" x="896" y="-230" font-family="Arial" font-size="10.00" fill="#111827">user + management RIBP windows</text>
<text text-anchor="middle" x="896" y="-219" font-family="Arial" font-size="10.00" fill="#111827">atomic I/O, filter, locks, IRQ18</text>
</g>
<!-- ribp_adapter&#45;&gt;gpio_controller -->
<g id="edge20" class="edge">
<g id="edge21" class="edge">
<title>ribp_adapter&#45;&gt;gpio_controller</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M904.6,-318.61C892.5,-302.91 874.48,-279.53 860.38,-261.25"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="861.98,-259.31 855.77,-255.26 858.1,-262.3 861.98,-259.31"/>
<text text-anchor="middle" x="905" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<text text-anchor="middle" x="905" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">user/admin</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1200.46,-333.56C1084.74,-324.87 700,-296 700,-296 700,-296 700,-278 700,-278 700,-278 751.58,-266.29 801.82,-254.88"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="802.61,-257.22 808.89,-253.28 801.52,-252.44 802.61,-257.22"/>
<text text-anchor="middle" x="720" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<text text-anchor="middle" x="720" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">user/admin</text>
</g>
<!-- ribp_adapter&#45;&gt;timers -->
<g id="edge21" class="edge">
<g id="edge22" class="edge">
<title>ribp_adapter&#45;&gt;timers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M950.61,-332.27C1037.5,-322.34 1268,-296 1268,-296 1268,-296 1387.71,-272.84 1481.38,-254.71"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1481.95,-257.1 1488.36,-253.36 1481.02,-252.29 1481.95,-257.1"/>
<text text-anchor="middle" x="1363.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1265.59,-326.62C1306.67,-314.8 1372,-296 1372,-296 1372,-296 1406,-278 1406,-278 1406,-278 1717,-255 1717,-255 1717,-255 1719.33,-254.57 1723.33,-253.83"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1723.87,-256.22 1730.31,-252.53 1722.98,-251.4 1723.87,-256.22"/>
<text text-anchor="middle" x="1415.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_adapter&#45;&gt;ws2812 -->
<g id="edge22" class="edge">
<g id="edge23" class="edge">
<title>ribp_adapter&#45;&gt;ws2812</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M885.46,-323.74C842.24,-307.45 764.93,-278.32 709.85,-257.56"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="710.66,-255.25 703.25,-255.07 708.94,-259.84 710.66,-255.25"/>
<text text-anchor="middle" x="815.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1250.38,-318.91C1267.79,-301.8 1292,-278 1292,-278 1292,-278 1318.5,-268.09 1346.5,-257.62"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1347.54,-259.84 1353.24,-255.1 1345.83,-255.26 1347.54,-259.84"/>
<text text-anchor="middle" x="1301.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- apb_targets -->
<g id="node22" class="node">
<g id="node23" class="node">
<title>apb_targets</title>
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M1923.5,-255C1923.5,-255 1732.5,-255 1732.5,-255 1726.5,-255 1720.5,-249 1720.5,-243 1720.5,-243 1720.5,-222 1720.5,-222 1720.5,-216 1726.5,-210 1732.5,-210 1732.5,-210 1923.5,-210 1923.5,-210 1929.5,-210 1935.5,-216 1935.5,-222 1935.5,-222 1935.5,-243 1935.5,-243 1935.5,-249 1929.5,-255 1923.5,-255"/>
<text text-anchor="middle" x="1828" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
<text text-anchor="middle" x="1828" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
<text text-anchor="middle" x="1828" 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="M597.5,-255C597.5,-255 406.5,-255 406.5,-255 400.5,-255 394.5,-249 394.5,-243 394.5,-243 394.5,-222 394.5,-222 394.5,-216 400.5,-210 406.5,-210 406.5,-210 597.5,-210 597.5,-210 603.5,-210 609.5,-216 609.5,-222 609.5,-222 609.5,-243 609.5,-243 609.5,-249 603.5,-255 597.5,-255"/>
<text text-anchor="middle" x="502" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
<text text-anchor="middle" x="502" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
<text text-anchor="middle" x="502" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
</g>
<!-- apb_adapter&#45;&gt;apb_targets -->
<g id="edge23" class="edge">
<g id="edge24" class="edge">
<title>apb_adapter&#45;&gt;apb_targets</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1407.02,-325.7C1480.36,-309.64 1623.83,-278.22 1722.74,-256.55"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1723.47,-258.9 1729.78,-255.01 1722.42,-254.12 1723.47,-258.9"/>
<text text-anchor="middle" x="1630" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M606.08,-318.84C586.47,-302.77 556.88,-278.5 534.25,-259.95"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="535.63,-257.9 528.66,-255.36 532.52,-261.69 535.63,-257.9"/>
<text text-anchor="middle" x="583" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
</g>
<!-- irq -->
<g id="node24" class="node">
<g id="node25" class="node">
<title>irq</title>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M749,-155C749,-155 543,-155 543,-155 537,-155 531,-149 531,-143 531,-143 531,-131 531,-131 531,-125 537,-119 543,-119 543,-119 749,-119 749,-119 755,-119 761,-125 761,-131 761,-131 761,-143 761,-143 761,-149 755,-155 749,-155"/>
<text text-anchor="middle" x="646" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
<text text-anchor="middle" x="646" 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="M1515,-155C1515,-155 1309,-155 1309,-155 1303,-155 1297,-149 1297,-143 1297,-143 1297,-131 1297,-131 1297,-125 1303,-119 1309,-119 1309,-119 1515,-119 1515,-119 1521,-119 1527,-125 1527,-131 1527,-131 1527,-143 1527,-143 1527,-149 1521,-155 1515,-155"/>
<text text-anchor="middle" x="1412" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
<text text-anchor="middle" x="1412" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
</g>
<!-- clint&#45;&gt;irq -->
<g id="edge28" class="edge">
<g id="edge29" class="edge">
<title>clint&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M505.77,-209.89C532.41,-195.05 563,-178 563,-178 563,-178 583.39,-168.18 603.95,-158.26"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="605.08,-160.44 610.32,-155.2 602.95,-156.03 605.08,-160.44"/>
<text text-anchor="middle" x="601.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">machine IRQ0 / IRQ1</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M781.63,-213.55C790.22,-211.43 796,-210 796,-210 796,-210 960,-178 960,-178 960,-178 1284,-155 1284,-155 1284,-155 1286.1,-154.72 1289.77,-154.23"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1290.12,-156.66 1296.74,-153.31 1289.48,-151.8 1290.12,-156.66"/>
<text text-anchor="middle" x="998.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">machine IRQ0 / IRQ1</text>
</g>
<!-- ribp_targets&#45;&gt;ext_io -->
<g id="edge33" class="edge">
<g id="edge36" class="edge">
<title>ribp_targets&#45;&gt;ext_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1111.03,-203.97C1079.15,-164.03 1020.42,-90.44 988.7,-50.69"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1109.27,-205.69 1115.55,-209.63 1113.1,-202.63 1109.27,-205.69"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="990.5,-49.02 984.22,-45.07 986.67,-52.07 990.5,-49.02"/>
<text text-anchor="middle" x="1101" 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="M1311.9,-211.18C1316.39,-210.44 1319,-210 1319,-210 1319,-210 1564,-187 1564,-187 1564,-187 1573.65,-99.32 1578.82,-52.38"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1311.2,-208.82 1304.7,-212.38 1312.01,-213.65 1311.2,-208.82"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1581.28,-52.44 1579.61,-45.21 1576.41,-51.9 1581.28,-52.44"/>
<text text-anchor="middle" x="1605" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
</g>
<!-- ribp_targets&#45;&gt;gpio_controller -->
<g id="edge24" class="edge">
<g id="edge25" class="edge">
<title>ribp_targets&#45;&gt;gpio_controller</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1018.39,-232.5C990.19,-232.5 960.32,-232.5 933.21,-232.5"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="933.02,-230.05 926.02,-232.5 933.02,-234.95 933.02,-230.05"/>
<text text-anchor="middle" x="972.25" y="-238.1" font-family="Arial" font-size="8.00" fill="#374151">alternate functions</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1075.39,-232.5C1047.19,-232.5 1017.32,-232.5 990.21,-232.5"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="990.02,-230.05 983.02,-232.5 990.02,-234.95 990.02,-230.05"/>
<text text-anchor="middle" x="1029.25" y="-238.1" font-family="Arial" font-size="8.00" fill="#374151">alternate functions</text>
</g>
<!-- uart0&#45;&gt;ext_io -->
<g id="edge37" class="edge">
<title>uart0&#45;&gt;ext_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1999.17,-206.95C1908.15,-166.92 1728.85,-88.08 1637.83,-48.05"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1998.33,-209.25 2005.72,-209.83 2000.3,-204.77 1998.33,-209.25"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1638.56,-45.7 1631.17,-45.12 1636.59,-50.18 1638.56,-45.7"/>
<text text-anchor="middle" x="1901" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">UART pads</text>
</g>
<!-- uart0&#45;&gt;irq -->
<g id="edge34" class="edge">
<title>uart0&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1962.86,-212.81C1954.44,-211.1 1949,-210 1949,-210 1949,-210 1692.67,-175.63 1534.2,-154.38"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1534.46,-151.95 1527.2,-153.45 1533.81,-156.8 1534.46,-151.95"/>
<text text-anchor="middle" x="1784.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ2</text>
</g>
<!-- gpio_bridge -->
<g id="node23" class="node">
<g id="node24" class="node">
<title>gpio_bridge</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M935.5,-155C935.5,-155 800.5,-155 800.5,-155 794.5,-155 788.5,-149 788.5,-143 788.5,-143 788.5,-131 788.5,-131 788.5,-125 794.5,-119 800.5,-119 800.5,-119 935.5,-119 935.5,-119 941.5,-119 947.5,-125 947.5,-131 947.5,-131 947.5,-143 947.5,-143 947.5,-149 941.5,-155 935.5,-155"/>
<text text-anchor="middle" x="868" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
<text text-anchor="middle" x="868" y="-129" font-family="Arial" font-size="10.00" fill="#111827">PDK capability&#45;adapted controls</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1258.5,-155C1258.5,-155 1123.5,-155 1123.5,-155 1117.5,-155 1111.5,-149 1111.5,-143 1111.5,-143 1111.5,-131 1111.5,-131 1111.5,-125 1117.5,-119 1123.5,-119 1123.5,-119 1258.5,-119 1258.5,-119 1264.5,-119 1270.5,-125 1270.5,-131 1270.5,-131 1270.5,-143 1270.5,-143 1270.5,-149 1264.5,-155 1258.5,-155"/>
<text text-anchor="middle" x="1191" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
<text text-anchor="middle" x="1191" y="-129" font-family="Arial" font-size="10.00" fill="#111827">PDK capability&#45;adapted controls</text>
</g>
<!-- gpio_controller&#45;&gt;gpio_bridge -->
<g id="edge25" class="edge">
<g id="edge26" class="edge">
<title>gpio_controller&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M845.73,-209.81C850.15,-195.54 855.96,-176.83 860.53,-162.09"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="862.93,-162.62 862.66,-155.2 858.25,-161.16 862.93,-162.62"/>
<text text-anchor="middle" x="875" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M964.05,-209.93C1014.27,-194.02 1082,-172.55 1130.36,-157.22"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1131.12,-159.55 1137.06,-155.1 1129.64,-154.88 1131.12,-159.55"/>
<text text-anchor="middle" x="1081" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
</g>
<!-- gpio_controller&#45;&gt;irq -->
<g id="edge26" class="edge">
<g id="edge27" class="edge">
<title>gpio_controller&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M780.27,-209.9C749.44,-198.56 718,-187 718,-187 718,-187 696.6,-172.44 677.14,-159.19"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="678.35,-157.05 671.18,-155.14 675.59,-161.1 678.35,-157.05"/>
<text text-anchor="middle" x="730" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ18</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M983.24,-215.69C1073.8,-199.28 1215.3,-173.64 1310.73,-156.35"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1311.35,-158.73 1317.8,-155.07 1310.48,-153.91 1311.35,-158.73"/>
<text text-anchor="middle" x="1196" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ18</text>
</g>
<!-- timers&#45;&gt;irq -->
<g id="edge27" class="edge">
<g id="edge28" class="edge">
<title>timers&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1488.31,-212.47C1480.16,-210.96 1475,-210 1475,-210 1475,-210 775,-155 775,-155 775,-155 772.48,-154.67 768.16,-154.1"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="768.45,-151.67 761.19,-153.18 767.81,-156.52 768.45,-151.67"/>
<text text-anchor="middle" x="1188.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ3 / IRQ4</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1730.31,-212.47C1722.16,-210.96 1717,-210 1717,-210 1717,-210 1466,-187 1466,-187 1466,-187 1450.5,-172.93 1436.11,-159.88"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1437.72,-158.03 1430.89,-155.14 1434.42,-161.66 1437.72,-158.03"/>
<text text-anchor="middle" x="1488.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ3 / IRQ4</text>
</g>
<!-- ws2812&#45;&gt;gpio_bridge -->
<g id="edge29" class="edge">
<g id="edge30" class="edge">
<title>ws2812&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M697.21,-209.93C734.46,-194.24 784.51,-173.16 820.8,-157.88"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="821.91,-160.07 827.41,-155.1 820,-155.56 821.91,-160.07"/>
<text text-anchor="middle" x="792.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1360.25,-209.93C1323.34,-194.24 1273.74,-173.16 1237.78,-157.88"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1238.63,-155.58 1231.23,-155.1 1236.71,-160.09 1238.63,-155.58"/>
<text text-anchor="middle" x="1323.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
</g>
<!-- ws2812&#45;&gt;irq -->
<g id="edge31" class="edge">
<g id="edge32" class="edge">
<title>ws2812&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M646,-209.81C646,-195.66 646,-177.17 646,-162.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="648.45,-162.2 646,-155.2 643.55,-162.2 648.45,-162.2"/>
<text text-anchor="middle" x="658" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1410.51,-209.77C1410.26,-198.48 1410,-187 1410,-187 1410,-187 1410,-178 1410,-178 1410,-178 1410.37,-170.7 1410.78,-162.33"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1413.24,-162.31 1411.14,-155.2 1408.34,-162.06 1413.24,-162.31"/>
<text text-anchor="middle" x="1422" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
</g>
<!-- apb_targets&#45;&gt;gpio_controller -->
<g id="edge32" class="edge">
<g id="edge35" class="edge">
<title>apb_targets&#45;&gt;gpio_controller</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1720.41,-252.51C1712.19,-254.04 1707,-255 1707,-255 1707,-255 1192,-282.5 1192,-282.5 1192,-282.5 1156,-282.5 1156,-282.5 1156,-282.5 1026.45,-262.07 932.99,-247.32"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="933.34,-244.9 926.04,-246.23 932.57,-249.74 933.34,-244.9"/>
<text text-anchor="middle" x="1174" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M609.73,-254.58C675.1,-267.97 746,-282.5 746,-282.5 746,-282.5 782,-282.5 782,-282.5 782,-282.5 809.78,-270.32 837.91,-257.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="839.24,-260.07 844.67,-255.01 837.27,-255.58 839.24,-260.07"/>
<text text-anchor="middle" x="764" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
</g>
<!-- gpio_bridge&#45;&gt;ext_io -->
<g id="edge34" class="edge">
<g id="edge38" class="edge">
<title>gpio_bridge&#45;&gt;ext_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M887.73,-113.58C903.67,-95.47 926.16,-69.91 943.11,-50.65"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="885.82,-112.04 883.04,-118.91 889.5,-115.28 885.82,-112.04"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="944.95,-52.26 947.74,-45.39 941.27,-49.03 944.95,-52.26"/>
<text text-anchor="middle" x="946" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1228.68,-115.34C1254.46,-101.2 1284,-85 1284,-85 1284,-85 1386.02,-63.94 1470.68,-46.47"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1227.19,-113.36 1222.23,-118.88 1229.54,-117.66 1227.19,-113.36"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1471.41,-48.82 1477.77,-45.01 1470.42,-44.03 1471.41,-48.82"/>
<text text-anchor="middle" x="1383" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 40 KiB

+10 -1
View File
@@ -32,8 +32,17 @@ interface dma_hw_trg_if ();
logic i2s_rx_proc;
logic qspi_tx_proc;
logic qspi_rx_proc;
logic uart_tx_proc;
logic uart_rx_proc;
modport dut(input i2s_tx_proc, input i2s_rx_proc, input qspi_tx_proc, input qspi_rx_proc);
modport dut(
input i2s_tx_proc,
input i2s_rx_proc,
input qspi_tx_proc,
input qspi_rx_proc,
input uart_tx_proc,
input uart_rx_proc
);
endinterface
`endif
+4
View File
@@ -39,6 +39,8 @@ module dma_core (
localparam logic [2:0] HWT_I2S_RX_TRG = 3'd2;
localparam logic [2:0] HWT_QSPI_TX_TRG = 3'd3;
localparam logic [2:0] HWT_QSPI_RX_TRG = 3'd4;
localparam logic [2:0] HWT_UART_TX_TRG = 3'd5;
localparam logic [2:0] HWT_UART_RX_TRG = 3'd6;
localparam logic [2:0] FSM_IDLE = 3'd0;
localparam logic [2:0] FSM_RD_CMD = 3'd1;
@@ -86,6 +88,7 @@ module dma_core (
unique case (mode_i)
HWT_I2S_RX_TRG: s_read_trigger = hw_trg.i2s_rx_proc;
HWT_QSPI_RX_TRG: s_read_trigger = hw_trg.qspi_rx_proc;
HWT_UART_RX_TRG: s_read_trigger = hw_trg.uart_rx_proc;
default: s_read_trigger = 1'b1;
endcase
end
@@ -95,6 +98,7 @@ module dma_core (
unique case (mode_i)
HWT_I2S_TX_TRG: s_write_trigger = hw_trg.i2s_tx_proc;
HWT_QSPI_TX_TRG: s_write_trigger = hw_trg.qspi_tx_proc;
HWT_UART_TX_TRG: s_write_trigger = hw_trg.uart_tx_proc;
default: s_write_trigger = 1'b1;
endcase
end
+97
View File
@@ -0,0 +1,97 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module ribp_uart #(
parameter int TX_FIFO_DEPTH = 64,
parameter int RX_FIFO_DEPTH = 64
) (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o,
ribp_if.slave ribp,
uart_if.dut uart
// verilog_format: on
);
logic [23:0] s_baud_int;
logic [ 7:0] s_baud_frac;
logic [ 1:0] s_data_bits;
logic s_stop2;
logic [ 1:0] s_parity;
logic s_tx_enable;
logic s_rx_enable;
logic s_loopback;
logic s_break;
logic s_tx_data_valid;
logic [ 7:0] s_tx_data;
logic s_tx_data_pop;
logic s_tx_busy;
logic s_tx_done;
logic s_rx_active;
logic s_rx_data_valid;
logic [11:0] s_rx_data;
logic s_bit_tick;
logic s_irq;
logic s_tx;
assign uart.tx_o = s_tx;
assign uart.irq_o = s_irq;
uart_reg #(
.TX_FIFO_DEPTH(TX_FIFO_DEPTH),
.RX_FIFO_DEPTH(RX_FIFO_DEPTH)
) u_uart_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.baud_int_o (s_baud_int),
.baud_frac_o (s_baud_frac),
.data_bits_o (s_data_bits),
.stop2_o (s_stop2),
.parity_o (s_parity),
.tx_enable_o (s_tx_enable),
.rx_enable_o (s_rx_enable),
.loopback_o (s_loopback),
.break_o (s_break),
.tx_data_valid_o(s_tx_data_valid),
.tx_data_o (s_tx_data),
.tx_data_pop_i (s_tx_data_pop),
.tx_busy_i (s_tx_busy),
.tx_done_i (s_tx_done),
.rx_active_i (s_rx_active),
.rx_data_valid_i(s_rx_data_valid),
.rx_data_i (s_rx_data),
.bit_tick_i (s_bit_tick),
.dma_tx_stall_o (dma_tx_stall_o),
.dma_rx_stall_o (dma_rx_stall_o),
.irq_o (s_irq)
);
uart_core u_uart_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.baud_int_i (s_baud_int),
.baud_frac_i (s_baud_frac),
.data_bits_i (s_data_bits),
.stop2_i (s_stop2),
.parity_i (s_parity),
.tx_enable_i (s_tx_enable),
.rx_enable_i (s_rx_enable),
.loopback_i (s_loopback),
.break_i (s_break),
.tx_data_valid_i(s_tx_data_valid),
.tx_data_i (s_tx_data),
.tx_data_pop_o (s_tx_data_pop),
.tx_busy_o (s_tx_busy),
.tx_done_o (s_tx_done),
.rx_active_o (s_rx_active),
.rx_data_valid_o(s_rx_data_valid),
.rx_data_o (s_rx_data),
.bit_tick_o (s_bit_tick),
.rx_i (uart.rx_i),
.tx_o (s_tx)
);
endmodule
+78
View File
@@ -0,0 +1,78 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`ifndef RIBP_UART_DEFINE_SVH
`define RIBP_UART_DEFINE_SVH
// verilog_format: off
`define RIBP_UART_BAUD_INT 8'h00
`define RIBP_UART_BAUD_FRAC 8'h04
`define RIBP_UART_LINE_CTRL 8'h08
`define RIBP_UART_CTRL 8'h0C
`define RIBP_UART_TXDATA 8'h10
`define RIBP_UART_RXDATA 8'h14
`define RIBP_UART_STATUS 8'h18
`define RIBP_UART_FIFO_LEVEL 8'h1C
`define RIBP_UART_FIFO_CTRL 8'h20
`define RIBP_UART_TX_WATERMARK 8'h24
`define RIBP_UART_RX_WATERMARK 8'h28
`define RIBP_UART_RX_TIMEOUT_BITS 8'h2C
`define RIBP_UART_ERROR_STATUS 8'h30
`define RIBP_UART_INTR_STATE 8'h34
`define RIBP_UART_INTR_ENABLE 8'h38
`define RIBP_UART_INTR_STATUS 8'h3C
`define RIBP_UART_INTR_TEST 8'h40
`define RIBP_UART_DMA_CTRL 8'h44
`define RIBP_UART_IP_VERSION 8'hF8
`define RIBP_UART_CAPABILITY 8'hFC
`define UART_LINE_DATA_BITS 0
`define UART_LINE_STOP2 2
`define UART_LINE_PARITY 3
`define UART_CTRL_TX_ENABLE 0
`define UART_CTRL_RX_ENABLE 1
`define UART_CTRL_LOOPBACK 2
`define UART_CTRL_TX_BREAK 3
`define UART_FIFO_CTRL_TX_FLUSH 0
`define UART_FIFO_CTRL_RX_FLUSH 1
`define UART_STATUS_TX_ENABLED 0
`define UART_STATUS_RX_ENABLED 1
`define UART_STATUS_TX_BUSY 2
`define UART_STATUS_RX_ACTIVE 3
`define UART_STATUS_TX_EMPTY 4
`define UART_STATUS_TX_FULL 5
`define UART_STATUS_RX_EMPTY 6
`define UART_STATUS_RX_FULL 7
`define UART_STATUS_CONFIG_VALID 8
`define UART_STATUS_BREAK_ACTIVE 9
`define UART_STATUS_TX_DMA_REQ 10
`define UART_STATUS_RX_DMA_REQ 11
`define UART_RXDATA_PARITY_ERROR 8
`define UART_RXDATA_FRAME_ERROR 9
`define UART_RXDATA_BREAK 10
`define UART_RXDATA_NOISE 11
`define UART_ERROR_OVERRUN 0
`define UART_ERROR_PARITY 1
`define UART_ERROR_FRAME 2
`define UART_ERROR_BREAK 3
`define UART_ERROR_NOISE 4
`define UART_ERROR_CONFIG 5
`define UART_ERROR_COMMAND 6
`define UART_INTR_RX_WATERMARK 0
`define UART_INTR_RX_TIMEOUT 1
`define UART_INTR_TX_WATERMARK 2
`define UART_INTR_TX_DONE 3
`define UART_INTR_RX_ERROR 4
`define UART_INTR_BREAK 5
`define UART_DMA_TX_ENABLE 0
`define UART_DMA_RX_ENABLE 1
// verilog_format: on
`endif
+239
View File
@@ -0,0 +1,239 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module ribp_uart_rx (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic sample_tick_i,
input logic enable_i,
input logic [ 1:0] data_bits_i,
input logic stop2_i,
input logic [ 1:0] parity_i,
input logic rx_i,
output logic active_o,
output logic data_valid_o,
output logic [11:0] data_o
// verilog_format: on
);
localparam logic [2:0] STATE_IDLE = 3'd0;
localparam logic [2:0] STATE_START = 3'd1;
localparam logic [2:0] STATE_DATA = 3'd2;
localparam logic [2:0] STATE_PARITY = 3'd3;
localparam logic [2:0] STATE_STOP1 = 3'd4;
localparam logic [2:0] STATE_STOP2 = 3'd5;
logic s_rx_meta_d, s_rx_meta_q;
logic s_rx_sync_d, s_rx_sync_q;
logic [2:0] s_state_d, s_state_q;
logic [3:0] s_sample_d, s_sample_q;
logic [2:0] s_bit_d, s_bit_q;
logic [1:0] s_sample_sum_d, s_sample_sum_q;
logic s_sample_and_d, s_sample_and_q;
logic s_sample_or_d, s_sample_or_q;
logic s_sample_value_d, s_sample_value_q;
logic [7:0] s_data_d, s_data_q;
logic s_parity_error_d, s_parity_error_q;
logic s_frame_error_d, s_frame_error_q;
logic s_noise_d, s_noise_q;
logic [2:0] s_last_bit;
logic [7:0] s_data_mask;
logic s_majority;
logic s_samples_mixed;
logic s_expected_parity;
assign s_rx_meta_d = rx_i;
assign s_rx_sync_d = s_rx_meta_q;
assign s_last_bit = 3'd4 + {1'b0, data_bits_i};
assign s_majority = (s_sample_sum_q + s_rx_sync_q) >= 2'd2;
assign s_samples_mixed = (s_sample_and_q & s_rx_sync_q) != (s_sample_or_q | s_rx_sync_q);
assign active_o = s_state_q != STATE_IDLE;
always_comb begin
unique case (data_bits_i)
2'd0: s_data_mask = 8'h1F;
2'd1: s_data_mask = 8'h3F;
2'd2: s_data_mask = 8'h7F;
default: s_data_mask = 8'hFF;
endcase
end
assign s_expected_parity = (parity_i == 2'd2) ? ~^(s_data_q & s_data_mask) :
^(s_data_q & s_data_mask);
always_comb begin
s_state_d = s_state_q;
s_sample_d = s_sample_q;
s_bit_d = s_bit_q;
s_sample_sum_d = s_sample_sum_q;
s_sample_and_d = s_sample_and_q;
s_sample_or_d = s_sample_or_q;
s_sample_value_d = s_sample_value_q;
s_data_d = s_data_q;
s_parity_error_d = s_parity_error_q;
s_frame_error_d = s_frame_error_q;
s_noise_d = s_noise_q;
data_valid_o = 1'b0;
data_o = {
s_noise_q,
(s_frame_error_q && (s_data_q == 8'd0)),
s_frame_error_q,
s_parity_error_q,
s_data_q
};
if (!enable_i) begin
s_state_d = STATE_IDLE;
s_sample_d = '0;
s_bit_d = '0;
s_parity_error_d = 1'b0;
s_frame_error_d = 1'b0;
s_noise_d = 1'b0;
end else if ((s_state_q == STATE_IDLE) && !s_rx_sync_q) begin
s_state_d = STATE_START;
s_sample_d = '0;
s_bit_d = '0;
s_data_d = '0;
s_parity_error_d = 1'b0;
s_frame_error_d = 1'b0;
s_noise_d = 1'b0;
end else if ((s_state_q != STATE_IDLE) && sample_tick_i) begin
if (s_sample_q == 4'd7) begin
s_sample_sum_d = {1'b0, s_rx_sync_q};
s_sample_and_d = s_rx_sync_q;
s_sample_or_d = s_rx_sync_q;
end else if (s_sample_q == 4'd8) begin
s_sample_sum_d = s_sample_sum_q + s_rx_sync_q;
s_sample_and_d = s_sample_and_q & s_rx_sync_q;
s_sample_or_d = s_sample_or_q | s_rx_sync_q;
end else if (s_sample_q == 4'd9) begin
s_sample_value_d = s_majority;
s_noise_d = s_noise_q | s_samples_mixed;
unique case (s_state_q)
STATE_DATA: s_data_d[s_bit_q] = s_majority;
STATE_PARITY: s_parity_error_d = s_majority != s_expected_parity;
STATE_STOP1: s_frame_error_d = !s_majority;
STATE_STOP2: s_frame_error_d = s_frame_error_q | !s_majority;
default: begin
end
endcase
end
if (s_sample_q != 4'd15) begin
s_sample_d = s_sample_q + 1'b1;
end else begin
s_sample_d = '0;
unique case (s_state_q)
STATE_START: begin
if (s_sample_value_q) begin
s_state_d = STATE_IDLE;
end else begin
s_state_d = STATE_DATA;
end
end
STATE_DATA: begin
if (s_bit_q == s_last_bit) begin
s_state_d = (parity_i == 2'd0) ? STATE_STOP1 : STATE_PARITY;
end else begin
s_bit_d = s_bit_q + 1'b1;
end
end
STATE_PARITY: s_state_d = STATE_STOP1;
STATE_STOP1: begin
if (stop2_i) begin
s_state_d = STATE_STOP2;
end else begin
s_state_d = STATE_IDLE;
data_valid_o = 1'b1;
end
end
STATE_STOP2: begin
s_state_d = STATE_IDLE;
data_valid_o = 1'b1;
end
default: s_state_d = STATE_IDLE;
endcase
end
end
end
dffr #(1) u_rx_meta_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rx_meta_d),
.dat_o (s_rx_meta_q)
);
dffr #(1) u_rx_sync_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rx_sync_d),
.dat_o (s_rx_sync_q)
);
dffr #(3) u_state_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_state_d),
.dat_o (s_state_q)
);
dffr #(4) u_sample_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_d),
.dat_o (s_sample_q)
);
dffr #(3) u_bit_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_bit_d),
.dat_o (s_bit_q)
);
dffr #(2) u_sample_sum_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_sum_d),
.dat_o (s_sample_sum_q)
);
dffr #(1) u_sample_and_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_and_d),
.dat_o (s_sample_and_q)
);
dffr #(1) u_sample_or_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_or_d),
.dat_o (s_sample_or_q)
);
dffr #(1) u_sample_value_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_value_d),
.dat_o (s_sample_value_q)
);
dffr #(8) u_data_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_data_d),
.dat_o (s_data_q)
);
dffr #(1) u_parity_error_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_parity_error_d),
.dat_o (s_parity_error_q)
);
dffr #(1) u_frame_error_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_frame_error_d),
.dat_o (s_frame_error_q)
);
dffr #(1) u_noise_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_noise_d),
.dat_o (s_noise_q)
);
endmodule
+143
View File
@@ -0,0 +1,143 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module ribp_uart_tx (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic sample_tick_i,
input logic enable_i,
input logic break_i,
input logic [1:0] data_bits_i,
input logic stop2_i,
input logic [1:0] parity_i,
input logic data_valid_i,
input logic [7:0] data_i,
output logic data_pop_o,
output logic busy_o,
output logic done_o,
output logic tx_o
// verilog_format: on
);
localparam logic [2:0] STATE_IDLE = 3'd0;
localparam logic [2:0] STATE_START = 3'd1;
localparam logic [2:0] STATE_DATA = 3'd2;
localparam logic [2:0] STATE_PARITY = 3'd3;
localparam logic [2:0] STATE_STOP1 = 3'd4;
localparam logic [2:0] STATE_STOP2 = 3'd5;
logic [2:0] s_state_d, s_state_q;
logic [3:0] s_sample_d, s_sample_q;
logic [2:0] s_bit_d, s_bit_q;
logic [7:0] s_shift_d, s_shift_q;
logic s_parity_d, s_parity_q;
logic [2:0] s_last_bit;
logic [7:0] s_data_mask;
always_comb begin
unique case (data_bits_i)
2'd0: s_data_mask = 8'h1F;
2'd1: s_data_mask = 8'h3F;
2'd2: s_data_mask = 8'h7F;
default: s_data_mask = 8'hFF;
endcase
end
assign s_last_bit = 3'd4 + {1'b0, data_bits_i};
assign busy_o = s_state_q != STATE_IDLE;
always_comb begin
unique case (s_state_q)
STATE_START: tx_o = 1'b0;
STATE_DATA: tx_o = s_shift_q[0];
STATE_PARITY: tx_o = s_parity_q;
default: tx_o = 1'b1;
endcase
if (break_i) begin
tx_o = 1'b0;
end
end
always_comb begin
s_state_d = s_state_q;
s_sample_d = s_sample_q;
s_bit_d = s_bit_q;
s_shift_d = s_shift_q;
s_parity_d = s_parity_q;
data_pop_o = 1'b0;
done_o = 1'b0;
if ((s_state_q == STATE_IDLE) && enable_i && !break_i && data_valid_i && sample_tick_i) begin
s_state_d = STATE_START;
s_sample_d = '0;
s_bit_d = '0;
s_shift_d = data_i;
s_parity_d = (parity_i == 2'd2) ? ~^(data_i & s_data_mask) : ^(data_i & s_data_mask);
data_pop_o = 1'b1;
end else if ((s_state_q != STATE_IDLE) && sample_tick_i) begin
if (s_sample_q != 4'd15) begin
s_sample_d = s_sample_q + 1'b1;
end else begin
s_sample_d = '0;
unique case (s_state_q)
STATE_START: s_state_d = STATE_DATA;
STATE_DATA: begin
s_shift_d = {1'b0, s_shift_q[7:1]};
if (s_bit_q == s_last_bit) begin
s_state_d = (parity_i == 2'd0) ? STATE_STOP1 : STATE_PARITY;
end else begin
s_bit_d = s_bit_q + 1'b1;
end
end
STATE_PARITY: s_state_d = STATE_STOP1;
STATE_STOP1: begin
if (stop2_i) begin
s_state_d = STATE_STOP2;
end else begin
s_state_d = STATE_IDLE;
done_o = 1'b1;
end
end
STATE_STOP2: begin
s_state_d = STATE_IDLE;
done_o = 1'b1;
end
default: s_state_d = STATE_IDLE;
endcase
end
end
end
dffr #(3) u_state_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_state_d),
.dat_o (s_state_q)
);
dffr #(4) u_sample_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_d),
.dat_o (s_sample_q)
);
dffr #(3) u_bit_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_bit_d),
.dat_o (s_bit_q)
);
dffr #(8) u_shift_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_shift_d),
.dat_o (s_shift_q)
);
dffr #(1) u_parity_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_parity_d),
.dat_o (s_parity_q)
);
endmodule
-195
View File
@@ -1,195 +0,0 @@
/*
* Ravenna - A full example SoC using PicoRV32 in ASIC
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2018,2019 Tim Edwards <tim@efabless.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// -- Adaptable modifications are redistributed under compatible License --
//
// 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 RIBP_UART_DEF_SV
`define RIBP_UART_DEF_SV
// verilog_format: off
`define RIBP_UART_DIV 8'h00
`define RIBP_UART_DAT 8'h04
// verilog_format: on
`endif
module ribp_uart (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
uart_if.dut uart
// 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_uart_div_en;
logic [31:0] s_uart_div_d, s_uart_div_q;
logic s_send_dat_wait;
logic s_uart_dat_en;
// register
logic [ 3:0] r_recv_state;
logic [31:0] r_recv_divcnt;
logic [ 7:0] r_recv_pattern;
logic [ 7:0] r_recv_buf_data;
logic r_recv_buf_valid;
logic [ 9:0] r_send_pattern;
logic [ 3:0] r_send_bitcnt;
logic [31:0] r_send_divcnt;
logic r_send_dummy;
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 uart.tx_o = r_send_pattern[0];
assign uart.irq_o = r_recv_buf_valid;
assign s_uart_div_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_UART_DIV;
always_comb begin
s_uart_div_d = s_uart_div_q;
if (ribp.wstrb[0]) s_uart_div_d[7:0] = ribp.wdata[7:0];
if (ribp.wstrb[1]) s_uart_div_d[15:8] = ribp.wdata[15:8];
if (ribp.wstrb[2]) s_uart_div_d[23:16] = ribp.wdata[23:16];
if (ribp.wstrb[3]) s_uart_div_d[31:24] = ribp.wdata[31:24];
end
dfferh #(32) u_uart_div_dfferh (
clk_i,
rst_n_i,
s_uart_div_en,
s_uart_div_d,
s_uart_div_q
);
assign s_uart_dat_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_UART_DAT;
assign s_send_dat_wait = s_uart_dat_en && ribp.wstrb[0] && ((|r_send_bitcnt) || r_send_dummy);
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q) && (~s_send_dat_wait);
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_UART_DIV: s_ribp_rdata_d = s_uart_div_q;
`RIBP_UART_DAT: s_ribp_rdata_d = r_recv_buf_valid ? {24'd0, r_recv_buf_data} : '1;
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
);
always_ff @(posedge clk_i, negedge rst_n_i) begin
if (!rst_n_i) begin
r_recv_state <= '0;
r_recv_divcnt <= '0;
r_recv_pattern <= '0;
r_recv_buf_data <= '0;
r_recv_buf_valid <= '0;
end else begin
r_recv_divcnt <= r_recv_divcnt + 1'b1;
if (s_uart_dat_en) r_recv_buf_valid <= '0;
case (r_recv_state)
4'd0: begin
if (!uart.rx_i) r_recv_state <= 4'b1;
r_recv_divcnt <= '0;
end
4'd1: begin
if (2 * r_recv_divcnt > s_uart_div_q) begin
r_recv_state <= 4'd2;
r_recv_divcnt <= '0;
end
end
4'd10: begin
if (r_recv_divcnt > s_uart_div_q) begin
r_recv_buf_data <= r_recv_pattern;
r_recv_buf_valid <= 1'b1;
r_recv_state <= '0;
end
end
default: begin
if (r_recv_divcnt > s_uart_div_q) begin
r_recv_pattern <= {uart.rx_i, r_recv_pattern[7:1]};
r_recv_state <= r_recv_state + 1'b1;
r_recv_divcnt <= '0;
end
end
endcase
end
end
always_ff @(posedge clk_i, negedge rst_n_i) begin
if (!rst_n_i) begin
r_send_pattern <= '1;
r_send_bitcnt <= '0;
r_send_divcnt <= '0;
r_send_dummy <= 1'b1;
end else begin
if (s_uart_div_en) r_send_dummy <= 1'b1;
r_send_divcnt <= r_send_divcnt + 1'b1;
if (r_send_dummy && (~(|r_send_bitcnt))) begin
r_send_pattern <= '1;
r_send_bitcnt <= 4'd15;
r_send_divcnt <= '0;
r_send_dummy <= '0;
end else if (s_uart_dat_en && ribp.wstrb[0] && (~(|r_send_bitcnt))) begin
r_send_pattern <= {1'b1, ribp.wdata[7:0], 1'b0};
`ifndef SYNTHESIS
`ifdef SIMU_VERILATOR
$write("%c", ribp.wdata[7:0]); // NOTE: just for verilator sim
`endif
`endif
r_send_bitcnt <= 4'd10;
r_send_divcnt <= '0;
end else if (r_send_divcnt > s_uart_div_q && (|r_send_bitcnt)) begin
r_send_pattern <= {1'b1, r_send_pattern[9:1]};
r_send_bitcnt <= r_send_bitcnt - 1'b1;
r_send_divcnt <= '0;
end
end
end
endmodule
+56
View File
@@ -0,0 +1,56 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module uart_baudgen (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic enable_i,
input logic [23:0] baud_int_i,
input logic [ 7:0] baud_frac_i,
output logic sample_tick_o,
output logic bit_tick_o
// verilog_format: on
);
localparam logic [31:0] SAMPLE_STEP = 32'd4096;
logic [31:0] s_period;
logic [31:0] s_phase_d, s_phase_q;
logic [3:0] s_sample_count_d, s_sample_count_q;
logic [32:0] s_phase_sum;
assign s_period = {baud_int_i, baud_frac_i};
assign s_phase_sum = {1'b0, s_phase_q} + {1'b0, SAMPLE_STEP};
assign sample_tick_o = enable_i && (s_period >= SAMPLE_STEP) && (s_phase_sum >= {1'b0, s_period});
assign bit_tick_o = sample_tick_o && (s_sample_count_q == 4'd15);
always_comb begin
s_phase_d = s_phase_q;
s_sample_count_d = s_sample_count_q;
if (!enable_i || (s_period < SAMPLE_STEP)) begin
s_phase_d = '0;
s_sample_count_d = '0;
end else if (sample_tick_o) begin
s_phase_d = 32'(s_phase_sum - {1'b0, s_period});
s_sample_count_d = s_sample_count_q + 1'b1;
end else begin
s_phase_d = 32'(s_phase_sum);
end
end
dffr #(32) u_phase_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_phase_d),
.dat_o (s_phase_q)
);
dffr #(4) u_sample_count_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_sample_count_d),
.dat_o (s_sample_count_q)
);
endmodule
+79
View File
@@ -0,0 +1,79 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module uart_core (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic [23:0] baud_int_i,
input logic [ 7:0] baud_frac_i,
input logic [ 1:0] data_bits_i,
input logic stop2_i,
input logic [ 1:0] parity_i,
input logic tx_enable_i,
input logic rx_enable_i,
input logic loopback_i,
input logic break_i,
input logic tx_data_valid_i,
input logic [ 7:0] tx_data_i,
output logic tx_data_pop_o,
output logic tx_busy_o,
output logic tx_done_o,
output logic rx_active_o,
output logic rx_data_valid_o,
output logic [11:0] rx_data_o,
output logic bit_tick_o,
input logic rx_i,
output logic tx_o
// verilog_format: on
);
logic s_sample_tick;
logic s_tx;
logic s_rx;
assign s_rx = loopback_i ? s_tx : rx_i;
assign tx_o = s_tx;
uart_baudgen u_uart_baudgen (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.enable_i (tx_enable_i || rx_enable_i || tx_busy_o),
.baud_int_i (baud_int_i),
.baud_frac_i (baud_frac_i),
.sample_tick_o(s_sample_tick),
.bit_tick_o (bit_tick_o)
);
ribp_uart_tx u_ribp_uart_tx (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.sample_tick_i(s_sample_tick),
.enable_i (tx_enable_i),
.break_i (break_i),
.data_bits_i (data_bits_i),
.stop2_i (stop2_i),
.parity_i (parity_i),
.data_valid_i (tx_data_valid_i),
.data_i (tx_data_i),
.data_pop_o (tx_data_pop_o),
.busy_o (tx_busy_o),
.done_o (tx_done_o),
.tx_o (s_tx)
);
ribp_uart_rx u_ribp_uart_rx (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.sample_tick_i(s_sample_tick),
.enable_i (rx_enable_i),
.data_bits_i (data_bits_i),
.stop2_i (stop2_i),
.parity_i (parity_i),
.rx_i (s_rx),
.active_o (rx_active_o),
.data_valid_o (rx_data_valid_o),
.data_o (rx_data_o)
);
endmodule
+601
View File
@@ -0,0 +1,601 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "ribp_uart_define.svh"
module uart_reg #(
parameter int TX_FIFO_DEPTH = 64,
parameter int RX_FIFO_DEPTH = 64,
parameter int TX_FIFO_LOG_DEPTH = $clog2(TX_FIFO_DEPTH),
parameter int RX_FIFO_LOG_DEPTH = $clog2(RX_FIFO_DEPTH)
) (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
output logic [23:0] baud_int_o,
output logic [ 7:0] baud_frac_o,
output logic [ 1:0] data_bits_o,
output logic stop2_o,
output logic [ 1:0] parity_o,
output logic tx_enable_o,
output logic rx_enable_o,
output logic loopback_o,
output logic break_o,
output logic tx_data_valid_o,
output logic [ 7:0] tx_data_o,
input logic tx_data_pop_i,
input logic tx_busy_i,
input logic tx_done_i,
input logic rx_active_i,
input logic rx_data_valid_i,
input logic [11:0] rx_data_i,
input logic bit_tick_i,
output logic dma_tx_stall_o,
output logic dma_rx_stall_o,
output logic irq_o
// verilog_format: on
);
localparam logic [31:0] TX_WATERMARK_RESET = 32'd16;
localparam logic [31:0] RX_WATERMARK_RESET = 32'd32;
localparam logic [31:0] RX_TIMEOUT_RESET = 32'd32;
localparam logic [31:0] LINE_CTRL_RESET = 32'd3;
localparam logic [31:0] IP_VERSION = 32'h0002_0000;
localparam logic [31:0] CAPABILITY = 32'h00FF_4040;
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_baud_int_en;
logic [23:0] s_baud_int_d, s_baud_int_q;
logic s_baud_frac_en;
logic [7:0] s_baud_frac_d, s_baud_frac_q;
logic s_line_ctrl_en;
logic [4:0] s_line_ctrl_d, s_line_ctrl_q;
logic s_ctrl_en;
logic [3:0] s_ctrl_d, s_ctrl_q;
logic s_tx_watermark_en;
logic [6:0] s_tx_watermark_d, s_tx_watermark_q;
logic s_rx_watermark_en;
logic [6:0] s_rx_watermark_d, s_rx_watermark_q;
logic s_rx_timeout_en;
logic [15:0] s_rx_timeout_d, s_rx_timeout_q;
logic s_intr_enable_en;
logic [5:0] s_intr_enable_d, s_intr_enable_q;
logic s_dma_ctrl_en;
logic [1:0] s_dma_ctrl_d, s_dma_ctrl_q;
logic s_tx_flush;
logic s_tx_push;
logic s_tx_empty;
logic s_tx_full;
logic [ 7:0] s_tx_pop_data;
logic [TX_FIFO_LOG_DEPTH:0] s_tx_count;
logic s_rx_flush;
logic s_rx_push;
logic s_rx_pop;
logic s_rx_empty;
logic s_rx_full;
logic [ 11:0] s_rx_pop_data;
logic [RX_FIFO_LOG_DEPTH:0] s_rx_count;
logic [6:0] s_error_status_d, s_error_status_q;
logic [5:0] s_intr_state_d, s_intr_state_q;
logic [6:0] s_error_clear;
logic [5:0] s_intr_clear;
logic [5:0] s_intr_test;
logic s_config_error_event;
logic s_command_error_event;
logic s_overrun_event;
logic s_rx_error_event;
logic s_rx_timeout_event;
logic [15:0] s_rx_timeout_count_d, s_rx_timeout_count_q;
logic [31:0] s_status;
logic [31:0] s_fifo_level;
logic [31:0] s_merge_value;
logic s_config_valid;
logic s_tx_dma_req;
logic s_rx_dma_req;
logic s_tx_watermark_active;
logic s_rx_watermark_active;
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
initial begin
if ((TX_FIFO_DEPTH != 64) || (RX_FIFO_DEPTH != 64)) begin
$fatal(1, "uart_reg: UART V2 requires 64-entry FIFOs");
end
end
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 baud_int_o = s_baud_int_q;
assign baud_frac_o = s_baud_frac_q;
assign data_bits_o = s_line_ctrl_q[1:0];
assign stop2_o = s_line_ctrl_q[`UART_LINE_STOP2];
assign parity_o = s_line_ctrl_q[4:3];
assign tx_enable_o = s_ctrl_q[`UART_CTRL_TX_ENABLE];
assign rx_enable_o = s_ctrl_q[`UART_CTRL_RX_ENABLE];
assign loopback_o = s_ctrl_q[`UART_CTRL_LOOPBACK];
assign break_o = s_ctrl_q[`UART_CTRL_TX_BREAK];
assign tx_data_valid_o = !s_tx_empty;
assign tx_data_o = s_tx_pop_data;
assign s_config_valid = (s_baud_int_q >= 24'd16) && (s_line_ctrl_q[4:3] != 2'd3);
assign s_tx_dma_req = s_dma_ctrl_q[`UART_DMA_TX_ENABLE] && tx_enable_o &&
s_config_valid && !s_tx_full;
assign s_rx_dma_req = s_dma_ctrl_q[`UART_DMA_RX_ENABLE] && rx_enable_o && !s_rx_empty;
assign dma_tx_stall_o = !s_tx_dma_req;
assign dma_rx_stall_o = !s_rx_dma_req;
assign s_tx_watermark_active = tx_enable_o && (s_tx_count <= s_tx_watermark_q);
assign s_rx_watermark_active = rx_enable_o && (s_rx_count >= s_rx_watermark_q);
assign irq_o = |(s_intr_state_q & s_intr_enable_q);
always_comb begin
s_status = '0;
s_status[`UART_STATUS_TX_ENABLED] = tx_enable_o;
s_status[`UART_STATUS_RX_ENABLED] = rx_enable_o;
s_status[`UART_STATUS_TX_BUSY] = tx_busy_i;
s_status[`UART_STATUS_RX_ACTIVE] = rx_active_i;
s_status[`UART_STATUS_TX_EMPTY] = s_tx_empty;
s_status[`UART_STATUS_TX_FULL] = s_tx_full;
s_status[`UART_STATUS_RX_EMPTY] = s_rx_empty;
s_status[`UART_STATUS_RX_FULL] = s_rx_full;
s_status[`UART_STATUS_CONFIG_VALID] = s_config_valid;
s_status[`UART_STATUS_BREAK_ACTIVE] = break_o;
s_status[`UART_STATUS_TX_DMA_REQ] = s_tx_dma_req;
s_status[`UART_STATUS_RX_DMA_REQ] = s_rx_dma_req;
s_fifo_level = '0;
s_fifo_level[6:0] = 7'(s_tx_count);
s_fifo_level[22:16] = 7'(s_rx_count);
end
always_comb begin
s_req_accept = s_req;
s_access_error = 1'b0;
s_baud_int_en = 1'b0;
s_baud_frac_en = 1'b0;
s_line_ctrl_en = 1'b0;
s_ctrl_en = 1'b0;
s_tx_watermark_en = 1'b0;
s_rx_watermark_en = 1'b0;
s_rx_timeout_en = 1'b0;
s_intr_enable_en = 1'b0;
s_dma_ctrl_en = 1'b0;
s_baud_int_d = s_baud_int_q;
s_baud_frac_d = s_baud_frac_q;
s_line_ctrl_d = s_line_ctrl_q;
s_ctrl_d = s_ctrl_q;
s_tx_watermark_d = s_tx_watermark_q;
s_rx_watermark_d = s_rx_watermark_q;
s_rx_timeout_d = s_rx_timeout_q;
s_intr_enable_d = s_intr_enable_q;
s_dma_ctrl_d = s_dma_ctrl_q;
s_tx_flush = 1'b0;
s_rx_flush = 1'b0;
s_tx_push = 1'b0;
s_rx_pop = 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;
s_merge_value = '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_UART_BAUD_INT: begin
s_merge_value = merge_wstrb({8'd0, s_baud_int_q}, ribp.wdata, ribp.wstrb);
if (tx_enable_o || rx_enable_o || tx_busy_i || rx_active_i ||
(s_merge_value[31:24] != 8'd0) || (s_merge_value[23:0] < 24'd16)) begin
s_access_error = 1'b1;
s_config_error_event = 1'b1;
end else begin
s_baud_int_en = 1'b1;
s_baud_int_d = s_merge_value[23:0];
end
end
`RIBP_UART_BAUD_FRAC: begin
s_merge_value = merge_wstrb({24'd0, s_baud_frac_q}, ribp.wdata, ribp.wstrb);
if (tx_enable_o || rx_enable_o || tx_busy_i || rx_active_i ||
(s_merge_value[31:8] != 24'd0)) begin
s_access_error = 1'b1;
s_config_error_event = 1'b1;
end else begin
s_baud_frac_en = 1'b1;
s_baud_frac_d = s_merge_value[7:0];
end
end
`RIBP_UART_LINE_CTRL: begin
s_merge_value = merge_wstrb({27'd0, s_line_ctrl_q}, ribp.wdata, ribp.wstrb);
if (tx_enable_o || rx_enable_o || tx_busy_i || rx_active_i ||
(s_merge_value[31:5] != 27'd0) || (s_merge_value[4:3] == 2'd3)) begin
s_access_error = 1'b1;
s_config_error_event = 1'b1;
end else begin
s_line_ctrl_en = 1'b1;
s_line_ctrl_d = s_merge_value[4:0];
end
end
`RIBP_UART_CTRL: begin
s_merge_value = merge_wstrb({28'd0, s_ctrl_q}, ribp.wdata, ribp.wstrb);
if ((s_merge_value[31:4] != 28'd0) ||
((s_merge_value[1:0] != 2'd0) && !s_config_valid) ||
(s_merge_value[`UART_CTRL_TX_BREAK] && tx_busy_i) ||
((s_merge_value[`UART_CTRL_LOOPBACK] != loopback_o) &&
(tx_busy_i || rx_active_i))) begin
s_access_error = 1'b1;
s_config_error_event = 1'b1;
end else begin
s_ctrl_en = 1'b1;
s_ctrl_d = s_merge_value[3:0];
end
end
`RIBP_UART_TXDATA: begin
if (!ribp.wstrb[0] ||
(|(ribp.wdata[31:8] & {{8{ribp.wstrb[3]}}, {8{ribp.wstrb[2]}},
{8{ribp.wstrb[1]}}}))) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else if (s_tx_full && tx_enable_o && s_config_valid) begin
s_req_accept = 1'b0;
end else if (s_tx_full) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_tx_push = 1'b1;
end
end
`RIBP_UART_FIFO_CTRL: begin
if (!ribp.wstrb[0] || (ribp.wdata[31:2] != 30'd0) ||
(ribp.wdata[1:0] == 2'd0) ||
(ribp.wdata[`UART_FIFO_CTRL_TX_FLUSH] && (tx_enable_o || tx_busy_i)) ||
(ribp.wdata[`UART_FIFO_CTRL_RX_FLUSH] && (rx_enable_o || rx_active_i))) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_tx_flush = ribp.wdata[`UART_FIFO_CTRL_TX_FLUSH];
s_rx_flush = ribp.wdata[`UART_FIFO_CTRL_RX_FLUSH];
end
end
`RIBP_UART_TX_WATERMARK: begin
s_merge_value = merge_wstrb({25'd0, s_tx_watermark_q}, ribp.wdata, ribp.wstrb);
if ((s_merge_value[31:7] != 25'd0) || (s_merge_value[6:0] >= 7'(TX_FIFO_DEPTH))) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_tx_watermark_en = 1'b1;
s_tx_watermark_d = s_merge_value[6:0];
end
end
`RIBP_UART_RX_WATERMARK: begin
s_merge_value = merge_wstrb({25'd0, s_rx_watermark_q}, ribp.wdata, ribp.wstrb);
if ((s_merge_value[31:7] != 25'd0) || (s_merge_value[6:0] == 7'd0) ||
(s_merge_value[6:0] > 7'(RX_FIFO_DEPTH))) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_rx_watermark_en = 1'b1;
s_rx_watermark_d = s_merge_value[6:0];
end
end
`RIBP_UART_RX_TIMEOUT_BITS: begin
s_merge_value = merge_wstrb({16'd0, s_rx_timeout_q}, ribp.wdata, ribp.wstrb);
if (s_merge_value[31:16] != 16'd0) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_rx_timeout_en = 1'b1;
s_rx_timeout_d = s_merge_value[15:0];
end
end
`RIBP_UART_ERROR_STATUS: begin
if (!ribp.wstrb[0] || (ribp.wdata[31:7] != 25'd0)) begin
s_access_error = 1'b1;
end else begin
s_error_clear = ribp.wdata[6:0];
end
end
`RIBP_UART_INTR_STATE: begin
if (!ribp.wstrb[0] || (ribp.wdata[31:6] != 26'd0)) begin
s_access_error = 1'b1;
end else begin
s_intr_clear = ribp.wdata[5:0];
end
end
`RIBP_UART_INTR_ENABLE: begin
s_merge_value = merge_wstrb({26'd0, s_intr_enable_q}, ribp.wdata, ribp.wstrb);
if (s_merge_value[31:6] != 26'd0) begin
s_access_error = 1'b1;
end else begin
s_intr_enable_en = 1'b1;
s_intr_enable_d = s_merge_value[5:0];
end
end
`RIBP_UART_INTR_TEST: begin
if (!ribp.wstrb[0] || (ribp.wdata[31:6] != 26'd0)) begin
s_access_error = 1'b1;
end else begin
s_intr_test = ribp.wdata[5:0];
end
end
`RIBP_UART_DMA_CTRL: begin
s_merge_value = merge_wstrb({30'd0, s_dma_ctrl_q}, ribp.wdata, ribp.wstrb);
if (s_merge_value[31:2] != 30'd0) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_dma_ctrl_en = 1'b1;
s_dma_ctrl_d = s_merge_value[1:0];
end
end
default: s_access_error = 1'b1;
endcase
end else begin
unique case (ribp.addr[7:0])
`RIBP_UART_BAUD_INT: s_ribp_rdata_d = {8'd0, s_baud_int_q};
`RIBP_UART_BAUD_FRAC: s_ribp_rdata_d = {24'd0, s_baud_frac_q};
`RIBP_UART_LINE_CTRL: s_ribp_rdata_d = {27'd0, s_line_ctrl_q};
`RIBP_UART_CTRL: s_ribp_rdata_d = {28'd0, s_ctrl_q};
`RIBP_UART_RXDATA: begin
if (s_rx_empty) begin
s_access_error = 1'b1;
s_command_error_event = 1'b1;
end else begin
s_ribp_rdata_d = {20'd0, s_rx_pop_data};
s_rx_pop = 1'b1;
end
end
`RIBP_UART_STATUS: s_ribp_rdata_d = s_status;
`RIBP_UART_FIFO_LEVEL: s_ribp_rdata_d = s_fifo_level;
`RIBP_UART_TX_WATERMARK: s_ribp_rdata_d = {25'd0, s_tx_watermark_q};
`RIBP_UART_RX_WATERMARK: s_ribp_rdata_d = {25'd0, s_rx_watermark_q};
`RIBP_UART_RX_TIMEOUT_BITS: s_ribp_rdata_d = {16'd0, s_rx_timeout_q};
`RIBP_UART_ERROR_STATUS: s_ribp_rdata_d = {25'd0, s_error_status_q};
`RIBP_UART_INTR_STATE: s_ribp_rdata_d = {26'd0, s_intr_state_q};
`RIBP_UART_INTR_ENABLE: s_ribp_rdata_d = {26'd0, s_intr_enable_q};
`RIBP_UART_INTR_STATUS: s_ribp_rdata_d = {26'd0, (s_intr_state_q & s_intr_enable_q)};
`RIBP_UART_DMA_CTRL: s_ribp_rdata_d = {30'd0, s_dma_ctrl_q};
`RIBP_UART_IP_VERSION: s_ribp_rdata_d = IP_VERSION;
`RIBP_UART_CAPABILITY: s_ribp_rdata_d = CAPABILITY;
default: begin
s_access_error = 1'b1;
s_ribp_rdata_d = '0;
end
endcase
end
end
end
assign s_ribp_ready_d = s_req_accept;
assign s_ribp_resp_err_d = s_access_error;
assign s_rx_push = rx_data_valid_i && !s_rx_full;
assign s_overrun_event = rx_data_valid_i && s_rx_full;
assign s_rx_error_event = s_rx_push && (|rx_data_i[11:8]);
dffr #(1) u_ribp_ready_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_ribp_ready_d),
.dat_o (s_ribp_ready_q)
);
dffer #(1) u_ribp_resp_err_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_req_accept),
.dat_i (s_ribp_resp_err_d),
.dat_o (s_ribp_resp_err_q)
);
dffer #(32) u_ribp_rdata_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_req_accept),
.dat_i (s_ribp_rdata_d),
.dat_o (s_ribp_rdata_q)
);
dffer #(24) u_baud_int_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_baud_int_en),
.dat_i (s_baud_int_d),
.dat_o (s_baud_int_q)
);
dffer #(8) u_baud_frac_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_baud_frac_en),
.dat_i (s_baud_frac_d),
.dat_o (s_baud_frac_q)
);
dfferc #(
.DATA_WIDTH(5),
.RESET_VAL (5'(LINE_CTRL_RESET))
) u_line_ctrl_dfferc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_line_ctrl_en),
.dat_i (s_line_ctrl_d),
.dat_o (s_line_ctrl_q)
);
dffer #(4) u_ctrl_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_ctrl_en),
.dat_i (s_ctrl_d),
.dat_o (s_ctrl_q)
);
dfferc #(
.DATA_WIDTH(7),
.RESET_VAL (7'(TX_WATERMARK_RESET))
) u_tx_watermark_dfferc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_tx_watermark_en),
.dat_i (s_tx_watermark_d),
.dat_o (s_tx_watermark_q)
);
dfferc #(
.DATA_WIDTH(7),
.RESET_VAL (7'(RX_WATERMARK_RESET))
) u_rx_watermark_dfferc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_rx_watermark_en),
.dat_i (s_rx_watermark_d),
.dat_o (s_rx_watermark_q)
);
dfferc #(
.DATA_WIDTH(16),
.RESET_VAL (16'(RX_TIMEOUT_RESET))
) u_rx_timeout_dfferc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_rx_timeout_en),
.dat_i (s_rx_timeout_d),
.dat_o (s_rx_timeout_q)
);
dffer #(6) u_intr_enable_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_intr_enable_en),
.dat_i (s_intr_enable_d),
.dat_o (s_intr_enable_q)
);
dffer #(2) u_dma_ctrl_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_dma_ctrl_en),
.dat_i (s_dma_ctrl_d),
.dat_o (s_dma_ctrl_q)
);
fifo #(
.DATA_WIDTH (8),
.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_tx_flush),
.push_i (s_tx_push),
.full_o (s_tx_full),
.dat_i (ribp.wdata[7:0]),
.pop_i (tx_data_pop_i),
.empty_o(s_tx_empty),
.dat_o (s_tx_pop_data),
.cnt_o (s_tx_count)
);
fifo #(
.DATA_WIDTH (12),
.BUFFER_DEPTH (RX_FIFO_DEPTH),
.LOG_BUFFER_DEPTH(RX_FIFO_LOG_DEPTH)
) u_rx_fifo (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.flush_i(s_rx_flush),
.push_i (s_rx_push),
.full_o (s_rx_full),
.dat_i (rx_data_i),
.pop_i (s_rx_pop),
.empty_o(s_rx_empty),
.dat_o (s_rx_pop_data),
.cnt_o (s_rx_count)
);
always_comb begin
s_rx_timeout_count_d = s_rx_timeout_count_q;
s_rx_timeout_event = 1'b0;
if (s_rx_empty || s_rx_push || s_rx_pop || (s_rx_timeout_q == 16'd0)) begin
s_rx_timeout_count_d = '0;
end else if (bit_tick_i) begin
if (s_rx_timeout_count_q >= (s_rx_timeout_q - 1'b1)) begin
s_rx_timeout_count_d = '0;
s_rx_timeout_event = 1'b1;
end else begin
s_rx_timeout_count_d = s_rx_timeout_count_q + 1'b1;
end
end
end
dffr #(16) u_rx_timeout_count_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rx_timeout_count_d),
.dat_o (s_rx_timeout_count_q)
);
always_comb begin
s_error_status_d = s_error_status_q & ~s_error_clear;
if (s_overrun_event) s_error_status_d[`UART_ERROR_OVERRUN] = 1'b1;
if (s_rx_push && rx_data_i[`UART_RXDATA_PARITY_ERROR])
s_error_status_d[`UART_ERROR_PARITY] = 1'b1;
if (s_rx_push && rx_data_i[`UART_RXDATA_FRAME_ERROR])
s_error_status_d[`UART_ERROR_FRAME] = 1'b1;
if (s_rx_push && rx_data_i[`UART_RXDATA_BREAK]) s_error_status_d[`UART_ERROR_BREAK] = 1'b1;
if (s_rx_push && rx_data_i[`UART_RXDATA_NOISE]) s_error_status_d[`UART_ERROR_NOISE] = 1'b1;
if (s_config_error_event) s_error_status_d[`UART_ERROR_CONFIG] = 1'b1;
if (s_command_error_event) s_error_status_d[`UART_ERROR_COMMAND] = 1'b1;
end
dffr #(7) u_error_status_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_error_status_d),
.dat_o (s_error_status_q)
);
always_comb begin
s_intr_state_d = (s_intr_state_q & ~s_intr_clear) | s_intr_test;
if (s_rx_watermark_active) s_intr_state_d[`UART_INTR_RX_WATERMARK] = 1'b1;
if (s_rx_timeout_event) s_intr_state_d[`UART_INTR_RX_TIMEOUT] = 1'b1;
if (s_tx_watermark_active) s_intr_state_d[`UART_INTR_TX_WATERMARK] = 1'b1;
if (tx_done_i && s_tx_empty) s_intr_state_d[`UART_INTR_TX_DONE] = 1'b1;
if (s_rx_error_event || s_overrun_event) s_intr_state_d[`UART_INTR_RX_ERROR] = 1'b1;
if (s_rx_push && rx_data_i[`UART_RXDATA_BREAK]) s_intr_state_d[`UART_INTR_BREAK] = 1'b1;
end
dffr #(6) u_intr_state_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_intr_state_d),
.dat_o (s_intr_state_q)
);
`ifndef SYNTHESIS
`ifdef SIMU_VERILATOR
always_ff @(posedge clk_i) begin
if (s_tx_push && !loopback_o) begin
$write("%c", ribp.wdata[7:0]);
end
end
`endif
`endif
endmodule
+6 -1
View File
@@ -23,6 +23,12 @@
/ip/ribp/serial/ws2812_reg.sv
/ip/ribp/serial/ws2812_core.sv
/ip/ribp/serial/ribp_ws2812.sv
/ip/ribp/serial/uart_baudgen.sv
/ip/ribp/serial/ribp_uart_tx.sv
/ip/ribp/serial/ribp_uart_rx.sv
/ip/ribp/serial/uart_core.sv
/ip/ribp/serial/uart_reg.sv
/ip/ribp/serial/ribp_uart.sv
/ip/ribp/storage/xpi_reg.sv
/ip/ribp/storage/xpi_mm.sv
/ip/ribp/storage/xpi_clkgen.sv
@@ -46,7 +52,6 @@
/ip/ribp/peripheral/timer_core.sv
/ip/ribp/peripheral/timer_reg.sv
/ip/ribp/peripheral/ribp_timer.sv
/ip/ribp/serial/uart.sv
/ip/ribp/peripheral/gpio_if.sv
/ip/ribp/peripheral/user_gpio_if.sv
/ip/ribp/peripheral/gpio_core.sv
@@ -107,6 +107,20 @@ def source_files(target: str) -> list[Path]:
SERIAL / "ribp_ws2812.sv",
SCRIPT_DIR / "ws2812_formal.sv",
]
if target == "uart":
return [
COMMON_RTL / "interface/ribp_if.sv",
COMMON_RTL / "utils/register.sv",
COMMON_RTL / "utils/fifo.sv",
ROOT / "rtl/managed/clusterip/uart/rtl/uart_if.sv",
SERIAL / "uart_baudgen.sv",
SERIAL / "ribp_uart_tx.sv",
SERIAL / "ribp_uart_rx.sv",
SERIAL / "uart_core.sv",
SERIAL / "uart_reg.sv",
SERIAL / "ribp_uart.sv",
SCRIPT_DIR / "uart_formal.sv",
]
if target == "timer":
return [
COMMON_RTL / "interface/ribp_if.sv",
@@ -169,6 +183,7 @@ def parse_args() -> argparse.Namespace:
"pll_rcu",
"gpio",
"ws2812",
"uart",
"timer",
"clint",
),
+85
View File
@@ -0,0 +1,85 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module uart_formal_design (
// verilog_format: off
input logic clk_i,
output logic rst_n_i,
output logic f_past_valid,
output logic rib_valid,
output logic [31:0] rib_addr,
output logic [31:0] rib_wdata,
output logic [ 3:0] rib_wstrb,
output logic rib_ready,
output logic rib_resp_err,
output logic [ 6:0] tx_count,
output logic [ 6:0] rx_count,
output logic [ 6:0] error_status,
output logic [ 5:0] intr_state,
output logic [ 5:0] intr_enable,
output logic tx_enable,
output logic rx_enable,
output logic tx_busy,
output logic rx_active,
output logic break_active,
output logic tx_dma_stall,
output logic rx_dma_stall,
output logic tx,
output logic irq
// verilog_format: on
);
ribp_if ribp ();
uart_if uart ();
(* 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;
(* anyseq *)logic f_uart_rx;
assign ribp.valid = f_rib_valid;
assign ribp.addr = f_rib_addr;
assign ribp.wdata = f_rib_wdata;
assign ribp.wstrb = f_rib_wstrb;
assign uart.rx_i = f_uart_rx;
assign rib_valid = ribp.valid;
assign rib_addr = ribp.addr;
assign rib_wdata = ribp.wdata;
assign rib_wstrb = ribp.wstrb;
assign rib_ready = ribp.ready;
assign rib_resp_err = ribp.resp_err;
assign tx_count = u_dut.u_uart_reg.s_tx_count;
assign rx_count = u_dut.u_uart_reg.s_rx_count;
assign error_status = u_dut.u_uart_reg.s_error_status_q;
assign intr_state = u_dut.u_uart_reg.s_intr_state_q;
assign intr_enable = u_dut.u_uart_reg.s_intr_enable_q;
assign tx_enable = u_dut.s_tx_enable;
assign rx_enable = u_dut.s_rx_enable;
assign tx_busy = u_dut.s_tx_busy;
assign rx_active = u_dut.s_rx_active;
assign break_active = u_dut.s_break;
assign tx = uart.tx_o;
assign irq = uart.irq_o;
ribp_uart u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.dma_tx_stall_o(tx_dma_stall),
.dma_rx_stall_o(rx_dma_stall),
.ribp (ribp),
.uart (uart)
);
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
+79
View File
@@ -0,0 +1,79 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module uart_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 [ 6:0] tx_count;
wire [ 6:0] rx_count;
wire [ 6:0] error_status;
wire [ 5:0] intr_state;
wire [ 5:0] intr_enable;
wire tx_enable;
wire rx_enable;
wire tx_busy;
wire rx_active;
wire break_active;
wire tx_dma_stall;
wire rx_dma_stall;
wire tx;
wire irq;
uart_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),
.tx_count (tx_count),
.rx_count (rx_count),
.error_status(error_status),
.intr_state (intr_state),
.intr_enable (intr_enable),
.tx_enable (tx_enable),
.rx_enable (rx_enable),
.tx_busy (tx_busy),
.rx_active (rx_active),
.break_active(break_active),
.tx_dma_stall(tx_dma_stall),
.rx_dma_stall(rx_dma_stall),
.tx (tx),
.irq (irq)
);
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 (tx_count <= 7'd64);
assert (rx_count <= 7'd64);
assert (irq == |(intr_state & intr_enable));
if (break_active) assert (!tx);
if (!break_active && !tx_busy) assert (tx);
if (!tx_enable) assert (tx_dma_stall);
if (!rx_enable) assert (rx_dma_stall);
cover (rib_ready && rib_resp_err);
cover (tx_busy);
cover (rx_active);
cover (irq);
cover (error_status != 7'd0);
end
end
endmodule
+13 -2
View File
@@ -9,7 +9,7 @@ FORMAL_WS2812_DEPTH ?= 120
FORMAL_CLINT_DEPTH ?= 32
FORMAL_TIMEOUT ?= 60
FORMAL_WS2812_TIMEOUT ?= 120
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 timer clint
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart timer clint
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
@@ -27,6 +27,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(RTL_PATH)/formal/gpio_formal_props.sv \
$(RTL_PATH)/formal/ws2812_formal.sv \
$(RTL_PATH)/formal/ws2812_formal_props.sv \
$(RTL_PATH)/formal/uart_formal.sv \
$(RTL_PATH)/formal/uart_formal_props.sv \
$(RTL_PATH)/formal/timer_formal.sv \
$(RTL_PATH)/formal/timer_formal_props.sv \
$(RTL_PATH)/formal/clint_formal.sv \
@@ -50,6 +52,13 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.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 \
$(ROOT_PATH)/rtl/ip/ribp/serial/uart_baudgen.sv \
$(ROOT_PATH)/rtl/ip/ribp/serial/ribp_uart_tx.sv \
$(ROOT_PATH)/rtl/ip/ribp/serial/ribp_uart_rx.sv \
$(ROOT_PATH)/rtl/ip/ribp/serial/uart_core.sv \
$(ROOT_PATH)/rtl/ip/ribp/serial/uart_reg.sv \
$(ROOT_PATH)/rtl/ip/ribp/serial/ribp_uart.sv \
$(ROOT_PATH)/rtl/managed/clusterip/uart/rtl/uart_if.sv \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/timer_core.sv \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/timer_define.svh \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/timer_reg.sv \
@@ -154,6 +163,8 @@ formal-gpio: $(FORMAL_DIR)/gpio/.stamp | manifest
formal-ws2812: $(FORMAL_DIR)/ws2812/.stamp | manifest
formal-uart: $(FORMAL_DIR)/uart/.stamp | manifest
formal-timer: $(FORMAL_DIR)/timer/.stamp | manifest
formal-clint: $(FORMAL_DIR)/clint/.stamp | manifest
@@ -164,4 +175,4 @@ formal-doctor:
formal-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-timer formal-clint formal-doctor formal-clean
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-timer formal-clint formal-doctor formal-clean
+1
View File
@@ -67,6 +67,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
$(ROOT_PATH)/crt/src/service/test.c \
$(ROOT_PATH)/crt/src/hal/clint.c \
$(ROOT_PATH)/crt/src/hal/clock.c \
$(ROOT_PATH)/crt/src/hal/uart_math.c \
$(ROOT_PATH)/crt/src/hal/uart.c \
$(ROOT_PATH)/crt/src/hal/gpio_math.c \
$(ROOT_PATH)/crt/src/hal/gpio.c \
+9 -4
View File
@@ -58,6 +58,7 @@ module ip_ribp_wrapper (
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
logic s_dma_xpi_tx_stall, s_dma_xpi_rx_stall;
logic s_dma_uart_tx_stall, s_dma_uart_rx_stall;
logic s_dma_xfer_done;
logic s_tim0_irq, s_tim1_irq;
@@ -93,6 +94,8 @@ module ip_ribp_wrapper (
assign u_dma_hw_trg_if.i2s_rx_proc = ~s_dma_i2s_rx_stall;
assign u_dma_hw_trg_if.qspi_tx_proc = ~s_dma_xpi_tx_stall;
assign u_dma_hw_trg_if.qspi_rx_proc = ~s_dma_xpi_rx_stall;
assign u_dma_hw_trg_if.uart_tx_proc = ~s_dma_uart_tx_stall;
assign u_dma_hw_trg_if.uart_rx_proc = ~s_dma_uart_rx_stall;
// Uses ClusterIP common ribp_if and register.sv dffr through generated bindings.
`include "ribp_routes.svh"
@@ -117,10 +120,12 @@ module ip_ribp_wrapper (
// verilog_format: on
ribp_uart u_rib_uart (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (u_uart_ribp_if),
.uart (uart)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.dma_tx_stall_o(s_dma_uart_tx_stall),
.dma_rx_stall_o(s_dma_uart_rx_stall),
.ribp (u_uart_ribp_if),
.uart (uart)
);
ribp_timer u_rib_timer0 (
+1
View File
@@ -22,6 +22,7 @@ TEST_SOURCES = (
"crt/src/lib/string.c",
"crt/src/hal/gpio_math.c",
"crt/src/hal/ws2812_math.c",
"crt/src/hal/uart_math.c",
"crt/src/hal/timer_math.c",
"app/media/src/video_player.c",
"app/media/src/wav_audio.c",
+23 -1
View File
@@ -7,6 +7,7 @@
#include <retrosoc/hal/lcd.h>
#include <retrosoc/hal/spisd.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/hal/uart.h>
#include <retrosoc/hal/ws2812.h>
#include <retrosoc/lib/printf.h>
#include <retrosoc/lib/stdlib.h>
@@ -190,6 +191,26 @@ static int test_timer_helpers(void) {
return 0;
}
static int test_uart_helpers(void) {
rs_uart_timing_t timing;
if ((rs_uart_timing_calculate(72000000U, 921600U, &timing) != RS_OK) ||
(timing.baud_integer != 78U) || (timing.baud_fraction != 32U)) {
return 1;
}
if ((rs_uart_timing_calculate(16000000U, 1000000U, &timing) != RS_OK) ||
(timing.baud_integer != 16U) || (timing.baud_fraction != 0U)) {
return 2;
}
if ((rs_uart_timing_calculate(0U, 115200U, &timing) != RS_EINVAL) ||
(rs_uart_timing_calculate(72000000U, 0U, &timing) != RS_EINVAL) ||
(rs_uart_timing_calculate(1000000U, 1000000U, &timing) != RS_EINVAL) ||
(rs_uart_timing_calculate(72000000U, 115200U, NULL) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_gpio_helpers(void) {
rs_gpio_filter_timing_t timing;
@@ -252,7 +273,8 @@ int main(void) {
const int results[] = {
test_string_helpers(), test_formatter(), test_compiler_helpers(),
test_wait_helper(), test_ws2812_helpers(), test_timer_helpers(),
test_gpio_helpers(), test_wav_parser(), test_video_parser(),
test_uart_helpers(), test_gpio_helpers(), test_wav_parser(),
test_video_parser(),
};
for (size_t index = 0U; index < (sizeof(results) / sizeof(results[0])); ++index) {
+2
View File
@@ -143,6 +143,8 @@ module dma_error_tb;
hw_trg.i2s_rx_proc = 1'b0;
hw_trg.qspi_tx_proc = 1'b0;
hw_trg.qspi_rx_proc = 1'b0;
hw_trg.uart_tx_proc = 1'b0;
hw_trg.uart_rx_proc = 1'b0;
repeat (2) @(posedge clk_i);
rst_n_i = 1'b1;
+176
View File
@@ -0,0 +1,176 @@
`timescale 1ns / 1ps
`include "ribp_uart_define.svh"
module uart_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic dma_tx_stall;
logic dma_rx_stall;
ribp_if ribp ();
uart_if uart ();
always #5 clk_i = ~clk_i;
ribp_uart u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.dma_tx_stall_o(dma_tx_stall),
.dma_rx_stall_o(dma_rx_stall),
.ribp (ribp),
.uart (uart)
);
task automatic ribp_write(input logic [31:0] address, input logic [31:0] data,
input logic [3:0] strobe, input logic expected_error);
begin
@(negedge clk_i);
ribp.addr = address;
ribp.wdata = data;
ribp.wstrb = strobe;
ribp.valid = 1'b1;
while (!ribp.ready) begin
@(posedge clk_i);
#1;
end
if (ribp.resp_err !== expected_error) begin
$fatal(1, "UART 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, "UART 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);
begin
ribp_write(address, data, 4'hF, 1'b0);
end
endtask
task automatic configure_uart(input logic [4:0] line_control, input logic [3:0] control);
begin
write_ok(`RIBP_UART_CTRL, 0);
repeat (4) @(posedge clk_i);
write_ok(`RIBP_UART_FIFO_CTRL, 3);
write_ok(`RIBP_UART_BAUD_INT, 16);
write_ok(`RIBP_UART_BAUD_FRAC, 0);
write_ok(`RIBP_UART_LINE_CTRL, line_control);
write_ok(`RIBP_UART_CTRL, control);
end
endtask
task automatic send_external_8n1(input logic [7:0] data, input logic bad_stop);
integer bit_index;
begin
uart.rx_i = 1'b0;
repeat (16) @(posedge clk_i);
for (bit_index = 0; bit_index < 8; bit_index = bit_index + 1) begin
uart.rx_i = data[bit_index];
repeat (16) @(posedge clk_i);
end
uart.rx_i = !bad_stop;
repeat (16) @(posedge clk_i);
uart.rx_i = 1'b1;
repeat (24) @(posedge clk_i);
end
endtask
initial begin
logic [31:0] value;
integer index;
ribp.valid = 1'b0;
ribp.addr = '0;
ribp.wdata = '0;
ribp.wstrb = '0;
uart.rx_i = 1'b1;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
repeat (4) @(posedge clk_i);
ribp_read(`RIBP_UART_IP_VERSION, 1'b0, value);
if (value != 32'h0002_0000) $fatal(1, "UART IP version mismatch");
ribp_read(`RIBP_UART_CAPABILITY, 1'b0, value);
if (value != 32'h00FF_4040) $fatal(1, "UART capability mismatch");
ribp_read(32'h0000_0002, 1'b1, value);
ribp_read(`RIBP_UART_RXDATA, 1'b1, value);
configure_uart(5'd3, 4'b0111);
write_ok(`RIBP_UART_TXDATA, 8'hA5);
repeat (220) @(posedge clk_i);
ribp_read(`RIBP_UART_RXDATA, 1'b0, value);
if (value[11:0] != 12'h0A5) $fatal(1, "UART 8N1 loopback mismatch: %h", value);
configure_uart(5'd3, 4'b0001);
write_ok(`RIBP_UART_TXDATA, 8'h5A);
repeat (24) @(posedge clk_i);
ribp_read(`RIBP_UART_STATUS, 1'b0, value);
if (!value[`UART_STATUS_TX_BUSY]) $fatal(1, "UART TX did not start before disable");
write_ok(`RIBP_UART_CTRL, 0);
repeat (180) @(posedge clk_i);
ribp_read(`RIBP_UART_STATUS, 1'b0, value);
if (value[`UART_STATUS_TX_BUSY] || !value[`UART_STATUS_TX_EMPTY]) begin
$fatal(1, "UART TX did not finish its active frame after disable: %h", value);
end
write_ok(`RIBP_UART_INTR_ENABLE, 6'h3F);
write_ok(`RIBP_UART_INTR_TEST, 6'h20);
ribp_read(`RIBP_UART_INTR_STATUS, 1'b0, value);
if (!value[`UART_INTR_BREAK] || !uart.irq_o) $fatal(1, "UART interrupt test failed");
write_ok(`RIBP_UART_INTR_STATE, 6'h3F);
configure_uart(5'd3, 4'b0010);
fork
send_external_8n1(8'h3C, 1'b1);
join
ribp_read(`RIBP_UART_RXDATA, 1'b0, value);
if ((value[7:0] != 8'h3C) || !value[`UART_RXDATA_FRAME_ERROR]) begin
$fatal(1, "UART frame error was not retained: %h", value);
end
write_ok(`RIBP_UART_CTRL, 0);
repeat (4) @(posedge clk_i);
write_ok(`RIBP_UART_FIFO_CTRL, 3);
for (index = 0; index < 64; index = index + 1) begin
write_ok(`RIBP_UART_TXDATA, index);
end
ribp_write(`RIBP_UART_TXDATA, 32'h55, 4'hF, 1'b1);
ribp_read(`RIBP_UART_FIFO_LEVEL, 1'b0, value);
if (value[6:0] != 7'd64) $fatal(1, "UART TX FIFO depth mismatch: %h", value);
write_ok(`RIBP_UART_FIFO_CTRL, 3);
write_ok(`RIBP_UART_DMA_CTRL, 3);
if (!dma_tx_stall || !dma_rx_stall) $fatal(1, "Disabled UART asserted a DMA request");
$display("UART V2 register, FIFO, loopback, error, interrupt, and DMA test passed");
$finish;
end
initial begin
repeat (20000) @(posedge clk_i);
$fatal(1, "UART test timeout");
end
endmodule
+2
View File
@@ -217,6 +217,8 @@ module ws2812_dma_tb;
hw_trg.i2s_rx_proc = 1'b0;
hw_trg.qspi_tx_proc = 1'b0;
hw_trg.qspi_rx_proc = 1'b0;
hw_trg.uart_tx_proc = 1'b0;
hw_trg.uart_rx_proc = 1'b0;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
+66
View File
@@ -0,0 +1,66 @@
"""UART V2 register, FIFO, framing, interrupt, and DMA request tests."""
from __future__ import annotations
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_uart_v2_register_fifo_loopback_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"
cluster_uart = ROOT / "rtl/managed/clusterip/uart/rtl"
source_list = tmp_path / "uart.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(cluster_uart / "uart_if.sv"),
str(serial / "uart_baudgen.sv"),
str(serial / "ribp_uart_tx.sv"),
str(serial / "ribp_uart_rx.sv"),
str(serial / "uart_core.sv"),
str(serial / "uart_reg.sv"),
str(serial / "ribp_uart.sv"),
str(ROOT / "tests/rtl/uart_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "uart_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 / "uart_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "uart_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "UART V2 register, FIFO, loopback, error, interrupt, and DMA test passed" in result.stdout