feat: add RIBP Timer V2 support with formal verification and tests

- Updated filelist to include new timer peripheral files.
- Enhanced formal file generation script to support timer target.
- Created timer formal design and properties for formal verification.
- Modified formal makefile to include timer targets and source files.
- Added timer-related source files to software makefile.
- Updated core and management wrappers to include debug halted signal.
- Implemented timer testbench for RTL simulation.
- Added regression tests for timer functionality in Python.
- Introduced timer helper functions in C tests for validation.
This commit is contained in:
maksyuki committed 2026-08-08 10:05:39 +08:00
1 parent 1eb342245c
commit 3aa3d937e1
46 files changed
+1877 -465

No files matched your search

+2
View File
@@ -20,6 +20,8 @@ truth wins.
GitHub workflows define the active build and regression behavior. GitHub workflows define the active build and regression behavior.
- `quality/embedded_c_policy.json`, `quality/warnings/`, and - `quality/embedded_c_policy.json`, `quality/warnings/`, and
`quality/metrics/policy.json` define the active quality policy. `quality/metrics/policy.json` define the active quality policy.
- [rtl/README.md](rtl/README.md) defines the self-owned SystemVerilog naming,
register-state, macro, and formatting conventions.
Do not guess a profile, tool version, dependency revision, or generated-file Do not guess a profile, tool version, dependency revision, or generated-file
location. Inspect the corresponding source of truth first. location. Inspect the corresponding source of truth first.
+2 -2
View File
@@ -233,7 +233,7 @@ endif
benchmark-report coremark-report \ benchmark-report coremark-report \
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \ 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 \ check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
formal formal-bus formal-rib-adapter formal-rib2apb formal-ws2812 formal-clean formal-doctor formal formal-bus formal-rib-adapter formal-rib2apb formal-ws2812 formal-timer formal-clean formal-doctor
.NOTPARALLEL: setup .NOTPARALLEL: setup
help: help:
@@ -261,7 +261,7 @@ help:
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \ ' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \ ' 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 | formal-bus | formal-rib-adapter | formal-rib2apb run SBY protocol proofs' \
' formal-sysctrl | formal-pll-rcu | formal-gpio-user | formal-ws2812 run peripheral proofs' \ ' formal-sysctrl | formal-pll-rcu | formal-gpio-user | formal-ws2812 | formal-timer run peripheral proofs' \
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \ ' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
' benchmark-report run the memory/DMA profile and write meta/performance.json' \ ' benchmark-report run the memory/DMA profile and write meta/performance.json' \
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \ ' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
+2 -1
View File
@@ -27,7 +27,8 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
core, with a reproducible Verilator, OpenOCD, and GDB acceptance flow. core, with a reproducible Verilator, OpenOCD, and GDB acceptance flow.
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with - Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with
open-source CI coverage. open-source CI coverage.
- A memory-mapped peripheral subsystem with GPIO, UART, timers, PWM, I2C, I2S, PS2, - A memory-mapped peripheral subsystem with GPIO, UART,
[dual general timers](docs/ip/timer.md), PWM, I2C, I2S, PS2,
WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC
support. Available interfaces depend on the selected SoC configuration. support. Available interfaces depend on the selected SoC configuration.
- A standalone RISC-V runtime, HAL, board support, middleware, and `benchmark`, `bringup`, - A standalone RISC-V runtime, HAL, board support, middleware, and `benchmark`, `bringup`,
+77 -1
View File
@@ -1,4 +1,5 @@
#include <retrosoc/core/soc.h> #include <retrosoc/core/soc.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/hal/uart.h> #include <retrosoc/hal/uart.h>
#include <retrosoc/lib/printf.h> #include <retrosoc/lib/printf.h>
#include <retrosoc/service/test.h> #include <retrosoc/service/test.h>
@@ -12,14 +13,89 @@ static bool rs_ci_smoke_archinfo_matches_reset_values(void) {
(archinfo_idh == UINT32_C(0x00FFFFFF)); (archinfo_idh == UINT32_C(0x00FFFFFF));
} }
static bool rs_ci_smoke_timer_one_shot(void) {
const rs_timer_config_t config = {
.mode = RS_TIMER_MODE_ONE_SHOT,
.direction = RS_TIMER_DIRECTION_DOWN,
.prescale = 0U,
.load = 8U,
.compare0 = 4U,
.compare1 = 0U,
.interrupt_enable = RS_TIMER_INTERRUPT_TIMEOUT | RS_TIMER_INTERRUPT_COMPARE0,
.freeze_in_debug = true,
.compare0_enable = true,
.compare1_enable = false,
};
rs_timer_status_t status;
if ((rs_timer_configure(RS_TIMER_0, &config) != RS_OK) ||
(rs_timer_start(RS_TIMER_0) != RS_OK)) {
return false;
}
for (rs_timeout_t timeout = 1000U; timeout != 0U; --timeout) {
if (rs_timer_get_status(RS_TIMER_0, &status) != RS_OK) {
return false;
}
if (!status.active) {
return (status.value == 0U) &&
((status.interrupt_state &
(RS_TIMER_INTERRUPT_TIMEOUT | RS_TIMER_INTERRUPT_COMPARE0)) ==
(RS_TIMER_INTERRUPT_TIMEOUT | RS_TIMER_INTERRUPT_COMPARE0));
}
}
return false;
}
static bool rs_ci_smoke_timer_periodic(void) {
const rs_timer_config_t config = {
.mode = RS_TIMER_MODE_PERIODIC,
.direction = RS_TIMER_DIRECTION_UP,
.prescale = 0U,
.load = 7U,
.compare0 = 0U,
.compare1 = 3U,
.interrupt_enable = RS_TIMER_INTERRUPT_TIMEOUT | RS_TIMER_INTERRUPT_COMPARE1,
.freeze_in_debug = true,
.compare0_enable = false,
.compare1_enable = true,
};
rs_timer_status_t status;
bool passed = false;
if ((rs_timer_configure(RS_TIMER_1, &config) != RS_OK) ||
(rs_timer_start(RS_TIMER_1) != RS_OK)) {
return false;
}
for (rs_timeout_t timeout = 1000U; timeout != 0U; --timeout) {
if (rs_timer_get_status(RS_TIMER_1, &status) != RS_OK) {
break;
}
if ((status.interrupt_state & (RS_TIMER_INTERRUPT_TIMEOUT | RS_TIMER_INTERRUPT_COMPARE1)) ==
(RS_TIMER_INTERRUPT_TIMEOUT | RS_TIMER_INTERRUPT_COMPARE1)) {
passed = true;
break;
}
}
if (rs_timer_stop(RS_TIMER_1) != RS_OK) {
return false;
}
return passed;
}
int main(void) { int main(void) {
uart0_init(CPU_FREQ, UART_BPS); uart0_init(CPU_FREQ, UART_BPS);
if (!rs_ci_smoke_archinfo_matches_reset_values()) { if (!rs_ci_smoke_archinfo_matches_reset_values()) {
rs_test_finish(RS_TEST_FAILED, 1U); rs_test_finish(RS_TEST_FAILED, 1U);
} }
if (!rs_ci_smoke_timer_one_shot()) {
rs_test_finish(RS_TEST_FAILED, 2U);
}
if (!rs_ci_smoke_timer_periodic()) {
rs_test_finish(RS_TEST_FAILED, 3U);
}
printf("ci_smoke: archinfo readback passed\n"); printf("ci_smoke: archinfo and timer tests passed\n");
rs_test_finish(RS_TEST_PASSED, 0U); rs_test_finish(RS_TEST_PASSED, 0U);
return 0; return 0;
} }
+1 -3
View File
@@ -38,7 +38,6 @@ int main(void) {
lcd_init(); lcd_init();
// lv_init(); // lv_init();
// tim1_init();
// lv_tick_set_cb(my_get_millis); // lv_tick_set_cb(my_get_millis);
// lv_port_disp_init(); // lv_port_disp_init();
@@ -49,7 +48,6 @@ int main(void) {
// while(1) { // while(1) {
// lv_timer_handler(); // lv_timer_handler();
// delay_ms(5);
// printf("hello\n"); // printf("hello\n");
// } // }
@@ -57,7 +55,7 @@ int main(void) {
(void)rs_shell_register("app", "app info", true, rs_app_info_command); (void)rs_shell_register("app", "app info", true, rs_app_info_command);
(void)rs_shell_register("arch", "archinfo test", true, ip_archinfo_test); (void)rs_shell_register("arch", "archinfo test", true, ip_archinfo_test);
(void)rs_shell_register("ws2812", "ws2812 test", true, ip_ws2812_test); (void)rs_shell_register("ws2812", "ws2812 test", true, ip_ws2812_test);
(void)rs_shell_register("tim", "timer test", true, ip_tim_test); (void)rs_shell_register("tim", "timer test", true, rs_timer_shell_test);
(void)rs_shell_register("gpio", "gpio test", true, ip_gpio_test); (void)rs_shell_register("gpio", "gpio test", true, ip_gpio_test);
(void)rs_shell_register("pwm", "pwm test", true, ip_pwm_test); (void)rs_shell_register("pwm", "pwm test", true, ip_pwm_test);
(void)rs_shell_register("rtc", "rtc test", true, ip_rtc_test); (void)rs_shell_register("rtc", "rtc test", true, ip_rtc_test);
+8 -2
View File
@@ -78,7 +78,10 @@ void pcf8563b_test(int argc, char **argv) {
printf("[PCF8563B] %d-%d-%d %d %d:%d:%d\n", rd_info.date.year, rd_info.date.month, printf("[PCF8563B] %d-%d-%d %d %d:%d:%d\n", rd_info.date.year, rd_info.date.month,
rd_info.date.day, rd_info.date.weekday, rd_info.time.hour, rd_info.time.minute, rd_info.date.day, rd_info.date.weekday, rd_info.time.hour, rd_info.time.minute,
rd_info.time.second); rd_info.time.second);
delay_ms(1000); if (rs_timer_delay_ms(RS_TIMER_0, 1000U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("PCF8563B timer delay failed\n");
return;
}
} }
PCF8563B_info_t init2_info = {.time.second = 23, PCF8563B_info_t init2_info = {.time.second = 23,
@@ -94,7 +97,10 @@ void pcf8563b_test(int argc, char **argv) {
printf("[PCF8563B] %d-%d-%d %d %d:%d:%d\n", rd_info.date.year, rd_info.date.month, printf("[PCF8563B] %d-%d-%d %d %d:%d:%d\n", rd_info.date.year, rd_info.date.month,
rd_info.date.day, rd_info.date.weekday, rd_info.time.hour, rd_info.time.minute, rd_info.date.day, rd_info.date.weekday, rd_info.time.hour, rd_info.time.minute,
rd_info.time.second); rd_info.time.second);
delay_ms(1000); if (rs_timer_delay_ms(RS_TIMER_0, 1000U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("PCF8563B timer delay failed\n");
return;
}
} }
printf("PCF8563B test done\n"); printf("PCF8563B test done\n");
+4 -1
View File
@@ -22,7 +22,10 @@ void userip_main(int argc, char **argv) {
reg_user_ip_reg1 = (uint32_t)0xfffe; reg_user_ip_reg1 = (uint32_t)0xfffe;
printf("do val: %x\n", reg_user_ip_reg5); printf("do val: %x\n", reg_user_ip_reg5);
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
delay_ms(1); if (rs_timer_delay_ms(RS_TIMER_0, 1U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("timer delay failed\n");
return;
}
reg_user_ip_reg5 = ~reg_user_ip_reg5; reg_user_ip_reg5 = ~reg_user_ip_reg5;
printf("[%d]do val: %x\n", i, reg_user_ip_reg5); printf("[%d]do val: %x\n", i, reg_user_ip_reg5);
} }
-8
View File
@@ -50,14 +50,6 @@
// uart0 // uart0
#define reg_uart0_clkdiv RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0x00)) #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)) #define reg_uart0_data RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0x04))
// tim0
#define reg_tim0_cfg RS_SOC_REG32(RS_SOC_RIBP_TIM0_BASE, UINT32_C(0x00))
#define reg_tim0_rld RS_SOC_REG32(RS_SOC_RIBP_TIM0_BASE, UINT32_C(0x04))
#define reg_tim0_val RS_SOC_REG32(RS_SOC_RIBP_TIM0_BASE, UINT32_C(0x08))
// tim1
#define reg_tim1_cfg RS_SOC_REG32(RS_SOC_RIBP_TIM1_BASE, UINT32_C(0x00))
#define reg_tim1_rld RS_SOC_REG32(RS_SOC_RIBP_TIM1_BASE, UINT32_C(0x04))
#define reg_tim1_val RS_SOC_REG32(RS_SOC_RIBP_TIM1_BASE, UINT32_C(0x08))
// psram // psram
#define reg_psram_wait RS_SOC_REG32(RS_SOC_RIBP_PSRAM_BASE, UINT32_C(0x00)) #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)) #define reg_psram_chd RS_SOC_REG32(RS_SOC_RIBP_PSRAM_BASE, UINT32_C(0x04))
+2
View File
@@ -29,6 +29,8 @@ typedef struct {
} rs_clock_status_t; } rs_clock_status_t;
rs_status_t rs_clock_get_status(rs_clock_status_t *status); rs_status_t rs_clock_get_status(rs_clock_status_t *status);
rs_status_t rs_clock_frequency_hz(rs_clock_frequency_t frequency, uint32_t *frequency_hz);
rs_status_t rs_clock_get_active_hz(uint32_t *frequency_hz);
rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t timeout); rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t timeout);
#endif #endif
+68 -6
View File
@@ -1,10 +1,72 @@
#ifndef RETROSOC_TIM_H #ifndef RETROSOC_HAL_TIMER_H
#define RETROSOC_TIM_H #define RETROSOC_HAL_TIMER_H
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
void delay_ms(uint32_t val); #include <retrosoc/core/status.h>
void tim1_init(void);
uint32_t tim1_get_value(void); #define RS_TIMER_INTERRUPT_TIMEOUT UINT32_C(0x00000001)
void ip_tim_test(int argc, char **argv); #define RS_TIMER_INTERRUPT_COMPARE0 UINT32_C(0x00000002)
#define RS_TIMER_INTERRUPT_COMPARE1 UINT32_C(0x00000004)
#define RS_TIMER_INTERRUPT_ALL UINT32_C(0x00000007)
#define RS_TIMER_DELAY_TIMEOUT ((rs_timeout_t)UINT32_MAX)
typedef enum {
RS_TIMER_0 = 0,
RS_TIMER_1 = 1,
} rs_timer_id_t;
typedef enum {
RS_TIMER_MODE_FREE_RUNNING = 0,
RS_TIMER_MODE_PERIODIC = 1,
RS_TIMER_MODE_ONE_SHOT = 2,
} rs_timer_mode_t;
typedef enum {
RS_TIMER_DIRECTION_UP = 0,
RS_TIMER_DIRECTION_DOWN = 1,
} rs_timer_direction_t;
typedef struct {
rs_timer_mode_t mode;
rs_timer_direction_t direction;
uint16_t prescale;
uint32_t load;
uint32_t compare0;
uint32_t compare1;
uint32_t interrupt_enable;
bool freeze_in_debug;
bool compare0_enable;
bool compare1_enable;
} rs_timer_config_t;
typedef struct {
uint32_t value;
uint32_t interrupt_state;
bool active;
bool debug_frozen;
} rs_timer_status_t;
typedef struct {
uint16_t prescale;
uint32_t load;
} rs_timer_period_t;
rs_status_t rs_timer_period_from_ms(uint32_t source_clock_hz, uint32_t milliseconds,
rs_timer_period_t *period);
rs_status_t rs_timer_configure(rs_timer_id_t timer, const rs_timer_config_t *config);
rs_status_t rs_timer_start(rs_timer_id_t timer);
rs_status_t rs_timer_stop(rs_timer_id_t timer);
rs_status_t rs_timer_set_load(rs_timer_id_t timer, uint32_t load);
rs_status_t rs_timer_set_background_load(rs_timer_id_t timer, uint32_t load);
rs_status_t rs_timer_set_compare(rs_timer_id_t timer, uint32_t channel, uint32_t compare);
rs_status_t rs_timer_get_value(rs_timer_id_t timer, uint32_t *value);
rs_status_t rs_timer_get_status(rs_timer_id_t timer, rs_timer_status_t *status);
rs_status_t rs_timer_interrupt_enable(rs_timer_id_t timer, uint32_t mask);
rs_status_t rs_timer_interrupt_clear(rs_timer_id_t timer, uint32_t mask);
rs_status_t rs_timer_interrupt_test(rs_timer_id_t timer, uint32_t mask);
rs_status_t rs_timer_delay_ms(rs_timer_id_t timer, uint32_t milliseconds, rs_timeout_t timeout);
void rs_timer_shell_test(int argc, char **argv);
#endif #endif
+3 -1
View File
@@ -35,7 +35,9 @@ static rs_status_t rs_irq_wait_for_count(volatile uint32_t *counter, uint32_t ta
if (*counter >= target) { if (*counter >= target) {
return RS_OK; return RS_OK;
} }
delay_ms(1U); if (rs_timer_delay_ms(RS_TIMER_0, 1U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
return RS_ETIMEOUT;
}
} }
return RS_ETIMEOUT; return RS_ETIMEOUT;
} }
+27
View File
@@ -38,6 +38,33 @@ rs_status_t rs_clock_get_status(rs_clock_status_t *status) {
return RS_OK; return RS_OK;
} }
rs_status_t rs_clock_frequency_hz(rs_clock_frequency_t frequency, uint32_t *frequency_hz) {
if (!rs_clock_frequency_valid(frequency) || (frequency_hz == NULL)) {
return RS_EINVAL;
}
*frequency_hz = ((uint32_t)frequency + 1U) * UINT32_C(24000000);
return RS_OK;
}
rs_status_t rs_clock_get_active_hz(uint32_t *frequency_hz) {
rs_clock_status_t status;
if (frequency_hz == NULL) {
return RS_EINVAL;
}
if (rs_clock_get_status(&status) != RS_OK) {
return RS_EIO;
}
if (!status.capable) {
*frequency_hz = CPU_FREQ * UINT32_C(1000000);
return RS_OK;
}
if (!status.active_valid || status.busy) {
return RS_EIO;
}
return rs_clock_frequency_hz(status.active_frequency, frequency_hz);
}
rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t timeout) { rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t timeout) {
rs_clock_status_t status; rs_clock_status_t status;
bool busy_observed = false; bool busy_observed = false;
+8 -2
View File
@@ -22,7 +22,10 @@ void ip_gpio_test(int argc, char **argv) {
printf("led output test\n"); printf("led output test\n");
for (int i = 0; i < 50; ++i) { for (int i = 0; i < 50; ++i) {
delay_ms(300); if (rs_timer_delay_ms(RS_TIMER_0, 300U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("timer delay failed\n");
return;
}
if (reg_gpio_do == 0b00) if (reg_gpio_do == 0b00)
reg_gpio_do = (uint32_t)0b01; reg_gpio_do = (uint32_t)0b01;
else else
@@ -38,7 +41,10 @@ void ip_gpio_test(int argc, char **argv) {
for (int i = 0; i < 60; ++i) { for (int i = 0; i < 60; ++i) {
uint32_t led_val = 0b00; uint32_t led_val = 0b00;
if (((reg_gpio_do & 0b10) >> 1) == 0b0) { if (((reg_gpio_do & 0b10) >> 1) == 0b0) {
delay_ms(100); // debouncing if (rs_timer_delay_ms(RS_TIMER_0, 100U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("timer delay failed\n");
return;
}
if (((reg_gpio_do & 0b10) >> 1) == 0b0) { if (((reg_gpio_do & 0b10) >> 1) == 0b0) {
printf("key detect\n"); printf("key detect\n");
if (led_val == 0b00) { if (led_val == 0b00) {
+8 -4
View File
@@ -75,9 +75,15 @@ static void lcd_wr_data32(uint32_t *dat, uint32_t len) {
} }
void lcd_init(void) { void lcd_init(void) {
delay_ms(500); if (rs_timer_delay_ms(RS_TIMER_0, 500U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("LCD reset delay failed\n");
return;
}
lcd_wr_dc_cmd(0x11); lcd_wr_dc_cmd(0x11);
delay_ms(120); if (rs_timer_delay_ms(RS_TIMER_0, 120U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("LCD sleep-exit delay failed\n");
return;
}
lcd_wr_dc_cmd(0x36); lcd_wr_dc_cmd(0x36);
if (USE_HORIZONTAL == 0) if (USE_HORIZONTAL == 0)
lcd_wr_dc_data8(0x00); lcd_wr_dc_data8(0x00);
@@ -344,8 +350,6 @@ void ip_lcd_test(int argc, char **argv) {
// } // }
// lcd_frame(0, pref_cnt); // lcd_frame(0, pref_cnt);
// delay_ms(1000);
// for (int i = 0; i < 100; ++i) // for (int i = 0; i < 100; ++i)
// { // {
// lcd_fill_video(0, 0, 240, 135, only_my_railgun[i]); // lcd_fill_video(0, 0, 240, 135, only_my_railgun[i]);
+8 -2
View File
@@ -20,7 +20,10 @@ void ip_pwm_test(int argc, char **argv) {
reg_pwm_cr0 = j; reg_pwm_cr0 = j;
reg_pwm_ctrl = (uint32_t)3; reg_pwm_ctrl = (uint32_t)3;
reg_pwm_pscr = 49; reg_pwm_pscr = 49;
delay_ms(1); if (rs_timer_delay_ms(RS_TIMER_0, 1U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("timer delay failed\n");
return;
}
} }
for (int j = 990; j >= 10; --j) { for (int j = 990; j >= 10; --j) {
@@ -28,7 +31,10 @@ void ip_pwm_test(int argc, char **argv) {
reg_pwm_cr0 = j; reg_pwm_cr0 = j;
reg_pwm_ctrl = (uint32_t)3; reg_pwm_ctrl = (uint32_t)3;
reg_pwm_pscr = 49; reg_pwm_pscr = 49;
delay_ms(1); if (rs_timer_delay_ms(RS_TIMER_0, 1U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("timer delay failed\n");
return;
}
} }
printf("[PWM]: %d/6\n", i + 1); printf("[PWM]: %d/6\n", i + 1);
} }
+238 -36
View File
@@ -1,49 +1,251 @@
#include <stddef.h>
#include <retrosoc/core/soc.h> #include <retrosoc/core/soc.h>
#include <retrosoc/lib/printf.h> #include <retrosoc/hal/clock.h>
#include <retrosoc/hal/timer.h> #include <retrosoc/hal/timer.h>
#include <retrosoc/lib/printf.h>
void delay_ms(uint32_t val) { #define RS_TIMER_CTRL_OFFSET UINT32_C(0x000)
reg_tim0_val = (uint32_t)(CPU_FREQ * val * 1000 - 1); #define RS_TIMER_LOAD_OFFSET UINT32_C(0x004)
reg_tim0_cfg = (uint32_t)0b0011; // irq disable, count down, oneshot mode, timer enable #define RS_TIMER_VALUE_OFFSET UINT32_C(0x008)
while (reg_tim0_val) #define RS_TIMER_BGLOAD_OFFSET UINT32_C(0x00C)
; #define RS_TIMER_PRESCALE_OFFSET UINT32_C(0x010)
reg_tim0_cfg = (uint32_t)0b0000; #define RS_TIMER_COMPARE0_OFFSET UINT32_C(0x014)
#define RS_TIMER_COMPARE1_OFFSET UINT32_C(0x018)
#define RS_TIMER_STATUS_OFFSET UINT32_C(0x01C)
#define RS_TIMER_INTR_STATE_OFFSET UINT32_C(0x020)
#define RS_TIMER_INTR_ENABLE_OFFSET UINT32_C(0x024)
#define RS_TIMER_INTR_TEST_OFFSET UINT32_C(0x02C)
#define RS_TIMER_CTRL_ENABLE_SHIFT 0U
#define RS_TIMER_CTRL_MODE_SHIFT 1U
#define RS_TIMER_CTRL_DIRECTION_SHIFT 3U
#define RS_TIMER_CTRL_ENABLE_MASK UINT32_C(0x00000001)
#define RS_TIMER_CTRL_DEBUG_FREEZE_MASK UINT32_C(0x00000010)
#define RS_TIMER_CTRL_COMPARE0_ENABLE_MASK UINT32_C(0x00000020)
#define RS_TIMER_CTRL_COMPARE1_ENABLE_MASK UINT32_C(0x00000040)
#define RS_TIMER_STATUS_ACTIVE_MASK UINT32_C(0x00000001)
#define RS_TIMER_STATUS_DEBUG_FROZEN_MASK UINT32_C(0x00000002)
static bool rs_timer_id_valid(rs_timer_id_t timer) {
return (timer == RS_TIMER_0) || (timer == RS_TIMER_1);
} }
void tim1_init(void) { static uintptr_t rs_timer_base(rs_timer_id_t timer) {
reg_tim1_cfg = (uint32_t)0b0000; return timer == RS_TIMER_0 ? RS_SOC_RIBP_TIM0_BASE : RS_SOC_RIBP_TIM1_BASE;
reg_tim1_rld = (uint32_t)0xFFFFFFFF;
reg_tim1_val = (uint32_t)0;
// printf("tim1 cfg: %x\n", reg_tim1_cfg);
// printf("tim1 rld: %x\n", reg_tim1_rld);
// printf("tim1 val: %x\n", reg_tim1_val);
reg_tim1_cfg = (uint32_t)0b0111;
// printf("tim1 cfg: %d\n", reg_tim1_cfg);
} }
uint32_t tim1_get_value(void) { static volatile uint32_t *rs_timer_register(rs_timer_id_t timer, uint32_t offset) {
return reg_tim1_val; return (volatile uint32_t *)(rs_timer_base(timer) + (uintptr_t)offset);
} }
void ip_tim_test(int argc, char **argv) { static uint32_t rs_timer_ctrl_from_config(const rs_timer_config_t *config) {
uint32_t control = ((uint32_t)config->mode << RS_TIMER_CTRL_MODE_SHIFT) |
((uint32_t)config->direction << RS_TIMER_CTRL_DIRECTION_SHIFT);
if (config->freeze_in_debug) {
control |= RS_TIMER_CTRL_DEBUG_FREEZE_MASK;
}
if (config->compare0_enable) {
control |= RS_TIMER_CTRL_COMPARE0_ENABLE_MASK;
}
if (config->compare1_enable) {
control |= RS_TIMER_CTRL_COMPARE1_ENABLE_MASK;
}
return control;
}
static bool rs_timer_config_valid(const rs_timer_config_t *config) {
return (config != NULL) && ((uint32_t)config->mode <= (uint32_t)RS_TIMER_MODE_ONE_SHOT) &&
((uint32_t)config->direction <= (uint32_t)RS_TIMER_DIRECTION_DOWN) &&
((config->interrupt_enable & ~RS_TIMER_INTERRUPT_ALL) == 0U);
}
rs_status_t rs_timer_configure(rs_timer_id_t timer, const rs_timer_config_t *config) {
volatile uint32_t *control;
uint32_t control_value;
if (!rs_timer_id_valid(timer) || !rs_timer_config_valid(config)) {
return RS_EINVAL;
}
control = rs_timer_register(timer, RS_TIMER_CTRL_OFFSET);
*control &= ~RS_TIMER_CTRL_ENABLE_MASK;
control_value = rs_timer_ctrl_from_config(config);
*control = control_value;
*rs_timer_register(timer, RS_TIMER_PRESCALE_OFFSET) = (uint32_t)config->prescale;
*rs_timer_register(timer, RS_TIMER_COMPARE0_OFFSET) = config->compare0;
*rs_timer_register(timer, RS_TIMER_COMPARE1_OFFSET) = config->compare1;
*rs_timer_register(timer, RS_TIMER_LOAD_OFFSET) = config->load;
*rs_timer_register(timer, RS_TIMER_INTR_STATE_OFFSET) = RS_TIMER_INTERRUPT_ALL;
*rs_timer_register(timer, RS_TIMER_INTR_ENABLE_OFFSET) = config->interrupt_enable;
return RS_OK;
}
rs_status_t rs_timer_start(rs_timer_id_t timer) {
volatile uint32_t *control;
if (!rs_timer_id_valid(timer)) {
return RS_EINVAL;
}
control = rs_timer_register(timer, RS_TIMER_CTRL_OFFSET);
*control |= RS_TIMER_CTRL_ENABLE_MASK;
return RS_OK;
}
rs_status_t rs_timer_stop(rs_timer_id_t timer) {
volatile uint32_t *control;
if (!rs_timer_id_valid(timer)) {
return RS_EINVAL;
}
control = rs_timer_register(timer, RS_TIMER_CTRL_OFFSET);
*control &= ~RS_TIMER_CTRL_ENABLE_MASK;
return RS_OK;
}
rs_status_t rs_timer_set_load(rs_timer_id_t timer, uint32_t load) {
if (!rs_timer_id_valid(timer)) {
return RS_EINVAL;
}
*rs_timer_register(timer, RS_TIMER_LOAD_OFFSET) = load;
return RS_OK;
}
rs_status_t rs_timer_set_background_load(rs_timer_id_t timer, uint32_t load) {
if (!rs_timer_id_valid(timer)) {
return RS_EINVAL;
}
*rs_timer_register(timer, RS_TIMER_BGLOAD_OFFSET) = load;
return RS_OK;
}
rs_status_t rs_timer_set_compare(rs_timer_id_t timer, uint32_t channel, uint32_t compare) {
if (!rs_timer_id_valid(timer) || (channel > 1U)) {
return RS_EINVAL;
}
*rs_timer_register(timer, channel == 0U ? RS_TIMER_COMPARE0_OFFSET : RS_TIMER_COMPARE1_OFFSET) =
compare;
return RS_OK;
}
rs_status_t rs_timer_get_value(rs_timer_id_t timer, uint32_t *value) {
if (!rs_timer_id_valid(timer) || (value == NULL)) {
return RS_EINVAL;
}
*value = *rs_timer_register(timer, RS_TIMER_VALUE_OFFSET);
return RS_OK;
}
rs_status_t rs_timer_get_status(rs_timer_id_t timer, rs_timer_status_t *status) {
uint32_t value;
if (!rs_timer_id_valid(timer) || (status == NULL)) {
return RS_EINVAL;
}
value = *rs_timer_register(timer, RS_TIMER_STATUS_OFFSET);
status->value = *rs_timer_register(timer, RS_TIMER_VALUE_OFFSET);
status->interrupt_state = *rs_timer_register(timer, RS_TIMER_INTR_STATE_OFFSET);
status->active = (value & RS_TIMER_STATUS_ACTIVE_MASK) != 0U;
status->debug_frozen = (value & RS_TIMER_STATUS_DEBUG_FROZEN_MASK) != 0U;
return RS_OK;
}
rs_status_t rs_timer_interrupt_enable(rs_timer_id_t timer, uint32_t mask) {
if (!rs_timer_id_valid(timer) || ((mask & ~RS_TIMER_INTERRUPT_ALL) != 0U)) {
return RS_EINVAL;
}
*rs_timer_register(timer, RS_TIMER_INTR_ENABLE_OFFSET) = mask;
return RS_OK;
}
rs_status_t rs_timer_interrupt_clear(rs_timer_id_t timer, uint32_t mask) {
if (!rs_timer_id_valid(timer) || ((mask & ~RS_TIMER_INTERRUPT_ALL) != 0U)) {
return RS_EINVAL;
}
*rs_timer_register(timer, RS_TIMER_INTR_STATE_OFFSET) = mask;
return RS_OK;
}
rs_status_t rs_timer_interrupt_test(rs_timer_id_t timer, uint32_t mask) {
if (!rs_timer_id_valid(timer) || ((mask & ~RS_TIMER_INTERRUPT_ALL) != 0U)) {
return RS_EINVAL;
}
*rs_timer_register(timer, RS_TIMER_INTR_TEST_OFFSET) = mask;
return RS_OK;
}
rs_status_t rs_timer_delay_ms(rs_timer_id_t timer, uint32_t milliseconds, rs_timeout_t timeout) {
rs_timer_config_t config = {
.mode = RS_TIMER_MODE_ONE_SHOT,
.direction = RS_TIMER_DIRECTION_DOWN,
.prescale = 0U,
.load = 0U,
.compare0 = 0U,
.compare1 = 0U,
.interrupt_enable = 0U,
.freeze_in_debug = true,
.compare0_enable = false,
.compare1_enable = false,
};
rs_timer_period_t period;
uint32_t frequency_hz;
if (!rs_timer_id_valid(timer)) {
return RS_EINVAL;
}
if (milliseconds == 0U) {
return RS_OK;
}
if ((rs_clock_get_active_hz(&frequency_hz) != RS_OK) ||
(rs_timer_period_from_ms(frequency_hz, milliseconds, &period) != RS_OK)) {
return RS_EINVAL;
}
config.prescale = period.prescale;
config.load = period.load;
if ((rs_timer_configure(timer, &config) != RS_OK) || (rs_timer_start(timer) != RS_OK)) {
return RS_EIO;
}
while (timeout-- != 0U) {
if ((*rs_timer_register(timer, RS_TIMER_STATUS_OFFSET) & RS_TIMER_STATUS_ACTIVE_MASK) ==
0U) {
return RS_OK;
}
}
(void)rs_timer_stop(timer);
return RS_ETIMEOUT;
}
void rs_timer_shell_test(int argc, char **argv) {
rs_timer_config_t config = {
.mode = RS_TIMER_MODE_PERIODIC,
.direction = RS_TIMER_DIRECTION_UP,
.prescale = 0U,
.load = UINT32_C(0x00FFFFFF),
.compare0 = UINT32_C(0x0000FFFF),
.compare1 = UINT32_C(0x000FFFFF),
.interrupt_enable = 0U,
.freeze_in_debug = true,
.compare0_enable = true,
.compare1_enable = true,
};
uint32_t value;
(void)argc; (void)argc;
(void)argv; (void)argv;
printf("[RIBP IP] general timer test\n");
printf("[RIB IP] counter timer test\n"); if ((rs_timer_configure(RS_TIMER_1, &config) != RS_OK) ||
printf("[tim0 reload] %x\n", reg_tim0_rld); (rs_timer_start(RS_TIMER_1) != RS_OK)) {
printf("[tim0 config] %x\n", reg_tim0_cfg); printf("timer configuration failed\n");
printf("[tim1 reload] %x\n", reg_tim1_rld); return;
printf("[tim1 config] %x\n", reg_tim1_cfg);
reg_tim0_rld = (uint32_t)0xffffffff;
reg_tim0_cfg = (uint32_t)0b0001; // irq disable, count down, continuous mode, timer enable
reg_tim1_rld = (uint32_t)0x00ffffff;
reg_tim1_val = (uint32_t)0;
reg_tim1_cfg = (uint32_t)0b0101; // irq disable, count up, continuous mode, timer enable
for (int i = 0; i < 10; ++i) {
printf("[tim0 val] %x\n", reg_tim0_val);
printf("[tim1 val] %x\n", reg_tim1_val);
} }
for (uint32_t index = 0U; index < 10U; ++index) {
if (rs_timer_get_value(RS_TIMER_1, &value) != RS_OK) {
printf("timer read failed\n");
break;
}
printf("[timer1 value] %x\n", value);
}
(void)rs_timer_stop(RS_TIMER_1);
} }
+39
View File
@@ -0,0 +1,39 @@
#include <stddef.h>
#include <stdint.h>
#include <retrosoc/hal/timer.h>
#define RS_MILLISECONDS_PER_SECOND UINT64_C(1000)
#define RS_TIMER_MAX_DIVIDER UINT64_C(65536)
#define RS_TIMER_COUNTER_VALUES (UINT64_C(1) << 32U)
rs_status_t rs_timer_period_from_ms(uint32_t source_clock_hz, uint32_t milliseconds,
rs_timer_period_t *period) {
uint64_t product;
uint64_t cycles;
uint64_t divider;
uint64_t ticks;
if ((source_clock_hz == 0U) || (milliseconds == 0U) || (period == NULL)) {
return RS_EINVAL;
}
product = (uint64_t)source_clock_hz * (uint64_t)milliseconds;
if (product > (UINT64_MAX - (RS_MILLISECONDS_PER_SECOND - 1U))) {
return RS_EINVAL;
}
cycles = (product + (RS_MILLISECONDS_PER_SECOND - 1U)) / RS_MILLISECONDS_PER_SECOND;
divider = (cycles + (RS_TIMER_COUNTER_VALUES - 1U)) / RS_TIMER_COUNTER_VALUES;
if (divider == 0U) {
divider = 1U;
}
if (divider > RS_TIMER_MAX_DIVIDER) {
return RS_EINVAL;
}
ticks = (cycles + (divider - 1U)) / divider;
if ((ticks == 0U) || (ticks > RS_TIMER_COUNTER_VALUES)) {
return RS_EINVAL;
}
period->prescale = (uint16_t)(divider - 1U);
period->load = (uint32_t)(ticks - 1U);
return RS_OK;
}
+6 -3
View File
@@ -97,8 +97,8 @@ void rs_app_info(void) {
printf("Memory Map IO Device:\n"); printf("Memory Map IO Device:\n");
printf(" 1 x GPIO(32PIN) @%p\n", (void *)&reg_gpio_oe); printf(" 1 x GPIO(32PIN) @%p\n", (void *)&reg_gpio_oe);
printf(" 1 x UART0 @%p\n", (void *)&reg_uart0_clkdiv); printf(" 1 x UART0 @%p\n", (void *)&reg_uart0_clkdiv);
printf(" 2 x TIMER(0,1) @%p,%p\n", (void *)&reg_tim0_cfg, printf(" 2 x TIMER(0,1) @%p,%p\n",
(void *)&reg_tim1_cfg); (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); printf(" 1 x PSRAM @%p\n", (void *)&reg_psram_wait);
printf(" 1 x SPISD @%p\n", (void *)&reg_spisd_mode); printf(" 1 x SPISD @%p\n", (void *)&reg_spisd_mode);
printf(" 1 x I2C0 @%p\n", (void *)&reg_i2c0_clkdiv); printf(" 1 x I2C0 @%p\n", (void *)&reg_i2c0_clkdiv);
@@ -181,7 +181,10 @@ static uint8_t rs_booter_check_key(void) {
uint8_t enter_boot_delay = 6, enter_shell = 0; uint8_t enter_boot_delay = 6, enter_shell = 0;
for (uint8_t i = 1; i <= enter_boot_delay; ++i) { for (uint8_t i = 1; i <= enter_boot_delay; ++i) {
printf("delay %ds...[all %ds]\n", i, enter_boot_delay); printf("delay %ds...[all %ds]\n", i, enter_boot_delay);
delay_ms(1000); if (rs_timer_delay_ms(RS_TIMER_0, 1000U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("booter timer delay failed\n");
return 0U;
}
// if(i == 5) enter_shell = 1; // mock the oper // if(i == 5) enter_shell = 1; // mock the oper
if (enter_shell) { if (enter_shell) {
printf("\n"); printf("\n");
+4 -8
View File
@@ -629,7 +629,10 @@ static void rs_shell_app_image_cmd(int argc, char **argv) {
uint32_t *frame_data = file_buffer_words + (video_info.payload_offset / sizeof(uint32_t)) + uint32_t *frame_data = file_buffer_words + (video_info.payload_offset / sizeof(uint32_t)) +
(frame * frame_words); (frame * frame_words);
lcd_fill_image(0U, 0U, (uint16_t)video_info.width, (uint16_t)video_info.height, frame_data); lcd_fill_image(0U, 0U, (uint16_t)video_info.width, (uint16_t)video_info.height, frame_data);
delay_ms(3000U); if (rs_timer_delay_ms(RS_TIMER_0, 3000U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
printf("video frame delay failed\n");
return;
}
} }
} }
@@ -645,17 +648,11 @@ static void rs_shell_app_audio_cmd(int argc, char **argv) {
(void)argv; (void)argv;
} }
// val * 1000 / CPU_FREQ / 1000 / 1000
// uint32_t my_get_millis(void) {
// return reg_tim1_val / CPU_FREQ / 1000;
// }
static void rs_shell_app_lvgl_cmd(int argc, char **argv) { static void rs_shell_app_lvgl_cmd(int argc, char **argv) {
(void)argc; (void)argc;
(void)argv; (void)argv;
// lv_init(); // lv_init();
// tim1_init();
// lv_tick_set_cb(my_get_millis); // lv_tick_set_cb(my_get_millis);
// lv_port_disp_init(); // lv_port_disp_init();
@@ -666,7 +663,6 @@ static void rs_shell_app_lvgl_cmd(int argc, char **argv) {
// while(1) { // while(1) {
// lv_timer_handler(); // lv_timer_handler();
// delay_ms(5);
// printf("hello\n"); // printf("hello\n");
// } // }
} }
+3 -1
View File
@@ -23,8 +23,10 @@ the root README and subsystem guides.
and its commercial reference points. and its commercial reference points.
- [rib-interconnect.md](rib-interconnect.md) defines the RIB v1 linear-burst - [rib-interconnect.md](rib-interconnect.md) defines the RIB v1 linear-burst
contract, compatibility boundaries, target status, and verification. contract, compatibility boundaries, target status, and verification.
- [ws2812.md](ws2812.md) defines the WS2812 transmitter register ABI, - [ip/ws2812.md](ip/ws2812.md) defines the WS2812 transmitter register ABI,
timing, FIFO, interrupt, DMA, and integration contracts. timing, FIFO, interrupt, DMA, and integration contracts.
- [ip/timer.md](ip/timer.md) defines the dual general timer register ABI,
counting modes, interrupt, debug-freeze, HAL, and verification contracts.
- [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated - [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated
pin-map workflow and SoC integration boundary. pin-map workflow and SoC integration boundary.
- [mini-soc-block-diagram.svg](mini-soc-block-diagram.svg) is the Mini SoC - [mini-soc-block-diagram.svg](mini-soc-block-diagram.svg) is the Mini SoC
+11
View File
@@ -0,0 +1,11 @@
# IP Documentation
This directory owns architecture, register ABI, software contract, and
verification documentation for self-owned retroSoC peripheral IP.
- [timer.md](timer.md) defines the dual RIBP general timer.
- [ws2812.md](ws2812.md) defines the WS2812 transmitter.
The corresponding RTL and HAL implementations remain the executable sources
of truth. Update the affected document whenever an IP interface or register ABI
changes.
+96
View File
@@ -0,0 +1,96 @@
# RIBP General Timer
The Mini SoC contains two identical 32-bit general-purpose timers. Each timer
has a 16-bit prescaler, free-running, periodic, and one-shot modes, selectable
up/down counting, two compare channels, sticky interrupts, and optional freeze
while the management Hazard3 core is halted by its Debug Module.
## Integration
| Property | Timer 0 | Timer 1 |
| --- | --- | --- |
| RIBP base address | `0x10002000` | `0x10003000` |
| RIBP interrupt group bit | 3 | 4 |
| Management-core interrupt | 3 | 4 |
| Counter width | 32 bits | 32 bits |
| Prescaler width | 16 bits | 16 bits |
| Compare channels | 2 | 2 |
The timer remains accessible while its counter is debug-frozen. The freeze
input is the management hart's synchronized halted indication; it does not
create or gate a clock. Both the prescaler and the main counter use the normal
SoC clock and stop through synchronous enables.
## Register ABI
All registers are 32 bits and naturally aligned. Unmapped, unaligned, and
direction-invalid accesses complete with `resp_err`. Partial writes are
supported for RW registers. Write-one-to-clear and software-interrupt writes
only act on a selected low byte.
| Offset | Name | Access | Description |
| --- | --- | --- | --- |
| `0x000` | `CTRL` | RW | Enable, mode, direction, debug freeze, and compare enables. |
| `0x004` | `LOAD` | RW | Active period value; a write also loads the live counter. |
| `0x008` | `VALUE` | RO | Current counter value. |
| `0x00C` | `BGLOAD` | RW | Replaces `LOAD` without changing the live counter; used at the next periodic reload. |
| `0x010` | `PRESCALE` | RW | Divide the source clock by `PRESCALE + 1`; writable only while stopped. |
| `0x014` | `COMPARE0` | RW | Compare channel 0 value. |
| `0x018` | `COMPARE1` | RW | Compare channel 1 value. |
| `0x01C` | `STATUS` | RO | Bit 0 `ACTIVE`, bit 1 `DEBUG_FROZEN`. |
| `0x020` | `INTR_STATE` | RW1C | Sticky timeout, compare 0, and compare 1 state. |
| `0x024` | `INTR_ENABLE` | RW | Interrupt enable mask. |
| `0x028` | `INTR_STATUS` | RO | `INTR_STATE & INTR_ENABLE`. |
| `0x02C` | `INTR_TEST` | WO | Write-one software interrupt test. |
| `0x0F8` | `IP_VERSION` | RO | ABI version, currently `0x00020000` (2.0). |
| `0x0FC` | `CAPABILITY` | RO | Implemented counter, prescaler, mode, compare, direction, and debug-freeze capabilities. |
`CTRL.MODE` is `0` for free-running, `1` for periodic, and `2` for one-shot;
`3` is reserved and rejected. Bit 3 selects down-counting. Bits 4 through 6
enable debug freeze, compare 0, and compare 1 respectively. Mode and direction
cannot change while `CTRL.ENABLE` is set. Software must stop the timer before
changing either field or the prescaler.
The three interrupt bits are timeout at bit 0, compare 0 at bit 1, and compare
1 at bit 2. Events win over a simultaneous software clear, preventing hardware
events from being lost. The external interrupt is the reduction OR of
`INTR_STATE & INTR_ENABLE`.
The RTL ABI constants are maintained directly in
`rtl/ip/ribp/peripheral/timer_define.svh`. The matching HAL offsets and masks
are maintained directly in `crt/src/hal/timer.c`. Changes to either definition
must update the other definition, this document, and the RTL/software tests in
the same change.
## Counting Semantics
One counter update occurs every `PRESCALE + 1` SoC clocks. For up-counting
periodic and one-shot modes, a terminal event occurs at `VALUE >= LOAD`. For
down-counting modes, it occurs at `VALUE == 0`. A periodic timer reloads zero
when counting up and `LOAD` when counting down. A one-shot timer holds its
terminal value and clears `CTRL.ENABLE`.
Free-running mode wraps at the natural 32-bit boundary. Periodic and one-shot
periods contain `LOAD + 1` timer ticks. Compare events sample the current value
on a timer tick and become sticky when the corresponding compare channel is
enabled.
The HAL exposes structured configuration, bounded millisecond delays, value
and status snapshots, compare programming, and interrupt control. Delay
conversion uses the active clock reported by SYSCTRL and selects the smallest
16-bit prescaler that fits the requested interval in the 32-bit counter.
## Verification and Current Scope
The self-checking RTL test covers both count directions, all operating modes,
prescaling, background reload, both compare channels, debug freeze/resume,
sticky interrupt clear/test behavior, byte strobes, and RIBP access errors.
The SBY target proves response, hold, one-shot stop, sticky-event, and interrupt
invariants and covers normal and error paths. Host C tests cover period
conversion boundaries, and the `ci_smoke` firmware exercises both timer
instances through the public HAL.
The current ABI does not include capture inputs, PWM outputs, cascaded 64-bit
operation, DMA requests, or multiple clock sources. Those features require new
SoC pins or routing and a versioned ABI extension; they must not reinterpret
the existing register fields.
File renamed without changes.
+9 -2
View File
@@ -124,7 +124,11 @@ digraph mini_soc_block_diagram {
]; ];
ribp_targets [ ribp_targets [
fillcolor="#F9E1E7", fillcolor="#F9E1E7",
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nGPIO, UART0, timers, I2C and I2S" label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nGPIO, UART0, I2C and I2S"
];
timers [
fillcolor="#F9E1E7",
label="General timers 0/1\n32-bit counter, 16-bit prescaler\nperiodic / one-shot, compare, debug freeze"
]; ];
ws2812 [ ws2812 [
fillcolor="#F9E1E7", fillcolor="#F9E1E7",
@@ -149,7 +153,7 @@ digraph mini_soc_block_diagram {
{ rank=same; user_core; dma; } { rank=same; user_core; dma; }
{ rank=same; fault; fabric; sram; } { rank=same; fault; fabric; sram; }
{ rank=same; ribp_adapter; apb_adapter; } { rank=same; ribp_adapter; apb_adapter; }
{ rank=same; sysctrl; ribp_targets; ws2812; apb_targets; } { rank=same; sysctrl; ribp_targets; timers; ws2812; apb_targets; }
{ rank=same; gpio_bridge; irq; } { rank=same; gpio_bridge; irq; }
ext_clock -> rcu [label="clock / reset"]; ext_clock -> rcu [label="clock / reset"];
@@ -159,6 +163,7 @@ digraph mini_soc_block_diagram {
jtag_dtm -> debug_module [label="DMI, asynchronous CDC"]; jtag_dtm -> debug_module [label="DMI, asynchronous CDC"];
debug_module -> mgmt_core [label="halt, resume, abstract commands"]; debug_module -> mgmt_core [label="halt, resume, abstract commands"];
debug_module -> mgmt_adapter [label="reset after bridge idle", style=dashed]; debug_module -> mgmt_adapter [label="reset after bridge idle", style=dashed];
debug_module -> timers [label="halted", style=dashed];
mgmt_core -> mgmt_adapter [label="RIBP"]; mgmt_core -> mgmt_adapter [label="RIBP"];
mgmt_adapter -> fabric [label="RIB"]; mgmt_adapter -> fabric [label="RIB"];
@@ -171,10 +176,12 @@ digraph mini_soc_block_diagram {
fabric -> apb_adapter [label="RIB"]; fabric -> apb_adapter [label="RIB"];
ribp_adapter -> sysctrl [label="RIBP"]; ribp_adapter -> sysctrl [label="RIBP"];
ribp_adapter -> ribp_targets [label="RIBP"]; ribp_adapter -> ribp_targets [label="RIBP"];
ribp_adapter -> timers [label="RIBP"];
ribp_adapter -> ws2812 [label="RIBP"]; ribp_adapter -> ws2812 [label="RIBP"];
apb_adapter -> apb_targets [label="APB"]; apb_adapter -> apb_targets [label="APB"];
ribp_targets -> gpio_bridge [label="GPIO alternate functions"]; ribp_targets -> gpio_bridge [label="GPIO alternate functions"];
timers -> irq [label="IRQ3 / IRQ4"];
ws2812 -> gpio_bridge [label="GPIO2 ALT1"]; ws2812 -> gpio_bridge [label="GPIO2 ALT1"];
dma -> ws2812 [label="TXDATA writes", style=dashed]; dma -> ws2812 [label="TXDATA writes", style=dashed];
ws2812 -> irq [label="IRQ17"]; ws2812 -> irq [label="IRQ17"];
+198 -169
View File
@@ -4,19 +4,19 @@
<!-- Generated by graphviz version 2.43.0 (0) <!-- Generated by graphviz version 2.43.0 (0)
--> -->
<!-- Title: mini_soc_block_diagram Pages: 1 --> <!-- Title: mini_soc_block_diagram Pages: 1 -->
<svg width="1315pt" height="887pt" <svg width="1546pt" height="887pt"
viewBox="0.00 0.00 1315.00 887.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> viewBox="0.00 0.00 1546.00 887.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 883.48)"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 883.48)">
<title>mini_soc_block_diagram</title> <title>mini_soc_block_diagram</title>
<text text-anchor="middle" x="132" y="-861.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text> <text text-anchor="middle" x="132" y="-861.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text>
<g id="clust1" class="cluster"> <g id="clust1" class="cluster">
<title>cluster_asic</title> <title>cluster_asic</title>
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 1287,-85 1287,-85 1293,-85 1299,-91 1299,-97 1299,-97 1299,-763.48 1299,-763.48 1299,-769.48 1293,-775.48 1287,-775.48 1287,-775.48 160,-775.48 160,-775.48 154,-775.48 148,-769.48 148,-763.48 148,-763.48 148,-97 148,-97 148,-91 154,-85 160,-85"/> <path fill="transparent" stroke="#111827" d="M160,-85C160,-85 1518,-85 1518,-85 1524,-85 1530,-91 1530,-97 1530,-97 1530,-763.48 1530,-763.48 1530,-769.48 1524,-775.48 1518,-775.48 1518,-775.48 160,-775.48 160,-775.48 154,-775.48 148,-769.48 148,-763.48 148,-763.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
<text text-anchor="middle" x="196.5" y="-760.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text> <text text-anchor="middle" x="196.5" y="-760.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text>
</g> </g>
<g id="clust2" class="cluster"> <g id="clust2" class="cluster">
<title>cluster_soc</title> <title>cluster_soc</title>
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 1269,-103 1269,-103 1275,-103 1281,-109 1281,-115 1281,-115 1281,-720.48 1281,-720.48 1281,-726.48 1275,-732.48 1269,-732.48 1269,-732.48 390,-732.48 390,-732.48 384,-732.48 378,-726.48 378,-720.48 378,-720.48 378,-115 378,-115 378,-109 384,-103 390,-103"/> <path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 1500,-103 1500,-103 1506,-103 1512,-109 1512,-115 1512,-115 1512,-720.48 1512,-720.48 1512,-726.48 1506,-732.48 1500,-732.48 1500,-732.48 390,-732.48 390,-732.48 384,-732.48 378,-726.48 378,-720.48 378,-720.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
<text text-anchor="middle" x="407.5" y="-718.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text> <text text-anchor="middle" x="407.5" y="-718.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
</g> </g>
<!-- ext_clock --> <!-- ext_clock -->
@@ -44,313 +44,342 @@
<!-- ext_io --> <!-- ext_io -->
<g id="node2" class="node"> <g id="node2" class="node">
<title>ext_io</title> <title>ext_io</title>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M903,-45C903,-45 711,-45 711,-45 705,-45 699,-39 699,-33 699,-33 699,-12 699,-12 699,-6 705,0 711,0 711,0 903,0 903,0 909,0 915,-6 915,-12 915,-12 915,-33 915,-33 915,-39 909,-45 903,-45"/> <path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M1257,-45C1257,-45 1065,-45 1065,-45 1059,-45 1053,-39 1053,-33 1053,-33 1053,-12 1053,-12 1053,-6 1059,0 1065,0 1065,0 1257,0 1257,0 1263,0 1269,-6 1269,-12 1269,-12 1269,-33 1269,-33 1269,-39 1263,-45 1257,-45"/>
<text text-anchor="middle" x="807" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text> <text text-anchor="middle" x="1161" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
<text text-anchor="middle" x="807" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text> <text text-anchor="middle" x="1161" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
<text text-anchor="middle" x="807" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text> <text text-anchor="middle" x="1161" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
</g> </g>
<!-- ext_jtag --> <!-- ext_jtag -->
<g id="node3" class="node"> <g id="node3" class="node">
<title>ext_jtag</title> <title>ext_jtag</title>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M569.5,-851.48C569.5,-851.48 438.5,-851.48 438.5,-851.48 432.5,-851.48 426.5,-845.48 426.5,-839.48 426.5,-839.48 426.5,-827.48 426.5,-827.48 426.5,-821.48 432.5,-815.48 438.5,-815.48 438.5,-815.48 569.5,-815.48 569.5,-815.48 575.5,-815.48 581.5,-821.48 581.5,-827.48 581.5,-827.48 581.5,-839.48 581.5,-839.48 581.5,-845.48 575.5,-851.48 569.5,-851.48"/> <path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M749.5,-851.48C749.5,-851.48 618.5,-851.48 618.5,-851.48 612.5,-851.48 606.5,-845.48 606.5,-839.48 606.5,-839.48 606.5,-827.48 606.5,-827.48 606.5,-821.48 612.5,-815.48 618.5,-815.48 618.5,-815.48 749.5,-815.48 749.5,-815.48 755.5,-815.48 761.5,-821.48 761.5,-827.48 761.5,-827.48 761.5,-839.48 761.5,-839.48 761.5,-845.48 755.5,-851.48 749.5,-851.48"/>
<text text-anchor="middle" x="504" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text> <text text-anchor="middle" x="684" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
<text text-anchor="middle" x="504" y="-825.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text> <text text-anchor="middle" x="684" y="-825.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text>
</g> </g>
<!-- jtag_dtm --> <!-- jtag_dtm -->
<g id="node6" class="node"> <g id="node6" class="node">
<title>jtag_dtm</title> <title>jtag_dtm</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M579,-669.98C579,-669.98 429,-669.98 429,-669.98 423,-669.98 417,-663.98 417,-657.98 417,-657.98 417,-645.98 417,-645.98 417,-639.98 423,-633.98 429,-633.98 429,-633.98 579,-633.98 579,-633.98 585,-633.98 591,-639.98 591,-645.98 591,-645.98 591,-657.98 591,-657.98 591,-663.98 585,-669.98 579,-669.98"/> <path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M759,-669.98C759,-669.98 609,-669.98 609,-669.98 603,-669.98 597,-663.98 597,-657.98 597,-657.98 597,-645.98 597,-645.98 597,-639.98 603,-633.98 609,-633.98 609,-633.98 759,-633.98 759,-633.98 765,-633.98 771,-639.98 771,-645.98 771,-645.98 771,-657.98 771,-657.98 771,-663.98 765,-669.98 759,-669.98"/>
<text text-anchor="middle" x="504" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text> <text text-anchor="middle" x="684" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
<text text-anchor="middle" x="504" y="-643.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text> <text text-anchor="middle" x="684" y="-643.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
</g> </g>
<!-- ext_jtag&#45;&gt;jtag_dtm --> <!-- ext_jtag&#45;&gt;jtag_dtm -->
<g id="edge2" class="edge"> <g id="edge2" class="edge">
<title>ext_jtag&#45;&gt;jtag_dtm</title> <title>ext_jtag&#45;&gt;jtag_dtm</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M504,-815.27C504,-783.24 504,-714.39 504,-677.51"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M684,-815.27C684,-783.24 684,-714.39 684,-677.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="506.45,-677.14 504,-670.14 501.55,-677.14 506.45,-677.14"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="686.45,-677.14 684,-670.14 681.55,-677.14 686.45,-677.14"/>
<text text-anchor="middle" x="524" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text> <text text-anchor="middle" x="704" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
</g> </g>
<!-- fabric --> <!-- fabric -->
<g id="node11" class="node"> <g id="node11" class="node">
<title>fabric</title> <title>fabric</title>
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M853.66,-442.31C853.66,-442.31 785.98,-470.16 785.98,-470.16 780.43,-472.45 768.88,-474.73 762.88,-474.73 762.88,-474.73 607.12,-474.73 607.12,-474.73 601.12,-474.73 589.57,-472.45 584.02,-470.16 584.02,-470.16 516.34,-442.31 516.34,-442.31 510.79,-440.03 510.79,-435.46 516.34,-433.18 516.34,-433.18 584.02,-405.32 584.02,-405.32 589.57,-403.04 601.12,-400.76 607.12,-400.76 607.12,-400.76 762.88,-400.76 762.88,-400.76 768.88,-400.76 780.43,-403.04 785.98,-405.32 785.98,-405.32 853.66,-433.18 853.66,-433.18 859.21,-435.46 859.21,-440.03 853.66,-442.31"/> <path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M810.66,-442.31C810.66,-442.31 742.98,-470.16 742.98,-470.16 737.43,-472.45 725.88,-474.73 719.88,-474.73 719.88,-474.73 564.12,-474.73 564.12,-474.73 558.12,-474.73 546.57,-472.45 541.02,-470.16 541.02,-470.16 473.34,-442.31 473.34,-442.31 467.79,-440.03 467.79,-435.46 473.34,-433.18 473.34,-433.18 541.02,-405.32 541.02,-405.32 546.57,-403.04 558.12,-400.76 564.12,-400.76 564.12,-400.76 719.88,-400.76 719.88,-400.76 725.88,-400.76 737.43,-403.04 742.98,-405.32 742.98,-405.32 810.66,-433.18 810.66,-433.18 816.21,-435.46 816.21,-440.03 810.66,-442.31"/>
<text text-anchor="middle" x="685" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text> <text text-anchor="middle" x="642" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
<text text-anchor="middle" x="685" y="-435.24" font-family="Arial" font-size="10.00" fill="#111827">3&#45;master round&#45;robin arbitration</text> <text text-anchor="middle" x="642" y="-435.24" font-family="Arial" font-size="10.00" fill="#111827">3&#45;master round&#45;robin arbitration</text>
<text text-anchor="middle" x="685" y="-424.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text> <text text-anchor="middle" x="642" y="-424.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
</g> </g>
<!-- rcu&#45;&gt;fabric --> <!-- rcu&#45;&gt;fabric -->
<g id="edge3" class="edge"> <g id="edge3" class="edge">
<title>rcu&#45;&gt;fabric</title> <title>rcu&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M344.67,-529.48C408.63,-512.43 498.81,-488.38 570.28,-469.33"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M336.43,-529.48C391.76,-513.05 468.96,-490.13 531.91,-471.43"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="571,-471.67 577.13,-467.5 569.74,-466.94 571,-471.67"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="532.72,-473.75 538.74,-469.41 531.33,-469.05 532.72,-473.75"/>
<text text-anchor="middle" x="496" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text> <text text-anchor="middle" x="476" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
</g> </g>
<!-- mgmt_core --> <!-- mgmt_core -->
<g id="node5" class="node"> <g id="node5" class="node">
<title>mgmt_core</title> <title>mgmt_core</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1164,-674.48C1164,-674.48 1010,-674.48 1010,-674.48 1004,-674.48 998,-668.48 998,-662.48 998,-662.48 998,-641.48 998,-641.48 998,-635.48 1004,-629.48 1010,-629.48 1010,-629.48 1164,-629.48 1164,-629.48 1170,-629.48 1176,-635.48 1176,-641.48 1176,-641.48 1176,-662.48 1176,-662.48 1176,-668.48 1170,-674.48 1164,-674.48"/> <path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M964,-674.48C964,-674.48 810,-674.48 810,-674.48 804,-674.48 798,-668.48 798,-662.48 798,-662.48 798,-641.48 798,-641.48 798,-635.48 804,-629.48 810,-629.48 810,-629.48 964,-629.48 964,-629.48 970,-629.48 976,-635.48 976,-641.48 976,-641.48 976,-662.48 976,-662.48 976,-668.48 970,-674.48 964,-674.48"/>
<text text-anchor="middle" x="1087" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text> <text text-anchor="middle" x="887" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
<text text-anchor="middle" x="1087" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text> <text text-anchor="middle" x="887" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
<text text-anchor="middle" x="1087" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text> <text text-anchor="middle" x="887" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
</g> </g>
<!-- mgmt_adapter --> <!-- mgmt_adapter -->
<g id="node8" class="node"> <g id="node8" class="node">
<title>mgmt_adapter</title> <title>mgmt_adapter</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M809.5,-569.98C809.5,-569.98 768.5,-569.98 768.5,-569.98 762.5,-569.98 756.5,-563.98 756.5,-557.98 756.5,-557.98 756.5,-545.98 756.5,-545.98 756.5,-539.98 762.5,-533.98 768.5,-533.98 768.5,-533.98 809.5,-533.98 809.5,-533.98 815.5,-533.98 821.5,-539.98 821.5,-545.98 821.5,-545.98 821.5,-557.98 821.5,-557.98 821.5,-563.98 815.5,-569.98 809.5,-569.98"/> <path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M907.5,-569.98C907.5,-569.98 866.5,-569.98 866.5,-569.98 860.5,-569.98 854.5,-563.98 854.5,-557.98 854.5,-557.98 854.5,-545.98 854.5,-545.98 854.5,-539.98 860.5,-533.98 866.5,-533.98 866.5,-533.98 907.5,-533.98 907.5,-533.98 913.5,-533.98 919.5,-539.98 919.5,-545.98 919.5,-545.98 919.5,-557.98 919.5,-557.98 919.5,-563.98 913.5,-569.98 907.5,-569.98"/>
<text text-anchor="middle" x="789" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text> <text text-anchor="middle" x="887" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
</g> </g>
<!-- mgmt_core&#45;&gt;mgmt_adapter --> <!-- mgmt_core&#45;&gt;mgmt_adapter -->
<g id="edge7" class="edge"> <g id="edge8" class="edge">
<title>mgmt_core&#45;&gt;mgmt_adapter</title> <title>mgmt_core&#45;&gt;mgmt_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1021.6,-629.48C962.53,-610.05 877.54,-582.1 828.32,-565.92"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M887,-629.24C887,-613.92 887,-593.4 887,-577.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="829.04,-563.57 821.62,-563.71 827.51,-568.23 829.04,-563.57"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="889.45,-577.12 887,-570.12 884.55,-577.12 889.45,-577.12"/>
<text text-anchor="middle" x="955.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text> <text text-anchor="middle" x="896.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g> </g>
<!-- debug_module --> <!-- debug_module -->
<g id="node7" class="node"> <g id="node7" class="node">
<title>debug_module</title> <title>debug_module</title>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M840.5,-674.48C840.5,-674.48 719.5,-674.48 719.5,-674.48 713.5,-674.48 707.5,-668.48 707.5,-662.48 707.5,-662.48 707.5,-641.48 707.5,-641.48 707.5,-635.48 713.5,-629.48 719.5,-629.48 719.5,-629.48 840.5,-629.48 840.5,-629.48 846.5,-629.48 852.5,-635.48 852.5,-641.48 852.5,-641.48 852.5,-662.48 852.5,-662.48 852.5,-668.48 846.5,-674.48 840.5,-674.48"/> <path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1254.5,-674.48C1254.5,-674.48 1133.5,-674.48 1133.5,-674.48 1127.5,-674.48 1121.5,-668.48 1121.5,-662.48 1121.5,-662.48 1121.5,-641.48 1121.5,-641.48 1121.5,-635.48 1127.5,-629.48 1133.5,-629.48 1133.5,-629.48 1254.5,-629.48 1254.5,-629.48 1260.5,-629.48 1266.5,-635.48 1266.5,-641.48 1266.5,-641.48 1266.5,-662.48 1266.5,-662.48 1266.5,-668.48 1260.5,-674.48 1254.5,-674.48"/>
<text text-anchor="middle" x="780" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text> <text text-anchor="middle" x="1194" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
<text text-anchor="middle" x="780" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text> <text text-anchor="middle" x="1194" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
<text text-anchor="middle" x="780" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">management&#45;hart&#45;only reset</text> <text text-anchor="middle" x="1194" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">management&#45;hart&#45;only reset</text>
</g> </g>
<!-- jtag_dtm&#45;&gt;debug_module --> <!-- jtag_dtm&#45;&gt;debug_module -->
<g id="edge4" class="edge"> <g id="edge4" class="edge">
<title>jtag_dtm&#45;&gt;debug_module</title> <title>jtag_dtm&#45;&gt;debug_module</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M591.33,-651.98C626.12,-651.98 665.91,-651.98 699.95,-651.98"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M702.06,-670.13C731.11,-699.33 785,-753.48 785,-753.48 785,-753.48 990,-753.48 990,-753.48 990,-753.48 1081.81,-707.8 1142.25,-677.73"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="700.12,-654.43 707.12,-651.98 700.12,-649.53 700.12,-654.43"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1143.55,-679.82 1148.73,-674.51 1141.37,-675.44 1143.55,-679.82"/>
<text text-anchor="middle" x="649.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text> <text text-anchor="middle" x="946" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
</g> </g>
<!-- debug_module&#45;&gt;mgmt_core --> <!-- debug_module&#45;&gt;mgmt_core -->
<g id="edge5" class="edge"> <g id="edge5" class="edge">
<title>debug_module&#45;&gt;mgmt_core</title> <title>debug_module&#45;&gt;mgmt_core</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M852.75,-651.98C893.99,-651.98 946.09,-651.98 990.69,-651.98"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1121.11,-651.98C1079.89,-651.98 1027.84,-651.98 983.29,-651.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="990.77,-654.43 997.77,-651.98 990.77,-649.53 990.77,-654.43"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="983.21,-649.53 976.21,-651.98 983.21,-654.43 983.21,-649.53"/>
<text text-anchor="middle" x="925.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text> <text text-anchor="middle" x="1048.75" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
</g> </g>
<!-- debug_module&#45;&gt;mgmt_adapter --> <!-- debug_module&#45;&gt;mgmt_adapter -->
<g id="edge6" class="edge"> <g id="edge6" class="edge">
<title>debug_module&#45;&gt;mgmt_adapter</title> <title>debug_module&#45;&gt;mgmt_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M782,-629.24C783.4,-613.92 785.29,-593.4 786.75,-577.51"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1126.63,-629.48C1065.43,-609.94 977.24,-581.79 926.67,-565.65"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="789.23,-577.31 787.43,-570.12 784.35,-576.86 789.23,-577.31"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="927.21,-563.25 919.79,-563.45 925.72,-567.92 927.21,-563.25"/>
<text text-anchor="middle" x="822" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text> <text text-anchor="middle" x="1087" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
</g>
<!-- timers -->
<g id="node18" class="node">
<title>timers</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1484.5,-255C1484.5,-255 1303.5,-255 1303.5,-255 1297.5,-255 1291.5,-249 1291.5,-243 1291.5,-243 1291.5,-222 1291.5,-222 1291.5,-216 1297.5,-210 1303.5,-210 1303.5,-210 1484.5,-210 1484.5,-210 1490.5,-210 1496.5,-216 1496.5,-222 1496.5,-222 1496.5,-243 1496.5,-243 1496.5,-249 1490.5,-255 1484.5,-255"/>
<text text-anchor="middle" x="1394" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
<text text-anchor="middle" x="1394" 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="1394" 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="M1211.98,-629.24C1235.84,-600.36 1275,-552.98 1275,-552.98 1275,-552.98 1275,-552.98 1275,-327 1275,-327 1325.68,-287.18 1360.89,-259.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1362.41,-261.44 1366.4,-255.19 1359.38,-257.58 1362.41,-261.44"/>
<text text-anchor="middle" x="1286" y="-435.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
</g> </g>
<!-- mgmt_adapter&#45;&gt;fabric --> <!-- mgmt_adapter&#45;&gt;fabric -->
<g id="edge8" class="edge"> <g id="edge9" class="edge">
<title>mgmt_adapter&#45;&gt;fabric</title> <title>mgmt_adapter&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M773.2,-533.94C759.91,-519.59 740.34,-498.47 723.01,-479.77"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M854.47,-536.08C821.96,-521.19 770.62,-497.67 726.55,-477.48"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="724.75,-478.03 718.19,-474.57 721.15,-481.37 724.75,-478.03"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="727.49,-475.21 720.11,-474.53 725.45,-479.67 727.49,-475.21"/>
<text text-anchor="middle" x="753" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text> <text text-anchor="middle" x="793" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g> </g>
<!-- user_core --> <!-- user_core -->
<g id="node9" class="node"> <g id="node9" class="node">
<title>user_core</title> <title>user_core</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M717,-574.48C717,-574.48 641,-574.48 641,-574.48 635,-574.48 629,-568.48 629,-562.48 629,-562.48 629,-541.48 629,-541.48 629,-535.48 635,-529.48 641,-529.48 641,-529.48 717,-529.48 717,-529.48 723,-529.48 729,-535.48 729,-541.48 729,-541.48 729,-562.48 729,-562.48 729,-568.48 723,-574.48 717,-574.48"/> <path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M680,-574.48C680,-574.48 604,-574.48 604,-574.48 598,-574.48 592,-568.48 592,-562.48 592,-562.48 592,-541.48 592,-541.48 592,-535.48 598,-529.48 604,-529.48 604,-529.48 680,-529.48 680,-529.48 686,-529.48 692,-535.48 692,-541.48 692,-541.48 692,-562.48 692,-562.48 692,-568.48 686,-574.48 680,-574.48"/>
<text text-anchor="middle" x="679" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text> <text text-anchor="middle" x="642" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="679" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text> <text text-anchor="middle" x="642" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text>
<text text-anchor="middle" x="679" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text> <text text-anchor="middle" x="642" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
</g> </g>
<!-- user_core&#45;&gt;fabric --> <!-- user_core&#45;&gt;fabric -->
<g id="edge9" class="edge"> <g id="edge10" class="edge">
<title>user_core&#45;&gt;fabric</title> <title>user_core&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M680.16,-529.34C680.87,-515.97 681.81,-498.34 682.68,-482.19"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M642,-529.34C642,-515.97 642,-498.34 642,-482.19"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="685.14,-482.01 683.07,-474.89 680.25,-481.75 685.14,-482.01"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="644.45,-481.89 642,-474.89 639.55,-481.89 644.45,-481.89"/>
<text text-anchor="middle" x="688" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text> <text text-anchor="middle" x="649" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g> </g>
<!-- dma --> <!-- dma -->
<g id="node10" class="node"> <g id="node10" class="node">
<title>dma</title> <title>dma</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M570,-569.98C570,-569.98 452,-569.98 452,-569.98 446,-569.98 440,-563.98 440,-557.98 440,-557.98 440,-545.98 440,-545.98 440,-539.98 446,-533.98 452,-533.98 452,-533.98 570,-533.98 570,-533.98 576,-533.98 582,-539.98 582,-545.98 582,-545.98 582,-557.98 582,-557.98 582,-563.98 576,-569.98 570,-569.98"/> <path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1197,-569.98C1197,-569.98 1079,-569.98 1079,-569.98 1073,-569.98 1067,-563.98 1067,-557.98 1067,-557.98 1067,-545.98 1067,-545.98 1067,-539.98 1073,-533.98 1079,-533.98 1079,-533.98 1197,-533.98 1197,-533.98 1203,-533.98 1209,-539.98 1209,-545.98 1209,-545.98 1209,-557.98 1209,-557.98 1209,-563.98 1203,-569.98 1197,-569.98"/>
<text text-anchor="middle" x="511" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text> <text text-anchor="middle" x="1138" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
<text text-anchor="middle" x="511" y="-543.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text> <text text-anchor="middle" x="1138" y="-543.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
</g> </g>
<!-- dma&#45;&gt;fabric --> <!-- dma&#45;&gt;fabric -->
<g id="edge10" class="edge"> <g id="edge11" class="edge">
<title>dma&#45;&gt;fabric</title> <title>dma&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M537.43,-533.94C560.15,-519.28 593.81,-497.56 623.25,-478.57"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1080.16,-533.98C1026.87,-518.32 956,-497.48 956,-497.48 956,-497.48 857.85,-479.12 771.3,-462.93"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="624.91,-480.42 629.47,-474.57 622.26,-476.3 624.91,-480.42"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="771.63,-460.5 764.3,-461.62 770.73,-465.32 771.63,-460.5"/>
<text text-anchor="middle" x="599" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text> <text text-anchor="middle" x="993" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g> </g>
<!-- ws2812 --> <!-- ws2812 -->
<g id="node18" class="node"> <g id="node19" class="node">
<title>ws2812</title> <title>ws2812</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M540,-255C540,-255 406,-255 406,-255 400,-255 394,-249 394,-243 394,-243 394,-222 394,-222 394,-216 400,-210 406,-210 406,-210 540,-210 540,-210 546,-210 552,-216 552,-222 552,-222 552,-243 552,-243 552,-249 546,-255 540,-255"/> <path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1253,-255C1253,-255 1119,-255 1119,-255 1113,-255 1107,-249 1107,-243 1107,-243 1107,-222 1107,-222 1107,-216 1113,-210 1119,-210 1119,-210 1253,-210 1253,-210 1259,-210 1265,-216 1265,-222 1265,-222 1265,-243 1265,-243 1265,-249 1259,-255 1253,-255"/>
<text text-anchor="middle" x="473" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text> <text text-anchor="middle" x="1186" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
<text text-anchor="middle" x="473" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24&#45;bit MSB&#45;first serializer</text> <text text-anchor="middle" x="1186" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24&#45;bit MSB&#45;first serializer</text>
<text text-anchor="middle" x="473" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16&#45;word FIFO, IRQ17, DMA&#45;fed</text> <text text-anchor="middle" x="1186" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16&#45;word FIFO, IRQ17, DMA&#45;fed</text>
</g> </g>
<!-- dma&#45;&gt;ws2812 --> <!-- dma&#45;&gt;ws2812 -->
<g id="edge21" class="edge"> <g id="edge24" class="edge">
<title>dma&#45;&gt;ws2812</title> <title>dma&#45;&gt;ws2812</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M506.69,-533.63C501.08,-511.05 492,-474.48 492,-474.48 492,-474.48 480.31,-326.28 475.27,-262.32"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1145.49,-533.63C1155.22,-511.05 1171,-474.48 1171,-474.48 1171,-474.48 1180.23,-326.28 1184.21,-262.32"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="477.71,-262.1 474.72,-255.31 472.83,-262.48 477.71,-262.1"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1186.65,-262.45 1184.64,-255.31 1181.76,-262.15 1186.65,-262.45"/>
<text text-anchor="middle" x="511.5" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text> <text text-anchor="middle" x="1204.5" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
</g> </g>
<!-- fault --> <!-- fault -->
<g id="node12" class="node"> <g id="node12" class="node">
<title>fault</title> <title>fault</title>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1065.5,-455.74C1065.5,-455.74 956.5,-455.74 956.5,-455.74 950.5,-455.74 944.5,-449.74 944.5,-443.74 944.5,-443.74 944.5,-431.74 944.5,-431.74 944.5,-425.74 950.5,-419.74 956.5,-419.74 956.5,-419.74 1065.5,-419.74 1065.5,-419.74 1071.5,-419.74 1077.5,-425.74 1077.5,-431.74 1077.5,-431.74 1077.5,-443.74 1077.5,-443.74 1077.5,-449.74 1071.5,-455.74 1065.5,-455.74"/> <path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1145.5,-455.74C1145.5,-455.74 1036.5,-455.74 1036.5,-455.74 1030.5,-455.74 1024.5,-449.74 1024.5,-443.74 1024.5,-443.74 1024.5,-431.74 1024.5,-431.74 1024.5,-425.74 1030.5,-419.74 1036.5,-419.74 1036.5,-419.74 1145.5,-419.74 1145.5,-419.74 1151.5,-419.74 1157.5,-425.74 1157.5,-431.74 1157.5,-431.74 1157.5,-443.74 1157.5,-443.74 1157.5,-449.74 1151.5,-455.74 1145.5,-455.74"/>
<text text-anchor="middle" x="1011" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text> <text text-anchor="middle" x="1091" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
<text text-anchor="middle" x="1011" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text> <text text-anchor="middle" x="1091" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
</g> </g>
<!-- fabric&#45;&gt;fault --> <!-- fabric&#45;&gt;fault -->
<g id="edge11" class="edge"> <g id="edge12" class="edge">
<title>fabric&#45;&gt;fault</title> <title>fabric&#45;&gt;fault</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M871.98,-437.74C894.93,-437.74 917.24,-437.74 937.02,-437.74"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M764.45,-466.01C829.63,-481.05 896.5,-496.48 896.5,-496.48 896.5,-496.48 949.5,-496.48 949.5,-496.48 949.5,-496.48 1011,-474.48 1011,-474.48 1011,-474.48 1027.11,-467.08 1044.88,-458.93"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="871.69,-435.29 864.69,-437.74 871.69,-440.19 871.69,-435.29"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="764.71,-463.55 757.34,-464.36 763.61,-468.33 764.71,-463.55"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="937.19,-440.19 944.19,-437.74 937.19,-435.29 937.19,-440.19"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1046.13,-461.05 1051.47,-455.9 1044.08,-456.59 1046.13,-461.05"/>
<text text-anchor="middle" x="904.56" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text> <text text-anchor="middle" x="923" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
</g> </g>
<!-- sram --> <!-- sram -->
<g id="node13" class="node"> <g id="node13" class="node">
<title>sram</title> <title>sram</title>
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1215,-455.74C1215,-455.74 1117,-455.74 1117,-455.74 1111,-455.74 1105,-449.74 1105,-443.74 1105,-443.74 1105,-431.74 1105,-431.74 1105,-425.74 1111,-419.74 1117,-419.74 1117,-419.74 1215,-419.74 1215,-419.74 1221,-419.74 1227,-425.74 1227,-431.74 1227,-431.74 1227,-443.74 1227,-443.74 1227,-449.74 1221,-455.74 1215,-455.74"/> <path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M985,-455.74C985,-455.74 887,-455.74 887,-455.74 881,-455.74 875,-449.74 875,-443.74 875,-443.74 875,-431.74 875,-431.74 875,-425.74 881,-419.74 887,-419.74 887,-419.74 985,-419.74 985,-419.74 991,-419.74 997,-425.74 997,-431.74 997,-431.74 997,-443.74 997,-443.74 997,-449.74 991,-455.74 985,-455.74"/>
<text text-anchor="middle" x="1166" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On&#45;chip SRAM</text> <text text-anchor="middle" x="936" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On&#45;chip SRAM</text>
<text text-anchor="middle" x="1166" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text> <text text-anchor="middle" x="936" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
</g> </g>
<!-- fabric&#45;&gt;sram --> <!-- fabric&#45;&gt;sram -->
<g id="edge12" class="edge"> <g id="edge13" class="edge">
<title>fabric&#45;&gt;sram</title> <title>fabric&#45;&gt;sram</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M805.88,-462.06C886.21,-478.22 977,-496.48 977,-496.48 977,-496.48 991,-496.48 991,-496.48 991,-496.48 1091,-474.48 1091,-474.48 1091,-474.48 1105.84,-467.21 1122.32,-459.14"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M821.91,-437.74C837.95,-437.74 853.44,-437.74 867.56,-437.74"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1123.73,-461.18 1128.94,-455.9 1121.58,-456.78 1123.73,-461.18"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="867.81,-440.19 874.81,-437.74 867.81,-435.29 867.81,-440.19"/>
<text text-anchor="middle" x="984" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text> <text text-anchor="middle" x="848.31" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g> </g>
<!-- ribp_adapter --> <!-- ribp_adapter -->
<g id="node14" class="node"> <g id="node14" class="node">
<title>ribp_adapter</title> <title>ribp_adapter</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M708.5,-346C708.5,-346 667.5,-346 667.5,-346 661.5,-346 655.5,-340 655.5,-334 655.5,-334 655.5,-322 655.5,-322 655.5,-316 661.5,-310 667.5,-310 667.5,-310 708.5,-310 708.5,-310 714.5,-310 720.5,-316 720.5,-322 720.5,-322 720.5,-334 720.5,-334 720.5,-340 714.5,-346 708.5,-346"/> <path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M985.5,-346C985.5,-346 944.5,-346 944.5,-346 938.5,-346 932.5,-340 932.5,-334 932.5,-334 932.5,-322 932.5,-322 932.5,-316 938.5,-310 944.5,-310 944.5,-310 985.5,-310 985.5,-310 991.5,-310 997.5,-316 997.5,-322 997.5,-322 997.5,-334 997.5,-334 997.5,-340 991.5,-346 985.5,-346"/>
<text text-anchor="middle" x="688" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text> <text text-anchor="middle" x="965" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
</g> </g>
<!-- fabric&#45;&gt;ribp_adapter --> <!-- fabric&#45;&gt;ribp_adapter -->
<g id="edge13" class="edge"> <g id="edge14" class="edge">
<title>fabric&#45;&gt;ribp_adapter</title> <title>fabric&#45;&gt;ribp_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M686,-400.87C686.43,-385.27 686.93,-367.39 687.32,-353.38"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M740.23,-403.98C802.54,-383.19 879.79,-357.42 925.59,-342.15"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="689.78,-353.09 687.53,-346.02 684.88,-352.95 689.78,-353.09"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="926.52,-344.42 932.39,-339.88 924.97,-339.77 926.52,-344.42"/>
<text text-anchor="middle" x="693" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text> <text text-anchor="middle" x="848" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g> </g>
<!-- apb_adapter --> <!-- apb_adapter -->
<g id="node15" class="node"> <g id="node15" class="node">
<title>apb_adapter</title> <title>apb_adapter</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M875,-346C875,-346 805,-346 805,-346 799,-346 793,-340 793,-334 793,-334 793,-322 793,-322 793,-316 799,-310 805,-310 805,-310 875,-310 875,-310 881,-310 887,-316 887,-322 887,-322 887,-334 887,-334 887,-340 881,-346 875,-346"/> <path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M618,-346C618,-346 548,-346 548,-346 542,-346 536,-340 536,-334 536,-334 536,-322 536,-322 536,-316 542,-310 548,-310 548,-310 618,-310 618,-310 624,-310 630,-316 630,-322 630,-322 630,-334 630,-334 630,-340 624,-346 618,-346"/>
<text text-anchor="middle" x="840" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text> <text text-anchor="middle" x="583" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
<text text-anchor="middle" x="840" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text> <text text-anchor="middle" x="583" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
</g> </g>
<!-- fabric&#45;&gt;apb_adapter --> <!-- fabric&#45;&gt;apb_adapter -->
<g id="edge14" class="edge"> <g id="edge15" class="edge">
<title>fabric&#45;&gt;apb_adapter</title> <title>fabric&#45;&gt;apb_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M736.61,-400.87C760.82,-384.04 788.83,-364.57 809.59,-350.14"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M622.35,-400.87C613.57,-384.83 603.48,-366.4 595.71,-352.22"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="811.16,-352.03 815.51,-346.02 808.37,-348.01 811.16,-352.03"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="597.83,-350.98 592.32,-346.02 593.53,-353.34 597.83,-350.98"/>
<text text-anchor="middle" x="787" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text> <text text-anchor="middle" x="615" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g> </g>
<!-- sysctrl --> <!-- sysctrl -->
<g id="node16" class="node"> <g id="node16" class="node">
<title>sysctrl</title> <title>sysctrl</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1010.5,-255C1010.5,-255 847.5,-255 847.5,-255 841.5,-255 835.5,-249 835.5,-243 835.5,-243 835.5,-222 835.5,-222 835.5,-216 841.5,-210 847.5,-210 847.5,-210 1010.5,-210 1010.5,-210 1016.5,-210 1022.5,-216 1022.5,-222 1022.5,-222 1022.5,-243 1022.5,-243 1022.5,-249 1016.5,-255 1010.5,-255"/> <path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M811.5,-255C811.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 811.5,-210 811.5,-210 817.5,-210 823.5,-216 823.5,-222 823.5,-222 823.5,-243 823.5,-243 823.5,-249 817.5,-255 811.5,-255"/>
<text text-anchor="middle" x="929" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL and CLINT</text> <text text-anchor="middle" x="730" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL and CLINT</text>
<text text-anchor="middle" x="929" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user&#45;core select/reset/bus enable</text> <text text-anchor="middle" x="730" 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="929" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text> <text text-anchor="middle" x="730" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
</g> </g>
<!-- ribp_adapter&#45;&gt;sysctrl --> <!-- ribp_adapter&#45;&gt;sysctrl -->
<g id="edge15" class="edge"> <g id="edge16" class="edge">
<title>ribp_adapter&#45;&gt;sysctrl</title> <title>ribp_adapter&#45;&gt;sysctrl</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M720.5,-314.39C757.85,-299.9 820,-275.79 866.75,-257.65"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M932.32,-314C895.78,-299.46 835.8,-275.6 790.62,-257.62"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="867.89,-259.84 873.53,-255.02 866.12,-255.27 867.89,-259.84"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="791.47,-255.32 784.06,-255.01 789.66,-259.87 791.47,-255.32"/>
<text text-anchor="middle" x="817.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text> <text text-anchor="middle" x="870.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g> </g>
<!-- ribp_targets --> <!-- ribp_targets -->
<g id="node17" class="node"> <g id="node17" class="node">
<title>ribp_targets</title> <title>ribp_targets</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M796.5,-255C796.5,-255 591.5,-255 591.5,-255 585.5,-255 579.5,-249 579.5,-243 579.5,-243 579.5,-222 579.5,-222 579.5,-216 585.5,-210 591.5,-210 591.5,-210 796.5,-210 796.5,-210 802.5,-210 808.5,-216 808.5,-222 808.5,-222 808.5,-243 808.5,-243 808.5,-249 802.5,-255 796.5,-255"/> <path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1067.5,-255C1067.5,-255 862.5,-255 862.5,-255 856.5,-255 850.5,-249 850.5,-243 850.5,-243 850.5,-222 850.5,-222 850.5,-216 856.5,-210 862.5,-210 862.5,-210 1067.5,-210 1067.5,-210 1073.5,-210 1079.5,-216 1079.5,-222 1079.5,-222 1079.5,-243 1079.5,-243 1079.5,-249 1073.5,-255 1067.5,-255"/>
<text text-anchor="middle" x="694" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text> <text text-anchor="middle" x="965" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
<text text-anchor="middle" x="694" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI&#45;SD and DVP</text> <text text-anchor="middle" x="965" 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="694" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, timers, I2C and I2S</text> <text text-anchor="middle" x="965" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, I2C and I2S</text>
</g> </g>
<!-- ribp_adapter&#45;&gt;ribp_targets --> <!-- ribp_adapter&#45;&gt;ribp_targets -->
<g id="edge16" class="edge"> <g id="edge17" class="edge">
<title>ribp_adapter&#45;&gt;ribp_targets</title> <title>ribp_adapter&#45;&gt;ribp_targets</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M689.1,-309.85C689.95,-296.62 691.14,-278.02 692.14,-262.49"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M965,-309.85C965,-296.62 965,-278.02 965,-262.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="694.61,-262.29 692.61,-255.15 689.72,-261.98 694.61,-262.29"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="967.45,-262.15 965,-255.15 962.55,-262.15 967.45,-262.15"/>
<text text-anchor="middle" x="700.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text> <text text-anchor="middle" x="974.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_adapter&#45;&gt;timers -->
<g id="edge18" class="edge">
<title>ribp_adapter&#45;&gt;timers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M997.6,-319.9C1058.64,-306.59 1192.62,-277.39 1287.89,-256.63"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1288.65,-258.97 1294.97,-255.08 1287.61,-254.18 1288.65,-258.97"/>
<text text-anchor="middle" x="1188.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g> </g>
<!-- ribp_adapter&#45;&gt;ws2812 --> <!-- ribp_adapter&#45;&gt;ws2812 -->
<g id="edge17" class="edge"> <g id="edge19" class="edge">
<title>ribp_adapter&#45;&gt;ws2812</title> <title>ribp_adapter&#45;&gt;ws2812</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M655.35,-312.8C622.03,-298.31 569.68,-275.54 529.6,-258.11"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M997.61,-313.2C1031.91,-298.69 1086.6,-275.55 1128.23,-257.94"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="530.17,-255.69 522.77,-255.15 528.21,-260.18 530.17,-255.69"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1129.31,-260.15 1134.8,-255.16 1127.4,-255.63 1129.31,-260.15"/>
<text text-anchor="middle" x="602.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text> <text text-anchor="middle" x="1084.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g> </g>
<!-- apb_targets --> <!-- apb_targets -->
<g id="node19" class="node"> <g id="node20" class="node">
<title>apb_targets</title> <title>apb_targets</title>
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M1252.5,-255C1252.5,-255 1061.5,-255 1061.5,-255 1055.5,-255 1049.5,-249 1049.5,-243 1049.5,-243 1049.5,-222 1049.5,-222 1049.5,-216 1055.5,-210 1061.5,-210 1061.5,-210 1252.5,-210 1252.5,-210 1258.5,-210 1264.5,-216 1264.5,-222 1264.5,-222 1264.5,-243 1264.5,-243 1264.5,-249 1258.5,-255 1252.5,-255"/> <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="1157" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text> <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="1157" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text> <text text-anchor="middle" x="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="1157" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</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> </g>
<!-- apb_adapter&#45;&gt;apb_targets --> <!-- apb_adapter&#45;&gt;apb_targets -->
<g id="edge18" class="edge"> <g id="edge20" class="edge">
<title>apb_adapter&#45;&gt;apb_targets</title> <title>apb_adapter&#45;&gt;apb_targets</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M887.12,-313.1C937.19,-298.33 1017.25,-274.72 1077.19,-257.04"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M568.14,-309.85C556.27,-296.14 539.39,-276.66 525.66,-260.81"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1078,-259.35 1084.02,-255.02 1076.62,-254.65 1078,-259.35"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="527.19,-258.84 520.75,-255.15 523.49,-262.04 527.19,-258.84"/>
<text text-anchor="middle" x="1006" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text> <text text-anchor="middle" x="555" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
</g> </g>
<!-- ribp_targets&#45;&gt;ext_io --> <!-- ribp_targets&#45;&gt;ext_io -->
<g id="edge24" class="edge"> <g id="edge27" class="edge">
<title>ribp_targets&#45;&gt;ext_io</title> <title>ribp_targets&#45;&gt;ext_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M780.98,-208.04C820.68,-197.33 859,-187 859,-187 859,-187 859,-178 859,-178 859,-178 837,-85 837,-85 837,-85 828.54,-67.66 820.6,-51.39"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1086.9,-211.18C1091.39,-210.44 1094,-210 1094,-210 1094,-210 1342,-187 1342,-187 1342,-187 1342,-178 1342,-178 1342,-178 1320,-85 1320,-85 1320,-85 1267.94,-64.86 1223.4,-47.64"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="780.2,-205.71 774.08,-209.9 781.48,-210.44 780.2,-205.71"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1086.2,-208.82 1079.7,-212.38 1087.01,-213.65 1086.2,-208.82"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="822.76,-50.23 817.49,-45.01 818.36,-52.38 822.76,-50.23"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1224.02,-45.25 1216.61,-45.01 1222.26,-49.82 1224.02,-45.25"/>
<text text-anchor="middle" x="883" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text> <text text-anchor="middle" x="1366" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
</g> </g>
<!-- gpio_bridge --> <!-- gpio_bridge -->
<g id="node20" class="node"> <g id="node21" class="node">
<title>gpio_bridge</title> <title>gpio_bridge</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M811,-155C811,-155 663,-155 663,-155 657,-155 651,-149 651,-143 651,-143 651,-131 651,-131 651,-125 657,-119 663,-119 663,-119 811,-119 811,-119 817,-119 823,-125 823,-131 823,-131 823,-143 823,-143 823,-149 817,-155 811,-155"/> <path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1037,-155C1037,-155 889,-155 889,-155 883,-155 877,-149 877,-143 877,-143 877,-131 877,-131 877,-125 883,-119 889,-119 889,-119 1037,-119 1037,-119 1043,-119 1049,-125 1049,-131 1049,-131 1049,-143 1049,-143 1049,-149 1043,-155 1037,-155"/>
<text text-anchor="middle" x="737" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text> <text text-anchor="middle" x="963" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
<text text-anchor="middle" x="737" y="-129" font-family="Arial" font-size="10.00" fill="#111827">software, alternate and user modes</text> <text text-anchor="middle" x="963" y="-129" font-family="Arial" font-size="10.00" fill="#111827">software, alternate and user modes</text>
</g> </g>
<!-- ribp_targets&#45;&gt;gpio_bridge --> <!-- ribp_targets&#45;&gt;gpio_bridge -->
<g id="edge19" class="edge"> <g id="edge21" class="edge">
<title>ribp_targets&#45;&gt;gpio_bridge</title> <title>ribp_targets&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M695.22,-209.74C696.05,-194.93 697,-178 697,-178 697,-178 705.52,-169.48 714.69,-160.31"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M964.54,-209.81C964.23,-195.66 963.84,-177.17 963.52,-162.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="716.59,-161.88 719.8,-155.2 713.12,-158.41 716.59,-161.88"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="965.97,-162.15 963.37,-155.2 961.07,-162.25 965.97,-162.15"/>
<text text-anchor="middle" x="741" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text> <text text-anchor="middle" x="1008" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text>
</g>
<!-- ws2812&#45;&gt;gpio_bridge -->
<g id="edge20" class="edge">
<title>ws2812&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M533.9,-209.93C578.56,-194.11 638.71,-172.81 681.94,-157.5"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="682.94,-159.74 688.73,-155.1 681.31,-155.12 682.94,-159.74"/>
<text text-anchor="middle" x="642.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
</g> </g>
<!-- irq --> <!-- irq -->
<g id="node21" class="node"> <g id="node22" class="node">
<title>irq</title> <title>irq</title>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M612,-155C612,-155 406,-155 406,-155 400,-155 394,-149 394,-143 394,-143 394,-131 394,-131 394,-125 400,-119 406,-119 406,-119 612,-119 612,-119 618,-119 624,-125 624,-131 624,-131 624,-143 624,-143 624,-149 618,-155 612,-155"/> <path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1294,-155C1294,-155 1088,-155 1088,-155 1082,-155 1076,-149 1076,-143 1076,-143 1076,-131 1076,-131 1076,-125 1082,-119 1088,-119 1088,-119 1294,-119 1294,-119 1300,-119 1306,-125 1306,-131 1306,-131 1306,-143 1306,-143 1306,-149 1300,-155 1294,-155"/>
<text text-anchor="middle" x="509" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text> <text text-anchor="middle" x="1191" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
<text text-anchor="middle" x="509" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text> <text text-anchor="middle" x="1191" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
</g>
<!-- timers&#45;&gt;irq -->
<g id="edge22" class="edge">
<title>timers&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1347.17,-209.93C1313.25,-194.31 1267.72,-173.34 1234.58,-158.07"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1235.5,-155.8 1228.12,-155.1 1233.45,-160.25 1235.5,-155.8"/>
<text text-anchor="middle" x="1314.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ3 / IRQ4</text>
</g>
<!-- ws2812&#45;&gt;gpio_bridge -->
<g id="edge23" class="edge">
<title>ws2812&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1134.56,-209.93C1097.14,-194.24 1046.86,-173.16 1010.42,-157.88"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1011.18,-155.54 1003.78,-155.1 1009.29,-160.06 1011.18,-155.54"/>
<text text-anchor="middle" x="1096.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
</g> </g>
<!-- ws2812&#45;&gt;irq --> <!-- ws2812&#45;&gt;irq -->
<g id="edge22" class="edge"> <g id="edge25" class="edge">
<title>ws2812&#45;&gt;irq</title> <title>ws2812&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M481.35,-209.81C486.85,-195.54 494.05,-176.83 499.73,-162.09"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1187.16,-209.81C1187.92,-195.66 1188.91,-177.17 1189.69,-162.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="502.15,-162.62 502.38,-155.2 497.57,-160.86 502.15,-162.62"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1192.15,-162.32 1190.08,-155.2 1187.26,-162.06 1192.15,-162.32"/>
<text text-anchor="middle" x="505" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text> <text text-anchor="middle" x="1200" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
</g> </g>
<!-- apb_targets&#45;&gt;gpio_bridge --> <!-- apb_targets&#45;&gt;gpio_bridge -->
<g id="edge23" class="edge"> <g id="edge26" class="edge">
<title>apb_targets&#45;&gt;gpio_bridge</title> <title>apb_targets&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1060.38,-209.99C987.9,-193.86 889.69,-171.99 820.58,-156.61"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M608.05,-209.99C687.77,-193.82 795.84,-171.9 871.72,-156.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="820.93,-154.17 813.56,-155.04 819.86,-158.96 820.93,-154.17"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="872.59,-158.84 878.97,-155.04 871.62,-154.03 872.59,-158.84"/>
<text text-anchor="middle" x="965" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text> <text text-anchor="middle" x="778" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
</g> </g>
<!-- gpio_bridge&#45;&gt;ext_io --> <!-- gpio_bridge&#45;&gt;ext_io -->
<g id="edge25" class="edge"> <g id="edge28" class="edge">
<title>gpio_bridge&#45;&gt;ext_io</title> <title>gpio_bridge&#45;&gt;ext_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M751.43,-112.81C762.49,-95.04 777.79,-70.44 789.54,-51.56"/> <path fill="none" stroke="#4b5563" stroke-width="1.2" d="M999.4,-115.32C1032.38,-96.58 1081.08,-68.91 1116.39,-48.84"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="749.25,-111.68 747.63,-118.91 753.41,-114.26 749.25,-111.68"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="997.95,-113.33 993.07,-118.91 1000.37,-117.59 997.95,-113.33"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="791.76,-52.63 793.38,-45.39 787.6,-50.04 791.76,-52.63"/> <polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1117.95,-50.78 1122.83,-45.19 1115.53,-46.52 1117.95,-50.78"/>
<text text-anchor="middle" x="798" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text> <text text-anchor="middle" x="1099" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 32 KiB

+1 -1
View File
@@ -37,7 +37,7 @@ reset/latch time, after abort, and after underflow.
The RIBP TX FIFO is also a fixed-address target for the generic DMA engine. The RIBP TX FIFO is also a fixed-address target for the generic DMA engine.
DMA remains a normal RIB master and receives RIBP backpressure when the FIFO DMA remains a normal RIB master and receives RIBP backpressure when the FIFO
is full; the transmitter does not own a private DMA request channel. See is full; the transmitter does not own a private DMA request channel. See
[ws2812.md](ws2812.md) for the register and transfer contract. [ws2812.md](ip/ws2812.md) for the register and transfer contract.
## Management JTAG ## Management JTAG
+29
View File
@@ -14,6 +14,35 @@ RTL changes require an affected firmware build and simulation. Use
`make regress-pr` or `make regress-nightly` for supported regression coverage; `make regress-pr` or `make regress-nightly` for supported regression coverage;
see [Engineering Workflow](../docs/engineering.md) for results and artifacts. see [Engineering Workflow](../docs/engineering.md) for results and artifacts.
## Self-Owned RTL Naming
Self-owned SystemVerilog follows these signal and register naming rules. New
RTL and local changes to existing RTL must preserve them:
- Declare synthesizable data, state, and interconnect signals as `logic`.
Reserve explicit net types for signals that require net resolution semantics.
- Use `_i` and `_o` for module ports, `s_` for internal signals, and `u_` for
module instances.
- Name state owned by the current module `s_<name>_d` for next state and
`s_<name>_q` for registered current state. Keep the pair adjacent in the
declaration and connect it through a reusable register component from
ClusterIP Common.
- Name a register write enable `s_<name>_en`. Do not add `_d` or `_q` to an
ordinary combinational signal or to a parent-module connection simply
because its source is registered inside a child module.
- Use `s_req`, `s_write`, `s_req_accept`, and `s_access_error` for a RIBP slave
transaction. Name its registered response signals `s_ribp_ready_d/q`,
`s_ribp_rdata_d/q`, and `s_ribp_resp_err_d/q`.
- Name register offsets `RIBP_<IP>_<REGISTER>` and field bit positions
`<IP>_<REGISTER>_<FIELD>`. Do not add redundant `_OFFSET`, `_LSB`, `_MASK`,
or `_VALUE` suffixes; keep implementation-only masks and constant values as
typed `localparam` declarations in the owning module.
Run `verible-verilog-format --flagfile=.verible-format` on changed RTL. Where
the formatter cannot preserve required macro or port-column alignment, use a
narrow `// verilog_format: off/on` region and align the enclosed declarations
manually.
The Verilator harness uses a zero-delay SDRAM protocol model because Verilator The Verilator harness uses a zero-delay SDRAM protocol model because Verilator
does not elaborate the tri-state delays in the Micron model. The Icarus does not elaborate the tri-state delays in the Micron model. The Icarus
testbench retains that Micron timing model, so it is the reference for SDRAM testbench retains that Micron timing model, so it is the reference for SDRAM
+85
View File
@@ -0,0 +1,85 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module ribp_timer (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic debug_halted_i,
ribp_if.slave ribp,
output logic irq_o
// verilog_format: on
);
logic s_enable;
logic [ 1:0] s_mode;
logic s_direction;
logic s_debug_freeze_enable;
logic s_compare0_enable;
logic s_compare1_enable;
logic [15:0] s_prescale;
logic [31:0] s_load;
logic [31:0] s_compare0;
logic [31:0] s_compare1;
logic s_start;
logic s_stop;
logic s_load_now;
logic [31:0] s_value;
logic s_debug_frozen;
logic s_timeout_event;
logic s_compare0_event;
logic s_compare1_event;
logic s_one_shot_done;
timer_reg u_timer_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.value_i (s_value),
.debug_frozen_i (s_debug_frozen),
.timeout_event_i (s_timeout_event),
.compare0_event_i (s_compare0_event),
.compare1_event_i (s_compare1_event),
.one_shot_done_i (s_one_shot_done),
.enable_o (s_enable),
.mode_o (s_mode),
.direction_o (s_direction),
.debug_freeze_enable_o(s_debug_freeze_enable),
.compare0_enable_o (s_compare0_enable),
.compare1_enable_o (s_compare1_enable),
.prescale_o (s_prescale),
.load_o (s_load),
.compare0_o (s_compare0),
.compare1_o (s_compare1),
.start_o (s_start),
.stop_o (s_stop),
.load_now_o (s_load_now),
.irq_o (irq_o)
);
timer_core u_timer_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.enable_i (s_enable),
.mode_i (s_mode),
.direction_i (s_direction),
.debug_freeze_enable_i(s_debug_freeze_enable),
.debug_halted_i (debug_halted_i),
.compare0_enable_i (s_compare0_enable),
.compare1_enable_i (s_compare1_enable),
.prescale_i (s_prescale),
.load_i (s_load),
.compare0_i (s_compare0),
.compare1_i (s_compare1),
.start_i (s_start),
.stop_i (s_stop),
.load_now_i (s_load_now),
.value_o (s_value),
.debug_frozen_o (s_debug_frozen),
.timeout_event_o (s_timeout_event),
.compare0_event_o (s_compare0_event),
.compare1_event_o (s_compare1_event),
.one_shot_done_o (s_one_shot_done)
);
endmodule
-183
View File
@@ -1,183 +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.
*
* Simple 32-bit counter-timer for ravenna. */
// -- 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_TIMER_DEF_SV
`define RIBP_TIMER_DEF_SV
// verilog_format: off
`define RIBP_TIMER_CFG 8'h00
`define RIBP_TIMER_RLD 8'h04
`define RIBP_TIMER_VAL 8'h08
// verilog_format: on
`endif
module ribp_timer (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
output logic irq_o
// verilog_format: on
);
// ribp
logic s_irq_d, s_irq_q;
logic s_ribp_wr_hdshk, s_ribp_rd_hdshk;
logic s_ribp_ready_d, s_ribp_ready_q;
logic s_ribp_rdata_en;
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
// register
logic s_tim_cfg_en;
logic [3:0] s_tim_cfg_d, s_tim_cfg_q;
logic s_tim_rld_en;
logic [31:0] s_tim_rld_d, s_tim_rld_q;
logic [31:0] s_tim_val_d, s_tim_val_q;
// enable (start) the counter/timer
// set s_bit_oneshot (1) mode or continuous (0) mode
// count up (1) or down (0)
// enable interrupt on timeout
logic s_bit_en, s_bit_oneshot;
logic s_bit_updown, s_bit_irq_en;
// irq
assign irq_o = s_irq_q;
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && (|ribp.wstrb);
assign s_ribp_rd_hdshk = ribp.valid && (~s_ribp_ready_q) && (~(|ribp.wstrb));
assign ribp.ready = s_ribp_ready_q;
assign ribp.resp_err = 1'b0;
assign ribp.rdata = s_ribp_rdata_q;
assign s_bit_en = s_tim_cfg_q[0];
assign s_bit_oneshot = s_tim_cfg_q[1];
assign s_bit_updown = s_tim_cfg_q[2];
assign s_bit_irq_en = s_tim_cfg_q[3];
// register
assign s_tim_cfg_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_TIMER_CFG;
assign s_tim_cfg_d = ribp.wdata[3:0];
dffer #(4) u_tim_cfg_dffer (
clk_i,
rst_n_i,
s_tim_cfg_en && ribp.wstrb[0],
s_tim_cfg_d,
s_tim_cfg_q
);
assign s_tim_rld_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_TIMER_RLD;
always_comb begin
s_tim_rld_d = s_tim_rld_q;
if (ribp.wstrb[0]) s_tim_rld_d[7:0] = ribp.wdata[7:0];
if (ribp.wstrb[1]) s_tim_rld_d[15:8] = ribp.wdata[15:8];
if (ribp.wstrb[2]) s_tim_rld_d[23:16] = ribp.wdata[23:16];
if (ribp.wstrb[3]) s_tim_rld_d[31:24] = ribp.wdata[31:24];
end
dffer #(32) u_tim_rld_dffer (
clk_i,
rst_n_i,
s_tim_rld_en,
s_tim_rld_d,
s_tim_rld_q
);
always_comb begin
s_tim_val_d = s_tim_val_q;
s_irq_d = s_irq_q;
if (s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_TIMER_VAL) begin
if (ribp.wstrb[0]) s_tim_val_d[7:0] = ribp.wdata[7:0];
if (ribp.wstrb[1]) s_tim_val_d[15:8] = ribp.wdata[15:8];
if (ribp.wstrb[2]) s_tim_val_d[23:16] = ribp.wdata[23:16];
if (ribp.wstrb[3]) s_tim_val_d[31:24] = ribp.wdata[31:24];
end else if (s_bit_en) begin
if (s_bit_updown) begin
if (s_tim_val_q == s_tim_rld_q) begin
if (~s_bit_oneshot) s_tim_val_d = '0;
s_irq_d = s_bit_irq_en;
end else begin
s_tim_val_d = s_tim_val_q + 1'b1;
s_irq_d = '0;
end
end else begin
if (s_tim_val_q == '0) begin
if (~s_bit_oneshot) s_tim_val_d = s_tim_rld_q;
s_irq_d = s_bit_irq_en;
end else begin
s_tim_val_d = s_tim_val_q - 1'b1;
s_irq_d = '0;
end
end
end
end
dffr #(32) u_tim_val_dffr (
clk_i,
rst_n_i,
s_tim_val_d,
s_tim_val_q
);
dffr #(1) u_irq_dffr (
clk_i,
rst_n_i,
s_irq_d,
s_irq_q
);
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q);
dffr #(1) u_ribp_ready_dffr (
clk_i,
rst_n_i,
s_ribp_ready_d,
s_ribp_ready_q
);
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
always_comb begin
s_ribp_rdata_d = s_ribp_rdata_q;
unique case (ribp.addr[7:0])
`RIBP_TIMER_CFG: s_ribp_rdata_d = {28'd0, s_tim_cfg_q};
`RIBP_TIMER_RLD: s_ribp_rdata_d = s_tim_rld_q;
`RIBP_TIMER_VAL: s_ribp_rdata_d = s_tim_val_q;
default: s_ribp_rdata_d = s_ribp_rdata_q;
endcase
end
dffer #(32) u_ribp_rdata_dffer (
clk_i,
rst_n_i,
s_ribp_rdata_en,
s_ribp_rdata_d,
s_ribp_rdata_q
);
endmodule
+124
View File
@@ -0,0 +1,124 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module timer_core #(
parameter int COUNTER_WIDTH = 32,
parameter int PRESCALE_WIDTH = 16
) (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic enable_i,
input logic [1:0] mode_i,
input logic direction_i,
input logic debug_freeze_enable_i,
input logic debug_halted_i,
input logic compare0_enable_i,
input logic compare1_enable_i,
input logic [PRESCALE_WIDTH-1:0] prescale_i,
input logic [COUNTER_WIDTH-1:0] load_i,
input logic [COUNTER_WIDTH-1:0] compare0_i,
input logic [COUNTER_WIDTH-1:0] compare1_i,
input logic start_i,
input logic stop_i,
input logic load_now_i,
output logic [COUNTER_WIDTH-1:0] value_o,
output logic debug_frozen_o,
output logic timeout_event_o,
output logic compare0_event_o,
output logic compare1_event_o,
output logic one_shot_done_o
// verilog_format: on
);
localparam logic [1:0] MODE_FREE_RUNNING = 2'b00;
localparam logic [1:0] MODE_PERIODIC = 2'b01;
localparam logic [1:0] MODE_ONE_SHOT = 2'b10;
logic [PRESCALE_WIDTH-1:0] s_prescale_count;
logic s_prescale_load;
logic s_prescale_enable;
logic s_tick;
logic s_terminal;
logic s_prescale_overflow;
logic [COUNTER_WIDTH-1:0] s_value_d, s_value_q;
initial begin
if (COUNTER_WIDTH < 1 || PRESCALE_WIDTH < 1) begin
$fatal(1, "timer_core: parameter widths must be positive");
end
end
assign debug_frozen_o = enable_i && debug_freeze_enable_i && debug_halted_i;
assign value_o = s_value_q;
assign s_tick = enable_i && !debug_frozen_o && !start_i && !stop_i && !load_now_i &&
(s_prescale_count == '0) && !s_prescale_overflow;
assign s_prescale_load = start_i || (enable_i && load_now_i) || s_tick;
assign s_prescale_enable = enable_i && !debug_frozen_o && !start_i && !stop_i && !load_now_i &&
!s_tick;
rs_counter #(
.DATA_WIDTH(PRESCALE_WIDTH)
) u_prescale_counter (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.clr_i (1'b0),
.en_i (s_prescale_enable),
.load_i (s_prescale_load),
.down_i (1'b1),
.dat_i (prescale_i),
.dat_o (s_prescale_count),
.ovf_o (s_prescale_overflow)
);
always_comb begin
unique case (mode_i)
MODE_FREE_RUNNING: s_terminal = direction_i ? s_value_q == '0 : s_value_q == '1;
MODE_PERIODIC, MODE_ONE_SHOT: begin
s_terminal = direction_i ? s_value_q == '0 : s_value_q >= load_i;
end
default: s_terminal = 1'b0;
endcase
end
always_comb begin
timeout_event_o = 1'b0;
compare0_event_o = 1'b0;
compare1_event_o = 1'b0;
one_shot_done_o = 1'b0;
if (s_tick) begin
compare0_event_o = compare0_enable_i && (s_value_q == compare0_i);
compare1_event_o = compare1_enable_i && (s_value_q == compare1_i);
timeout_event_o = s_terminal;
one_shot_done_o = s_terminal && (mode_i == MODE_ONE_SHOT);
end
end
always_comb begin
s_value_d = s_value_q;
if (load_now_i) begin
s_value_d = direction_i ? load_i : '0;
end else if (s_tick) begin
unique case (mode_i)
MODE_FREE_RUNNING: s_value_d = direction_i ? s_value_q - 1'b1 : s_value_q + 1'b1;
MODE_PERIODIC: begin
if (s_terminal) s_value_d = direction_i ? load_i : '0;
else s_value_d = direction_i ? s_value_q - 1'b1 : s_value_q + 1'b1;
end
MODE_ONE_SHOT: begin
if (!s_terminal) s_value_d = direction_i ? s_value_q - 1'b1 : s_value_q + 1'b1;
end
default: s_value_d = s_value_q;
endcase
end
end
dffr #(COUNTER_WIDTH) u_value_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_value_d),
.dat_o (s_value_q)
);
endmodule
+31
View File
@@ -0,0 +1,31 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`ifndef RIBP_TIMER_DEFINE_SVH
`define RIBP_TIMER_DEFINE_SVH
// verilog_format: off
`define RIBP_TIMER_CTRL 12'h000
`define RIBP_TIMER_LOAD 12'h004
`define RIBP_TIMER_VALUE 12'h008
`define RIBP_TIMER_BGLOAD 12'h00C
`define RIBP_TIMER_PRESCALE 12'h010
`define RIBP_TIMER_COMPARE0 12'h014
`define RIBP_TIMER_COMPARE1 12'h018
`define RIBP_TIMER_STATUS 12'h01C
`define RIBP_TIMER_INTR_STATE 12'h020
`define RIBP_TIMER_INTR_ENABLE 12'h024
`define RIBP_TIMER_INTR_STATUS 12'h028
`define RIBP_TIMER_INTR_TEST 12'h02C
`define RIBP_TIMER_IP_VERSION 12'h0F8
`define RIBP_TIMER_CAPABILITY 12'h0FC
`define TIMER_CTRL_ENABLE 0
`define TIMER_CTRL_MODE 1
`define TIMER_CTRL_DIRECTION 3
`define TIMER_CTRL_DEBUG_FREEZE 4
`define TIMER_CTRL_COMPARE0_ENABLE 5
`define TIMER_CTRL_COMPARE1_ENABLE 6
// verilog_format: on
`endif
+305
View File
@@ -0,0 +1,305 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "timer_define.svh"
module timer_reg (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
input logic [31:0] value_i,
input logic debug_frozen_i,
input logic timeout_event_i,
input logic compare0_event_i,
input logic compare1_event_i,
input logic one_shot_done_i,
output logic enable_o,
output logic [1:0] mode_o,
output logic direction_o,
output logic debug_freeze_enable_o,
output logic compare0_enable_o,
output logic compare1_enable_o,
output logic [15:0] prescale_o,
output logic [31:0] load_o,
output logic [31:0] compare0_o,
output logic [31:0] compare1_o,
output logic start_o,
output logic stop_o,
output logic load_now_o,
output logic irq_o
// verilog_format: on
);
localparam logic [1:0] MODE_RESERVED = 2'b11;
localparam logic [31:0] IP_VERSION = 32'h0002_0000;
localparam logic [31:0] CAPABILITY = 32'h00F2_1020;
localparam logic [31:0] CTRL_ENABLE_MASK = 32'b1 << `TIMER_CTRL_ENABLE;
localparam logic [31:0] CTRL_MODE_MASK = 32'b11 << `TIMER_CTRL_MODE;
localparam logic [31:0] CTRL_DIRECTION_MASK = 32'b1 << `TIMER_CTRL_DIRECTION;
localparam logic [31:0] CTRL_DEBUG_FREEZE_MASK = 32'b1 << `TIMER_CTRL_DEBUG_FREEZE;
localparam logic [31:0] CTRL_COMPARE0_ENABLE_MASK = 32'b1 << `TIMER_CTRL_COMPARE0_ENABLE;
localparam logic [31:0] CTRL_COMPARE1_ENABLE_MASK = 32'b1 << `TIMER_CTRL_COMPARE1_ENABLE;
localparam logic [31:0] CTRL_WRITABLE_MASK =
CTRL_ENABLE_MASK | CTRL_MODE_MASK | CTRL_DIRECTION_MASK | CTRL_DEBUG_FREEZE_MASK |
CTRL_COMPARE0_ENABLE_MASK | CTRL_COMPARE1_ENABLE_MASK;
localparam logic [31:0] CTRL_ACTIVE_IMMUTABLE_MASK = CTRL_MODE_MASK | CTRL_DIRECTION_MASK;
logic s_req;
logic s_write;
logic s_req_accept;
logic [11:0] s_offset;
logic s_aligned;
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 [31:0] s_ctrl_write_value;
logic [31:0] s_load_write_value;
logic [31:0] s_bgload_write_value;
logic [15:0] s_prescale_write_value;
logic [31:0] s_compare0_write_value;
logic [31:0] s_compare1_write_value;
logic [ 2:0] s_intr_enable_write_value;
logic [ 2:0] s_intr_clear;
logic [ 2:0] s_intr_set;
logic [ 2:0] s_intr_state_d;
logic [ 2:0] s_intr_state_q;
logic [ 2:0] s_intr_enable_d;
logic [ 2:0] s_intr_enable_q;
logic [31:0] s_ctrl_d, s_ctrl_q;
logic [31:0] s_load_d, s_load_q;
logic [15:0] s_prescale_d, s_prescale_q;
logic [31:0] s_compare0_d, s_compare0_q;
logic [31:0] s_compare1_d, s_compare1_q;
function automatic logic [31:0] merge_wstrb(input logic [31:0] current, input logic [31:0] value,
input logic [3:0] strobe);
logic [31:0] merged;
begin
merged = current;
for (int byte_index = 0; byte_index < 4; byte_index++) begin
if (strobe[byte_index]) begin
merged[byte_index*8+:8] = value[byte_index*8+:8];
end
end
return merged;
end
endfunction
assign s_req = ribp.valid && !s_ribp_ready_q;
assign s_write = |ribp.wstrb;
assign s_req_accept = s_req;
assign s_offset = ribp.addr[11:0];
assign s_aligned = ribp.addr[1:0] == 2'b00;
assign ribp.ready = s_ribp_ready_q;
assign ribp.rdata = s_ribp_rdata_q;
assign ribp.resp_err = s_ribp_resp_err_q;
assign s_ctrl_write_value = merge_wstrb(s_ctrl_q, ribp.wdata, ribp.wstrb) & CTRL_WRITABLE_MASK;
assign s_load_write_value = merge_wstrb(s_load_q, ribp.wdata, ribp.wstrb);
assign s_bgload_write_value = merge_wstrb(s_load_q, ribp.wdata, ribp.wstrb);
assign s_prescale_write_value = 16'(merge_wstrb({16'd0, s_prescale_q}, ribp.wdata, ribp.wstrb));
assign s_compare0_write_value = merge_wstrb(s_compare0_q, ribp.wdata, ribp.wstrb);
assign s_compare1_write_value = merge_wstrb(s_compare1_q, ribp.wdata, ribp.wstrb);
assign s_intr_enable_write_value = 3'(merge_wstrb(
{29'd0, s_intr_enable_q}, ribp.wdata, ribp.wstrb
));
always_comb begin
s_access_error = !s_aligned;
s_ribp_rdata_d = '0;
if (s_aligned) begin
unique case (s_offset)
`RIBP_TIMER_CTRL: begin
s_ribp_rdata_d = s_ctrl_q;
if (s_write) begin
s_access_error =
(s_ctrl_write_value[2:1] == MODE_RESERVED) ||
(enable_o && (|((s_ctrl_write_value ^ s_ctrl_q) & CTRL_ACTIVE_IMMUTABLE_MASK)));
end
end
`RIBP_TIMER_LOAD: s_ribp_rdata_d = s_load_q;
`RIBP_TIMER_VALUE: begin
s_ribp_rdata_d = value_i;
s_access_error = s_write;
end
`RIBP_TIMER_BGLOAD: s_ribp_rdata_d = s_load_q;
`RIBP_TIMER_PRESCALE: begin
s_ribp_rdata_d = {16'd0, s_prescale_q};
s_access_error = s_write && enable_o;
end
`RIBP_TIMER_COMPARE0: s_ribp_rdata_d = s_compare0_q;
`RIBP_TIMER_COMPARE1: s_ribp_rdata_d = s_compare1_q;
`RIBP_TIMER_STATUS: begin
s_ribp_rdata_d = {30'd0, debug_frozen_i, enable_o};
s_access_error = s_write;
end
`RIBP_TIMER_INTR_STATE: s_ribp_rdata_d = {29'd0, s_intr_state_q};
`RIBP_TIMER_INTR_ENABLE: s_ribp_rdata_d = {29'd0, s_intr_enable_q};
`RIBP_TIMER_INTR_STATUS: begin
s_ribp_rdata_d = {29'd0, s_intr_state_q & s_intr_enable_q};
s_access_error = s_write;
end
`RIBP_TIMER_INTR_TEST: s_access_error = !s_write;
`RIBP_TIMER_IP_VERSION: begin
s_ribp_rdata_d = IP_VERSION;
s_access_error = s_write;
end
`RIBP_TIMER_CAPABILITY: begin
s_ribp_rdata_d = CAPABILITY;
s_access_error = s_write;
end
default: s_access_error = 1'b1;
endcase
end
end
assign start_o = s_req_accept && s_write && !s_access_error &&
(s_offset == `RIBP_TIMER_CTRL) && !enable_o &&
s_ctrl_write_value[`TIMER_CTRL_ENABLE];
assign stop_o = s_req_accept && s_write && !s_access_error &&
(s_offset == `RIBP_TIMER_CTRL) && enable_o &&
!s_ctrl_write_value[`TIMER_CTRL_ENABLE];
assign load_now_o = s_req_accept && s_write && !s_access_error && (s_offset == `RIBP_TIMER_LOAD);
always_comb begin
s_ctrl_d = s_ctrl_q;
if (s_req_accept && s_write && !s_access_error && (s_offset == `RIBP_TIMER_CTRL)) begin
s_ctrl_d = s_ctrl_write_value;
end
if (one_shot_done_i) begin
s_ctrl_d[`TIMER_CTRL_ENABLE] = 1'b0;
end
end
dffr #(32) u_ctrl_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_ctrl_d),
.dat_o (s_ctrl_q)
);
always_comb begin
s_load_d = s_load_q;
if (s_req_accept && s_write && !s_access_error) begin
if (s_offset == `RIBP_TIMER_LOAD) s_load_d = s_load_write_value;
else if (s_offset == `RIBP_TIMER_BGLOAD) s_load_d = s_bgload_write_value;
end
end
dffr #(32) u_load_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_load_d),
.dat_o (s_load_q)
);
always_comb begin
s_prescale_d = s_prescale_q;
if (s_req_accept && s_write && !s_access_error && (s_offset == `RIBP_TIMER_PRESCALE)) begin
s_prescale_d = s_prescale_write_value;
end
end
dffr #(16) u_prescale_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_prescale_d),
.dat_o (s_prescale_q)
);
always_comb begin
s_compare0_d = s_compare0_q;
s_compare1_d = s_compare1_q;
if (s_req_accept && s_write && !s_access_error) begin
if (s_offset == `RIBP_TIMER_COMPARE0) s_compare0_d = s_compare0_write_value;
if (s_offset == `RIBP_TIMER_COMPARE1) s_compare1_d = s_compare1_write_value;
end
end
dffr #(32) u_compare0_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_compare0_d),
.dat_o (s_compare0_q)
);
dffr #(32) u_compare1_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_compare1_d),
.dat_o (s_compare1_q)
);
always_comb begin
s_intr_enable_d = s_intr_enable_q;
if (s_req_accept && s_write && !s_access_error && (s_offset == `RIBP_TIMER_INTR_ENABLE)) begin
s_intr_enable_d = s_intr_enable_write_value;
end
end
dffr #(3) u_intr_enable_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_intr_enable_d),
.dat_o (s_intr_enable_q)
);
always_comb begin
s_intr_clear = '0;
s_intr_set = {compare1_event_i, compare0_event_i, timeout_event_i};
if (s_req_accept && s_write && !s_access_error) begin
if ((s_offset == `RIBP_TIMER_INTR_STATE) && ribp.wstrb[0]) begin
s_intr_clear = ribp.wdata[2:0];
end
if ((s_offset == `RIBP_TIMER_INTR_TEST) && ribp.wstrb[0]) begin
s_intr_set = s_intr_set | ribp.wdata[2:0];
end
end
s_intr_state_d = (s_intr_state_q & ~s_intr_clear) | s_intr_set;
end
dffr #(3) 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)
);
assign enable_o = s_ctrl_q[`TIMER_CTRL_ENABLE];
assign mode_o = s_ctrl_q[2:1];
assign direction_o = s_ctrl_q[`TIMER_CTRL_DIRECTION];
assign debug_freeze_enable_o = s_ctrl_q[`TIMER_CTRL_DEBUG_FREEZE];
assign compare0_enable_o = s_ctrl_q[`TIMER_CTRL_COMPARE0_ENABLE];
assign compare1_enable_o = s_ctrl_q[`TIMER_CTRL_COMPARE1_ENABLE];
assign prescale_o = s_prescale_q;
assign load_o = (s_req_accept && s_write && !s_access_error &&
((s_offset == `RIBP_TIMER_LOAD) ||
(s_offset == `RIBP_TIMER_BGLOAD))) ?
(s_offset == `RIBP_TIMER_LOAD ?
s_load_write_value : s_bgload_write_value) :
s_load_q;
assign compare0_o = s_compare0_q;
assign compare1_o = s_compare1_q;
assign irq_o = |(s_intr_state_q & s_intr_enable_q);
assign s_ribp_ready_d = s_req_accept;
assign s_ribp_resp_err_d = s_access_error;
dffr #(1) u_ribp_ready_dffr (
clk_i,
rst_n_i,
s_ribp_ready_d,
s_ribp_ready_q
);
dffer #(1) u_ribp_resp_err_dffer (
clk_i,
rst_n_i,
s_req_accept,
s_ribp_resp_err_d,
s_ribp_resp_err_q
);
dffer #(32) u_ribp_rdata_dffer (
clk_i,
rst_n_i,
s_req_accept,
s_ribp_rdata_d,
s_ribp_rdata_q
);
endmodule
+3 -1
View File
@@ -39,7 +39,9 @@
/ip/ribp/memory/sdram.sv /ip/ribp/memory/sdram.sv
/ip/ribp/multimedia/dvp_core.sv /ip/ribp/multimedia/dvp_core.sv
/ip/ribp/multimedia/dvp.sv /ip/ribp/multimedia/dvp.sv
/ip/ribp/peripheral/timer.sv /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/serial/uart.sv
/ip/ribp/peripheral/gpio.sv /ip/ribp/peripheral/gpio.sv
/top/ahbl2ribp.sv /top/ahbl2ribp.sv
@@ -99,6 +99,16 @@ def source_files(target: str) -> list[Path]:
SERIAL / "ribp_ws2812.sv", SERIAL / "ribp_ws2812.sv",
SCRIPT_DIR / "ws2812_formal.sv", SCRIPT_DIR / "ws2812_formal.sv",
] ]
if target == "timer":
return [
COMMON_RTL / "interface/ribp_if.sv",
COMMON_RTL / "utils/register.sv",
COMMON_RTL / "clkrst/counter.sv",
PERIPHERAL / "timer_core.sv",
PERIPHERAL / "timer_reg.sv",
PERIPHERAL / "ribp_timer.sv",
SCRIPT_DIR / "timer_formal.sv",
]
raise ValueError(f"unsupported formal target: {target}") raise ValueError(f"unsupported formal target: {target}")
@@ -140,6 +150,7 @@ def parse_args() -> argparse.Namespace:
"pll_rcu", "pll_rcu",
"gpio_user", "gpio_user",
"ws2812", "ws2812",
"timer",
), ),
required=True, required=True,
) )
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module timer_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 debug_halted,
output logic active,
output logic debug_frozen,
output logic [31:0] value,
output logic start,
output logic stop,
output logic load_now,
output logic timeout_event,
output logic compare0_event,
output logic compare1_event,
output logic one_shot_done,
output logic [ 2:0] intr_state,
output logic [ 2:0] intr_enable,
output logic irq
// verilog_format: on
);
ribp_if rib ();
(* 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_debug_halted;
assign rib.valid = f_rib_valid;
assign rib.addr = f_rib_addr;
assign rib.wdata = f_rib_wdata;
assign rib.wstrb = f_rib_wstrb;
assign rib_valid = rib.valid;
assign rib_addr = rib.addr;
assign rib_wdata = rib.wdata;
assign rib_wstrb = rib.wstrb;
assign rib_ready = rib.ready;
assign rib_resp_err = rib.resp_err;
assign debug_halted = f_debug_halted;
assign active = u_dut.s_enable;
assign debug_frozen = u_dut.s_debug_frozen;
assign value = u_dut.s_value;
assign start = u_dut.s_start;
assign stop = u_dut.s_stop;
assign load_now = u_dut.s_load_now;
assign timeout_event = u_dut.s_timeout_event;
assign compare0_event = u_dut.s_compare0_event;
assign compare1_event = u_dut.s_compare1_event;
assign one_shot_done = u_dut.s_one_shot_done;
assign intr_state = u_dut.u_timer_reg.s_intr_state_q;
assign intr_enable = u_dut.u_timer_reg.s_intr_enable_q;
ribp_timer u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.debug_halted_i(f_debug_halted),
.ribp (rib),
.irq_o (irq)
);
initial begin
rst_n_i = 1'b0;
f_past_valid = 1'b0;
end
always_ff @(posedge clk_i) begin
rst_n_i <= 1'b1;
f_past_valid <= 1'b1;
end
endmodule
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module timer_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 debug_halted;
wire active;
wire debug_frozen;
wire [31:0] value;
wire start;
wire stop;
wire load_now;
wire timeout_event;
wire compare0_event;
wire compare1_event;
wire one_shot_done;
wire [ 2:0] intr_state;
wire [ 2:0] intr_enable;
wire irq;
timer_formal_design u_design (.*);
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 (irq == |(intr_state & intr_enable));
if (f_past_valid && $past(rst_n_i && rib_valid && !rib_ready)) begin
assert (rib_ready);
end
if (f_past_valid && $past(rst_n_i && !active && !load_now)) begin
assert (value == $past(value));
end
if (f_past_valid && $past(rst_n_i && debug_frozen && !load_now && !stop)) begin
assert (value == $past(value));
end
if (f_past_valid && $past(rst_n_i && timeout_event)) begin
assert (intr_state[0]);
end
if (f_past_valid && $past(rst_n_i && compare0_event)) begin
assert (intr_state[1]);
end
if (f_past_valid && $past(rst_n_i && compare1_event)) begin
assert (intr_state[2]);
end
if (f_past_valid && $past(rst_n_i && one_shot_done)) begin
assert (!active);
end
cover (start);
cover (debug_frozen && debug_halted);
cover (timeout_event);
cover (compare0_event && compare1_event);
cover (irq);
cover (rib_ready && rib_resp_err);
end
end
endmodule
+11 -2
View File
@@ -8,7 +8,7 @@ FORMAL_DEPTH ?= 20
FORMAL_WS2812_DEPTH ?= 120 FORMAL_WS2812_DEPTH ?= 120
FORMAL_TIMEOUT ?= 60 FORMAL_TIMEOUT ?= 60
FORMAL_WS2812_TIMEOUT ?= 120 FORMAL_WS2812_TIMEOUT ?= 120
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user ws2812 FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user ws2812 timer
FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py
FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py
FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py
@@ -26,6 +26,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(RTL_PATH)/formal/gpio_user_formal_props.sv \ $(RTL_PATH)/formal/gpio_user_formal_props.sv \
$(RTL_PATH)/formal/ws2812_formal.sv \ $(RTL_PATH)/formal/ws2812_formal.sv \
$(RTL_PATH)/formal/ws2812_formal_props.sv \ $(RTL_PATH)/formal/ws2812_formal_props.sv \
$(RTL_PATH)/formal/timer_formal.sv \
$(RTL_PATH)/formal/timer_formal_props.sv \
$(RTL_PATH)/top/bus.sv \ $(RTL_PATH)/top/bus.sv \
$(RTL_PATH)/top/rib_error_slave.sv \ $(RTL_PATH)/top/rib_error_slave.sv \
$(RTL_PATH)/top/rib_if.sv \ $(RTL_PATH)/top/rib_if.sv \
@@ -41,6 +43,11 @@ 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_reg.sv \
$(ROOT_PATH)/rtl/ip/ribp/serial/ws2812_core.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/ribp_ws2812.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 \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/ribp_timer.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/clkrst/counter.sv \
$(RTL_PATH)/top/rcu.sv \ $(RTL_PATH)/top/rcu.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/ribp_if.sv \ $(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/ribp_if.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/apb4_pure_if.sv \ $(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/apb4_pure_if.sv \
@@ -135,10 +142,12 @@ formal-gpio-user: $(FORMAL_DIR)/gpio_user/.stamp | manifest
formal-ws2812: $(FORMAL_DIR)/ws2812/.stamp | manifest formal-ws2812: $(FORMAL_DIR)/ws2812/.stamp | manifest
formal-timer: $(FORMAL_DIR)/timer/.stamp | manifest
formal-doctor: formal-doctor:
$(MAKE) FORMAL=YES SIMU=IVERILOG SYNTH=YOSYS STA=NONE doctor $(MAKE) FORMAL=YES SIMU=IVERILOG SYNTH=YOSYS STA=NONE doctor
formal-clean: formal-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR) python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio-user formal-ws2812 formal-doctor formal-clean .PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio-user formal-ws2812 formal-timer formal-doctor formal-clean
+1
View File
@@ -67,6 +67,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
$(ROOT_PATH)/crt/src/hal/clock.c \ $(ROOT_PATH)/crt/src/hal/clock.c \
$(ROOT_PATH)/crt/src/hal/uart.c \ $(ROOT_PATH)/crt/src/hal/uart.c \
$(ROOT_PATH)/crt/src/hal/gpio.c \ $(ROOT_PATH)/crt/src/hal/gpio.c \
$(ROOT_PATH)/crt/src/hal/timer_math.c \
$(ROOT_PATH)/crt/src/hal/timer.c \ $(ROOT_PATH)/crt/src/hal/timer.c \
$(ROOT_PATH)/crt/src/hal/pwm.c \ $(ROOT_PATH)/crt/src/hal/pwm.c \
$(ROOT_PATH)/crt/src/hal/rtc.c \ $(ROOT_PATH)/crt/src/hal/rtc.c \
+11 -9
View File
@@ -18,20 +18,22 @@ module core_wrapper (
input logic jtag_tdi_i, input logic jtag_tdi_i,
input logic jtag_trst_n_i, input logic jtag_trst_n_i,
output logic jtag_tdo_o, output logic jtag_tdo_o,
output logic debug_halted_o,
ribp_if.master ribp ribp_if.master ribp
// verilog_format: on // verilog_format: on
); );
mgmt_core_wrapper u_mgmt_core_wrapper ( mgmt_core_wrapper u_mgmt_core_wrapper (
.clk_i (clk_i), .clk_i (clk_i),
.rst_n_i (rst_n_i), .rst_n_i (rst_n_i),
.irq_i (irq_i), .irq_i (irq_i),
.jtag_tck_i (jtag_tck_i), .jtag_tck_i (jtag_tck_i),
.jtag_tms_i (jtag_tms_i), .jtag_tms_i (jtag_tms_i),
.jtag_tdi_i (jtag_tdi_i), .jtag_tdi_i (jtag_tdi_i),
.jtag_trst_n_i(jtag_trst_n_i), .jtag_trst_n_i (jtag_trst_n_i),
.jtag_tdo_o (jtag_tdo_o), .jtag_tdo_o (jtag_tdo_o),
.ribp (ribp) .debug_halted_o(debug_halted_o),
.ribp (ribp)
); );
endmodule endmodule
+11 -8
View File
@@ -18,6 +18,7 @@ module ip_ribp_wrapper (
input logic rst_n_i, input logic rst_n_i,
input logic clk_aud_i, input logic clk_aud_i,
input logic rst_aud_n_i, input logic rst_aud_n_i,
input logic debug_halted_i,
rib_if.slave rib, rib_if.slave rib,
gpio_if.dut gpio, gpio_if.dut gpio,
user_gpio_if.padctrl user_gpio, user_gpio_if.padctrl user_gpio,
@@ -98,17 +99,19 @@ module ip_ribp_wrapper (
); );
ribp_timer u_rib_timer0 ( ribp_timer u_rib_timer0 (
.clk_i (clk_i), .clk_i (clk_i),
.rst_n_i(rst_n_i), .rst_n_i (rst_n_i),
.ribp (u_tim0_ribp_if), .debug_halted_i(debug_halted_i),
.irq_o (s_tim0_irq) .ribp (u_tim0_ribp_if),
.irq_o (s_tim0_irq)
); );
ribp_timer u_rib_timer1 ( ribp_timer u_rib_timer1 (
.clk_i (clk_i), .clk_i (clk_i),
.rst_n_i(rst_n_i), .rst_n_i (rst_n_i),
.ribp (u_tim1_ribp_if), .debug_halted_i(debug_halted_i),
.irq_o (s_tim1_irq) .ribp (u_tim1_ribp_if),
.irq_o (s_tim1_irq)
); );
ribp_psram u_rib_psram ( ribp_psram u_rib_psram (
+4 -1
View File
@@ -20,7 +20,8 @@ module mgmt_core_wrapper (
input logic jtag_tdi_i, input logic jtag_tdi_i,
input logic jtag_trst_n_i, input logic jtag_trst_n_i,
output logic jtag_tdo_o, output logic jtag_tdo_o,
ribp_if.master ribp output logic debug_halted_o,
ribp_if.master ribp
// verilog_format: on // verilog_format: on
); );
@@ -48,6 +49,8 @@ module mgmt_core_wrapper (
logic s_dbg_sbus_err; logic s_dbg_sbus_err;
logic [31:0] s_dbg_sbus_wdata; logic [31:0] s_dbg_sbus_wdata;
logic [31:0] s_dbg_sbus_rdata; logic [31:0] s_dbg_sbus_rdata;
assign debug_halted_o = s_dbg_halted;
// verilog_format: off // verilog_format: off
ahbl_if u_ahbl_if (clk_i, s_core_rst_n); ahbl_if u_ahbl_if (clk_i, s_core_rst_n);
ahbl2ribp u_ahbl2ribp (u_ahbl_if, ribp, s_ahbl_idle); ahbl2ribp u_ahbl2ribp (u_ahbl_if, ribp, s_ahbl_idle);
+11 -8
View File
@@ -60,6 +60,7 @@ module retrosoc (
// verilog_format: on // verilog_format: on
logic s_tmr_capch; logic s_tmr_capch;
logic s_mgmt_debug_halted;
logic [`SOC_IRQ_VECTOR_WIDTH-1:0] s_irq; logic [`SOC_IRQ_VECTOR_WIDTH-1:0] s_irq;
logic [ `SOC_IRQ_RIBP_WIDTH-1:0] s_ribp_irq; logic [ `SOC_IRQ_RIBP_WIDTH-1:0] s_ribp_irq;
logic [ `SOC_IRQ_APB_WIDTH-1:0] s_apb_irq; logic [ `SOC_IRQ_APB_WIDTH-1:0] s_apb_irq;
@@ -111,15 +112,16 @@ module retrosoc (
`include "soc_gpio_alt_bindings.svh" `include "soc_gpio_alt_bindings.svh"
core_wrapper u_core_wrapper ( core_wrapper u_core_wrapper (
.clk_i (clk_i), .clk_i (clk_i),
.rst_n_i (rst_n_i), .rst_n_i (rst_n_i),
`include "soc_mgmt_core_wrapper_fabric.svh" `include "soc_mgmt_core_wrapper_fabric.svh"
.irq_i (s_irq), .irq_i (s_irq),
.jtag_tck_i (jtag_tck_i), .jtag_tck_i (jtag_tck_i),
.jtag_tms_i (jtag_tms_i), .jtag_tms_i (jtag_tms_i),
.jtag_tdi_i (jtag_tdi_i), .jtag_tdi_i (jtag_tdi_i),
.jtag_trst_n_i(jtag_trst_n_i), .jtag_trst_n_i (jtag_trst_n_i),
.jtag_tdo_o (jtag_tdo_o) .jtag_tdo_o (jtag_tdo_o),
.debug_halted_o(s_mgmt_debug_halted)
); );
assign s_user_irq = u_sysctrl_if.user_bus_enable_o ? s_irq : '0; assign s_user_irq = u_sysctrl_if.user_bus_enable_o ? s_irq : '0;
@@ -165,6 +167,7 @@ core_wrapper u_core_wrapper (
.rst_n_i (rst_n_i), .rst_n_i (rst_n_i),
.clk_aud_i (clk_aud_i), .clk_aud_i (clk_aud_i),
.rst_aud_n_i (rst_aud_n_i), .rst_aud_n_i (rst_aud_n_i),
.debug_halted_i (s_mgmt_debug_halted),
`include "ip_ribp_wrapper_fabric.svh" `include "ip_ribp_wrapper_fabric.svh"
.gpio (u_gpio_if), .gpio (u_gpio_if),
.user_gpio (u_user_gpio_if), .user_gpio (u_user_gpio_if),
+1
View File
@@ -21,6 +21,7 @@ TEST_SOURCES = (
"crt/src/lib/stdlib.c", "crt/src/lib/stdlib.c",
"crt/src/lib/string.c", "crt/src/lib/string.c",
"crt/src/hal/ws2812_math.c", "crt/src/hal/ws2812_math.c",
"crt/src/hal/timer_math.c",
"app/media/src/video_player.c", "app/media/src/video_player.c",
"app/media/src/wav_audio.c", "app/media/src/wav_audio.c",
"tests/c/test_runtime.c", "tests/c/test_runtime.c",
+23
View File
@@ -5,6 +5,7 @@
#include <retrosoc/core/wait.h> #include <retrosoc/core/wait.h>
#include <retrosoc/hal/lcd.h> #include <retrosoc/hal/lcd.h>
#include <retrosoc/hal/spisd.h> #include <retrosoc/hal/spisd.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/hal/ws2812.h> #include <retrosoc/hal/ws2812.h>
#include <retrosoc/lib/printf.h> #include <retrosoc/lib/printf.h>
#include <retrosoc/lib/stdlib.h> #include <retrosoc/lib/stdlib.h>
@@ -186,6 +187,27 @@ static int test_ws2812_helpers(void)
return 0; return 0;
} }
static int test_timer_helpers(void)
{
rs_timer_period_t period;
if ((rs_timer_period_from_ms(72000000U, 1U, &period) != RS_OK) ||
(period.prescale != 0U) || (period.load != 71999U)) {
return 1;
}
if ((rs_timer_period_from_ms(72000000U, 1000U, &period) != RS_OK) ||
(period.prescale != 0U) || (period.load != 71999999U)) {
return 2;
}
if ((rs_timer_period_from_ms(0U, 1U, &period) != RS_EINVAL) ||
(rs_timer_period_from_ms(72000000U, 0U, &period) != RS_EINVAL) ||
(rs_timer_period_from_ms(72000000U, 1U, NULL) != RS_EINVAL) ||
(rs_timer_period_from_ms(UINT32_MAX, UINT32_MAX, &period) != RS_EINVAL)) {
return 3;
}
return 0;
}
static int test_wav_parser(void) static int test_wav_parser(void)
{ {
static const uint8_t wav[] = { static const uint8_t wav[] = {
@@ -235,6 +257,7 @@ int main(void)
test_compiler_helpers(), test_compiler_helpers(),
test_wait_helper(), test_wait_helper(),
test_ws2812_helpers(), test_ws2812_helpers(),
test_timer_helpers(),
test_wav_parser(), test_wav_parser(),
test_video_parser(), test_video_parser(),
}; };
+175
View File
@@ -0,0 +1,175 @@
`timescale 1ns / 1ps
module timer_tb;
localparam logic [31:0] CTRL_ENABLE = 32'h0000_0001;
localparam logic [31:0] CTRL_PERIODIC = 32'h0000_0002;
localparam logic [31:0] CTRL_ONE_SHOT = 32'h0000_0004;
localparam logic [31:0] CTRL_DIRECTION_DOWN = 32'h0000_0008;
localparam logic [31:0] CTRL_DEBUG_FREEZE = 32'h0000_0010;
localparam logic [31:0] CTRL_COMPARE_ENABLE = 32'h0000_0060;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic debug_halted_i = 1'b0;
logic irq_o;
ribp_if ribp ();
always #5 clk_i = ~clk_i;
ribp_timer u_dut (
.clk_i,
.rst_n_i,
.debug_halted_i,
.ribp,
.irq_o
);
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.valid = 1'b1;
ribp.addr = address;
ribp.wdata = data;
ribp.wstrb = strobe;
do @(negedge clk_i); while (!ribp.ready);
if (ribp.resp_err !== expected_error) begin
$fatal(1, "write %h error=%b expected=%b", address, ribp.resp_err, expected_error);
end
ribp.valid = 1'b0;
ribp.wstrb = '0;
end
endtask
task automatic ribp_read(input logic [31:0] address, output logic [31:0] data,
input logic expected_error);
begin
@(negedge clk_i);
ribp.valid = 1'b1;
ribp.addr = address;
ribp.wdata = '0;
ribp.wstrb = '0;
do @(negedge clk_i); while (!ribp.ready);
data = ribp.rdata;
if (ribp.resp_err !== expected_error) begin
$fatal(1, "read %h error=%b expected=%b", address, ribp.resp_err, expected_error);
end
ribp.valid = 1'b0;
end
endtask
task automatic wait_inactive;
logic [31:0] status;
int cycles;
begin
status = '1;
cycles = 0;
while ((status[0] != 1'b0) && (cycles < 64)) begin
ribp_read(32'h0000_001C, status, 1'b0);
cycles++;
end
if (status[0] != 1'b0) $fatal(1, "timer did not enter inactive state");
end
endtask
logic [31:0] value;
logic [31:0] frozen_value;
logic [31:0] status;
logic [31:0] intr_state;
initial begin
ribp.valid = 1'b0;
ribp.addr = '0;
ribp.wdata = '0;
ribp.wstrb = '0;
repeat (4) @(posedge clk_i);
rst_n_i = 1'b1;
ribp_read(32'h0000_00F8, value, 1'b0);
if (value != 32'h0002_0000) $fatal(1, "unexpected timer version %h", value);
ribp_read(32'h0000_00FC, value, 1'b0);
if (value != 32'h00F2_1020) $fatal(1, "unexpected timer capability %h", value);
ribp_read(32'h0000_0100, value, 1'b1);
if (value != 32'd0) $fatal(1, "invalid read did not return zero");
ribp_read(32'h0000_0002, value, 1'b1);
ribp_write(32'h0000_0008, 32'h1234_5678, 4'hF, 1'b1);
ribp_read(32'h0000_002C, value, 1'b1);
ribp_write(32'h0000_0000, 32'h0000_0006, 4'hF, 1'b1);
// Free-running mode wraps naturally and stops without changing its value.
ribp_write(32'h0000_0000, CTRL_ENABLE, 4'hF, 1'b0);
repeat (6) @(posedge clk_i);
ribp_read(32'h0000_0008, value, 1'b0);
if (value == 32'd0) $fatal(1, "free-running timer did not advance");
ribp_write(32'h0000_0000, 32'd0, 4'hF, 1'b0);
// Up-counting periodic mode with both compare channels.
ribp_write(32'h0000_0010, 32'd1, 4'hF, 1'b0);
ribp_write(32'h0000_0014, 32'd1, 4'hF, 1'b0);
ribp_write(32'h0000_0018, 32'd2, 4'hF, 1'b0);
ribp_write(32'h0000_0004, 32'd3, 4'hF, 1'b0);
ribp_write(32'h0000_0024, 32'h0000_0007, 4'hF, 1'b0);
ribp_write(32'h0000_0000, CTRL_ENABLE | CTRL_PERIODIC | CTRL_COMPARE_ENABLE, 4'hF, 1'b0);
ribp_write(32'h0000_0010, 32'd0, 4'hF, 1'b1);
repeat (12) @(posedge clk_i);
ribp_read(32'h0000_0020, intr_state, 1'b0);
if (intr_state[2:0] != 3'b111 || !irq_o) begin
$fatal(1, "periodic compare/timeout state invalid: %h irq=%b", intr_state, irq_o);
end
ribp_write(32'h0000_0020, 32'h0000_0007, 4'h1, 1'b0);
ribp_write(32'h0000_0000, CTRL_PERIODIC | CTRL_COMPARE_ENABLE, 4'hF, 1'b0);
// Down-counting one-shot stops at zero and leaves a sticky timeout.
ribp_write(32'h0000_0004, 32'd2, 4'hF, 1'b0);
ribp_write(32'h0000_0020, 32'h0000_0007, 4'h1, 1'b0);
ribp_write(32'h0000_0000, CTRL_ENABLE | CTRL_ONE_SHOT | CTRL_DIRECTION_DOWN, 4'hF, 1'b0);
wait_inactive();
ribp_read(32'h0000_0008, value, 1'b0);
ribp_read(32'h0000_0020, intr_state, 1'b0);
if (value != 32'd0 || !intr_state[0]) begin
$fatal(1, "one-shot completion invalid value=%h state=%h", value, intr_state);
end
// Background load updates the next down-counting period without an immediate reload.
ribp_write(32'h0000_0020, 32'h0000_0007, 4'h1, 1'b0);
ribp_write(32'h0000_0004, 32'd5, 4'hF, 1'b0);
ribp_write(32'h0000_0010, 32'd3, 4'hF, 1'b0);
ribp_write(32'h0000_0000, CTRL_ENABLE | CTRL_PERIODIC | CTRL_DIRECTION_DOWN, 4'hF, 1'b0);
ribp_read(32'h0000_0008, value, 1'b0);
ribp_write(32'h0000_000C, 32'd1, 4'hF, 1'b0);
ribp_read(32'h0000_0008, frozen_value, 1'b0);
if (frozen_value == 32'd1) $fatal(1, "BGLOAD changed the live counter immediately");
repeat (32) @(posedge clk_i);
ribp_read(32'h0000_0008, value, 1'b0);
if (value > 32'd1) $fatal(1, "BGLOAD was not used by the next period: %h", value);
ribp_write(32'h0000_0000, CTRL_PERIODIC | CTRL_DIRECTION_DOWN, 4'hF, 1'b0);
// Debug freeze stops both prescaler and counter while keeping RIBP readable.
ribp_write(32'h0000_0004, 32'd20, 4'hF, 1'b0);
ribp_write(32'h0000_0010, 32'd0, 4'hF, 1'b0);
ribp_write(32'h0000_0000, CTRL_ENABLE | CTRL_PERIODIC | CTRL_DEBUG_FREEZE, 4'hF, 1'b0);
debug_halted_i = 1'b1;
repeat (2) @(posedge clk_i);
ribp_read(32'h0000_0008, frozen_value, 1'b0);
repeat (8) @(posedge clk_i);
ribp_read(32'h0000_0008, value, 1'b0);
ribp_read(32'h0000_001C, status, 1'b0);
if (value != frozen_value || status[1:0] != 2'b11) begin
$fatal(1, "debug freeze invalid before=%h after=%h status=%h", frozen_value, value, status);
end
debug_halted_i = 1'b0;
repeat (4) @(posedge clk_i);
ribp_read(32'h0000_0008, value, 1'b0);
if (value == frozen_value) $fatal(1, "timer did not resume after debug halt");
// Software interrupt test and W1C clear.
ribp_write(32'h0000_002C, 32'h0000_0006, 4'h1, 1'b0);
ribp_read(32'h0000_0020, intr_state, 1'b0);
if ((intr_state[2:1] != 2'b11) || !irq_o) $fatal(1, "interrupt test failed");
ribp_write(32'h0000_0020, 32'h0000_0007, 4'h1, 1'b0);
$display("RIBP Timer V2 register, mode, interrupt, and error test passed");
$finish;
end
endmodule
+60
View File
@@ -0,0 +1,60 @@
"""RIBP Timer V2 RTL regression tests."""
from __future__ import annotations
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PERIPHERAL = ROOT / "rtl/ip/ribp/peripheral"
def test_timer_modes_interrupts_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"
source_list = tmp_path / "timer.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{common / 'utils'}",
f"+incdir+{common / 'clkrst'}",
f"+incdir+{PERIPHERAL}",
str(common / "interface/ribp_if.sv"),
str(common / "utils/register.sv"),
str(common / "clkrst/counter.sv"),
str(PERIPHERAL / "timer_core.sv"),
str(PERIPHERAL / "timer_reg.sv"),
str(PERIPHERAL / "ribp_timer.sv"),
str(ROOT / "tests/rtl/timer_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "timer_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 / "timer_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "timer_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "RIBP Timer V2 register, mode, interrupt, and error test passed" in result.stdout