feat: add CLINT peripheral support and related enhancements

- Updated the formal file list generator to include CLINT source files.
- Added CLINT timebase to the clock and reset domains configuration.
- Enhanced the SOC topology generation to include CLINT interrupts and their mappings.
- Introduced a new CLINT testbench to validate multi-hart and timebase functionality.
- Modified the software build configuration to define CLINT timebase frequency.
- Updated the RCU module to integrate CLINT timebase generation.
- Adjusted the IRQ configuration to reflect changes in CLINT interrupt signals.
- Added user-visible flags for interrupts in the topology configuration.
- Enhanced the clock reset domain checks to include CLINT timebase.
- Updated the memory map tests to validate CLINT peripheral integration.
This commit is contained in:
maksyuki committed 2026-08-08 13:31:48 +08:00
1 parent 3aa3d937e1
commit 4b40dbf262
55 files changed
+1706 -956

No files matched your search

+23 -3
View File
@@ -41,6 +41,8 @@ HAVE_SRAM_MACRO ?= NO
PDK_BEHAV ?= NO
HAVE_SVA ?= NO
JTAG_IDCODE ?= DEADBEEF
EXT_CLK_HZ ?= 72000000
CLINT_TIMEBASE_HZ ?= 1000000
WAVE ?= NO
FORMAL ?= NO
VCS_USE_LSF ?= YES
@@ -80,7 +82,8 @@ JOBS ?= $(shell count=$$(nproc 2>/dev/null || printf '1'); \
if [ "$$count" -gt "$(MAX_JOBS)" ]; then printf '%s' '$(MAX_JOBS)'; \
else printf '%s' "$$count"; fi)
CONFIG_KEY_VARS := SOC PDK HAVE_PLL HAVE_SRAM_IF HAVE_SRAM_MACRO PDK_BEHAV HAVE_SVA \
JTAG_IDCODE ISA HAVE_CSR APP LINK_TYPE COREMARK_MODE RTL_TOP FIRMWARE_NAME
JTAG_IDCODE EXT_CLK_HZ CLINT_TIMEBASE_HZ ISA HAVE_CSR APP LINK_TYPE \
COREMARK_MODE RTL_TOP FIRMWARE_NAME
VARIANT_ID := $(strip $(shell $(VCS_SHELL_PYTHON) $(ROOT_PATH)/scripts/config_key.py \
--lock $(LOCK_FILE) --profile $(PROFILE_NAME) --timestamp $(BUILD_TIMESTAMP) \
$(foreach var,$(CONFIG_KEY_VARS),--value $(var)=$($(var))) | tail -n 1))
@@ -145,6 +148,20 @@ endif
JTAG_IDCODE_DEC := $(shell value=$$(printf '%u' 0x$(JTAG_IDCODE)); \
if [ $$value -gt 2147483647 ]; then echo $$((value - 4294967296)); else echo $$value; fi)
EXT_CLK_HZ_VALID := $(shell printf '%s' '$(EXT_CLK_HZ)' | grep -E '^[1-9][[:digit:]]*$$')
ifneq ($(EXT_CLK_HZ_VALID),$(EXT_CLK_HZ))
$(error EXT_CLK_HZ='$(EXT_CLK_HZ)' must be a positive integer)
endif
CLINT_TIMEBASE_HZ_VALID := $(shell printf '%s' '$(CLINT_TIMEBASE_HZ)' | grep -E '^[1-9][[:digit:]]*$$')
ifneq ($(CLINT_TIMEBASE_HZ_VALID),$(CLINT_TIMEBASE_HZ))
$(error CLINT_TIMEBASE_HZ='$(CLINT_TIMEBASE_HZ)' must be a positive integer)
endif
CLINT_TIMEBASE_RATIO_VALID := $(shell if [ '$(EXT_CLK_HZ)' -ge '$(CLINT_TIMEBASE_HZ)' ] && \
[ $$(( $(EXT_CLK_HZ) % $(CLINT_TIMEBASE_HZ) )) -eq 0 ]; then printf YES; fi)
ifneq ($(CLINT_TIMEBASE_RATIO_VALID),YES)
$(error EXT_CLK_HZ must be an integer multiple of CLINT_TIMEBASE_HZ)
endif
ifneq ($(filter benchmark-report,$(MAKECMDGOALS)),)
ifneq ($(APP),benchmark)
$(error benchmark-report requires APP=benchmark)
@@ -178,6 +195,8 @@ endif
DEF_LIST ?= +define+PDK_$(PDK)
DEF_LIST += +define+SIMU_$(SIMU)
DEF_LIST += +define+SOC_JTAG_IDCODE=$(JTAG_IDCODE_DEC)
DEF_LIST += +define+SOC_EXT_CLK_HZ=$(EXT_CLK_HZ)
DEF_LIST += +define+SOC_CLINT_TIMEBASE_HZ=$(CLINT_TIMEBASE_HZ)
ifeq ($(HAVE_PLL), YES)
ifneq ($(filter $(PDK),GF180 SKY130),)
@@ -261,7 +280,7 @@ help:
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
' formal | formal-bus | formal-rib-adapter | formal-rib2apb run SBY protocol proofs' \
' formal-sysctrl | formal-pll-rcu | formal-gpio-user | formal-ws2812 | formal-timer run peripheral proofs' \
' formal-sysctrl | formal-pll-rcu | formal-gpio-user | formal-ws2812 | formal-timer | formal-clint run peripheral proofs' \
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
' benchmark-report run the memory/DMA profile and write meta/performance.json' \
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
@@ -294,7 +313,8 @@ config:
VCS_USE_LSF '$(VCS_USE_LSF)' PDK '$(PDK)' \
HAVE_PLL '$(HAVE_PLL)' HAVE_SRAM_IF '$(HAVE_SRAM_IF)' \
HAVE_SRAM_MACRO '$(HAVE_SRAM_MACRO)' PDK_BEHAV '$(PDK_BEHAV)' HAVE_SVA '$(HAVE_SVA)' \
JTAG_IDCODE '$(JTAG_IDCODE)' \
JTAG_IDCODE '$(JTAG_IDCODE)' EXT_CLK_HZ '$(EXT_CLK_HZ)' \
CLINT_TIMEBASE_HZ '$(CLINT_TIMEBASE_HZ)' \
ISA '$(ISA)' HAVE_CSR '$(HAVE_CSR)' APP '$(APP)' \
LINK_TYPE '$(LINK_TYPE)' COREMARK_MODE '$(COREMARK_MODE)'
+35 -3
View File
@@ -1,4 +1,5 @@
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/clint.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/hal/uart.h>
#include <retrosoc/lib/printf.h>
@@ -13,6 +14,34 @@ static bool rs_ci_smoke_archinfo_matches_reset_values(void) {
(archinfo_idh == UINT32_C(0x00FFFFFF));
}
static bool rs_ci_smoke_clint_standard_map(void) {
uint64_t first;
uint64_t current;
uint64_t compare;
bool pending;
if (rs_clint_get_time(&first) != RS_OK) {
return false;
}
current = first;
for (rs_timeout_t timeout = 512U; (timeout != 0U) && (current == first); --timeout) {
if (rs_clint_get_time(&current) != RS_OK) {
return false;
}
}
if ((current <= first) || (rs_clint_set_compare(0U, current + UINT64_C(1000)) != RS_OK) ||
(rs_clint_get_compare(0U, &compare) != RS_OK) || (compare != (current + UINT64_C(1000)))) {
return false;
}
if ((rs_clint_set_software_interrupt(0U, true) != RS_OK) ||
(rs_clint_get_software_interrupt(0U, &pending) != RS_OK) || !pending ||
(rs_clint_set_software_interrupt(0U, false) != RS_OK) ||
(rs_clint_get_software_interrupt(0U, &pending) != RS_OK) || pending) {
return false;
}
return rs_clint_set_compare(0U, UINT64_MAX) == RS_OK;
}
static bool rs_ci_smoke_timer_one_shot(void) {
const rs_timer_config_t config = {
.mode = RS_TIMER_MODE_ONE_SHOT,
@@ -88,14 +117,17 @@ int main(void) {
if (!rs_ci_smoke_archinfo_matches_reset_values()) {
rs_test_finish(RS_TEST_FAILED, 1U);
}
if (!rs_ci_smoke_timer_one_shot()) {
if (!rs_ci_smoke_clint_standard_map()) {
rs_test_finish(RS_TEST_FAILED, 2U);
}
if (!rs_ci_smoke_timer_periodic()) {
if (!rs_ci_smoke_timer_one_shot()) {
rs_test_finish(RS_TEST_FAILED, 3U);
}
if (!rs_ci_smoke_timer_periodic()) {
rs_test_finish(RS_TEST_FAILED, 4U);
}
printf("ci_smoke: archinfo and timer tests passed\n");
printf("ci_smoke: archinfo, CLINT, and timer tests passed\n");
rs_test_finish(RS_TEST_PASSED, 0U);
return 0;
}
@@ -1,12 +1,14 @@
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := YES
APP := coremark
COREMARK_MODE := standard
LINK_TYPE := ld2_all_sram
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := YES
APP := coremark
COREMARK_MODE := standard
LINK_TYPE := ld2_all_sram
+14 -12
View File
@@ -1,12 +1,14 @@
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := YES
APP := coremark
COREMARK_MODE := quick
LINK_TYPE := ld2_all_sram
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := YES
APP := coremark
COREMARK_MODE := quick
LINK_TYPE := ld2_all_sram
+13 -11
View File
@@ -1,11 +1,13 @@
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := benchmark
LINK_TYPE := ld2_sram
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := benchmark
LINK_TYPE := ld2_sram
+12 -10
View File
@@ -1,10 +1,12 @@
SOC := MINI
PDK := GF180
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
SOC := MINI
PDK := GF180
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
+12 -10
View File
@@ -1,10 +1,12 @@
SOC := MINI
PDK := ICS55
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
SOC := MINI
PDK := ICS55
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
+14 -12
View File
@@ -1,12 +1,14 @@
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := debug
FIRMWARE_NAME := retrosoc_debug
LINK_TYPE := ld2_sram
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := YES
HAVE_SRAM_MACRO := YES
PDK_BEHAV := YES
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := debug
FIRMWARE_NAME := retrosoc_debug
LINK_TYPE := ld2_sram
+12 -10
View File
@@ -1,10 +1,12 @@
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := YES
APP := shell
LINK_TYPE := ld2_psram
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := YES
APP := shell
LINK_TYPE := ld2_psram
+12 -10
View File
@@ -1,10 +1,12 @@
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
SOC := MINI
PDK := IHP130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
+12 -10
View File
@@ -1,10 +1,12 @@
SOC := MINI
PDK := SKY130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
SOC := MINI
PDK := SKY130
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
+12 -10
View File
@@ -1,10 +1,12 @@
SOC := MINI
PDK := ICS55
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
SOC := MINI
PDK := ICS55
HAVE_PLL := NO
HAVE_SRAM_IF := NO
HAVE_SRAM_MACRO := NO
HAVE_SVA := NO
EXT_CLK_HZ := 72000000
CLINT_TIMEBASE_HZ := 1000000
ISA := RV32IM
HAVE_CSR := NO
APP := bringup
LINK_TYPE := ld2_psram
@@ -1,218 +0,0 @@
/*
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// -- 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 __SYSTEM_TIMER_H__
#define __SYSTEM_TIMER_H__
#include <retrosoc/arch/riscv/system_gcc.h>
#include <retrosoc/arch/riscv/system_base.h>
typedef struct {
__IOM uint64_t mtime;
__IOM uint64_t mtimecmp;
__IOM uint32_t msip;
__IOM uint32_t clkdiv;
} SysTimer_Type;
/* Timer Control / Status Register Definitions */
#define SysTimer_MSIP_MSIP_POS 0U /*!< SysTick Timer msip: msip bit Position */
#define SysTimer_MSIP_MSIP_MASK \
(1UL << SysTimer_MSIP_MSIP_POS) /*!< SysTick Timer msip: msip Mask */
#define SysTimer_MTIMER_MASK (0xFFFFFFFFFFFFFFFFULL) /*!< SysTick Timer MTIMER value Mask */
#define SysTimer_MTIMERCMP_MASK (0xFFFFFFFFFFFFFFFFULL) /*!< SysTick Timer MTIMERCMP value Mask */
#define SysTimer_MSIP_MASK (0xFFFFFFFFUL) /*!< SysTick Timer msip value Mask */
#define __SYSTIMER_BASEADDR 0x1000C000
#ifndef __SYSTIMER_BASEADDR
/* Base address of SYSTIMER(__SYSTIMER_BASEADDR) should be defined in <Device.h> */
#error "__SYSTIMER_BASEADDR is not defined, please check!"
#endif
/* System Timer Memory mapping of Device */
#define SysTimer_BASE __SYSTIMER_BASEADDR /*!< SysTick Base Address */
#define SysTimer ((SysTimer_Type *)SysTimer_BASE) /*!< SysTick configuration struct */
/**
* \defgroup NMSIS_Core_SysTimer SysTimer Functions
* \brief Functions that configure the Core System Timer.
* @{
*/
/**
* \brief Set system timer load value
* \details
* This function set the system timer load value in MTIMER register.
* \param [in] value value to set system timer MTIMER register.
* \remarks
* - Load value is 64bits wide.
* - \ref SysTimer_GetLoadValue
*/
__STATIC_FORCEINLINE void SysTimer_SetMtimeValue(uint64_t value) {
SysTimer->mtime = value;
}
/**
* \brief Get system timer load value
* \details
* This function get the system timer current value in MTIMER register.
* \return current value(64bit) of system timer MTIMER register.
* \remarks
* - Load value is 64bits wide.
* - \ref SysTimer_SetLoadValue
*/
__STATIC_FORCEINLINE uint64_t SysTimer_GetMtimeValue(void) {
return SysTimer->mtime;
}
/**
* \brief Set system timer compare value
* \details
* This function set the system Timer compare value in MTIMERCMP register.
* \param [in] value compare value to set system timer MTIMERCMP register.
* \remarks
* - Compare value is 64bits wide.
* - If compare value is larger than current value timer interrupt generate.
* - Modify the load value or compare value less to clear the interrupt.
* - \ref SysTimer_GetCompareValue
*/
__STATIC_FORCEINLINE void SysTimer_SetMtimecmpValue(uint64_t value) {
SysTimer->mtimecmp = value;
}
/**
* \brief Get system timer compare value
* \details
* This function get the system timer compare value in MTIMERCMP register.
* \return compare value of system timer MTIMERCMP register.
* \remarks
* - Compare value is 64bits wide.
* - \ref SysTimer_SetCompareValue
*/
__STATIC_FORCEINLINE uint64_t SysTimer_GetMtimecmpValue(void) {
return SysTimer->mtimecmp;
}
/**
* \brief Trigger or set software interrupt via system timer
* \details
* This function set the system timer MSIP bit in MSIP register.
* \remarks
* - Set system timer MSIP bit and generate a SW interrupt.
* - \ref SysTimer_ClearSWIRQ
* - \ref SysTimer_GetMsipValue
*/
__STATIC_FORCEINLINE void SysTimer_SetSoftwareIRQ(void) {
SysTimer->msip |= SysTimer_MSIP_MSIP_MASK;
}
/**
* \brief Clear system timer software interrupt pending request
* \details
* This function clear the system timer MSIP bit in MSIP register.
* \remarks
* - Clear system timer MSIP bit in MSIP register to clear the software interrupt pending.
* - \ref SysTimer_SetSWIRQ
* - \ref SysTimer_GetMsipValue
*/
__STATIC_FORCEINLINE void SysTimer_ClearSoftwareIRQ(void) {
SysTimer->msip &= ~SysTimer_MSIP_MSIP_MASK;
}
/**
* \brief Get system timer MSIP register value
* \details
* This function get the system timer MSIP register value.
* \return Value of Timer MSIP register.
* \remarks
* - Bit0 is SW interrupt flag.
* Bit0 is 1 then SW interrupt set. Bit0 is 0 then SW interrupt clear.
* - \ref SysTimer_SetSWIRQ
* - \ref SysTimer_ClearSWIRQ
*/
__STATIC_FORCEINLINE uint32_t SysTimer_GetMsipValue(void) {
return (uint32_t)(SysTimer->msip & SysTimer_MSIP_MASK);
}
/**
* \brief Set system timer MSIP register value
* \details
* This function set the system timer MSIP register value.
* \param [in] msip value to set MSIP register
*/
__STATIC_FORCEINLINE void SysTimer_SetMsipValue(uint32_t msip) {
SysTimer->msip = (msip & SysTimer_MSIP_MASK);
}
/**
* \brief System Tick Configuration
* \details Initializes the System Timer and its non-vector interrupt, and starts the System Tick
* Timer.
*
* In our default implementation, the timer counter will be set to zero, and it will start a timer
* compare non-vector interrupt when it matchs the ticks user set, during the timer interrupt user
* should reload the system tick using \ref SysTick_Reload function or similar function written by
* user, so it can produce period timer interrupt. \param [in] ticks Number of ticks between two
* interrupts. \return 0 Function succeeded. \return 1 Function failed. \sa
* - \ref SysTimer_SetCompareValue; SysTimer_SetLoadValue
*/
__STATIC_INLINE uint32_t SysTick_Config(uint64_t ticks) {
SysTimer_SetMtimeValue(0);
SysTimer_SetMtimecmpValue(ticks);
__enable_timer_irq();
return (0UL);
}
/**
* \brief System Tick Reload
* \details Reload the System Timer Tick when the MTIMECMP reached TIME value
*
* \param [in] ticks Number of ticks between two interrupts.
* \return 0 Function succeeded.
* \return 1 Function failed.
* \sa
* - \ref SysTimer_SetCompareValue
* - \ref SysTimer_SetLoadValue
*/
__STATIC_FORCEINLINE uint32_t SysTick_Reload(uint64_t ticks) {
uint64_t cur_ticks = SysTimer->mtime;
uint64_t reload_ticks = ticks + cur_ticks;
if (__USUALLY(reload_ticks > cur_ticks)) {
SysTimer->mtimecmp = reload_ticks;
} else {
/* When added the ticks value, then the MTIMERCMP < TIMER,
* which means the MTIMERCMP is overflowed,
* so we need to reset the counter to zero */
SysTimer->mtime = 0;
SysTimer->mtimecmp = ticks;
}
return (0UL);
}
#endif
-7
View File
@@ -204,13 +204,6 @@
#define RS_SOC_PERF_CTRL_ENABLE UINT32_C(0x00000001)
#define RS_SOC_PERF_CTRL_CLEAR UINT32_C(0x00000002)
#define RS_SOC_PERF_CTRL_SNAPSHOT UINT32_C(0x00000004)
// clint
#define reg_clint_mtimel RS_SOC_REG32(RS_SOC_RIBP_CLINT_BASE, UINT32_C(0x00))
#define reg_clint_mtimeh RS_SOC_REG32(RS_SOC_RIBP_CLINT_BASE, UINT32_C(0x04))
#define reg_clint_mtimecmpl RS_SOC_REG32(RS_SOC_RIBP_CLINT_BASE, UINT32_C(0x08))
#define reg_clint_mtimecmph RS_SOC_REG32(RS_SOC_RIBP_CLINT_BASE, UINT32_C(0x0C))
#define reg_clint_msip RS_SOC_REG32(RS_SOC_RIBP_CLINT_BASE, UINT32_C(0x10))
#define reg_clint_clkdiv RS_SOC_REG32(RS_SOC_RIBP_CLINT_BASE, UINT32_C(0x14))
// sdram
#define reg_sdram_clkdiv RS_SOC_REG32(RS_SOC_RIBP_SDRAM_BASE, UINT32_C(0x00))
#define reg_sdram_cfg RS_SOC_REG32(RS_SOC_RIBP_SDRAM_BASE, UINT32_C(0x04))
+22
View File
@@ -0,0 +1,22 @@
#ifndef RETROSOC_HAL_CLINT_H
#define RETROSOC_HAL_CLINT_H
#include <stdbool.h>
#include <stdint.h>
#include <retrosoc/core/status.h>
#define RS_CLINT_HART_COUNT UINT32_C(1)
#ifndef RS_CLINT_TIMEBASE_HZ
#define RS_CLINT_TIMEBASE_HZ UINT32_C(1000000)
#endif
rs_status_t rs_clint_get_time(uint64_t *time);
rs_status_t rs_clint_set_time(uint64_t time);
rs_status_t rs_clint_get_compare(uint32_t hart, uint64_t *compare);
rs_status_t rs_clint_set_compare(uint32_t hart, uint64_t compare);
rs_status_t rs_clint_get_software_interrupt(uint32_t hart, bool *pending);
rs_status_t rs_clint_set_software_interrupt(uint32_t hart, bool pending);
#endif
+16 -8
View File
@@ -1,11 +1,11 @@
#include <retrosoc/arch/riscv/system_base.h>
#include <retrosoc/arch/riscv/system_csr.h>
#include <retrosoc/arch/riscv/system_timer.h>
#include <retrosoc/core/irq.h>
#include <retrosoc/hal/clint.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/lib/printf.h>
#define RS_TIMER_DELTA_VALUE 360000UL
#define RS_TIMER_DELTA_VALUE (RS_CLINT_TIMEBASE_HZ / UINT32_C(200))
#define RS_IRQ_TEST_TIMEOUT_MS 6000U
static volatile uint32_t timer_irq_count;
@@ -18,14 +18,15 @@ static void rs_timer_irq_handler(uintptr_t mcause, uintptr_t stack_pointer) {
(void)mcause;
(void)stack_pointer;
++timer_irq_count;
now = SysTimer_GetMtimeValue();
SysTimer_SetMtimecmpValue(now + RS_TIMER_DELTA_VALUE);
if (rs_clint_get_time(&now) == RS_OK) {
(void)rs_clint_set_compare(0U, now + RS_TIMER_DELTA_VALUE);
}
}
static void rs_software_irq_handler(uintptr_t mcause, uintptr_t stack_pointer) {
(void)mcause;
(void)stack_pointer;
SysTimer_ClearSoftwareIRQ();
(void)rs_clint_set_software_interrupt(0U, false);
++software_irq_count;
software_irq_ready = 1U;
}
@@ -56,8 +57,12 @@ void irq_test(int argc, char **argv) {
return;
}
__enable_irq();
now = SysTimer_GetMtimeValue();
SysTimer_SetMtimecmpValue(now + RS_TIMER_DELTA_VALUE);
if ((rs_clint_get_time(&now) != RS_OK) ||
(rs_clint_set_compare(0U, now + RS_TIMER_DELTA_VALUE) != RS_OK)) {
printf("unable to configure machine timer\n");
__disable_core_irq(IRQ_M_TIMER);
return;
}
if (rs_irq_wait_for_count(&timer_irq_count, 6U) != RS_OK) {
printf("timer irq timed out\n");
@@ -76,7 +81,10 @@ void irq_test(int argc, char **argv) {
return;
}
software_irq_ready = 0U;
SysTimer_SetSoftwareIRQ();
if (rs_clint_set_software_interrupt(0U, true) != RS_OK) {
printf("unable to trigger software irq\n");
return;
}
if (rs_irq_wait_for_count(&software_irq_count, attempt + 1U) != RS_OK) {
printf("software irq timed out\n");
return;
+93
View File
@@ -0,0 +1,93 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/clint.h>
#define RS_CLINT_MSIP_OFFSET UINT32_C(0x0000)
#define RS_CLINT_MTIMECMP_OFFSET UINT32_C(0x4000)
#define RS_CLINT_MTIME_OFFSET UINT32_C(0xBFF8)
#define RS_CLINT_MSIP_STRIDE UINT32_C(4)
#define RS_CLINT_MTIMECMP_STRIDE UINT32_C(8)
#define RS_CLINT_HIGH_WORD_OFFSET UINT32_C(4)
#define RS_CLINT_SNAPSHOT_ATTEMPTS UINT32_C(4)
#define RS_CLINT_SOFTWARE_IRQ_PENDING UINT32_C(1)
static volatile uint32_t *rs_clint_register(uint32_t offset) {
return (volatile uint32_t *)(uintptr_t)(RS_SOC_RIBP_CLINT_BASE + offset);
}
static bool rs_clint_hart_valid(uint32_t hart) {
return hart < RS_CLINT_HART_COUNT;
}
static rs_status_t rs_clint_read64(uint32_t offset, uint64_t *value) {
uint32_t high_before;
uint32_t low;
uint32_t high_after;
if (value == NULL) {
return RS_EINVAL;
}
for (uint32_t attempt = 0U; attempt < RS_CLINT_SNAPSHOT_ATTEMPTS; ++attempt) {
high_before = *rs_clint_register(offset + RS_CLINT_HIGH_WORD_OFFSET);
low = *rs_clint_register(offset);
high_after = *rs_clint_register(offset + RS_CLINT_HIGH_WORD_OFFSET);
if (high_before == high_after) {
*value = ((uint64_t)high_after << 32U) | (uint64_t)low;
return RS_OK;
}
}
return RS_ETIMEOUT;
}
rs_status_t rs_clint_get_time(uint64_t *time) {
return rs_clint_read64(RS_CLINT_MTIME_OFFSET, time);
}
rs_status_t rs_clint_set_time(uint64_t time) {
*rs_clint_register(RS_CLINT_MTIME_OFFSET + RS_CLINT_HIGH_WORD_OFFSET) = (uint32_t)(time >> 32U);
*rs_clint_register(RS_CLINT_MTIME_OFFSET) = (uint32_t)time;
return RS_OK;
}
rs_status_t rs_clint_get_compare(uint32_t hart, uint64_t *compare) {
if (!rs_clint_hart_valid(hart)) {
return RS_EINVAL;
}
return rs_clint_read64(RS_CLINT_MTIMECMP_OFFSET + (hart * RS_CLINT_MTIMECMP_STRIDE), compare);
}
rs_status_t rs_clint_set_compare(uint32_t hart, uint64_t compare) {
uint32_t offset;
if (!rs_clint_hart_valid(hart)) {
return RS_EINVAL;
}
offset = RS_CLINT_MTIMECMP_OFFSET + (hart * RS_CLINT_MTIMECMP_STRIDE);
*rs_clint_register(offset) = UINT32_MAX;
*rs_clint_register(offset + RS_CLINT_HIGH_WORD_OFFSET) = (uint32_t)(compare >> 32U);
*rs_clint_register(offset) = (uint32_t)compare;
return RS_OK;
}
rs_status_t rs_clint_get_software_interrupt(uint32_t hart, bool *pending) {
uint32_t offset;
if (!rs_clint_hart_valid(hart) || (pending == NULL)) {
return RS_EINVAL;
}
offset = RS_CLINT_MSIP_OFFSET + (hart * RS_CLINT_MSIP_STRIDE);
*pending = (*rs_clint_register(offset) & RS_CLINT_SOFTWARE_IRQ_PENDING) != 0U;
return RS_OK;
}
rs_status_t rs_clint_set_software_interrupt(uint32_t hart, bool pending) {
uint32_t offset;
if (!rs_clint_hart_valid(hart)) {
return RS_EINVAL;
}
offset = RS_CLINT_MSIP_OFFSET + (hart * RS_CLINT_MSIP_STRIDE);
*rs_clint_register(offset) = pending ? RS_CLINT_SOFTWARE_IRQ_PENDING : 0U;
return RS_OK;
}
+2 -1
View File
@@ -107,7 +107,8 @@ void rs_app_info(void) {
printf(" 1 x XPI @%p\n", (void *)&reg_xpi_cfgidx);
printf(" 1 x DMA @%p\n", (void *)&reg_dma_mode);
printf(" 1 x SYSCTRL @%p\n", (void *)&reg_sysctrl_coresel);
printf(" 1 x CLINT @%p\n", (void *)&reg_clint_mtimel);
printf(" 1 x CLINT @%p\n",
(void *)(uintptr_t)RS_SOC_RIBP_CLINT_BASE);
printf(" 1 x SDRAM @%p\n", (void *)&reg_sdram_clkdiv);
printf(" 1 x DVP @%p\n", (void *)&reg_dvp_recven);
printf(" 1 x I2C1 @%p\n", (void *)&reg_i2c1_clkdiv);
+4 -5
View File
@@ -16,17 +16,16 @@ the root README and subsystem guides.
- [coremark.md](coremark.md) defines the SRAM-resident Hazard3 CoreMark quick
measurement, optional standard hardware run, and structured result format.
- [soc-family-positioning.md](soc-family-positioning.md) defines the planned
Tiny, Mini, Std, and Pro product ladder, target capabilities, claim gates,
and commercial reference points.
- [mini-product-positioning.md](mini-product-positioning.md) separates the
implemented Mini baseline from the planned VexiiRiscv Linux product target
and its commercial reference points.
Tiny, Mini, Std, and Pro product ladder, the implemented Mini baseline,
planned product targets, claim gates, and commercial reference points.
- [rib-interconnect.md](rib-interconnect.md) defines the RIB v1 linear-burst
contract, compatibility boundaries, target status, and verification.
- [ip/ws2812.md](ip/ws2812.md) defines the WS2812 transmitter register ABI,
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.
- [ip/clint.md](ip/clint.md) defines the standard CLINT register map, fixed
timebase, RV32 access rules, interrupt behavior, and verification contract.
- [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated
pin-map workflow and SoC integration boundary.
- [mini-soc-block-diagram.svg](mini-soc-block-diagram.svg) is the Mini SoC
+1
View File
@@ -5,6 +5,7 @@ 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.
- [clint.md](clint.md) defines the management-hart software and timer interrupt block.
The corresponding RTL and HAL implementations remain the executable sources
of truth. Update the affected document whenever an IP interface or register ABI
+80
View File
@@ -0,0 +1,80 @@
# Core-Local Interruptor
The Mini SoC CLINT provides machine software and machine timer interrupts for
the management hart. Its register layout follows the conventional SiFive
CLINT and RISC-V ACLINT-compatible offsets, while its bus-facing logic uses the
retroSoC RIBP target protocol.
## Integration
| Property | Value |
| --- | --- |
| RIBP base address | `0x10020000` |
| RIBP aperture | 64 KiB |
| Implemented Mini SoC harts | 1 management hart |
| RTL hart parameter range | 1 through 4095 |
| Timebase frequency | 1 MHz |
| Management-core interrupts | software IRQ 0, timer IRQ 1 |
| User-core access | denied by the RIB access policy |
| User-core interrupt visibility | masked |
The timebase divider runs from the buffered external reference clock, not the
PLL-selected system clock. A toggle crosses into the system domain through the
Common `edge_det` synchronizer and produces one system-clock pulse per
microsecond. Consequently, changing the PLL frequency does not change the
meaning of an `mtime` tick. `EXT_CLK_HZ` must be an integer multiple of
`CLINT_TIMEBASE_HZ`; committed profiles use 72 MHz and 1 MHz respectively.
## Register ABI
All implemented registers are 32-bit aligned RIBP accesses. Unmapped,
unimplemented-hart, and unaligned accesses complete with `resp_err` and read as
zero. Partial writes use byte strobes. The Mini SoC implements hart 0; the RTL
array dimensions and address decoder are parameterized for additional harts.
| Offset | Name | Access | Reset | Description |
| --- | --- | --- | --- | --- |
| `0x0000 + 4 * hart` | `MSIP` | RW | 0 | Bit 0 controls the hart machine software interrupt. |
| `0x4000 + 8 * hart` | `MTIMECMP_LO` | RW | all ones | Low half of the 64-bit timer comparison value. |
| `0x4004 + 8 * hart` | `MTIMECMP_HI` | RW | all ones | High half of the 64-bit timer comparison value. |
| `0xBFF8` | `MTIME_LO` | RW | 0 | Low half of the shared 64-bit time counter. |
| `0xBFFC` | `MTIME_HI` | RW | 0 | High half of the shared 64-bit time counter. |
The timer interrupt for hart `n` is asserted when `mtime >= mtimecmp[n]` and is
deasserted after software moves the comparison into the future. The registered
interrupt output adds one system-clock cycle of latency. Resetting
`mtimecmp` to all ones prevents an unintended interrupt at reset.
## RV32 Software Contract
The public `<retrosoc/hal/clint.h>` API avoids C 64-bit volatile accesses,
which are not atomic on RV32. Time and comparison reads use a bounded
high-low-high sequence and retry if the high word rolls over. Comparison
writes use the recommended low-all-ones, high, low sequence so an intermediate
value cannot spuriously assert the timer interrupt.
Writing `mtime` itself is inherently non-atomic on a 32-bit bus. Software that
changes it must first prevent concurrent timer handling and account for the
global discontinuity. Normal scheduling code should leave `mtime` running and
only update `mtimecmp`.
## Verification and Current Scope
The self-checking RTL test instantiates two harts and covers reset values,
standard offsets, independent software interrupts, timer comparison, `mtime`
writes, byte strobes, invalid accesses, and synchronized reference-clock
ticks. The SBY target proves bounded RIBP response, `mtime` load/tick/hold
priority, registered timer interrupt behavior, and reaches software interrupt,
timer interrupt, write-time, and error paths. The `ci_smoke` firmware checks
the standard map through the public HAL before completing the normal SoC boot
test.
The current Mini integration does not implement supervisor timer comparison,
multiple privilege domains, or per-hart access filtering inside CLINT. Adding
those features should use the RISC-V ACLINT MTIMER and MSWI split-device model
and a versioned SoC integration update.
The register layout and machine interrupt behavior follow the RISC-V
[machine timer requirements](https://docs.riscv.org/reference/isa/priv/machine.html),
the conventional [SiFive E31 CLINT map](https://starfivetech.com/uploads/e31_core_complex_manual_21G1.pdf),
and the [RISC-V ACLINT specification](https://github.com/riscvarchive/riscv-aclint/blob/main/riscv-aclint.adoc).
-126
View File
@@ -1,126 +0,0 @@
# retroSoC Mini Product Positioning
## Status
retroSoC Mini is currently an open-source RISC-V microcontroller-class SoC
with a fixed Hazard3 management core and one software-selected user core. This
document also defines a planned Linux-capable configuration built around a
32-bit VexiiRiscv user core. The VexiiRiscv integration and Linux boot flow are
product targets, not supported repository configurations yet.
Mini is the price, complexity, and Linux-capability anchor for the planned
[retroSoC product family](soc-family-positioning.md). Tiny removes the Linux
and external-DRAM requirements for low-power MCU use, while Std adds RV32
performance and efficiency cores, full AXI4 memory transport, and graphical
and AI acceleration. Pro is the only planned RV64 tier.
The target product position is a low-cost, heterogeneous, 32-bit RISC-V Linux
control SoC for embedded control, compact human-machine interfaces, gateways,
and retro multimedia systems. It is not intended to compete with general-purpose
Linux application processors that require RV64, cache-coherent multiprocessing,
or high-bandwidth DDR interfaces.
## Current Mini Baseline
The current executable RTL and generated integration inputs define these
capabilities:
- A fixed Hazard3 management core owns system control and has a permanent JTAG
Debug Module.
- The C0-C5 extension fabric permits one selected user core to run at a time.
- SYSCTRL controls user-core selection, reset, interrupt admission, and bus
admission. A stop request blocks new user transactions, drains an accepted
transaction, and then asserts reset.
- The canonical address map exposes 128 KiB of on-chip SRAM, a 32 MiB SDRAM
window, and an 8 MiB PSRAM window. Address-window capacity does not guarantee
that every implementation includes the corresponding physical memory.
- RIB v1 is a 32-bit interconnect with `INCR1` and aligned four-word `INCR4`
transfers and one outstanding transaction per master.
- Current external-memory targets serialize an accepted RIB burst into ordered
scalar RIBP accesses. They do not yet combine an `INCR4` request into a native
SDRAM, PSRAM, or flash streaming transaction.
The generated address map, user-extension map, and
[RIB protocol contract](rib-interconnect.md) remain the executable sources of
truth for the implemented baseline.
## Planned Linux Configuration
The Linux configuration keeps Hazard3 as the always-available trusted
management core and adds VexiiRiscv as the application processor. Hazard3 is
responsible for clock and memory initialization, image selection, VexiiRiscv
boot release, fault recovery, and final power-state control. Linux must not be
able to reconfigure the management-core lifecycle controls.
The initial VexiiRiscv configuration should provide:
- RV32IMAC with machine, supervisor, and user modes.
- Sv32 virtual memory, hardware page-table walking, and the privileged CSRs
required by the supported Linux kernel.
- LR/SC atomics, separate 16 KiB instruction and data caches, and uncached MMIO
regions.
- A PLIC-compatible external interrupt controller, CLINT-compatible timer and
software interrupts, and a deterministic reset vector.
- A documented DMA cache-maintenance contract unless the memory system supplies
hardware coherency.
The management firmware initializes external memory, verifies and places the
OpenSBI firmware, device tree, kernel, and initial filesystem, programs the
VexiiRiscv entry point, and then enables its bus access and releases reset. A
normal stop first requests Linux shutdown through a mailbox. After Linux
acknowledges and flushes persistent data, the management core disables new bus
transactions, drains the final accepted transaction, and asserts reset. A
bounded timeout permits fault recovery through forced isolation and reset.
## Product Targets
The following values define a useful commercial target rather than an
implemented or cross-PDK guarantee:
| Area | Minimum target | Preferred target |
| --- | --- | --- |
| VexiiRiscv frequency | 150 MHz | PDK-qualified maximum above 150 MHz |
| Main memory | 64 MiB SDRAM | 128 MiB SDRAM |
| L1 caches | 16 KiB I-cache and 16 KiB D-cache | Same, with measured refill and DMA behavior |
| Memory transport | Native cache-line burst | Native burst with two to four outstanding transactions per master |
| Boot storage | SPI NAND or qualified SDIO path | SDIO/eMMC plus recovery image |
| Linux platform devices | UART, timer, interrupt controller, storage | Ethernet or USB selected by the product profile |
Meeting these targets requires enlarging the current 32 MiB SDRAM address
window and replacing the scalar external-memory bottleneck. A dedicated memory
fabric may evolve independently while RIBP and APB remain the stable peripheral
register interfaces. Frequency claims must be qualified separately for each
PDK and physical implementation.
## Commercial Reference Points
The products below are reference points along different axes. None is a
pin-compatible or performance-equivalent substitute for retroSoC Mini.
| Commercial SoC | Relevant architecture | Comparison with the planned Mini |
| --- | --- | --- |
| [Bouffalo Lab BL808](https://github.com/bouffalolab/bl808_linux) | RISC-V Linux application core with separate MCU and low-power cores | Closest RISC-V heterogeneous architecture; substantially stronger wireless, multimedia, memory, and application-core capability |
| [NXP i.MX 7ULP](https://www.nxp.com/products/i.MX7ULP) | Cortex-A7 Linux core and Cortex-M4 system master with boot and power-control responsibilities | Closest commercial lifecycle-control model; a much larger application-processor platform |
| [ST STM32MP151](https://www.st.com/en/microcontrollers-microprocessors/stm32mp151a.html) | Single Cortex-A7 Linux core and Cortex-M4 real-time core | Useful industrial heterogeneous-MPU reference; DDR, cache, interconnect, and peripheral capabilities are substantially higher |
| [CV1800B and SG2002](https://milkv.io/docs/duo/overview) | Two RISC-V application-class cores supporting Linux and real-time workloads, with 64 or 256 MiB SiP memory | Closest low-cost dual-system RISC-V market reference; 64-bit cores and multimedia acceleration place it above Mini |
| [Allwinner F133](https://www.allwinnertech.com/index.php?c=product&id=101) | RV64 C906 Linux processor with 64 MiB SiP DDR and display/video functions | Direct low-cost RISC-V Linux market reference without the same independent management-core model |
| [Allwinner F1C200s](https://www.allwinnertech.com/uploads/pdf/201812181725033b.pdf) | 32-bit ARM9 Linux processor with 64 MiB SiP DDR in a compact package | Closest cost, memory, and lightweight-Linux application reference, but without a separate management core |
| [Ingenic X1000/X1000E](https://www.ingenic.com.cn/products-detail/id-50.html) | 32-bit MIPS Linux processor with 32 or 64 MiB LPDDR and fast-boot positioning | Comparable low-power Linux product segment with much higher CPU frequency and a mature multimedia subsystem |
| [Espressif ESP32-P4](https://docs.espressif.com/projects/esp-techpedia/en/latest/esp-friends/get-started/board-selection.html) | Dual 32-bit RISC-V high-performance cores and a low-power core | Relevant core-topology and power-control reference, but not a direct general-purpose MMU Linux competitor |
Commercial information and links in this table were checked on 2026-08-06.
Specifications can change and must be revalidated before being used in product,
cost, or performance claims.
## Positioning Summary
The closest architectural reference points are BL808 and i.MX 7ULP. The
closest cost and lightweight-Linux reference is F1C200s, while F133 and
CV1800B represent the nearest commercial RISC-V Linux market. ESP32-P4 is a
control-topology reference rather than a Linux performance reference.
After the Linux configuration meets the memory and interconnect targets above,
retroSoC Mini should be positioned between F1C200s and BL808: less capable than
modern 64-bit multimedia SoCs, but differentiated by open RTL and explicit
management-core control over Linux-core boot, bus admission, shutdown, and
fault recovery.
+10 -3
View File
@@ -61,7 +61,7 @@ digraph mini_soc_block_diagram {
rcu [
fillcolor="#EDE9FE",
label="RCU\nclock buffering and reset synchronization\nPLL request/acknowledgment CDC"
label="RCU\nclock buffering and reset synchronization\nPLL CDC and fixed 1 MHz timebase"
];
subgraph cluster_soc {
@@ -120,7 +120,11 @@ digraph mini_soc_block_diagram {
];
sysctrl [
fillcolor="#F9E1E7",
label="SYSCTRL and CLINT\nPLL, user-core select/reset/bus enable\nfault and performance control"
label="SYSCTRL\nPLL, user-core select/reset/bus enable\nfault and performance control"
];
clint [
fillcolor="#F9E1E7",
label="CLINT\nstandard 64 KiB register map\nmtime, mtimecmp and MSIP"
];
ribp_targets [
fillcolor="#F9E1E7",
@@ -153,7 +157,7 @@ digraph mini_soc_block_diagram {
{ rank=same; user_core; dma; }
{ rank=same; fault; fabric; sram; }
{ rank=same; ribp_adapter; apb_adapter; }
{ rank=same; sysctrl; ribp_targets; timers; ws2812; apb_targets; }
{ rank=same; sysctrl; clint; ribp_targets; timers; ws2812; apb_targets; }
{ rank=same; gpio_bridge; irq; }
ext_clock -> rcu [label="clock / reset"];
@@ -164,6 +168,7 @@ digraph mini_soc_block_diagram {
debug_module -> mgmt_core [label="halt, resume, abstract commands"];
debug_module -> mgmt_adapter [label="reset after bridge idle", style=dashed];
debug_module -> timers [label="halted", style=dashed];
rcu -> clint [label="1 MHz tick", style=dashed];
mgmt_core -> mgmt_adapter [label="RIBP"];
mgmt_adapter -> fabric [label="RIB"];
@@ -175,6 +180,7 @@ digraph mini_soc_block_diagram {
fabric -> ribp_adapter [label="RIB"];
fabric -> apb_adapter [label="RIB"];
ribp_adapter -> sysctrl [label="RIBP"];
ribp_adapter -> clint [label="RIBP"];
ribp_adapter -> ribp_targets [label="RIBP"];
ribp_adapter -> timers [label="RIBP"];
ribp_adapter -> ws2812 [label="RIBP"];
@@ -182,6 +188,7 @@ digraph mini_soc_block_diagram {
ribp_targets -> gpio_bridge [label="GPIO alternate functions"];
timers -> irq [label="IRQ3 / IRQ4"];
clint -> irq [label="machine IRQ0 / IRQ1"];
ws2812 -> gpio_bridge [label="GPIO2 ALT1"];
dma -> ws2812 [label="TXDATA writes", style=dashed];
ws2812 -> irq [label="IRQ17"];
+222 -193
View File
@@ -4,19 +4,19 @@
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: mini_soc_block_diagram Pages: 1 -->
<svg width="1546pt" height="887pt"
viewBox="0.00 0.00 1546.00 887.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="1719pt" height="887pt"
viewBox="0.00 0.00 1719.00 887.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 883.48)">
<title>mini_soc_block_diagram</title>
<text text-anchor="middle" x="132" y="-861.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text>
<g id="clust1" class="cluster">
<title>cluster_asic</title>
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 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"/>
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 1691,-85 1691,-85 1697,-85 1703,-91 1703,-97 1703,-97 1703,-763.48 1703,-763.48 1703,-769.48 1697,-775.48 1691,-775.48 1691,-775.48 160,-775.48 160,-775.48 154,-775.48 148,-769.48 148,-763.48 148,-763.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
<text text-anchor="middle" x="196.5" y="-760.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text>
</g>
<g id="clust2" class="cluster">
<title>cluster_soc</title>
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 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"/>
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 1673,-103 1673,-103 1679,-103 1685,-109 1685,-115 1685,-115 1685,-720.48 1685,-720.48 1685,-726.48 1679,-732.48 1673,-732.48 1673,-732.48 390,-732.48 390,-732.48 384,-732.48 378,-726.48 378,-720.48 378,-720.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
<text text-anchor="middle" x="407.5" y="-718.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
</g>
<!-- ext_clock -->
@@ -32,7 +32,7 @@
<path fill="#ede9fe" stroke="#4b5563" stroke-width="1.1" d="M350,-574.48C350,-574.48 178,-574.48 178,-574.48 172,-574.48 166,-568.48 166,-562.48 166,-562.48 166,-541.48 166,-541.48 166,-535.48 172,-529.48 178,-529.48 178,-529.48 350,-529.48 350,-529.48 356,-529.48 362,-535.48 362,-541.48 362,-541.48 362,-562.48 362,-562.48 362,-568.48 356,-574.48 350,-574.48"/>
<text text-anchor="middle" x="264" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">RCU</text>
<text text-anchor="middle" x="264" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">clock buffering and reset synchronization</text>
<text text-anchor="middle" x="264" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PLL request/acknowledgment CDC</text>
<text text-anchor="middle" x="264" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PLL CDC and fixed 1 MHz timebase</text>
</g>
<!-- ext_clock&#45;&gt;rcu -->
<g id="edge1" class="edge">
@@ -44,342 +44,371 @@
<!-- ext_io -->
<g id="node2" class="node">
<title>ext_io</title>
<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="1161" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</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="1161" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M1557,-45C1557,-45 1365,-45 1365,-45 1359,-45 1353,-39 1353,-33 1353,-33 1353,-12 1353,-12 1353,-6 1359,0 1365,0 1365,0 1557,0 1557,0 1563,0 1569,-6 1569,-12 1569,-12 1569,-33 1569,-33 1569,-39 1563,-45 1557,-45"/>
<text text-anchor="middle" x="1461" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
<text text-anchor="middle" x="1461" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
<text text-anchor="middle" x="1461" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
</g>
<!-- ext_jtag -->
<g id="node3" class="node">
<title>ext_jtag</title>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="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="684" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</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>
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M678.5,-851.48C678.5,-851.48 547.5,-851.48 547.5,-851.48 541.5,-851.48 535.5,-845.48 535.5,-839.48 535.5,-839.48 535.5,-827.48 535.5,-827.48 535.5,-821.48 541.5,-815.48 547.5,-815.48 547.5,-815.48 678.5,-815.48 678.5,-815.48 684.5,-815.48 690.5,-821.48 690.5,-827.48 690.5,-827.48 690.5,-839.48 690.5,-839.48 690.5,-845.48 684.5,-851.48 678.5,-851.48"/>
<text text-anchor="middle" x="613" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
<text text-anchor="middle" x="613" y="-825.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text>
</g>
<!-- jtag_dtm -->
<g id="node6" class="node">
<title>jtag_dtm</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="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="684" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</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>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M688,-669.98C688,-669.98 538,-669.98 538,-669.98 532,-669.98 526,-663.98 526,-657.98 526,-657.98 526,-645.98 526,-645.98 526,-639.98 532,-633.98 538,-633.98 538,-633.98 688,-633.98 688,-633.98 694,-633.98 700,-639.98 700,-645.98 700,-645.98 700,-657.98 700,-657.98 700,-663.98 694,-669.98 688,-669.98"/>
<text text-anchor="middle" x="613" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
<text text-anchor="middle" x="613" y="-643.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
</g>
<!-- ext_jtag&#45;&gt;jtag_dtm -->
<g id="edge2" class="edge">
<title>ext_jtag&#45;&gt;jtag_dtm</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M684,-815.27C684,-783.24 684,-714.39 684,-677.51"/>
<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="704" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M613,-815.27C613,-783.24 613,-714.39 613,-677.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="615.45,-677.14 613,-670.14 610.55,-677.14 615.45,-677.14"/>
<text text-anchor="middle" x="633" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
</g>
<!-- fabric -->
<g id="node11" class="node">
<title>fabric</title>
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="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="642" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</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="642" y="-424.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M1066.66,-442.31C1066.66,-442.31 998.98,-470.16 998.98,-470.16 993.43,-472.45 981.88,-474.73 975.88,-474.73 975.88,-474.73 820.12,-474.73 820.12,-474.73 814.12,-474.73 802.57,-472.45 797.02,-470.16 797.02,-470.16 729.34,-442.31 729.34,-442.31 723.79,-440.03 723.79,-435.46 729.34,-433.18 729.34,-433.18 797.02,-405.32 797.02,-405.32 802.57,-403.04 814.12,-400.76 820.12,-400.76 820.12,-400.76 975.88,-400.76 975.88,-400.76 981.88,-400.76 993.43,-403.04 998.98,-405.32 998.98,-405.32 1066.66,-433.18 1066.66,-433.18 1072.21,-435.46 1072.21,-440.03 1066.66,-442.31"/>
<text text-anchor="middle" x="898" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
<text text-anchor="middle" x="898" 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="898" y="-424.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
</g>
<!-- rcu&#45;&gt;fabric -->
<g id="edge3" class="edge">
<title>rcu&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="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="532.72,-473.75 538.74,-469.41 531.33,-469.05 532.72,-473.75"/>
<text text-anchor="middle" x="476" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M362.03,-531.47C368.2,-530.24 372,-529.48 372,-529.48 372,-529.48 697,-474.48 697,-474.48 697,-474.48 728.7,-468.85 766.93,-462.05"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="767.67,-464.41 774.14,-460.77 766.82,-459.58 767.67,-464.41"/>
<text text-anchor="middle" x="588" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
</g>
<!-- clint -->
<g id="node17" class="node">
<title>clint</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M527.5,-255C527.5,-255 406.5,-255 406.5,-255 400.5,-255 394.5,-249 394.5,-243 394.5,-243 394.5,-222 394.5,-222 394.5,-216 400.5,-210 406.5,-210 406.5,-210 527.5,-210 527.5,-210 533.5,-210 539.5,-216 539.5,-222 539.5,-222 539.5,-243 539.5,-243 539.5,-249 533.5,-255 527.5,-255"/>
<text text-anchor="middle" x="467" y="-241" font-family="Arial" font-size="10.00" fill="#111827">CLINT</text>
<text text-anchor="middle" x="467" y="-230" font-family="Arial" font-size="10.00" fill="#111827">standard 64 KiB register map</text>
<text text-anchor="middle" x="467" y="-219" font-family="Arial" font-size="10.00" fill="#111827">mtime, mtimecmp and MSIP</text>
</g>
<!-- rcu&#45;&gt;clint -->
<g id="edge8" class="edge">
<title>rcu&#45;&gt;clint</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M277.95,-529.16C313.89,-472.95 409.6,-323.28 449.33,-261.14"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="451.51,-262.27 453.22,-255.05 447.38,-259.63 451.51,-262.27"/>
<text text-anchor="middle" x="397.5" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">1 MHz tick</text>
</g>
<!-- mgmt_core -->
<g id="node5" class="node">
<title>mgmt_core</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="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="887" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</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="887" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1273,-674.48C1273,-674.48 1119,-674.48 1119,-674.48 1113,-674.48 1107,-668.48 1107,-662.48 1107,-662.48 1107,-641.48 1107,-641.48 1107,-635.48 1113,-629.48 1119,-629.48 1119,-629.48 1273,-629.48 1273,-629.48 1279,-629.48 1285,-635.48 1285,-641.48 1285,-641.48 1285,-662.48 1285,-662.48 1285,-668.48 1279,-674.48 1273,-674.48"/>
<text text-anchor="middle" x="1196" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
<text text-anchor="middle" x="1196" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
<text text-anchor="middle" x="1196" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
</g>
<!-- mgmt_adapter -->
<g id="node8" class="node">
<title>mgmt_adapter</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="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="887" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1216.5,-569.98C1216.5,-569.98 1175.5,-569.98 1175.5,-569.98 1169.5,-569.98 1163.5,-563.98 1163.5,-557.98 1163.5,-557.98 1163.5,-545.98 1163.5,-545.98 1163.5,-539.98 1169.5,-533.98 1175.5,-533.98 1175.5,-533.98 1216.5,-533.98 1216.5,-533.98 1222.5,-533.98 1228.5,-539.98 1228.5,-545.98 1228.5,-545.98 1228.5,-557.98 1228.5,-557.98 1228.5,-563.98 1222.5,-569.98 1216.5,-569.98"/>
<text text-anchor="middle" x="1196" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
</g>
<!-- mgmt_core&#45;&gt;mgmt_adapter -->
<g id="edge8" class="edge">
<g id="edge9" class="edge">
<title>mgmt_core&#45;&gt;mgmt_adapter</title>
<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="889.45,-577.12 887,-570.12 884.55,-577.12 889.45,-577.12"/>
<text text-anchor="middle" x="896.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1196,-629.24C1196,-613.92 1196,-593.4 1196,-577.51"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1198.45,-577.12 1196,-570.12 1193.55,-577.12 1198.45,-577.12"/>
<text text-anchor="middle" x="1205.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- debug_module -->
<g id="node7" class="node">
<title>debug_module</title>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="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="1194" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</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="1194" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">management&#45;hart&#45;only reset</text>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M949.5,-674.48C949.5,-674.48 828.5,-674.48 828.5,-674.48 822.5,-674.48 816.5,-668.48 816.5,-662.48 816.5,-662.48 816.5,-641.48 816.5,-641.48 816.5,-635.48 822.5,-629.48 828.5,-629.48 828.5,-629.48 949.5,-629.48 949.5,-629.48 955.5,-629.48 961.5,-635.48 961.5,-641.48 961.5,-641.48 961.5,-662.48 961.5,-662.48 961.5,-668.48 955.5,-674.48 949.5,-674.48"/>
<text text-anchor="middle" x="889" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
<text text-anchor="middle" x="889" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
<text text-anchor="middle" x="889" y="-638.48" font-family="Arial" font-size="10.00" fill="#111827">management&#45;hart&#45;only reset</text>
</g>
<!-- jtag_dtm&#45;&gt;debug_module -->
<g id="edge4" class="edge">
<title>jtag_dtm&#45;&gt;debug_module</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="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="1143.55,-679.82 1148.73,-674.51 1141.37,-675.44 1143.55,-679.82"/>
<text text-anchor="middle" x="946" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M700.33,-651.98C735.12,-651.98 774.91,-651.98 808.95,-651.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="809.12,-654.43 816.12,-651.98 809.12,-649.53 809.12,-654.43"/>
<text text-anchor="middle" x="758.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
</g>
<!-- debug_module&#45;&gt;mgmt_core -->
<g id="edge5" class="edge">
<title>debug_module&#45;&gt;mgmt_core</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="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="983.21,-649.53 976.21,-651.98 983.21,-654.43 983.21,-649.53"/>
<text text-anchor="middle" x="1048.75" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M961.75,-651.98C1002.99,-651.98 1055.09,-651.98 1099.69,-651.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1099.77,-654.43 1106.77,-651.98 1099.77,-649.53 1099.77,-654.43"/>
<text text-anchor="middle" x="1034.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
</g>
<!-- debug_module&#45;&gt;mgmt_adapter -->
<g id="edge6" class="edge">
<title>debug_module&#45;&gt;mgmt_adapter</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="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="927.21,-563.25 919.79,-563.45 925.72,-567.92 927.21,-563.25"/>
<text text-anchor="middle" x="1087" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M961.7,-629.68C1038.93,-607.04 1150,-574.48 1150,-574.48 1150,-574.48 1152.57,-573.29 1156.49,-571.45"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1157.75,-573.56 1163.06,-568.38 1155.68,-569.13 1157.75,-573.56"/>
<text text-anchor="middle" x="1103" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
</g>
<!-- timers -->
<g id="node18" class="node">
<g id="node19" 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>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M759.5,-255C759.5,-255 578.5,-255 578.5,-255 572.5,-255 566.5,-249 566.5,-243 566.5,-243 566.5,-222 566.5,-222 566.5,-216 572.5,-210 578.5,-210 578.5,-210 759.5,-210 759.5,-210 765.5,-210 771.5,-216 771.5,-222 771.5,-222 771.5,-243 771.5,-243 771.5,-249 765.5,-255 759.5,-255"/>
<text text-anchor="middle" x="669" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
<text text-anchor="middle" x="669" 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="669" 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>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M840.72,-629.48C775.96,-600.63 669,-552.98 669,-552.98 669,-552.98 669,-552.98 669,-327 669,-327 669,-289.76 669,-262.28"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="671.45,-262.19 669,-255.19 666.55,-262.19 671.45,-262.19"/>
<text text-anchor="middle" x="680" y="-435.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
</g>
<!-- mgmt_adapter&#45;&gt;fabric -->
<g id="edge9" class="edge">
<g id="edge10" class="edge">
<title>mgmt_adapter&#45;&gt;fabric</title>
<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="727.49,-475.21 720.11,-474.53 725.45,-479.67 727.49,-475.21"/>
<text text-anchor="middle" x="793" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1177.65,-533.76C1160.99,-518.12 1139,-497.48 1139,-497.48 1139,-497.48 1077.55,-482.51 1016.71,-467.68"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1017.06,-465.24 1009.68,-465.96 1015.9,-470 1017.06,-465.24"/>
<text text-anchor="middle" x="1155" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- user_core -->
<g id="node9" class="node">
<title>user_core</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M680,-574.48C680,-574.48 604,-574.48 604,-574.48 598,-574.48 592,-568.48 592,-562.48 592,-562.48 592,-541.48 592,-541.48 592,-535.48 598,-529.48 604,-529.48 604,-529.48 680,-529.48 680,-529.48 686,-529.48 692,-535.48 692,-541.48 692,-541.48 692,-562.48 692,-562.48 692,-568.48 686,-574.48 680,-574.48"/>
<text text-anchor="middle" x="642" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="642" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text>
<text text-anchor="middle" x="642" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1124,-574.48C1124,-574.48 1048,-574.48 1048,-574.48 1042,-574.48 1036,-568.48 1036,-562.48 1036,-562.48 1036,-541.48 1036,-541.48 1036,-535.48 1042,-529.48 1048,-529.48 1048,-529.48 1124,-529.48 1124,-529.48 1130,-529.48 1136,-535.48 1136,-541.48 1136,-541.48 1136,-562.48 1136,-562.48 1136,-568.48 1130,-574.48 1124,-574.48"/>
<text text-anchor="middle" x="1086" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="1086" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text>
<text text-anchor="middle" x="1086" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
</g>
<!-- user_core&#45;&gt;fabric -->
<g id="edge10" class="edge">
<g id="edge11" class="edge">
<title>user_core&#45;&gt;fabric</title>
<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="644.45,-481.89 642,-474.89 639.55,-481.89 644.45,-481.89"/>
<text text-anchor="middle" x="649" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1102.11,-529.26C1110.49,-517.96 1119,-506.48 1119,-506.48 1119,-506.48 1119,-497.48 1119,-497.48 1119,-497.48 1066.59,-483.55 1012.81,-469.26"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1013.3,-466.86 1005.91,-467.43 1012.05,-471.59 1013.3,-466.86"/>
<text text-anchor="middle" x="1126" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- dma -->
<g id="node10" class="node">
<title>dma</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="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="1138" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</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>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1487,-569.98C1487,-569.98 1369,-569.98 1369,-569.98 1363,-569.98 1357,-563.98 1357,-557.98 1357,-557.98 1357,-545.98 1357,-545.98 1357,-539.98 1363,-533.98 1369,-533.98 1369,-533.98 1487,-533.98 1487,-533.98 1493,-533.98 1499,-539.98 1499,-545.98 1499,-545.98 1499,-557.98 1499,-557.98 1499,-563.98 1493,-569.98 1487,-569.98"/>
<text text-anchor="middle" x="1428" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
<text text-anchor="middle" x="1428" y="-543.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
</g>
<!-- dma&#45;&gt;fabric -->
<g id="edge11" class="edge">
<g id="edge12" class="edge">
<title>dma&#45;&gt;fabric</title>
<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="771.63,-460.5 764.3,-461.62 770.73,-465.32 771.63,-460.5"/>
<text text-anchor="middle" x="993" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1356.8,-535.91C1271.31,-517.8 1126.48,-487.13 1022.39,-465.08"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1022.63,-462.63 1015.28,-463.58 1021.62,-467.43 1022.63,-462.63"/>
<text text-anchor="middle" x="1217" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- ws2812 -->
<g id="node19" class="node">
<g id="node20" class="node">
<title>ws2812</title>
<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="1186" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</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="1186" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16&#45;word FIFO, IRQ17, DMA&#45;fed</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1400,-255C1400,-255 1266,-255 1266,-255 1260,-255 1254,-249 1254,-243 1254,-243 1254,-222 1254,-222 1254,-216 1260,-210 1266,-210 1266,-210 1400,-210 1400,-210 1406,-210 1412,-216 1412,-222 1412,-222 1412,-243 1412,-243 1412,-249 1406,-255 1400,-255"/>
<text text-anchor="middle" x="1333" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
<text text-anchor="middle" x="1333" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24&#45;bit MSB&#45;first serializer</text>
<text text-anchor="middle" x="1333" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16&#45;word FIFO, IRQ17, DMA&#45;fed</text>
</g>
<!-- dma&#45;&gt;ws2812 -->
<g id="edge24" class="edge">
<g id="edge27" class="edge">
<title>dma&#45;&gt;ws2812</title>
<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="1186.65,-262.45 1184.64,-255.31 1181.76,-262.15 1186.65,-262.45"/>
<text text-anchor="middle" x="1204.5" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1433.9,-533.63C1441.57,-511.05 1454,-474.48 1454,-474.48 1454,-474.48 1454,-401 1454,-401 1454,-401 1387.1,-308.39 1352.79,-260.89"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1354.66,-259.29 1348.57,-255.05 1350.68,-262.16 1354.66,-259.29"/>
<text text-anchor="middle" x="1463.5" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
</g>
<!-- fault -->
<g id="node12" class="node">
<title>fault</title>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="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="1091" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
<text text-anchor="middle" x="1091" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1278.5,-455.74C1278.5,-455.74 1169.5,-455.74 1169.5,-455.74 1163.5,-455.74 1157.5,-449.74 1157.5,-443.74 1157.5,-443.74 1157.5,-431.74 1157.5,-431.74 1157.5,-425.74 1163.5,-419.74 1169.5,-419.74 1169.5,-419.74 1278.5,-419.74 1278.5,-419.74 1284.5,-419.74 1290.5,-425.74 1290.5,-431.74 1290.5,-431.74 1290.5,-443.74 1290.5,-443.74 1290.5,-449.74 1284.5,-455.74 1278.5,-455.74"/>
<text text-anchor="middle" x="1224" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
<text text-anchor="middle" x="1224" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
</g>
<!-- fabric&#45;&gt;fault -->
<g id="edge12" class="edge">
<g id="edge13" class="edge">
<title>fabric&#45;&gt;fault</title>
<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="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="1046.13,-461.05 1051.47,-455.9 1044.08,-456.59 1046.13,-461.05"/>
<text text-anchor="middle" x="923" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1084.98,-437.74C1107.93,-437.74 1130.24,-437.74 1150.02,-437.74"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1084.69,-435.29 1077.69,-437.74 1084.69,-440.19 1084.69,-435.29"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1150.19,-440.19 1157.19,-437.74 1150.19,-435.29 1150.19,-440.19"/>
<text text-anchor="middle" x="1117.56" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
</g>
<!-- sram -->
<g id="node13" class="node">
<title>sram</title>
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="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="936" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On&#45;chip SRAM</text>
<text text-anchor="middle" x="936" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1428,-455.74C1428,-455.74 1330,-455.74 1330,-455.74 1324,-455.74 1318,-449.74 1318,-443.74 1318,-443.74 1318,-431.74 1318,-431.74 1318,-425.74 1324,-419.74 1330,-419.74 1330,-419.74 1428,-419.74 1428,-419.74 1434,-419.74 1440,-425.74 1440,-431.74 1440,-431.74 1440,-443.74 1440,-443.74 1440,-449.74 1434,-455.74 1428,-455.74"/>
<text text-anchor="middle" x="1379" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On&#45;chip SRAM</text>
<text text-anchor="middle" x="1379" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
</g>
<!-- fabric&#45;&gt;sram -->
<g id="edge13" class="edge">
<g id="edge14" class="edge">
<title>fabric&#45;&gt;sram</title>
<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="867.81,-440.19 874.81,-437.74 867.81,-435.29 867.81,-440.19"/>
<text text-anchor="middle" x="848.31" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1004.32,-468.06C1054.69,-482.42 1104,-496.48 1104,-496.48 1104,-496.48 1118,-496.48 1118,-496.48 1118,-496.48 1304,-474.48 1304,-474.48 1304,-474.48 1318.84,-467.21 1335.32,-459.14"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1336.73,-461.18 1341.94,-455.9 1334.58,-456.78 1336.73,-461.18"/>
<text text-anchor="middle" x="1111" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- ribp_adapter -->
<g id="node14" class="node">
<title>ribp_adapter</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="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="965" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1060.5,-346C1060.5,-346 1019.5,-346 1019.5,-346 1013.5,-346 1007.5,-340 1007.5,-334 1007.5,-334 1007.5,-322 1007.5,-322 1007.5,-316 1013.5,-310 1019.5,-310 1019.5,-310 1060.5,-310 1060.5,-310 1066.5,-310 1072.5,-316 1072.5,-322 1072.5,-322 1072.5,-334 1072.5,-334 1072.5,-340 1066.5,-346 1060.5,-346"/>
<text text-anchor="middle" x="1040" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
</g>
<!-- fabric&#45;&gt;ribp_adapter -->
<g id="edge14" class="edge">
<g id="edge15" class="edge">
<title>fabric&#45;&gt;ribp_adapter</title>
<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="926.52,-344.42 932.39,-339.88 924.97,-339.77 926.52,-344.42"/>
<text text-anchor="middle" x="848" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M945.28,-400.87C967.36,-384.11 992.9,-364.73 1011.89,-350.33"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1013.47,-352.2 1017.57,-346.02 1010.51,-348.3 1013.47,-352.2"/>
<text text-anchor="middle" x="992" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- apb_adapter -->
<g id="node15" class="node">
<title>apb_adapter</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="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="583" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
<text text-anchor="middle" x="583" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M938,-346C938,-346 868,-346 868,-346 862,-346 856,-340 856,-334 856,-334 856,-322 856,-322 856,-316 862,-310 868,-310 868,-310 938,-310 938,-310 944,-310 950,-316 950,-322 950,-322 950,-334 950,-334 950,-340 944,-346 938,-346"/>
<text text-anchor="middle" x="903" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
<text text-anchor="middle" x="903" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
</g>
<!-- fabric&#45;&gt;apb_adapter -->
<g id="edge15" class="edge">
<g id="edge16" class="edge">
<title>fabric&#45;&gt;apb_adapter</title>
<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="597.83,-350.98 592.32,-346.02 593.53,-353.34 597.83,-350.98"/>
<text text-anchor="middle" x="615" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M899.66,-400.87C900.39,-385.27 901.22,-367.39 901.87,-353.38"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="904.33,-353.13 902.21,-346.02 899.44,-352.9 904.33,-353.13"/>
<text text-anchor="middle" x="908" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
</g>
<!-- sysctrl -->
<g id="node16" class="node">
<title>sysctrl</title>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="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="730" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL and CLINT</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="730" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1215.5,-255C1215.5,-255 1052.5,-255 1052.5,-255 1046.5,-255 1040.5,-249 1040.5,-243 1040.5,-243 1040.5,-222 1040.5,-222 1040.5,-216 1046.5,-210 1052.5,-210 1052.5,-210 1215.5,-210 1215.5,-210 1221.5,-210 1227.5,-216 1227.5,-222 1227.5,-222 1227.5,-243 1227.5,-243 1227.5,-249 1221.5,-255 1215.5,-255"/>
<text text-anchor="middle" x="1134" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
<text text-anchor="middle" x="1134" 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="1134" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
</g>
<!-- ribp_adapter&#45;&gt;sysctrl -->
<g id="edge16" class="edge">
<g id="edge17" class="edge">
<title>ribp_adapter&#45;&gt;sysctrl</title>
<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="791.47,-255.32 784.06,-255.01 789.66,-259.87 791.47,-255.32"/>
<text text-anchor="middle" x="870.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1057.24,-309.85C1071.15,-296.02 1090.95,-276.32 1106.96,-260.39"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1109,-261.82 1112.24,-255.15 1105.54,-258.35 1109,-261.82"/>
<text text-anchor="middle" x="1096.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_adapter&#45;&gt;clint -->
<g id="edge18" class="edge">
<title>ribp_adapter&#45;&gt;clint</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1007.33,-319.69C986.73,-315.08 964,-310 964,-310 964,-310 553,-255 553,-255 553,-255 550.57,-254.39 546.54,-253.38"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="546.95,-250.96 539.56,-251.64 545.76,-255.72 546.95,-250.96"/>
<text text-anchor="middle" x="792.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_targets -->
<g id="node17" class="node">
<g id="node18" class="node">
<title>ribp_targets</title>
<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="965" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</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="965" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, I2C and I2S</text>
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1656.5,-255C1656.5,-255 1451.5,-255 1451.5,-255 1445.5,-255 1439.5,-249 1439.5,-243 1439.5,-243 1439.5,-222 1439.5,-222 1439.5,-216 1445.5,-210 1451.5,-210 1451.5,-210 1656.5,-210 1656.5,-210 1662.5,-210 1668.5,-216 1668.5,-222 1668.5,-222 1668.5,-243 1668.5,-243 1668.5,-249 1662.5,-255 1656.5,-255"/>
<text text-anchor="middle" x="1554" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
<text text-anchor="middle" x="1554" 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="1554" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, I2C and I2S</text>
</g>
<!-- ribp_adapter&#45;&gt;ribp_targets -->
<g id="edge17" class="edge">
<g id="edge19" class="edge">
<title>ribp_adapter&#45;&gt;ribp_targets</title>
<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="967.45,-262.15 965,-255.15 962.55,-262.15 967.45,-262.15"/>
<text text-anchor="middle" x="974.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1072.54,-321.08C1143.35,-308.2 1314.49,-277.07 1432.4,-255.62"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1432.94,-258.01 1439.39,-254.35 1432.06,-253.19 1432.94,-258.01"/>
<text text-anchor="middle" x="1306.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">
<g id="edge20" 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>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1007.42,-318.91C960.37,-307.22 879,-287 879,-287 879,-287 817,-271.21 760.38,-256.78"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="760.9,-254.38 753.51,-255.03 759.69,-259.13 760.9,-254.38"/>
<text text-anchor="middle" x="888.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- ribp_adapter&#45;&gt;ws2812 -->
<g id="edge19" class="edge">
<g id="edge21" class="edge">
<title>ribp_adapter&#45;&gt;ws2812</title>
<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="1129.31,-260.15 1134.8,-255.16 1127.4,-255.63 1129.31,-260.15"/>
<text text-anchor="middle" x="1084.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1072.76,-316.55C1117.4,-302.3 1198.65,-276.37 1258.52,-257.27"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1259.42,-259.55 1265.35,-255.09 1257.93,-254.88 1259.42,-259.55"/>
<text text-anchor="middle" x="1195.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
</g>
<!-- apb_targets -->
<g id="node20" class="node">
<g id="node21" class="node">
<title>apb_targets</title>
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M597.5,-255C597.5,-255 406.5,-255 406.5,-255 400.5,-255 394.5,-249 394.5,-243 394.5,-243 394.5,-222 394.5,-222 394.5,-216 400.5,-210 406.5,-210 406.5,-210 597.5,-210 597.5,-210 603.5,-210 609.5,-216 609.5,-222 609.5,-222 609.5,-243 609.5,-243 609.5,-249 603.5,-255 597.5,-255"/>
<text text-anchor="middle" x="502" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
<text text-anchor="middle" x="502" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
<text text-anchor="middle" x="502" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M1001.5,-255C1001.5,-255 810.5,-255 810.5,-255 804.5,-255 798.5,-249 798.5,-243 798.5,-243 798.5,-222 798.5,-222 798.5,-216 804.5,-210 810.5,-210 810.5,-210 1001.5,-210 1001.5,-210 1007.5,-210 1013.5,-216 1013.5,-222 1013.5,-222 1013.5,-243 1013.5,-243 1013.5,-249 1007.5,-255 1001.5,-255"/>
<text text-anchor="middle" x="906" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
<text text-anchor="middle" x="906" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
<text text-anchor="middle" x="906" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
</g>
<!-- apb_adapter&#45;&gt;apb_targets -->
<g id="edge20" class="edge">
<g id="edge22" class="edge">
<title>apb_adapter&#45;&gt;apb_targets</title>
<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="527.19,-258.84 520.75,-255.15 523.49,-262.04 527.19,-258.84"/>
<text text-anchor="middle" x="555" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
</g>
<!-- ribp_targets&#45;&gt;ext_io -->
<g id="edge27" class="edge">
<title>ribp_targets&#45;&gt;ext_io</title>
<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="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="1224.02,-45.25 1216.61,-45.01 1222.26,-49.82 1224.02,-45.25"/>
<text text-anchor="middle" x="1366" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
</g>
<!-- gpio_bridge -->
<g id="node21" class="node">
<title>gpio_bridge</title>
<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="963" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</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>
<!-- ribp_targets&#45;&gt;gpio_bridge -->
<g id="edge21" class="edge">
<title>ribp_targets&#45;&gt;gpio_bridge</title>
<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="965.97,-162.15 963.37,-155.2 961.07,-162.25 965.97,-162.15"/>
<text text-anchor="middle" x="1008" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M903.55,-309.85C903.97,-296.62 904.57,-278.02 905.07,-262.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="907.53,-262.22 905.31,-255.15 902.63,-262.07 907.53,-262.22"/>
<text text-anchor="middle" x="912" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
</g>
<!-- irq -->
<g id="node22" class="node">
<g id="node23" class="node">
<title>irq</title>
<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="1191" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</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>
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M772,-155C772,-155 566,-155 566,-155 560,-155 554,-149 554,-143 554,-143 554,-131 554,-131 554,-125 560,-119 566,-119 566,-119 772,-119 772,-119 778,-119 784,-125 784,-131 784,-131 784,-143 784,-143 784,-149 778,-155 772,-155"/>
<text text-anchor="middle" x="669" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
<text text-anchor="middle" x="669" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
</g>
<!-- clint&#45;&gt;irq -->
<g id="edge25" class="edge">
<title>clint&#45;&gt;irq</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M513.6,-209.93C547.35,-194.31 592.66,-173.34 625.64,-158.07"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="626.74,-160.26 632.06,-155.1 624.68,-155.81 626.74,-160.26"/>
<text text-anchor="middle" x="618.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">machine IRQ0 / IRQ1</text>
</g>
<!-- ribp_targets&#45;&gt;ext_io -->
<g id="edge30" class="edge">
<title>ribp_targets&#45;&gt;ext_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1541.78,-203.07C1536.28,-190.28 1531,-178 1531,-178 1531,-178 1494.07,-96.48 1473.85,-51.87"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1539.63,-204.28 1544.65,-209.74 1544.13,-202.34 1539.63,-204.28"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1476,-50.67 1470.88,-45.31 1471.54,-52.7 1476,-50.67"/>
<text text-anchor="middle" x="1550" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
</g>
<!-- gpio_bridge -->
<g id="node22" class="node">
<title>gpio_bridge</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1448,-155C1448,-155 1300,-155 1300,-155 1294,-155 1288,-149 1288,-143 1288,-143 1288,-131 1288,-131 1288,-125 1294,-119 1300,-119 1300,-119 1448,-119 1448,-119 1454,-119 1460,-125 1460,-131 1460,-131 1460,-143 1460,-143 1460,-149 1454,-155 1448,-155"/>
<text text-anchor="middle" x="1374" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
<text text-anchor="middle" x="1374" y="-129" font-family="Arial" font-size="10.00" fill="#111827">software, alternate and user modes</text>
</g>
<!-- ribp_targets&#45;&gt;gpio_bridge -->
<g id="edge23" class="edge">
<title>ribp_targets&#45;&gt;gpio_bridge</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1499.16,-209.9C1470.36,-198.56 1441,-187 1441,-187 1441,-187 1421.43,-172.69 1403.44,-159.53"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1404.53,-157.29 1397.43,-155.14 1401.64,-161.25 1404.53,-157.29"/>
<text text-anchor="middle" x="1485" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text>
</g>
<!-- timers&#45;&gt;irq -->
<g id="edge22" class="edge">
<g id="edge24" 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>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M669,-209.81C669,-195.66 669,-177.17 669,-162.49"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="671.45,-162.2 669,-155.2 666.55,-162.2 671.45,-162.2"/>
<text text-anchor="middle" x="691.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">
<g id="edge26" 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>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1341.95,-209.74C1348.04,-194.93 1355,-178 1355,-178 1355,-178 1358.68,-170.25 1362.8,-161.58"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1365.04,-162.57 1365.83,-155.2 1360.62,-160.47 1365.04,-162.57"/>
<text text-anchor="middle" x="1377.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
</g>
<!-- ws2812&#45;&gt;irq -->
<g id="edge25" class="edge">
<g id="edge28" class="edge">
<title>ws2812&#45;&gt;irq</title>
<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="1192.15,-162.32 1190.08,-155.2 1187.26,-162.06 1192.15,-162.32"/>
<text text-anchor="middle" x="1200" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1253.79,-212.99C1246.05,-211.18 1241,-210 1241,-210 1241,-210 959.53,-174.57 791.48,-153.42"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="791.32,-150.93 784.06,-152.48 790.7,-155.79 791.32,-150.93"/>
<text text-anchor="middle" x="1067" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
</g>
<!-- apb_targets&#45;&gt;gpio_bridge -->
<g id="edge26" class="edge">
<g id="edge29" class="edge">
<title>apb_targets&#45;&gt;gpio_bridge</title>
<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="872.59,-158.84 878.97,-155.04 871.62,-154.03 872.59,-158.84"/>
<text text-anchor="middle" x="778" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1013.66,-209.99C1094.75,-193.79 1204.75,-171.81 1281.8,-156.42"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1282.3,-158.82 1288.69,-155.04 1281.34,-154.01 1282.3,-158.82"/>
<text text-anchor="middle" x="1186" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
</g>
<!-- gpio_bridge&#45;&gt;ext_io -->
<g id="edge28" class="edge">
<g id="edge31" class="edge">
<title>gpio_bridge&#45;&gt;ext_io</title>
<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="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="1117.95,-50.78 1122.83,-45.19 1115.53,-46.52 1117.95,-50.78"/>
<text text-anchor="middle" x="1099" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1391.54,-113.32C1405.42,-95.37 1424.86,-70.24 1439.64,-51.12"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1389.56,-111.88 1387.21,-118.91 1393.43,-114.88 1389.56,-111.88"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1441.73,-52.43 1444.07,-45.39 1437.85,-49.43 1441.73,-52.43"/>
<text text-anchor="middle" x="1445" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 35 KiB

+125 -34
View File
@@ -38,40 +38,6 @@ Tiny is not a Mini with features disabled, and Std is not a Mini that merely
adds a GPU. Their memory systems, power targets, software contracts, and
verification requirements differ materially.
## Mini: Family Anchor
### Position
Mini is the low-cost, heterogeneous, 32-bit Linux control SoC in the family. It
targets industrial control, protocol gateways, compact human-machine
interfaces, and retro multimedia systems that need Linux but do not need a
desktop-class graphics pipeline. Hazard3 remains the trusted management core,
and one RV32 VexiiRiscv application core runs Linux.
The product target starts at 64 MiB of external SDRAM, with 128 MiB preferred.
A simple display controller or framebuffer is compatible with the Mini
position, but a 3D GPU, NPU, coherent multiprocessing, and a full graphical
desktop are deliberately outside the defining Mini requirements. This keeps
Mini below Std in memory bandwidth, software complexity, die area, and power.
The detailed current baseline, planned Linux boot flow, lifecycle controls, and
memory-transport gaps are defined in
[Mini Product Positioning](mini-product-positioning.md).
### Commercial Reference Points
| Commercial SoC | Relevant axis | Position relative to Mini |
| --- | --- | --- |
| [Allwinner F1C200s](https://www.allwinnertech.com/uploads/pdf/201812181725033b.pdf) | Compact, low-cost Linux device with 64 MiB SiP DDR | Closest cost and lightweight-Linux reference, without an independent management core |
| [Bouffalo Lab BL808](https://github.com/bouffalolab/bl808_linux) | RISC-V application, MCU, and low-power core domains | Closest heterogeneous RISC-V topology, but with much stronger wireless and multimedia integration |
| [NXP i.MX 7ULP](https://www.nxp.com/products/i.MX7ULP) | Linux application core plus an independently useful MCU domain | Strong lifecycle and power-domain reference, but a larger application-processor platform |
| [Allwinner F133](https://www.allwinnertech.com/index.php?c=product&id=101) | Low-cost RISC-V Linux with SiP memory and display functions | Direct RISC-V Linux market reference with more multimedia integration and no equivalent trusted management model |
Mini should be positioned between F1C200s and BL808 after it boots Linux from a
qualified external-memory path. It differentiates itself through open RTL and
explicit management-core authority, not through headline CPU or multimedia
performance.
## Tiny: Low-Power MCU and Edge Connectivity
### Position
@@ -128,6 +94,131 @@ Tiny-MCU should be compared primarily with RP2350 and lower-memory STM32U5
devices. Tiny-Connect should be compared with ESP32-H2; ESP32-C6 is the upper
feature reference when Wi-Fi is included.
## Mini: Family Anchor
### Status and Position
retroSoC Mini is currently an open-source RISC-V microcontroller-class SoC
with a fixed Hazard3 management core and one software-selected user core. The
planned Linux-capable configuration adds a 32-bit VexiiRiscv user core. The
VexiiRiscv integration and Linux boot flow are product targets, not supported
repository configurations yet.
Mini is the price, complexity, and Linux-capability anchor for the family. It
targets industrial control, protocol gateways, compact human-machine
interfaces, and retro multimedia systems that need Linux but do not need a
desktop-class graphics pipeline. Hazard3 remains the trusted management core,
and one RV32 VexiiRiscv application core runs Linux in the planned
configuration.
The product target starts at 64 MiB of external SDRAM, with 128 MiB preferred.
A simple display controller or framebuffer is compatible with the Mini
position, but a 3D GPU, NPU, coherent multiprocessing, and a full graphical
desktop are deliberately outside the defining Mini requirements. This keeps
Mini below Std in memory bandwidth, software complexity, die area, and power.
Mini is not intended to compete with general-purpose Linux application
processors that require RV64, cache-coherent multiprocessing, or
high-bandwidth DDR interfaces.
### Current Mini Baseline
The current executable RTL and generated integration inputs define these
capabilities:
- A fixed Hazard3 management core owns system control and has a permanent JTAG
Debug Module.
- The C0-C5 extension fabric permits one selected user core to run at a time.
- SYSCTRL controls user-core selection, reset, interrupt admission, and bus
admission. A stop request blocks new user transactions, drains an accepted
transaction, and then asserts reset.
- The canonical address map exposes 128 KiB of on-chip SRAM, a 32 MiB SDRAM
window, and an 8 MiB PSRAM window. Address-window capacity does not guarantee
that every implementation includes the corresponding physical memory.
- RIB v1 is a 32-bit interconnect with `INCR1` and aligned four-word `INCR4`
transfers and one outstanding transaction per master.
- Current external-memory targets serialize an accepted RIB burst into ordered
scalar RIBP accesses. They do not yet combine an `INCR4` request into a native
SDRAM, PSRAM, or flash streaming transaction.
The generated address map, user-extension map, and
[RIB protocol contract](rib-interconnect.md) remain the executable sources of
truth for the implemented baseline.
### Planned Linux Configuration
The Linux configuration keeps Hazard3 as the always-available trusted
management core and adds VexiiRiscv as the application processor. Hazard3 is
responsible for clock and memory initialization, image selection, VexiiRiscv
boot release, fault recovery, and final power-state control. Linux must not be
able to reconfigure the management-core lifecycle controls.
The initial VexiiRiscv configuration should provide:
- RV32IMAC with machine, supervisor, and user modes.
- Sv32 virtual memory, hardware page-table walking, and the privileged CSRs
required by the supported Linux kernel.
- LR/SC atomics, separate 16 KiB instruction and data caches, and uncached MMIO
regions.
- A PLIC-compatible external interrupt controller, CLINT-compatible timer and
software interrupts, and a deterministic reset vector.
- A documented DMA cache-maintenance contract unless the memory system supplies
hardware coherency.
The management firmware initializes external memory, verifies and places the
OpenSBI firmware, device tree, kernel, and initial filesystem, programs the
VexiiRiscv entry point, and then enables its bus access and releases reset. A
normal stop first requests Linux shutdown through a mailbox. After Linux
acknowledges and flushes persistent data, the management core disables new bus
transactions, drains the final accepted transaction, and asserts reset. A
bounded timeout permits fault recovery through forced isolation and reset.
### Product Targets
The following values define a useful commercial target rather than an
implemented or cross-PDK guarantee:
| Area | Minimum target | Preferred target |
| --- | --- | --- |
| VexiiRiscv frequency | 150 MHz | PDK-qualified maximum above 150 MHz |
| Main memory | 64 MiB SDRAM | 128 MiB SDRAM |
| L1 caches | 16 KiB I-cache and 16 KiB D-cache | Same, with measured refill and DMA behavior |
| Memory transport | Native cache-line burst | Native burst with two to four outstanding transactions per master |
| Boot storage | SPI NAND or qualified SDIO path | SDIO/eMMC plus recovery image |
| Linux platform devices | UART, timer, interrupt controller, storage | Ethernet or USB selected by the product profile |
Meeting these targets requires enlarging the current 32 MiB SDRAM address
window and replacing the scalar external-memory bottleneck. A dedicated memory
fabric may evolve independently while RIBP and APB remain the stable peripheral
register interfaces. Frequency claims must be qualified separately for each
PDK and physical implementation.
### Commercial Reference Points
The products below are reference points along different axes. None is a
pin-compatible or performance-equivalent substitute for retroSoC Mini.
| Commercial SoC | Relevant architecture | Comparison with the planned Mini |
| --- | --- | --- |
| [Bouffalo Lab BL808](https://github.com/bouffalolab/bl808_linux) | RISC-V Linux application core with separate MCU and low-power cores | Closest RISC-V heterogeneous architecture; substantially stronger wireless, multimedia, memory, and application-core capability |
| [NXP i.MX 7ULP](https://www.nxp.com/products/i.MX7ULP) | Cortex-A7 Linux core and Cortex-M4 system master with boot and power-control responsibilities | Closest commercial lifecycle-control model; a much larger application-processor platform |
| [ST STM32MP151](https://www.st.com/en/microcontrollers-microprocessors/stm32mp151a.html) | Single Cortex-A7 Linux core and Cortex-M4 real-time core | Useful industrial heterogeneous-MPU reference; DDR, cache, interconnect, and peripheral capabilities are substantially higher |
| [CV1800B and SG2002](https://milkv.io/docs/duo/overview) | Two RISC-V application-class cores supporting Linux and real-time workloads, with 64 or 256 MiB SiP memory | Closest low-cost dual-system RISC-V market reference; 64-bit cores and multimedia acceleration place it above Mini |
| [Allwinner F133](https://www.allwinnertech.com/index.php?c=product&id=101) | RV64 C906 Linux processor with 64 MiB SiP DDR and display/video functions | Direct low-cost RISC-V Linux market reference without the same independent management-core model |
| [Allwinner F1C200s](https://www.allwinnertech.com/uploads/pdf/201812181725033b.pdf) | 32-bit ARM9 Linux processor with 64 MiB SiP DDR in a compact package | Closest cost, memory, and lightweight-Linux application reference, but without a separate management core |
| [Ingenic X1000/X1000E](https://www.ingenic.com.cn/products-detail/id-50.html) | 32-bit MIPS Linux processor with 32 or 64 MiB LPDDR and fast-boot positioning | Comparable low-power Linux product segment with much higher CPU frequency and a mature multimedia subsystem |
| [Espressif ESP32-P4](https://docs.espressif.com/projects/esp-techpedia/en/latest/esp-friends/get-started/board-selection.html) | Dual 32-bit RISC-V high-performance cores and a low-power core | Relevant core-topology and power-control reference, but not a direct general-purpose MMU Linux competitor |
The closest architectural reference points are BL808 and i.MX 7ULP. The
closest cost and lightweight-Linux reference is F1C200s, while F133 and
CV1800B represent the nearest commercial RISC-V Linux market. ESP32-P4 is a
control-topology reference rather than a Linux performance reference.
After the Linux configuration meets the memory and interconnect targets above,
retroSoC Mini should be positioned between F1C200s and BL808: less capable than
modern 64-bit multimedia SoCs, but differentiated by open RTL and explicit
management-core control over Linux-core boot, bus admission, shutdown, and
fault recovery.
## Std: RV32 Heterogeneous Graphical Linux
### Position
-181
View File
@@ -1,181 +0,0 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`ifndef CLINT_DEF_SV
`define CLINT_DEF_SV
// verilog_format: off
`define RIBP_CLINT_MTIMEL 8'h00
`define RIBP_CLINT_MTIMEH 8'h04
`define RIBP_CLINT_MTIMECMPL 8'h08
`define RIBP_CLINT_MTIMECMPH 8'h0C
`define RIBP_CLINT_MSIP 8'h10
`define RIBP_CLINT_CLKDIV 8'h14
// verilog_format: on
`endif
interface simp_clint_if ();
logic tmr_irq_o;
logic sfr_irq_o;
modport dut(output tmr_irq_o, output sfr_irq_o);
endinterface
module ribp_clint (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
simp_clint_if.dut clint
// verilog_format: on
);
logic s_ribp_wr_hdshk, s_ribp_rd_hdshk;
logic s_ribp_ready_d, s_ribp_ready_q;
logic s_ribp_rdata_en;
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
logic s_clint_clkdiv_en;
logic [7:0] s_clint_clkdiv_d, s_clint_clkdiv_q;
logic s_clint_mtime_en;
logic [63:0] s_clint_mtime_d, s_clint_mtime_q;
logic s_clint_mtimecmp_en;
logic [63:0] s_clint_mtimecmp_d, s_clint_mtimecmp_q;
logic s_clint_msip_en;
logic s_clint_msip_d, s_clint_msip_q;
// utils
logic [7:0] s_clk_cnt_d, s_clk_cnt_q;
// pipelined 64-bit compare: split into hi32 and lo32 stages
logic s_tmr_hi_gt, s_tmr_hi_eq, s_tmr_lo_ge;
logic s_tmr_irq_d, s_tmr_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;
// pipelined 64-bit magnitude compare (registered output)
assign s_tmr_hi_gt = s_clint_mtime_q[63:32] > s_clint_mtimecmp_q[63:32];
assign s_tmr_hi_eq = s_clint_mtime_q[63:32] == s_clint_mtimecmp_q[63:32];
assign s_tmr_lo_ge = s_clint_mtime_q[31:0] >= s_clint_mtimecmp_q[31:0];
assign s_tmr_irq_d = s_tmr_hi_gt || (s_tmr_hi_eq && s_tmr_lo_ge);
dffr #(1) u_tmr_irq_dffr (
clk_i,
rst_n_i,
s_tmr_irq_d,
s_tmr_irq_q
);
assign clint.tmr_irq_o = s_tmr_irq_q;
assign clint.sfr_irq_o = s_clint_msip_q;
assign s_clint_clkdiv_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_CLINT_CLKDIV;
assign s_clint_clkdiv_d = ribp.wdata[7:0];
dffer #(8) u_clint_clkdiv_dffer (
clk_i,
rst_n_i,
s_clint_clkdiv_en,
s_clint_clkdiv_d,
s_clint_clkdiv_q
);
always_comb begin
s_clk_cnt_d = s_clk_cnt_q;
if (s_clk_cnt_q == s_clint_clkdiv_q) begin
s_clk_cnt_d = '0;
end else begin
s_clk_cnt_d = s_clk_cnt_q + 1'b1;
end
end
dffr #(8) u_clk_cnt_dffr (
clk_i,
rst_n_i,
s_clk_cnt_d,
s_clk_cnt_q
);
assign s_clint_mtime_en = s_clk_cnt_q == s_clint_clkdiv_q;
assign s_clint_mtime_d = s_clint_mtime_q + 1'b1;
dffer #(64) u_clint_mtime_dffer (
clk_i,
rst_n_i,
s_clint_mtime_en,
s_clint_mtime_d,
s_clint_mtime_q
);
assign s_clint_mtimecmp_en = s_ribp_wr_hdshk && (ribp.addr[7:0] == `RIBP_CLINT_MTIMECMPL || ribp.addr[7:0] == `RIBP_CLINT_MTIMECMPH);
always_comb begin
s_clint_mtimecmp_d = s_clint_mtimecmp_q;
if (ribp.addr[7:0] == `RIBP_CLINT_MTIMECMPL) begin
if (ribp.wstrb[0]) s_clint_mtimecmp_d[7:0] = ribp.wdata[7:0];
if (ribp.wstrb[1]) s_clint_mtimecmp_d[15:8] = ribp.wdata[15:8];
if (ribp.wstrb[2]) s_clint_mtimecmp_d[23:16] = ribp.wdata[23:16];
if (ribp.wstrb[3]) s_clint_mtimecmp_d[31:24] = ribp.wdata[31:24];
end else if (ribp.addr[7:0] == `RIBP_CLINT_MTIMECMPH) begin
if (ribp.wstrb[0]) s_clint_mtimecmp_d[39:32] = ribp.wdata[7:0];
if (ribp.wstrb[1]) s_clint_mtimecmp_d[47:40] = ribp.wdata[15:8];
if (ribp.wstrb[2]) s_clint_mtimecmp_d[55:48] = ribp.wdata[23:16];
if (ribp.wstrb[3]) s_clint_mtimecmp_d[63:56] = ribp.wdata[31:24];
end
end
dfferh #(64) u_clint_mtimecmp_dfferh (
clk_i,
rst_n_i,
s_clint_mtimecmp_en,
s_clint_mtimecmp_d,
s_clint_mtimecmp_q
);
assign s_clint_msip_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_CLINT_MSIP;
assign s_clint_msip_d = ribp.wdata[0];
dffer #(1) u_clint_msip_dffer (
clk_i,
rst_n_i,
s_clint_msip_en,
s_clint_msip_d,
s_clint_msip_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_CLINT_CLKDIV: s_ribp_rdata_d = {24'd0, s_clint_clkdiv_q};
`RIBP_CLINT_MTIMEL: s_ribp_rdata_d = s_clint_mtime_q[31:0];
`RIBP_CLINT_MTIMEH: s_ribp_rdata_d = s_clint_mtime_q[63:32];
`RIBP_CLINT_MTIMECMPL: s_ribp_rdata_d = s_clint_mtimecmp_q[31:0];
`RIBP_CLINT_MTIMECMPH: s_ribp_rdata_d = s_clint_mtimecmp_q[63:32];
`RIBP_CLINT_MSIP: s_ribp_rdata_d = {31'd0, s_clint_msip_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
+58
View File
@@ -0,0 +1,58 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module clint_core #(
parameter int HART_NUM = 1
) (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic tick_i,
input logic mtime_load_i,
input logic [63:0] mtime_load_value_i,
input logic [63:0] mtimecmp_i [0:HART_NUM-1],
output logic [63:0] mtime_o,
output logic [HART_NUM-1:0] timer_irq_o
// verilog_format: on
);
logic [HART_NUM-1:0] s_timer_irq_d, s_timer_irq_q;
initial begin
if ((HART_NUM < 1) || (HART_NUM > 4095)) begin
$fatal(1, "clint_core: HART_NUM must be between 1 and 4095");
end
end
// MTIME wraps modulo 2^64, so the Common carry output is intentionally unused.
/* verilator lint_off PINCONNECTEMPTY */
rs_counter #(
.DATA_WIDTH(64)
) u_mtime_counter (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.clr_i (1'b0),
.en_i (tick_i),
.load_i (mtime_load_i),
.down_i (1'b0),
.dat_i (mtime_load_value_i),
.dat_o (mtime_o),
.ovf_o ()
);
/* verilator lint_on PINCONNECTEMPTY */
always_comb begin
for (int hart = 0; hart < HART_NUM; hart++) begin
s_timer_irq_d[hart] = mtime_o >= mtimecmp_i[hart];
end
end
dffr #(HART_NUM) u_timer_irq_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_timer_irq_d),
.dat_o (s_timer_irq_q)
);
assign timer_irq_o = s_timer_irq_q;
endmodule
+17
View File
@@ -0,0 +1,17 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`ifndef CLINT_DEFINE_SVH
`define CLINT_DEFINE_SVH
// verilog_format: off
`define RIBP_CLINT_MSIP 16'h0000
`define RIBP_CLINT_MTIMECMP 16'h4000
`define RIBP_CLINT_MTIME 16'hBFF8
`define RIBP_CLINT_MTIMEH 16'hBFFC
`define CLINT_MSIP_STRIDE 16'h0004
`define CLINT_MTIMECMP_STRIDE 16'h0008
// verilog_format: on
`endif
+11
View File
@@ -0,0 +1,11 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
interface clint_if #(
parameter int HART_NUM = 1
) ();
logic [HART_NUM-1:0] timer_irq_o;
logic [HART_NUM-1:0] software_irq_o;
modport dut(output timer_irq_o, output software_irq_o);
endinterface
+191
View File
@@ -0,0 +1,191 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "clint_define.svh"
module clint_reg #(
parameter int HART_NUM = 1
) (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
input logic [63:0] mtime_i,
output logic mtime_load_o,
output logic [63:0] mtime_load_value_o,
output logic [HART_NUM-1:0] msip_o,
output logic [63:0] mtimecmp_o [0:HART_NUM-1]
// verilog_format: on
);
localparam int HART_INDEX_WIDTH = HART_NUM > 1 ? $clog2(HART_NUM) : 1;
localparam logic [11:0] HART_COUNT = 12'(HART_NUM);
logic s_req;
logic s_write;
logic s_req_accept;
logic [15:0] s_offset;
logic s_aligned;
logic s_access_error;
logic s_msip_select;
logic s_mtimecmp_select;
logic s_mtimecmp_high;
logic s_mtime_select;
logic s_mtime_high;
logic [11:0] s_msip_hart;
logic [11:0] s_mtimecmp_hart;
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 [HART_NUM-1:0] s_msip_en;
logic [HART_NUM-1:0] s_msip_d, s_msip_q;
logic [HART_NUM-1:0] s_mtimecmp_en;
logic [ 63:0] s_mtimecmp_d [0:HART_NUM-1];
logic [ 63:0] s_mtimecmp_q [0:HART_NUM-1];
function automatic logic [31:0] merge_wstrb(input logic [31:0] current, input logic [31:0] value,
input logic [3:0] strobe);
logic [31:0] merged;
integer byte_index;
begin
merged = current;
for (byte_index = 0; byte_index < 4; byte_index = byte_index + 1) begin
if (strobe[byte_index]) begin
merged[byte_index*8+:8] = value[byte_index*8+:8];
end
end
return merged;
end
endfunction
initial begin
if ((HART_NUM < 1) || (HART_NUM > 4095)) begin
$fatal(1, "clint_reg: HART_NUM must be between 1 and 4095");
end
end
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[15:0];
assign s_aligned = ribp.addr[1:0] == 2'b00;
assign s_msip_hart = s_offset[13:2];
assign s_mtimecmp_hart = s_offset[14:3] - 12'h800;
assign s_msip_select = (s_offset < `RIBP_CLINT_MTIMECMP) && (s_msip_hart < HART_COUNT);
assign s_mtimecmp_select = (s_offset >= `RIBP_CLINT_MTIMECMP) &&
(s_offset < `RIBP_CLINT_MTIME) &&
(s_mtimecmp_hart < HART_COUNT);
assign s_mtimecmp_high = s_offset[2];
assign s_mtime_select = (s_offset == `RIBP_CLINT_MTIME) || (s_offset == `RIBP_CLINT_MTIMEH);
assign s_mtime_high = s_offset == `RIBP_CLINT_MTIMEH;
assign ribp.ready = s_ribp_ready_q;
assign ribp.rdata = s_ribp_rdata_q;
assign ribp.resp_err = s_ribp_resp_err_q;
always_comb begin
s_access_error = !s_aligned || !(s_msip_select || s_mtimecmp_select || s_mtime_select);
s_ribp_rdata_d = '0;
if (s_aligned) begin
if (s_msip_select) begin
s_ribp_rdata_d = {31'd0, s_msip_q[s_msip_hart[HART_INDEX_WIDTH-1:0]]};
end else if (s_mtimecmp_select) begin
if (s_mtimecmp_high) begin
s_ribp_rdata_d = s_mtimecmp_q[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]][63:32];
end else begin
s_ribp_rdata_d = s_mtimecmp_q[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]][31:0];
end
end else if (s_mtime_select) begin
s_ribp_rdata_d = s_mtime_high ? mtime_i[63:32] : mtime_i[31:0];
end
end
end
always_comb begin
s_msip_en = '0;
s_msip_d = s_msip_q;
if (s_req_accept && s_write && !s_access_error && s_msip_select && ribp.wstrb[0]) begin
s_msip_en[s_msip_hart[HART_INDEX_WIDTH-1:0]] = 1'b1;
s_msip_d[s_msip_hart[HART_INDEX_WIDTH-1:0]] = ribp.wdata[0];
end
end
for (genvar hart = 0; hart < HART_NUM; hart++) begin : gen_msip
dffer #(1) u_msip_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_msip_en[hart]),
.dat_i (s_msip_d[hart]),
.dat_o (s_msip_q[hart])
);
end
always_comb begin
s_mtimecmp_en = '0;
for (int hart = 0; hart < HART_NUM; hart++) begin
s_mtimecmp_d[hart] = s_mtimecmp_q[hart];
end
if (s_req_accept && s_write && !s_access_error && s_mtimecmp_select) begin
s_mtimecmp_en[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]] = 1'b1;
if (s_mtimecmp_high) begin
s_mtimecmp_d[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]][63:32] = merge_wstrb(
s_mtimecmp_q[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]][63:32], ribp.wdata, ribp.wstrb);
end else begin
s_mtimecmp_d[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]][31:0] = merge_wstrb(
s_mtimecmp_q[s_mtimecmp_hart[HART_INDEX_WIDTH-1:0]][31:0], ribp.wdata, ribp.wstrb);
end
end
end
for (genvar hart = 0; hart < HART_NUM; hart++) begin : gen_mtimecmp
dfferh #(64) u_mtimecmp_dfferh (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_mtimecmp_en[hart]),
.dat_i (s_mtimecmp_d[hart]),
.dat_o (s_mtimecmp_q[hart])
);
end
always_comb begin
mtime_load_o = 1'b0;
mtime_load_value_o = mtime_i;
if (s_req_accept && s_write && !s_access_error && s_mtime_select) begin
mtime_load_o = 1'b1;
if (s_mtime_high) begin
mtime_load_value_o[63:32] = merge_wstrb(mtime_i[63:32], ribp.wdata, ribp.wstrb);
end else begin
mtime_load_value_o[31:0] = merge_wstrb(mtime_i[31:0], ribp.wdata, ribp.wstrb);
end
end
end
assign msip_o = s_msip_q;
assign mtimecmp_o = s_mtimecmp_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 (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_ribp_ready_d),
.dat_o (s_ribp_ready_q)
);
dffer #(1) u_ribp_resp_err_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_req_accept),
.dat_i (s_ribp_resp_err_d),
.dat_o (s_ribp_resp_err_q)
);
dffer #(32) u_ribp_rdata_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_req_accept),
.dat_i (s_ribp_rdata_d),
.dat_o (s_ribp_rdata_q)
);
endmodule
+74
View File
@@ -0,0 +1,74 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module clint_timebase #(
parameter int REF_CLK_HZ = 72_000_000,
parameter int TIMEBASE_HZ = 1_000_000,
parameter int CDC_STAGE = 2
) (
// verilog_format: off
input logic ref_clk_i,
input logic ref_rst_n_i,
input logic sys_clk_i,
input logic sys_rst_n_i,
output logic tick_o
// verilog_format: on
);
localparam int DIVISOR = REF_CLK_HZ / TIMEBASE_HZ;
localparam int DIV_WIDTH = DIVISOR > 1 ? $clog2(DIVISOR) : 1;
logic [DIV_WIDTH-1:0] s_div_count;
logic s_div_terminal;
logic s_tick_toggle_d, s_tick_toggle_q;
logic s_tick_toggle_sync;
logic s_tick_re, s_tick_fe;
initial begin
if ((REF_CLK_HZ <= 0) || (TIMEBASE_HZ <= 0) || (REF_CLK_HZ < TIMEBASE_HZ) ||
((REF_CLK_HZ % TIMEBASE_HZ) != 0)) begin
$fatal(1, "clint_timebase: REF_CLK_HZ must be a positive multiple of TIMEBASE_HZ");
end
end
assign s_div_terminal = s_div_count == DIV_WIDTH'(DIVISOR - 1);
// The divider clears before its natural carry; the Common carry output is intentionally unused.
/* verilator lint_off PINCONNECTEMPTY */
rs_counter #(
.DATA_WIDTH(DIV_WIDTH)
) u_div_counter (
.clk_i (ref_clk_i),
.rst_n_i(ref_rst_n_i),
.clr_i (s_div_terminal),
.en_i (1'b1),
.load_i (1'b0),
.down_i (1'b0),
.dat_i ('0),
.dat_o (s_div_count),
.ovf_o ()
);
/* verilator lint_on PINCONNECTEMPTY */
assign s_tick_toggle_d = s_div_terminal ? ~s_tick_toggle_q : s_tick_toggle_q;
dffr #(1) u_tick_toggle_dffr (
.clk_i (ref_clk_i),
.rst_n_i(ref_rst_n_i),
.dat_i (s_tick_toggle_d),
.dat_o (s_tick_toggle_q)
);
edge_det #(
.STAGE(CDC_STAGE)
) u_tick_edge_det (
.clk_i (sys_clk_i),
.rst_n_i(sys_rst_n_i),
.dat_i (s_tick_toggle_q),
.dat_o (s_tick_toggle_sync),
.re_o (s_tick_re),
.fe_o (s_tick_fe)
);
assign tick_o = (s_tick_re && !s_tick_toggle_sync) || (s_tick_fe && s_tick_toggle_sync);
endmodule
+52
View File
@@ -0,0 +1,52 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module ribp_clint #(
parameter int HART_NUM = 1
) (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic timebase_tick_i,
ribp_if.slave ribp,
clint_if.dut clint
// verilog_format: on
);
logic s_mtime_load;
logic [ 63:0] s_mtime_load_value;
logic [ 63:0] s_mtime;
logic [HART_NUM-1:0] s_msip;
logic [ 63:0] s_mtimecmp [0:HART_NUM-1];
logic [HART_NUM-1:0] s_timer_irq;
clint_reg #(
.HART_NUM(HART_NUM)
) u_clint_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.mtime_i (s_mtime),
.mtime_load_o (s_mtime_load),
.mtime_load_value_o(s_mtime_load_value),
.msip_o (s_msip),
.mtimecmp_o (s_mtimecmp)
);
clint_core #(
.HART_NUM(HART_NUM)
) u_clint_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.tick_i (timebase_tick_i),
.mtime_load_i (s_mtime_load),
.mtime_load_value_i(s_mtime_load_value),
.mtimecmp_i (s_mtimecmp),
.mtime_o (s_mtime),
.timer_irq_o (s_timer_irq)
);
assign clint.software_irq_o = s_msip;
assign clint.timer_irq_o = s_timer_irq;
endmodule
+1 -1
View File
@@ -47,7 +47,7 @@
{"symbol": "RIBP_XPI", "base": "0x10009000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "RIBP_DMA", "base": "0x1000A000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "RIBP_SYSCTRL", "base": "0x1000B000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "RIBP_CLINT", "base": "0x1000C000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "RIBP_CLINT", "base": "0x10020000", "size": "0x00010000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "RIBP_SDRAM", "base": "0x1000D000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
{"symbol": "RIBP_DVP", "base": "0x1000E000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
{"symbol": "RIBP_SDIO", "base": "0x1000F000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
+5 -1
View File
@@ -32,7 +32,11 @@
/ip/ribp/peripheral/dma.sv
/ip/ribp/peripheral/pll_ctrl_if.sv
/ip/ribp/peripheral/sysctrl.sv
/ip/ribp/peripheral/clint.sv
/ip/ribp/peripheral/clint_if.sv
/ip/ribp/peripheral/clint_timebase.sv
/ip/ribp/peripheral/clint_reg.sv
/ip/ribp/peripheral/clint_core.sv
/ip/ribp/peripheral/ribp_clint.sv
/ip/ribp/memory/sdram_clkgen.sv
/ip/ribp/memory/sdram_reg.sv
/ip/ribp/memory/sdram_core.sv
+94
View File
@@ -0,0 +1,94 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module clint_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 tick,
output logic [63:0] mtime,
output logic mtime_load,
output logic [63:0] mtime_load_value,
output logic [ 1:0] msip,
output logic [ 1:0] timer_irq_next,
output logic [ 1:0] timer_irq
// verilog_format: on
);
ribp_if ribp ();
(* 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_tick;
logic s_mtime_load;
logic [63:0] s_mtime_load_value;
logic [63:0] s_mtime;
logic [ 1:0] s_msip;
logic [63:0] s_mtimecmp [0:1];
logic [ 1:0] s_timer_irq;
assign ribp.valid = f_rib_valid;
assign ribp.addr = f_rib_addr;
assign ribp.wdata = f_rib_wdata;
assign ribp.wstrb = f_rib_wstrb;
assign rib_valid = ribp.valid;
assign rib_addr = ribp.addr;
assign rib_wdata = ribp.wdata;
assign rib_wstrb = ribp.wstrb;
assign rib_ready = ribp.ready;
assign rib_resp_err = ribp.resp_err;
assign tick = f_tick;
assign mtime = s_mtime;
assign mtime_load = s_mtime_load;
assign mtime_load_value = s_mtime_load_value;
assign msip = s_msip;
assign timer_irq_next[0] = s_mtime >= s_mtimecmp[0];
assign timer_irq_next[1] = s_mtime >= s_mtimecmp[1];
assign timer_irq = s_timer_irq;
clint_reg #(
.HART_NUM(2)
) u_clint_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.mtime_i (s_mtime),
.mtime_load_o (s_mtime_load),
.mtime_load_value_o(s_mtime_load_value),
.msip_o (s_msip),
.mtimecmp_o (s_mtimecmp)
);
clint_core #(
.HART_NUM(2)
) u_clint_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.tick_i (f_tick),
.mtime_load_i (s_mtime_load),
.mtime_load_value_i(s_mtime_load_value),
.mtimecmp_i (s_mtimecmp),
.mtime_o (s_mtime),
.timer_irq_o (s_timer_irq)
);
initial begin
rst_n_i = 1'b1;
f_past_valid = 1'b0;
end
always_ff @(posedge clk_i) begin
rst_n_i <= f_past_valid;
f_past_valid <= 1'b1;
end
endmodule
+61
View File
@@ -0,0 +1,61 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module clint_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 tick;
wire [63:0] mtime;
wire mtime_load;
wire [63:0] mtime_load_value;
wire [ 1:0] msip;
wire [ 1:0] timer_irq_next;
wire [ 1:0] timer_irq;
clint_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 (f_past_valid && !$past(rst_n_i)) begin
assert (mtime == 64'd0);
assert (msip == 2'b00);
assert (timer_irq == 2'b00);
end
if (rst_n_i) begin
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)) begin
assert (timer_irq == $past(timer_irq_next));
if ($past(mtime_load)) begin
assert (mtime == $past(mtime_load_value));
end else if ($past(tick)) begin
assert (mtime == $past(mtime) + 64'd1);
end else begin
assert (mtime == $past(mtime));
end
end
cover (msip[0]);
cover (timer_irq[0]);
cover (rib_ready && rib_resp_err);
cover (mtime_load);
end
end
endmodule
@@ -75,7 +75,10 @@ def source_files(target: str) -> list[Path]:
COMMON_RTL / "cdc/cdc_rst_ctrlr.sv",
COMMON_RTL / "cdc/cdc_2phase.sv",
COMMON_RTL / "clkrst/rst_sync.sv",
COMMON_RTL / "clkrst/counter.sv",
COMMON_RTL / "utils/edge_det.sv",
PERIPHERAL / "pll_ctrl_if.sv",
PERIPHERAL / "clint_timebase.sv",
TOP / "rcu.sv",
SCRIPT_DIR / "pll_rcu_formal.sv",
]
@@ -109,6 +112,17 @@ def source_files(target: str) -> list[Path]:
PERIPHERAL / "ribp_timer.sv",
SCRIPT_DIR / "timer_formal.sv",
]
if target == "clint":
return [
COMMON_RTL / "interface/ribp_if.sv",
COMMON_RTL / "utils/register.sv",
COMMON_RTL / "clkrst/counter.sv",
PERIPHERAL / "clint_if.sv",
PERIPHERAL / "clint_reg.sv",
PERIPHERAL / "clint_core.sv",
PERIPHERAL / "ribp_clint.sv",
SCRIPT_DIR / "clint_formal.sv",
]
raise ValueError(f"unsupported formal target: {target}")
@@ -151,6 +165,7 @@ def parse_args() -> argparse.Namespace:
"gpio_user",
"ws2812",
"timer",
"clint",
),
required=True,
)
@@ -95,6 +95,14 @@
"path": "rtl/mini/top/rcu.sv",
"instance": "u_pll_response_cdc"
},
{
"name": "clint_timebase",
"source": "external",
"destination": "system",
"primitive": "edge_det",
"path": "rtl/ip/ribp/peripheral/clint_timebase.sv",
"instance": "u_tick_edge_det"
},
{
"name": "dvp_enable",
"source": "system",
+20 -5
View File
@@ -27,8 +27,8 @@ FABRIC_PROTOCOLS = {
IRQ_GROUP_NAMES = ("ribp", "apb")
IRQ_VECTOR_WIDTH = 32
COMPATIBILITY_IRQ_BINDINGS = (
("clint_software", "ribp", 0, 0, "u_clint_if.sfr_irq_o"),
("clint_timer", "ribp", 1, 1, "u_clint_if.tmr_irq_o"),
("clint_software", "ribp", 0, 0, "u_clint_if.software_irq_o[0]"),
("clint_timer", "ribp", 1, 1, "u_clint_if.timer_irq_o[0]"),
("uart0", "ribp", 2, 2, "uart.irq_o"),
("timer0", "ribp", 3, 3, "s_tim0_irq"),
("timer1", "ribp", 4, 4, "s_tim1_irq"),
@@ -102,6 +102,7 @@ class Interrupt:
group_bit: int
core_bit: int
signal: str
user_visible: bool
def atomic_write(path: Path, content: str) -> None:
@@ -442,6 +443,9 @@ def parse_interrupts(value: Any, groups: list[IrqGroup], vector_width: int) -> l
group_bit = interrupt.get("group_bit")
core_bit = interrupt.get("core_bit")
signal = require_value(interrupt.get("signal"), f"interrupts[{index}].signal")
user_visible = interrupt.get("user_visible", True)
if not isinstance(user_visible, bool):
raise ValueError(f"interrupts[{index}].user_visible must be boolean")
if group not in group_widths:
raise ValueError(f"interrupts[{index}].group is not a supported interrupt group")
if not isinstance(group_bit, int) or not 0 <= group_bit < group_widths[group]:
@@ -457,7 +461,9 @@ def parse_interrupts(value: Any, groups: list[IrqGroup], vector_width: int) -> l
names.add(name)
group_bits[group].add(group_bit)
core_bits.add(core_bit)
interrupts.append(Interrupt(name, description, group, group_bit, core_bit, signal))
interrupts.append(
Interrupt(name, description, group, group_bit, core_bit, signal, user_visible)
)
for group in groups:
expected = set(range(group.width))
@@ -768,13 +774,19 @@ def irq_width_macro(group: IrqGroup) -> str:
return f"SOC_IRQ_{group.name.upper()}_WIDTH"
def render_irq_config(vector_width: int, groups: list[IrqGroup]) -> str:
def render_irq_config(
vector_width: int, groups: list[IrqGroup], interrupts: list[Interrupt]
) -> str:
user_irq_mask = sum(
1 << interrupt.core_bit for interrupt in interrupts if interrupt.user_visible
)
lines = [
"// Generated by rtl/mini/integration/generate_soc_topology.py; do not edit.",
"`ifndef RETROSOC_SOC_IRQ_CONFIG_SVH",
"`define RETROSOC_SOC_IRQ_CONFIG_SVH",
"",
f"`define SOC_IRQ_VECTOR_WIDTH {vector_width}",
f"`define SOC_USER_IRQ_MASK {vector_width}'h{user_irq_mask:0{vector_width // 4}X}",
]
lines.extend(f"`define {irq_width_macro(group)} {group.width}" for group in groups)
lines.extend(["", "`endif"])
@@ -909,7 +921,10 @@ def generate(topology_path: Path, memory_map_path: Path, output_dir: Path) -> No
render_fabric_connection(fabric_links, "apb", "rib"),
)
atomic_write(rtl_dir / "soc_gpio_alt_bindings.svh", render_gpio_bindings(gpio_functions))
atomic_write(rtl_dir / "soc_irq_config.svh", render_irq_config(irq_vector_width, irq_groups))
atomic_write(
rtl_dir / "soc_irq_config.svh",
render_irq_config(irq_vector_width, irq_groups, interrupts),
)
for group in irq_groups:
filename = f"{group.name}_irq_bindings.svh"
if group.name != "ribp":
+2 -2
View File
@@ -7,8 +7,8 @@
{"name": "apb", "width": 7, "top_signal": "s_apb_irq"}
],
"interrupts": [
{"name": "clint_software", "description": "CLINT machine software interrupt", "group": "ribp", "group_bit": 0, "core_bit": 0, "signal": "u_clint_if.sfr_irq_o"},
{"name": "clint_timer", "description": "CLINT machine timer interrupt", "group": "ribp", "group_bit": 1, "core_bit": 1, "signal": "u_clint_if.tmr_irq_o"},
{"name": "clint_software", "description": "CLINT machine software interrupt", "group": "ribp", "group_bit": 0, "core_bit": 0, "signal": "u_clint_if.software_irq_o[0]", "user_visible": false},
{"name": "clint_timer", "description": "CLINT machine timer interrupt", "group": "ribp", "group_bit": 1, "core_bit": 1, "signal": "u_clint_if.timer_irq_o[0]", "user_visible": false},
{"name": "uart0", "description": "RIBP UART0 interrupt", "group": "ribp", "group_bit": 2, "core_bit": 2, "signal": "uart.irq_o"},
{"name": "timer0", "description": "RIBP timer0 interrupt", "group": "ribp", "group_bit": 3, "core_bit": 3, "signal": "s_tim0_irq"},
{"name": "timer1", "description": "RIBP timer1 interrupt", "group": "ribp", "group_bit": 4, "core_bit": 4, "signal": "s_tim1_irq"},
+14 -4
View File
@@ -6,9 +6,10 @@ FORMAL_SOLVER_DIR := $(FORMAL_DIR)/bin
FORMAL_SOLVER_WRAPPER := $(FORMAL_SOLVER_DIR)/bitwuzla
FORMAL_DEPTH ?= 20
FORMAL_WS2812_DEPTH ?= 120
FORMAL_CLINT_DEPTH ?= 32
FORMAL_TIMEOUT ?= 60
FORMAL_WS2812_TIMEOUT ?= 120
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user ws2812 timer
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user ws2812 timer clint
FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py
FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py
FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py
@@ -28,6 +29,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(RTL_PATH)/formal/ws2812_formal_props.sv \
$(RTL_PATH)/formal/timer_formal.sv \
$(RTL_PATH)/formal/timer_formal_props.sv \
$(RTL_PATH)/formal/clint_formal.sv \
$(RTL_PATH)/formal/clint_formal_props.sv \
$(RTL_PATH)/top/bus.sv \
$(RTL_PATH)/top/rib_error_slave.sv \
$(RTL_PATH)/top/rib_if.sv \
@@ -47,6 +50,11 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.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/ip/ribp/peripheral/clint_define.svh \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/clint_if.sv \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/clint_reg.sv \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/clint_core.sv \
$(ROOT_PATH)/rtl/ip/ribp/peripheral/ribp_clint.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/clkrst/counter.sv \
$(RTL_PATH)/top/rcu.sv \
$(ROOT_PATH)/rtl/managed/clusterip/common/rtl/interface/ribp_if.sv \
@@ -86,13 +94,13 @@ $(FORMAL_DIR)/%/prove.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_
$(FORMAL_SBY_GENERATOR)
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
--mode prove --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(FORMAL_DEPTH)) --output $@
--mode prove --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(FORMAL_DEPTH))) --output $@
$(FORMAL_DIR)/%/cover.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_props.sv \
$(FORMAL_SBY_GENERATOR)
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
--mode cover --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(FORMAL_DEPTH)) --output $@
--mode cover --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(FORMAL_DEPTH))) --output $@
$(FORMAL_SOLVER_WRAPPER): $(ROOT_PATH)/scripts/bitwuzla_smt2.py
@mkdir -p $(@D)
@@ -144,10 +152,12 @@ formal-ws2812: $(FORMAL_DIR)/ws2812/.stamp | manifest
formal-timer: $(FORMAL_DIR)/timer/.stamp | manifest
formal-clint: $(FORMAL_DIR)/clint/.stamp | manifest
formal-doctor:
$(MAKE) FORMAL=YES SIMU=IVERILOG SYNTH=YOSYS STA=NONE doctor
formal-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio-user formal-ws2812 formal-timer 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-clint formal-doctor formal-clean
+2
View File
@@ -44,6 +44,7 @@ DEF_VAL += -DAPP_$(APP)
DEF_VAL += -DCOMPILER_NAME='"$(CC)"'
DEF_VAL += -DCOMPILER_CFLAGS='"$(GCC_FLAGS) $(SW_WARN_FLAGS)"'
DEF_VAL += -DCOMPILER_ISA='"$(ISA_FLAGS)"'
DEF_VAL += -DRS_CLINT_TIMEBASE_HZ=$(CLINT_TIMEBASE_HZ)U
ifeq ($(HAVE_CSR),YES)
DEF_VAL += -DCSR_ENABLE
endif
@@ -64,6 +65,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
$(ROOT_PATH)/crt/src/service/bench.c \
$(ROOT_PATH)/crt/src/service/booter.c \
$(ROOT_PATH)/crt/src/service/test.c \
$(ROOT_PATH)/crt/src/hal/clint.c \
$(ROOT_PATH)/crt/src/hal/clock.c \
$(ROOT_PATH)/crt/src/hal/uart.c \
$(ROOT_PATH)/crt/src/hal/gpio.c \
+7 -5
View File
@@ -19,6 +19,7 @@ module ip_ribp_wrapper (
input logic clk_aud_i,
input logic rst_aud_n_i,
input logic debug_halted_i,
input logic timebase_tick_i,
rib_if.slave rib,
gpio_if.dut gpio,
user_gpio_if.padctrl user_gpio,
@@ -52,7 +53,7 @@ module ip_ribp_wrapper (
ribp_if ribp ();
// verilog_format: on
simp_clint_if u_clint_if ();
clint_if u_clint_if ();
dma_hw_trg_if u_dma_hw_trg_if ();
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
@@ -185,10 +186,11 @@ module ip_ribp_wrapper (
);
ribp_clint u_rib_clint (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.ribp (u_clint_ribp_if),
.clint (u_clint_if)
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.timebase_tick_i(timebase_tick_i),
.ribp (u_clint_ribp_if),
.clint (u_clint_if)
);
ribp_sdram u_rib_sdram (
+18 -3
View File
@@ -8,7 +8,10 @@
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
module rcu (
module rcu #(
parameter int EXT_CLK_HZ = 72_000_000,
parameter int CLINT_TIMEBASE_HZ = 1_000_000
) (
input logic ext_clk_i,
input logic aud_clk_i,
input logic ext_rst_n_i,
@@ -19,7 +22,8 @@ module rcu (
output logic sys_clk_o,
output logic sys_rst_n_o,
output logic aud_rst_n_o,
output logic sys_clkdiv4_o
output logic sys_clkdiv4_o,
output logic timebase_tick_o
);
logic s_ext_clk_buf;
logic s_aud_clk_buf;
@@ -183,7 +187,18 @@ module rcu (
assign aud_rst_n_o = s_aud_rst_n_sync;
assign sys_clkdiv4_o = s_sys_clkdiv4_q;
assign s_div_cnt_d = (s_div_cnt_q == 4'd1) ? '0 : s_div_cnt_q + 1'b1;
clint_timebase #(
.REF_CLK_HZ (EXT_CLK_HZ),
.TIMEBASE_HZ(CLINT_TIMEBASE_HZ)
) u_clint_timebase (
.ref_clk_i (s_ext_clk_buf),
.ref_rst_n_i(s_ext_rst_n_sync),
.sys_clk_i (sys_clk_o),
.sys_rst_n_i(sys_rst_n_o),
.tick_o (timebase_tick_o)
);
assign s_div_cnt_d = (s_div_cnt_q == 4'd1) ? '0 : s_div_cnt_q + 1'b1;
dffr #(4) u_div_cnt_dffr (
sys_clk_o,
sys_rst_n_o,
+3 -1
View File
@@ -19,6 +19,7 @@ module retrosoc (
input logic clk_aud_i,
input logic rst_aud_n_i,
input logic clkdiv4_i,
input logic timebase_tick_i,
pll_ctrl_if.sysctrl pll_ctrl,
`ifdef HAVE_SRAM_IF
ram_if.master ram,
@@ -124,7 +125,7 @@ core_wrapper u_core_wrapper (
.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 & `SOC_USER_IRQ_MASK) : '0;
user_core_top u_user_core_top (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
@@ -168,6 +169,7 @@ core_wrapper u_core_wrapper (
.clk_aud_i (clk_aud_i),
.rst_aud_n_i (rst_aud_n_i),
.debug_halted_i (s_mgmt_debug_halted),
.timebase_tick_i (timebase_tick_i),
`include "ip_ribp_wrapper_fabric.svh"
.gpio (u_gpio_if),
.user_gpio (u_user_gpio_if),
+36 -29
View File
@@ -9,6 +9,7 @@
// See the Mulan PSL v2 for more details.
`include "gpio_define.svh"
`include "soc_clock_config.svh"
`include "user_extensions.svh"
module retrosoc_asic (
@@ -17,6 +18,7 @@ module retrosoc_asic (
logic s_ext_clk;
logic s_aud_clk;
logic s_sys_clkdiv4;
logic s_timebase_tick;
`ifdef HAVE_PLL
logic s_xtal_io;
`endif
@@ -45,18 +47,22 @@ module retrosoc_asic (
`include "retrosoc_asic_pad_bindings.svh"
rcu u_rcu (
.ext_clk_i (s_ext_clk),
.aud_clk_i (s_aud_clk),
.ext_rst_n_i (s_ext_rst_n),
rcu #(
.EXT_CLK_HZ (`SOC_EXT_CLK_HZ),
.CLINT_TIMEBASE_HZ(`SOC_CLINT_TIMEBASE_HZ)
) u_rcu (
.ext_clk_i (s_ext_clk),
.aud_clk_i (s_aud_clk),
.ext_rst_n_i (s_ext_rst_n),
`ifdef HAVE_PLL
.xtal_clk_i (s_xtal_io),
.xtal_clk_i (s_xtal_io),
`endif
.pll_ctrl (u_pll_ctrl_if),
.sys_clk_o (s_sys_clk),
.sys_rst_n_o (s_sys_rst_n),
.aud_rst_n_o (s_aud_rst_n),
.sys_clkdiv4_o(s_sys_clkdiv4)
.pll_ctrl (u_pll_ctrl_if),
.sys_clk_o (s_sys_clk),
.sys_rst_n_o (s_sys_rst_n),
.aud_rst_n_o (s_aud_rst_n),
.sys_clkdiv4_o (s_sys_clkdiv4),
.timebase_tick_o(s_timebase_tick)
);
`ifdef HAVE_SRAM_IF
@@ -67,27 +73,28 @@ rcu u_rcu (
`endif
retrosoc u_retrosoc (
.clk_i (s_sys_clk),
.rst_n_i (s_sys_rst_n),
.clk_aud_i (s_aud_clk),
.rst_aud_n_i (s_aud_rst_n),
.clkdiv4_i (s_sys_clkdiv4),
.pll_ctrl (u_pll_ctrl_if),
.clk_i (s_sys_clk),
.rst_n_i (s_sys_rst_n),
.clk_aud_i (s_aud_clk),
.rst_aud_n_i (s_aud_rst_n),
.clkdiv4_i (s_sys_clkdiv4),
.timebase_tick_i(s_timebase_tick),
.pll_ctrl (u_pll_ctrl_if),
`ifdef HAVE_SRAM_IF
.ram (u_ram_if),
.ram (u_ram_if),
`endif
.gpio (u_gpio_if),
.uart0 (u_uart0_if),
.xpi (u_xpi_if),
.sdram (u_sdram_if),
.jtag_tck_i (s_jtag_tck),
.jtag_tms_i (s_jtag_tms),
.jtag_tdi_i (s_jtag_tdi),
.jtag_trst_n_i(s_jtag_trst_n),
.jtag_tdo_o (s_jtag_tdo),
.test_done_o (s_test_done),
.test_pass_o (s_test_pass),
.test_code_o (s_test_code)
.gpio (u_gpio_if),
.uart0 (u_uart0_if),
.xpi (u_xpi_if),
.sdram (u_sdram_if),
.jtag_tck_i (s_jtag_tck),
.jtag_tms_i (s_jtag_tms),
.jtag_tdi_i (s_jtag_tdi),
.jtag_trst_n_i (s_jtag_trst_n),
.jtag_tdo_o (s_jtag_tdo),
.test_done_o (s_test_done),
.test_pass_o (s_test_pass),
.test_code_o (s_test_code)
);
endmodule
+15
View File
@@ -0,0 +1,15 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`ifndef RETROSOC_SOC_CLOCK_CONFIG_SVH
`define RETROSOC_SOC_CLOCK_CONFIG_SVH
`ifndef SOC_EXT_CLK_HZ
`define SOC_EXT_CLK_HZ 72000000
`endif
`ifndef SOC_CLINT_TIMEBASE_HZ
`define SOC_CLINT_TIMEBASE_HZ 1000000
`endif
`endif
+7 -1
View File
@@ -11,7 +11,13 @@ from typing import Any
RESET_PRIMITIVES = {"rst_sync"}
CDC_PRIMITIVES = {"async_fifo", "cdc_2phase", "cdc_sync", "hazard3_apb_async_bridge"}
CDC_PRIMITIVES = {
"async_fifo",
"cdc_2phase",
"cdc_sync",
"edge_det",
"hazard3_apb_async_bridge",
}
IDENTIFIER_RE = re.compile(r"[A-Za-z_][A-Za-z0-9_]*$")
HIERARCHICAL_PIN_RE = re.compile(
r"[A-Za-z_][A-Za-z0-9_.]*(?:/[A-Za-z_][A-Za-z0-9_.]*)+$"
+135
View File
@@ -0,0 +1,135 @@
`timescale 1ns / 1ps
module clint_tb;
logic clk_i = 1'b0;
logic ref_clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic tick_i = 1'b0;
logic timebase_tick;
logic [31:0] value;
integer timebase_tick_count = 0;
ribp_if ribp ();
clint_if #(.HART_NUM(2)) clint ();
always #5 clk_i = ~clk_i;
always #2 ref_clk_i = ~ref_clk_i;
always @(posedge clk_i) begin
if (timebase_tick) timebase_tick_count <= timebase_tick_count + 1;
end
clint_timebase #(
.REF_CLK_HZ (4),
.TIMEBASE_HZ(1)
) u_timebase (
.ref_clk_i (ref_clk_i),
.ref_rst_n_i(rst_n_i),
.sys_clk_i (clk_i),
.sys_rst_n_i(rst_n_i),
.tick_o (timebase_tick)
);
ribp_clint #(
.HART_NUM(2)
) u_dut (
.clk_i,
.rst_n_i,
.timebase_tick_i(tick_i),
.ribp,
.clint
);
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 pulse_tick;
begin
@(negedge clk_i);
tick_i = 1'b1;
@(negedge clk_i);
tick_i = 1'b0;
end
endtask
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_0000, value, 1'b0);
if (value != 32'd0 || clint.software_irq_o != 2'b00) begin
$fatal(1, "MSIP reset state is invalid");
end
ribp_read(32'h0000_4000, value, 1'b0);
if (value != 32'hFFFF_FFFF) $fatal(1, "MTIMECMP low reset state is invalid");
ribp_read(32'h0000_4004, value, 1'b0);
if (value != 32'hFFFF_FFFF || clint.timer_irq_o != 2'b00) begin
$fatal(1, "MTIMECMP high reset state is invalid");
end
ribp_write(32'h0000_0004, 32'h0000_0001, 4'h1, 1'b0);
if (clint.software_irq_o != 2'b10) $fatal(1, "hart 1 MSIP did not assert");
ribp_write(32'h0000_0004, 32'h0000_0000, 4'h1, 1'b0);
if (clint.software_irq_o != 2'b00) $fatal(1, "hart 1 MSIP did not clear");
ribp_write(32'h0000_BFFC, 32'd0, 4'hF, 1'b0);
ribp_write(32'h0000_BFF8, 32'd10, 4'hF, 1'b0);
ribp_read(32'h0000_BFF8, value, 1'b0);
if (value != 32'd10) $fatal(1, "MTIME write/read failed: %h", value);
ribp_write(32'h0000_4004, 32'd0, 4'hF, 1'b0);
ribp_write(32'h0000_4000, 32'd12, 4'hF, 1'b0);
pulse_tick();
pulse_tick();
repeat (2) @(posedge clk_i);
if (clint.timer_irq_o[0] != 1'b1) $fatal(1, "hart 0 timer IRQ did not assert");
if (clint.timer_irq_o[1] != 1'b0) $fatal(1, "hart 1 timer IRQ asserted unexpectedly");
ribp_write(32'h0000_4001, 32'd0, 4'hF, 1'b1);
ribp_read(32'h0000_0010, value, 1'b1);
if (value != 32'd0) $fatal(1, "invalid read did not return zero");
repeat (20) @(posedge clk_i);
if (timebase_tick_count < 2) begin
$fatal(1, "reference-clock timebase did not produce synchronized ticks");
end
$display("CLINT standard map, multi-hart, IRQ, error, and timebase test passed");
$finish;
end
endmodule
+10 -9
View File
@@ -25,17 +25,18 @@ module pll_ctrl_tb;
always #27 aud_clk_i = ~aud_clk_i;
rcu u_rcu (
.ext_clk_i (ext_clk_i),
.aud_clk_i (aud_clk_i),
.ext_rst_n_i (rst_n_i),
.ext_clk_i (ext_clk_i),
.aud_clk_i (aud_clk_i),
.ext_rst_n_i (rst_n_i),
`ifdef HAVE_PLL
.xtal_clk_i (xtal_clk_i),
.xtal_clk_i (xtal_clk_i),
`endif
.pll_ctrl (pll_ctrl),
.sys_clk_o (sys_clk_o),
.sys_rst_n_o (sys_rst_n_o),
.aud_rst_n_o (aud_rst_n_o),
.sys_clkdiv4_o(sys_clkdiv4_o)
.pll_ctrl (pll_ctrl),
.sys_clk_o (sys_clk_o),
.sys_rst_n_o (sys_rst_n_o),
.aud_rst_n_o (aud_rst_n_o),
.sys_clkdiv4_o (sys_clkdiv4_o),
.timebase_tick_o()
);
ribp_sysctrl u_sysctrl (
+66
View File
@@ -0,0 +1,66 @@
"""CLINT 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_clint_standard_map_multi_hart_and_timebase(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 / "clint.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 / "utils/edge_det.sv"),
str(common / "cdc/cdc_sync.sv"),
str(common / "clkrst/counter.sv"),
str(PERIPHERAL / "clint_if.sv"),
str(PERIPHERAL / "clint_timebase.sv"),
str(PERIPHERAL / "clint_reg.sv"),
str(PERIPHERAL / "clint_core.sv"),
str(PERIPHERAL / "ribp_clint.sv"),
str(ROOT / "tests/rtl/clint_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "clint_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 / "clint_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "clint_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "CLINT standard map, multi-hart, IRQ, error, and timebase test passed" in result.stdout
+8 -1
View File
@@ -42,7 +42,14 @@ def test_clock_reset_domain_inventory_matches_the_rcu() -> None:
assert {
(crossing["name"], crossing["source"], crossing["destination"])
for crossing in document["crossings"]
} >= {("jtag_dmi", "jtag", "system")}
} >= {
("clint_timebase", "external", "system"),
("jtag_dmi", "jtag", "system"),
}
clint = next(
crossing for crossing in document["crossings"] if crossing["name"] == "clint_timebase"
)
assert clint["primitive"] == "edge_det"
def test_clock_reset_domain_inventory_rejects_unknown_domain_and_instance(tmp_path: Path) -> None:
+3
View File
@@ -227,7 +227,10 @@ def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path:
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_rst_ctrlr.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_2phase.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/rst_sync.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/counter.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/edge_det.sv"),
str(ROOT / "rtl/ip/ribp/peripheral/pll_ctrl_if.sv"),
str(ROOT / "rtl/ip/ribp/peripheral/clint_timebase.sv"),
str(ROOT / "rtl/ip/ribp/peripheral/sysctrl.sv"),
str(ROOT / "rtl/tech/tc_clk.sv"),
str(ROOT / "rtl/tech/tc_pll.sv"),
+9 -2
View File
@@ -205,6 +205,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
pll_rcu_filelist = tmp_path / "pll_rcu.fl"
gpio_user_filelist = tmp_path / "gpio_user.fl"
ws2812_filelist = tmp_path / "ws2812.fl"
clint_filelist = tmp_path / "clint.fl"
assert generate_formal_filelist("bus", bus_filelist, memory_map, topology, user_extensions)
assert generate_formal_filelist(
"rib_adapter", rib_adapter_filelist, memory_map, topology, user_extensions
@@ -224,6 +225,9 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
assert generate_formal_filelist(
"ws2812", ws2812_filelist, memory_map, topology, user_extensions
)
assert generate_formal_filelist(
"clint", clint_filelist, memory_map, topology, user_extensions
)
bus = parse_filelists([bus_filelist], require_files=False)
rib_adapter = parse_filelists([rib_adapter_filelist], require_files=False)
@@ -232,6 +236,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
pll_rcu = parse_filelists([pll_rcu_filelist], require_files=False)
gpio_user = parse_filelists([gpio_user_filelist], require_files=False)
ws2812 = parse_filelists([ws2812_filelist], require_files=False)
clint = parse_filelists([clint_filelist], require_files=False)
assert "+define+SV_ASSRT_DISABLE" in bus.defines
assert ROOT / "rtl/mini/top/bus.sv" in bus.files
assert ROOT / "rtl/mini/top/rib_if.sv" in bus.files
@@ -254,6 +259,8 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
assert ROOT / "rtl/ip/ribp/serial/ribp_ws2812.sv" in ws2812.files
assert ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv" in ws2812.files
assert ROOT / "rtl/mini/formal/ws2812_formal.sv" in ws2812.files
assert ROOT / "rtl/ip/ribp/peripheral/ribp_clint.sv" in clint.files
assert ROOT / "rtl/mini/formal/clint_formal.sv" in clint.files
def test_sysctrl_formal_properties_use_exported_user_core_shape() -> None:
@@ -751,8 +758,8 @@ def test_benchmark_profile_uses_functional_sram_and_reserved_data() -> None:
assert re.search(r"^PDK_BEHAV\s+\?= NO$", makefile, re.MULTILINE)
assert "PDK_BEHAV HAVE_SVA" in makefile
assert "PDK_BEHAV=YES is for functional simulation" in makefile
assert "HAVE_SRAM_MACRO := YES" in profile
assert "PDK_BEHAV := YES" in profile
assert re.search(r"^HAVE_SRAM_MACRO\s*:= YES$", profile, re.MULTILINE)
assert re.search(r"^PDK_BEHAV\s*:= YES$", profile, re.MULTILINE)
assert "RS_BENCHMARK_SRAM_OFFSET UINT32_C(0x10000)" in benchmark
+4 -3
View File
@@ -97,9 +97,10 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
assert ".apb_rib(u_apb_rib_if)" in bus_fabric
assert ".rib(u_rib_if)" in bus_fabric
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
assert "`define SOC_USER_IRQ_MASK 32'h0003FFFC" in irq_config
assert "`define SOC_IRQ_RIBP_WIDTH 11" in irq_config
assert "`define SOC_IRQ_APB_WIDTH 7" in irq_config
assert "assign irq_o[0] = u_clint_if.sfr_irq_o;" in rib_irq
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
assert "assign irq_o[5] = u_tmr_if.irq_o;" in apb_irq
assert "s_irq[16] = s_apb_irq[6];" in irq_wiring
@@ -122,8 +123,8 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
for interrupt in document["interrupts"]
]
assert mappings[:18] == [
("clint_software", "ribp", 0, 0, "u_clint_if.sfr_irq_o"),
("clint_timer", "ribp", 1, 1, "u_clint_if.tmr_irq_o"),
("clint_software", "ribp", 0, 0, "u_clint_if.software_irq_o[0]"),
("clint_timer", "ribp", 1, 1, "u_clint_if.timer_irq_o[0]"),
("uart0", "ribp", 2, 2, "uart.irq_o"),
("timer0", "ribp", 3, 3, "s_tim0_irq"),
("timer1", "ribp", 4, 4, "s_tim1_irq"),