feat: add System Control (SysCtrl) peripheral implementation and testbench

- Introduced sysctrl_define.svh to define register offsets and constants for SysCtrl.
- Created sysctrl_if.sv interface for communication with SysCtrl.
- Implemented sysctrl_reg.sv module to handle register read/write operations and state management.
- Developed sysctrl_tb.sv testbench to validate SysCtrl functionality, including lifecycle, fault handling, performance monitoring, and RTC wake status.
- Added Python regression test (test_sysctrl.py) to automate SysCtrl verification using Icarus Verilog.
This commit is contained in:
maksyuki committed 2026-08-15 21:08:59 +08:00
1 parent 24d425c3e8
commit 795559f785
31 files changed
+1441 -1025

No files matched your search

+6
View File
@@ -33,6 +33,12 @@ interrupts, and bounded self-test for the four-chip ESP-PSRAM64H controller.
See the [controller contract](../docs/ip/psram.md) before using its destructive
self-test or changing the memory timing.
`<retrosoc/hal/sysctrl.h>` owns typed access to SystemCtrl user-core/IP,
PLL, fault, performance, RTC-wake, and terminal-test functions. Existing
clock, user-core, performance, and test-service APIs use this HAL; direct
`reg_sysctrl_*` register macros are not public SDK interfaces. See the
[SystemCtrl contract](../docs/ip/sysctrl.md).
`crt/inc/` is legacy or generated compatibility material. It is not an active
public include root for the firmware build; new code must not add dependencies
on it.
+9 -68
View File
@@ -95,73 +95,14 @@
#define RS_SOC_DMA_ERROR_PENDING UINT32_C(0x00000001)
#define RS_SOC_DMA_ERROR_RESPONSE_SHIFT 1U
#define RS_SOC_DMA_ERROR_RESPONSE_MASK UINT32_C(0x0000000E)
// sys ctrl
#define RS_SOC_SYSCTRL_REG32(offset) RS_SOC_REG32(RS_SOC_RIBP_SYSCTRL_BASE, (offset))
#define reg_sysctrl_coresel RS_SOC_REG32(RS_SOC_RIBP_SYSCTRL_BASE, UINT32_C(0x00))
#define reg_sysctrl_ipsel RS_SOC_REG32(RS_SOC_RIBP_SYSCTRL_BASE, UINT32_C(0x04))
#define reg_sysctrl_pll_cfg RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PLL_CFG_OFFSET)
#define reg_sysctrl_pll_cmd RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PLL_CMD_OFFSET)
/* Status: bit 0 pending (W1C), bit 1 write, bits 3:2 reason (1 unmapped, 2 reserved). */
#define reg_sysctrl_bus_fault_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_STATUS_OFFSET)
#define reg_sysctrl_bus_fault_addr RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_ADDR_OFFSET)
#define reg_sysctrl_bus_fault_count RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_COUNT_OFFSET)
#define reg_sysctrl_pll_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PLL_STATUS_OFFSET)
#define reg_sysctrl_user_core_reset RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_USER_CORE_RESET_OFFSET)
#define reg_sysctrl_user_core_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_USER_CORE_STATUS_OFFSET)
#define reg_sysctrl_bus_fault_master RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_MASTER_OFFSET)
#define reg_sysctrl_bus_fault_detail RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_FAULT_DETAIL_OFFSET)
#define reg_sysctrl_perf_ctrl RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_CTRL_OFFSET)
#define reg_sysctrl_perf_mgmt_wait_lo RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_mgmt_wait_hi RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_user_wait_lo RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_USER_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_user_wait_hi RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_USER_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_dma_wait_lo RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_DMA_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_dma_wait_hi RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_DMA_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_ribp_wait_lo RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_ribp_wait_hi RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_apb_wait_lo RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_APB_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_apb_wait_hi RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_APB_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_sdram_wait_lo \
RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_sdram_wait_hi \
RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_psram_wait_lo \
RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_psram_wait_hi \
RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET)
#define reg_sysctrl_perf_flash_wait_lo \
RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET)
#define reg_sysctrl_perf_flash_wait_hi \
RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET)
#define reg_sysctrl_test_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_TEST_STATUS_OFFSET)
#define reg_sysctrl_rtc_wake_status RS_SOC_SYSCTRL_REG32(RS_SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET)
#define RS_SOC_TEST_STATUS_VALID UINT32_C(0x80000000)
#define RS_SOC_TEST_STATUS_CODE_SHIFT 8U
#define RS_SOC_TEST_STATUS_PASS UINT32_C(0x00000001)
#define RS_SOC_BUS_FAULT_PENDING UINT32_C(0x00000001)
#define RS_SOC_BUS_FAULT_WRITE UINT32_C(0x00000002)
#define RS_SOC_BUS_FAULT_REASON_MASK UINT32_C(0x0000000C)
#define RS_SOC_BUS_FAULT_REASON_UNMAPPED UINT32_C(0x00000004)
#define RS_SOC_BUS_FAULT_REASON_RESERVED UINT32_C(0x00000008)
#define RS_SOC_BUS_FAULT_RESPONSE_OK UINT32_C(0x00000000)
#define RS_SOC_BUS_FAULT_RESPONSE_DECERR UINT32_C(0x00000001)
#define RS_SOC_BUS_FAULT_RESPONSE_PROTERR UINT32_C(0x00000002)
#define RS_SOC_BUS_FAULT_RESPONSE_SLVERR UINT32_C(0x00000003)
#define RS_SOC_BUS_FAULT_RESPONSE_TIMEOUT UINT32_C(0x00000004)
#define RS_SOC_BUS_FAULT_RESPONSE_RESERVED UINT32_C(0x00000005)
#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)
#define RS_SOC_RTC_WAKE_LIVE UINT32_C(0x00000001)
#define RS_SOC_RTC_WAKE_SEEN UINT32_C(0x00000002)
// 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))
#define reg_user_ip_reg0 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x00))
#define reg_user_ip_reg1 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x04))
#define reg_user_ip_reg2 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x08))
#define reg_user_ip_reg3 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x0C))
#define reg_user_ip_reg4 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x10))
#define reg_user_ip_reg5 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x14))
#define reg_user_ip_reg6 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x18))
#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))
#define reg_user_ip_reg0 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x00))
#define reg_user_ip_reg1 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x04))
#define reg_user_ip_reg2 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x08))
#define reg_user_ip_reg3 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x0C))
#define reg_user_ip_reg4 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x10))
#define reg_user_ip_reg5 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x14))
#define reg_user_ip_reg6 RS_SOC_REG32(RS_SOC_APB_USER_IP_BASE, UINT32_C(0x18))
#endif
+71
View File
@@ -0,0 +1,71 @@
#ifndef RETROSOC_HAL_SYSCTRL_H
#define RETROSOC_HAL_SYSCTRL_H
#include <stdbool.h>
#include <stdint.h>
#include <retrosoc/core/status.h>
typedef enum {
RS_SYSCTRL_PERF_MGMT_WAIT = 0,
RS_SYSCTRL_PERF_USER_WAIT = 1,
RS_SYSCTRL_PERF_DMA_WAIT = 2,
RS_SYSCTRL_PERF_RIBP_WAIT = 3,
RS_SYSCTRL_PERF_APB_WAIT = 4,
RS_SYSCTRL_PERF_SDRAM_WAIT = 5,
RS_SYSCTRL_PERF_PSRAM_WAIT = 6,
RS_SYSCTRL_PERF_FLASH_WAIT = 7,
} rs_sysctrl_perf_counter_t;
typedef struct {
uint32_t reset_mask;
uint8_t selected_core;
bool bus_enabled;
bool bus_idle;
bool draining;
bool config_error;
} rs_sysctrl_user_core_status_t;
typedef struct {
uint32_t address;
uint32_t count;
uint8_t reason;
uint8_t detail;
uint8_t master;
bool pending;
bool write;
} rs_sysctrl_fault_status_t;
typedef struct {
uint32_t active_selection;
uint8_t error_reason;
bool active_valid;
bool busy;
bool error;
bool safe_clock;
bool pll_locked;
bool capable;
} rs_sysctrl_pll_status_t;
rs_status_t rs_sysctrl_get_core_select(uint8_t *core_id);
rs_status_t rs_sysctrl_set_core_select(uint8_t core_id);
rs_status_t rs_sysctrl_get_ip_select(uint8_t *ip_id);
rs_status_t rs_sysctrl_set_ip_select(uint8_t ip_id);
rs_status_t rs_sysctrl_get_user_core_status(rs_sysctrl_user_core_status_t *status);
rs_status_t rs_sysctrl_set_user_core_reset(uint32_t reset_mask);
rs_status_t rs_sysctrl_clear_user_core_config_error(void);
rs_status_t rs_sysctrl_get_pll_config(uint8_t *selection);
rs_status_t rs_sysctrl_set_pll_config(uint8_t selection);
rs_status_t rs_sysctrl_apply_pll_config(void);
rs_status_t rs_sysctrl_clear_pll_error(void);
rs_status_t rs_sysctrl_get_pll_status(rs_sysctrl_pll_status_t *status);
rs_status_t rs_sysctrl_get_fault_status(rs_sysctrl_fault_status_t *status);
rs_status_t rs_sysctrl_clear_fault(void);
rs_status_t rs_sysctrl_set_perf_control(bool enable, bool clear, bool snapshot);
rs_status_t rs_sysctrl_read_perf_counter(rs_sysctrl_perf_counter_t counter, uint64_t *value);
void rs_sysctrl_write_test_status(bool pass, uint8_t code);
rs_status_t rs_sysctrl_get_test_status(bool *done, bool *pass, uint8_t *code);
rs_status_t rs_sysctrl_get_rtc_wake_status(bool *live, bool *seen);
rs_status_t rs_sysctrl_clear_rtc_wake(void);
#endif
+22 -25
View File
@@ -2,39 +2,34 @@
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/clock.h>
#include <retrosoc/hal/sysctrl.h>
#define RS_CLOCK_CMD_APPLY UINT32_C(0x00000001)
#define RS_CLOCK_CMD_CLEAR_ERROR UINT32_C(0x00000002)
#define RS_CLOCK_STATUS_ACTIVE_MASK UINT32_C(0x00000007)
#define RS_CLOCK_STATUS_ACTIVE_VALID UINT32_C(0x00000008)
#define RS_CLOCK_STATUS_BUSY UINT32_C(0x00000010)
#define RS_CLOCK_STATUS_ERROR_SHIFT 6U
#define RS_CLOCK_STATUS_SAFE_CLOCK UINT32_C(0x00000100)
#define RS_CLOCK_STATUS_PLL_LOCKED UINT32_C(0x00000200)
#define RS_CLOCK_STATUS_CAPABLE UINT32_C(0x00000400)
#define RS_CLOCK_ERROR_UNSUPPORTED 1U
#define RS_CLOCK_ERROR_LOCK_TIMEOUT 2U
#define RS_CLOCK_ERROR_UNSUPPORTED 1U
#define RS_CLOCK_ERROR_LOCK_TIMEOUT 2U
static bool rs_clock_frequency_valid(rs_clock_frequency_t frequency) {
return (uint32_t)frequency <= (uint32_t)RS_CLOCK_FREQ_192MHZ;
}
rs_status_t rs_clock_get_status(rs_clock_status_t *status) {
uint32_t value;
rs_sysctrl_pll_status_t sysctrl_status;
uint8_t requested_frequency;
if (status == NULL) {
return RS_EINVAL;
}
value = reg_sysctrl_pll_status;
status->requested_frequency =
(rs_clock_frequency_t)(reg_sysctrl_pll_cfg & RS_CLOCK_STATUS_ACTIVE_MASK);
status->active_frequency = (rs_clock_frequency_t)(value & RS_CLOCK_STATUS_ACTIVE_MASK);
status->error_reason = (uint8_t)((value >> RS_CLOCK_STATUS_ERROR_SHIFT) & UINT32_C(0x3));
status->active_valid = (value & RS_CLOCK_STATUS_ACTIVE_VALID) != 0U;
status->busy = (value & RS_CLOCK_STATUS_BUSY) != 0U;
status->safe_clock = (value & RS_CLOCK_STATUS_SAFE_CLOCK) != 0U;
status->pll_locked = (value & RS_CLOCK_STATUS_PLL_LOCKED) != 0U;
status->capable = (value & RS_CLOCK_STATUS_CAPABLE) != 0U;
if ((rs_sysctrl_get_pll_config(&requested_frequency) != RS_OK) ||
(rs_sysctrl_get_pll_status(&sysctrl_status) != RS_OK)) {
return RS_EIO;
}
status->requested_frequency = (rs_clock_frequency_t)requested_frequency;
status->active_frequency = (rs_clock_frequency_t)sysctrl_status.active_selection;
status->error_reason = sysctrl_status.error_reason;
status->active_valid = sysctrl_status.active_valid;
status->busy = sysctrl_status.busy;
status->safe_clock = sysctrl_status.safe_clock;
status->pll_locked = sysctrl_status.pll_locked;
status->capable = sysctrl_status.capable;
return RS_OK;
}
@@ -82,9 +77,11 @@ rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t
return RS_EIO;
}
reg_sysctrl_pll_cmd = RS_CLOCK_CMD_CLEAR_ERROR;
reg_sysctrl_pll_cfg = (uint32_t)frequency;
reg_sysctrl_pll_cmd = RS_CLOCK_CMD_APPLY;
if ((rs_sysctrl_clear_pll_error() != RS_OK) ||
(rs_sysctrl_set_pll_config((uint8_t)frequency) != RS_OK) ||
(rs_sysctrl_apply_pll_config() != RS_OK)) {
return RS_EIO;
}
while (timeout-- != 0U) {
if (rs_clock_get_status(&status) != RS_OK) {
+20 -26
View File
@@ -1,21 +1,18 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/perf.h>
static uint64_t rs_perf_read_counter(volatile const uint32_t *low, volatile const uint32_t *high) {
return ((uint64_t)*high << 32) | (uint64_t)*low;
}
#include <retrosoc/hal/sysctrl.h>
rs_status_t rs_perf_start(void) {
reg_sysctrl_perf_ctrl = RS_SOC_PERF_CTRL_CLEAR;
reg_sysctrl_perf_ctrl = RS_SOC_PERF_CTRL_ENABLE;
if ((rs_sysctrl_set_perf_control(false, true, false) != RS_OK) ||
(rs_sysctrl_set_perf_control(true, false, false) != RS_OK)) {
return RS_EIO;
}
return RS_OK;
}
rs_status_t rs_perf_stop(void) {
reg_sysctrl_perf_ctrl = 0U;
return RS_OK;
return rs_sysctrl_set_perf_control(false, false, false);
}
rs_status_t rs_perf_snapshot(rs_perf_snapshot_t *snapshot) {
@@ -23,22 +20,19 @@ rs_status_t rs_perf_snapshot(rs_perf_snapshot_t *snapshot) {
return RS_EINVAL;
}
reg_sysctrl_perf_ctrl = RS_SOC_PERF_CTRL_ENABLE | RS_SOC_PERF_CTRL_SNAPSHOT;
snapshot->mgmt_wait =
rs_perf_read_counter(&reg_sysctrl_perf_mgmt_wait_lo, &reg_sysctrl_perf_mgmt_wait_hi);
snapshot->user_wait =
rs_perf_read_counter(&reg_sysctrl_perf_user_wait_lo, &reg_sysctrl_perf_user_wait_hi);
snapshot->dma_wait =
rs_perf_read_counter(&reg_sysctrl_perf_dma_wait_lo, &reg_sysctrl_perf_dma_wait_hi);
snapshot->ribp_wait =
rs_perf_read_counter(&reg_sysctrl_perf_ribp_wait_lo, &reg_sysctrl_perf_ribp_wait_hi);
snapshot->apb_wait =
rs_perf_read_counter(&reg_sysctrl_perf_apb_wait_lo, &reg_sysctrl_perf_apb_wait_hi);
snapshot->sdram_wait =
rs_perf_read_counter(&reg_sysctrl_perf_sdram_wait_lo, &reg_sysctrl_perf_sdram_wait_hi);
snapshot->psram_wait =
rs_perf_read_counter(&reg_sysctrl_perf_psram_wait_lo, &reg_sysctrl_perf_psram_wait_hi);
snapshot->flash_wait =
rs_perf_read_counter(&reg_sysctrl_perf_flash_wait_lo, &reg_sysctrl_perf_flash_wait_hi);
if ((rs_sysctrl_set_perf_control(true, false, true) != RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_MGMT_WAIT, &snapshot->mgmt_wait) != RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_USER_WAIT, &snapshot->user_wait) != RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_DMA_WAIT, &snapshot->dma_wait) != RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_RIBP_WAIT, &snapshot->ribp_wait) != RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_APB_WAIT, &snapshot->apb_wait) != RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_SDRAM_WAIT, &snapshot->sdram_wait) !=
RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_PSRAM_WAIT, &snapshot->psram_wait) !=
RS_OK) ||
(rs_sysctrl_read_perf_counter(RS_SYSCTRL_PERF_FLASH_WAIT, &snapshot->flash_wait) !=
RS_OK)) {
return RS_EIO;
}
return RS_OK;
}
+304
View File
@@ -0,0 +1,304 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/sysctrl.h>
#define RS_SYSCTRL_CORESEL_OFFSET RS_SOC_SYSCTRL_CORESEL_OFFSET
#define RS_SYSCTRL_IPSEL_OFFSET RS_SOC_SYSCTRL_IPSEL_OFFSET
#define RS_SYSCTRL_PLL_CFG_OFFSET RS_SOC_SYSCTRL_PLL_CFG_OFFSET
#define RS_SYSCTRL_PLL_CMD_OFFSET RS_SOC_SYSCTRL_PLL_CMD_OFFSET
#define RS_SYSCTRL_FAULT_STATUS_OFFSET RS_SOC_SYSCTRL_FAULT_STATUS_OFFSET
#define RS_SYSCTRL_FAULT_ADDR_OFFSET RS_SOC_SYSCTRL_FAULT_ADDR_OFFSET
#define RS_SYSCTRL_FAULT_COUNT_OFFSET RS_SOC_SYSCTRL_FAULT_COUNT_OFFSET
#define RS_SYSCTRL_PLL_STATUS_OFFSET RS_SOC_SYSCTRL_PLL_STATUS_OFFSET
#define RS_SYSCTRL_USER_CORE_RESET_OFFSET RS_SOC_SYSCTRL_USER_CORE_RESET_OFFSET
#define RS_SYSCTRL_USER_CORE_STATUS_OFFSET RS_SOC_SYSCTRL_USER_CORE_STATUS_OFFSET
#define RS_SYSCTRL_FAULT_MASTER_OFFSET RS_SOC_SYSCTRL_FAULT_MASTER_OFFSET
#define RS_SYSCTRL_FAULT_DETAIL_OFFSET RS_SOC_SYSCTRL_FAULT_DETAIL_OFFSET
#define RS_SYSCTRL_PERF_CTRL_OFFSET RS_SOC_SYSCTRL_PERF_CTRL_OFFSET
#define RS_SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_USER_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_USER_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_USER_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_USER_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_DMA_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_DMA_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_DMA_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_DMA_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_APB_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_APB_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_APB_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_APB_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET
#define RS_SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET RS_SOC_SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET
#define RS_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET RS_SOC_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET
#define RS_SYSCTRL_TEST_STATUS_OFFSET RS_SOC_SYSCTRL_TEST_STATUS_OFFSET
#define RS_SYSCTRL_RTC_WAKE_STATUS_OFFSET RS_SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET
#define RS_SYSCTRL_PLL_CMD_APPLY UINT32_C(0x00000001)
#define RS_SYSCTRL_PLL_CMD_CLEAR_ERROR UINT32_C(0x00000002)
#define RS_SYSCTRL_FAULT_PENDING UINT32_C(0x00000001)
#define RS_SYSCTRL_PERF_ENABLE UINT32_C(0x00000001)
#define RS_SYSCTRL_PERF_CLEAR UINT32_C(0x00000002)
#define RS_SYSCTRL_PERF_SNAPSHOT UINT32_C(0x00000004)
#define RS_SYSCTRL_PERF_CONTROL_MASK UINT32_C(0x00000007)
#define RS_SYSCTRL_TEST_STATUS_VALID UINT32_C(0x80000000)
#define RS_SYSCTRL_TEST_STATUS_PASS UINT32_C(0x00000001)
#define RS_SYSCTRL_TEST_STATUS_CODE_SHIFT 8U
#define RS_SYSCTRL_USER_CORE_SEL_MASK UINT32_C(0x0000001F)
#define RS_SYSCTRL_USER_CORE_BUS_ENABLED UINT32_C(0x00000100)
#define RS_SYSCTRL_USER_CORE_BUS_IDLE UINT32_C(0x00000200)
#define RS_SYSCTRL_USER_CORE_DRAINING UINT32_C(0x00000400)
#define RS_SYSCTRL_USER_CORE_CONFIG_ERROR UINT32_C(0x00000800)
#define RS_SYSCTRL_PLL_SELECTION_MASK UINT32_C(0x00000007)
#define RS_SYSCTRL_PLL_ACTIVE_VALID UINT32_C(0x00000008)
#define RS_SYSCTRL_PLL_BUSY UINT32_C(0x00000010)
#define RS_SYSCTRL_PLL_ERROR UINT32_C(0x00000020)
#define RS_SYSCTRL_PLL_ERROR_SHIFT 6U
#define RS_SYSCTRL_PLL_SAFE_CLOCK UINT32_C(0x00000100)
#define RS_SYSCTRL_PLL_LOCKED UINT32_C(0x00000200)
#define RS_SYSCTRL_PLL_CAPABLE UINT32_C(0x00000400)
#define RS_SYSCTRL_RTC_WAKE_LIVE UINT32_C(0x00000001)
#define RS_SYSCTRL_RTC_WAKE_SEEN UINT32_C(0x00000002)
static volatile uint32_t *rs_sysctrl_register(uint32_t offset) {
return (volatile uint32_t *)(RS_SOC_RIBP_SYSCTRL_BASE + (uintptr_t)offset);
}
static rs_status_t rs_sysctrl_perf_offsets(rs_sysctrl_perf_counter_t counter, uint32_t *low_offset,
uint32_t *high_offset) {
if ((low_offset == NULL) || (high_offset == NULL)) {
return RS_EINVAL;
}
switch (counter) {
case RS_SYSCTRL_PERF_MGMT_WAIT:
*low_offset = RS_SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_USER_WAIT:
*low_offset = RS_SYSCTRL_PERF_USER_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_USER_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_DMA_WAIT:
*low_offset = RS_SYSCTRL_PERF_DMA_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_DMA_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_RIBP_WAIT:
*low_offset = RS_SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_APB_WAIT:
*low_offset = RS_SYSCTRL_PERF_APB_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_APB_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_SDRAM_WAIT:
*low_offset = RS_SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_PSRAM_WAIT:
*low_offset = RS_SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET;
break;
case RS_SYSCTRL_PERF_FLASH_WAIT:
*low_offset = RS_SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET;
*high_offset = RS_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET;
break;
default:
return RS_EINVAL;
}
return RS_OK;
}
rs_status_t rs_sysctrl_get_core_select(uint8_t *core_id) {
if (core_id == NULL) {
return RS_EINVAL;
}
*core_id = (uint8_t)*rs_sysctrl_register(RS_SYSCTRL_CORESEL_OFFSET);
return RS_OK;
}
rs_status_t rs_sysctrl_set_core_select(uint8_t core_id) {
if ((uint32_t)core_id >= RS_SOC_USER_CORE_COUNT) {
return RS_EINVAL;
}
*rs_sysctrl_register(RS_SYSCTRL_CORESEL_OFFSET) = (uint32_t)core_id;
return RS_OK;
}
rs_status_t rs_sysctrl_get_ip_select(uint8_t *ip_id) {
if (ip_id == NULL) {
return RS_EINVAL;
}
*ip_id = (uint8_t)*rs_sysctrl_register(RS_SYSCTRL_IPSEL_OFFSET);
return RS_OK;
}
rs_status_t rs_sysctrl_set_ip_select(uint8_t ip_id) {
*rs_sysctrl_register(RS_SYSCTRL_IPSEL_OFFSET) = (uint32_t)ip_id;
return RS_OK;
}
rs_status_t rs_sysctrl_get_user_core_status(rs_sysctrl_user_core_status_t *status) {
uint32_t value;
if (status == NULL) {
return RS_EINVAL;
}
value = *rs_sysctrl_register(RS_SYSCTRL_USER_CORE_STATUS_OFFSET);
status->reset_mask = *rs_sysctrl_register(RS_SYSCTRL_USER_CORE_RESET_OFFSET);
status->selected_core = (uint8_t)(value & RS_SYSCTRL_USER_CORE_SEL_MASK);
status->bus_enabled = (value & RS_SYSCTRL_USER_CORE_BUS_ENABLED) != 0U;
status->bus_idle = (value & RS_SYSCTRL_USER_CORE_BUS_IDLE) != 0U;
status->draining = (value & RS_SYSCTRL_USER_CORE_DRAINING) != 0U;
status->config_error = (value & RS_SYSCTRL_USER_CORE_CONFIG_ERROR) != 0U;
return RS_OK;
}
rs_status_t rs_sysctrl_set_user_core_reset(uint32_t reset_mask) {
*rs_sysctrl_register(RS_SYSCTRL_USER_CORE_RESET_OFFSET) = reset_mask;
return RS_OK;
}
rs_status_t rs_sysctrl_clear_user_core_config_error(void) {
*rs_sysctrl_register(RS_SYSCTRL_USER_CORE_STATUS_OFFSET) = RS_SYSCTRL_USER_CORE_CONFIG_ERROR;
return RS_OK;
}
rs_status_t rs_sysctrl_get_pll_config(uint8_t *selection) {
if (selection == NULL) {
return RS_EINVAL;
}
*selection =
(uint8_t)(*rs_sysctrl_register(RS_SYSCTRL_PLL_CFG_OFFSET) & RS_SYSCTRL_PLL_SELECTION_MASK);
return RS_OK;
}
rs_status_t rs_sysctrl_set_pll_config(uint8_t selection) {
if (((uint32_t)selection & ~RS_SYSCTRL_PLL_SELECTION_MASK) != 0U) {
return RS_EINVAL;
}
*rs_sysctrl_register(RS_SYSCTRL_PLL_CFG_OFFSET) = (uint32_t)selection;
return RS_OK;
}
rs_status_t rs_sysctrl_apply_pll_config(void) {
*rs_sysctrl_register(RS_SYSCTRL_PLL_CMD_OFFSET) = RS_SYSCTRL_PLL_CMD_APPLY;
return RS_OK;
}
rs_status_t rs_sysctrl_clear_pll_error(void) {
*rs_sysctrl_register(RS_SYSCTRL_PLL_CMD_OFFSET) = RS_SYSCTRL_PLL_CMD_CLEAR_ERROR;
return RS_OK;
}
rs_status_t rs_sysctrl_get_pll_status(rs_sysctrl_pll_status_t *status) {
uint32_t value;
if (status == NULL) {
return RS_EINVAL;
}
value = *rs_sysctrl_register(RS_SYSCTRL_PLL_STATUS_OFFSET);
status->active_selection = value & RS_SYSCTRL_PLL_SELECTION_MASK;
status->error_reason = (uint8_t)((value >> RS_SYSCTRL_PLL_ERROR_SHIFT) & UINT32_C(0x3));
status->active_valid = (value & RS_SYSCTRL_PLL_ACTIVE_VALID) != 0U;
status->busy = (value & RS_SYSCTRL_PLL_BUSY) != 0U;
status->error = (value & RS_SYSCTRL_PLL_ERROR) != 0U;
status->safe_clock = (value & RS_SYSCTRL_PLL_SAFE_CLOCK) != 0U;
status->pll_locked = (value & RS_SYSCTRL_PLL_LOCKED) != 0U;
status->capable = (value & RS_SYSCTRL_PLL_CAPABLE) != 0U;
return RS_OK;
}
rs_status_t rs_sysctrl_get_fault_status(rs_sysctrl_fault_status_t *status) {
uint32_t value;
if (status == NULL) {
return RS_EINVAL;
}
value = *rs_sysctrl_register(RS_SYSCTRL_FAULT_STATUS_OFFSET);
status->address = *rs_sysctrl_register(RS_SYSCTRL_FAULT_ADDR_OFFSET);
status->count = *rs_sysctrl_register(RS_SYSCTRL_FAULT_COUNT_OFFSET);
status->master = (uint8_t)*rs_sysctrl_register(RS_SYSCTRL_FAULT_MASTER_OFFSET);
status->detail = (uint8_t)*rs_sysctrl_register(RS_SYSCTRL_FAULT_DETAIL_OFFSET);
status->pending = (value & RS_SYSCTRL_FAULT_PENDING) != 0U;
status->write = (value & UINT32_C(0x00000002)) != 0U;
status->reason = (uint8_t)((value >> 2U) & UINT32_C(0x7));
return RS_OK;
}
rs_status_t rs_sysctrl_clear_fault(void) {
*rs_sysctrl_register(RS_SYSCTRL_FAULT_STATUS_OFFSET) = RS_SYSCTRL_FAULT_PENDING;
return RS_OK;
}
rs_status_t rs_sysctrl_set_perf_control(bool enable, bool clear, bool snapshot) {
uint32_t control = 0U;
if (enable) {
control |= RS_SYSCTRL_PERF_ENABLE;
}
if (clear) {
control |= RS_SYSCTRL_PERF_CLEAR;
}
if (snapshot) {
control |= RS_SYSCTRL_PERF_SNAPSHOT;
}
*rs_sysctrl_register(RS_SYSCTRL_PERF_CTRL_OFFSET) = control & RS_SYSCTRL_PERF_CONTROL_MASK;
return RS_OK;
}
rs_status_t rs_sysctrl_read_perf_counter(rs_sysctrl_perf_counter_t counter, uint64_t *value) {
uint32_t low_offset;
uint32_t high_offset;
if (value == NULL) {
return RS_EINVAL;
}
if (rs_sysctrl_perf_offsets(counter, &low_offset, &high_offset) != RS_OK) {
return RS_EINVAL;
}
*value = ((uint64_t)*rs_sysctrl_register(high_offset) << 32U) |
(uint64_t)*rs_sysctrl_register(low_offset);
return RS_OK;
}
void rs_sysctrl_write_test_status(bool pass, uint8_t code) {
uint32_t value =
RS_SYSCTRL_TEST_STATUS_VALID | ((uint32_t)code << RS_SYSCTRL_TEST_STATUS_CODE_SHIFT);
if (pass) {
value |= RS_SYSCTRL_TEST_STATUS_PASS;
}
*rs_sysctrl_register(RS_SYSCTRL_TEST_STATUS_OFFSET) = value;
}
rs_status_t rs_sysctrl_get_test_status(bool *done, bool *pass, uint8_t *code) {
uint32_t value;
if ((done == NULL) || (pass == NULL) || (code == NULL)) {
return RS_EINVAL;
}
value = *rs_sysctrl_register(RS_SYSCTRL_TEST_STATUS_OFFSET);
*done = (value & RS_SYSCTRL_TEST_STATUS_VALID) != 0U;
*pass = (value & RS_SYSCTRL_TEST_STATUS_PASS) != 0U;
*code = (uint8_t)(value >> RS_SYSCTRL_TEST_STATUS_CODE_SHIFT);
return RS_OK;
}
rs_status_t rs_sysctrl_get_rtc_wake_status(bool *live, bool *seen) {
uint32_t value;
if ((live == NULL) || (seen == NULL)) {
return RS_EINVAL;
}
value = *rs_sysctrl_register(RS_SYSCTRL_RTC_WAKE_STATUS_OFFSET);
*live = (value & RS_SYSCTRL_RTC_WAKE_LIVE) != 0U;
*seen = (value & RS_SYSCTRL_RTC_WAKE_SEEN) != 0U;
return RS_OK;
}
rs_status_t rs_sysctrl_clear_rtc_wake(void) {
*rs_sysctrl_register(RS_SYSCTRL_RTC_WAKE_STATUS_OFFSET) = RS_SYSCTRL_RTC_WAKE_SEEN;
return RS_OK;
}
+21 -18
View File
@@ -1,38 +1,37 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/sysctrl.h>
#include <retrosoc/hal/user_core.h>
#define RS_USER_CORE_STATUS_SEL_MASK UINT32_C(0x0000001F)
#define RS_USER_CORE_STATUS_BUS_ENABLED UINT32_C(0x00000100)
#define RS_USER_CORE_STATUS_BUS_IDLE UINT32_C(0x00000200)
#define RS_USER_CORE_STATUS_DRAINING UINT32_C(0x00000400)
#define RS_USER_CORE_STATUS_CONFIG_ERROR UINT32_C(0x00000800)
static uint32_t rs_user_core_reset_mask_all(void) {
return UINT32_MAX >> (UINT32_C(32) - RS_SOC_USER_CORE_COUNT);
}
rs_status_t rs_user_core_get_status(rs_user_core_status_t *status) {
uint32_t value;
rs_sysctrl_user_core_status_t sysctrl_status;
if (status == NULL) {
return RS_EINVAL;
}
value = reg_sysctrl_user_core_status;
status->reset_mask = reg_sysctrl_user_core_reset;
status->selected_core = (uint8_t)(value & RS_USER_CORE_STATUS_SEL_MASK);
status->bus_enabled = (value & RS_USER_CORE_STATUS_BUS_ENABLED) != UINT32_C(0);
status->bus_idle = (value & RS_USER_CORE_STATUS_BUS_IDLE) != UINT32_C(0);
status->draining = (value & RS_USER_CORE_STATUS_DRAINING) != UINT32_C(0);
status->config_error = (value & RS_USER_CORE_STATUS_CONFIG_ERROR) != UINT32_C(0);
if (rs_sysctrl_get_user_core_status(&sysctrl_status) != RS_OK) {
return RS_EIO;
}
status->reset_mask = sysctrl_status.reset_mask;
status->selected_core = sysctrl_status.selected_core;
status->bus_enabled = sysctrl_status.bus_enabled;
status->bus_idle = sysctrl_status.bus_idle;
status->draining = sysctrl_status.draining;
status->config_error = sysctrl_status.config_error;
return RS_OK;
}
rs_status_t rs_user_core_stop(rs_timeout_t timeout) {
rs_user_core_status_t status;
reg_sysctrl_user_core_reset = rs_user_core_reset_mask_all();
if (rs_sysctrl_set_user_core_reset(rs_user_core_reset_mask_all()) != RS_OK) {
return RS_EIO;
}
while (timeout-- != 0U) {
if (rs_user_core_get_status(&status) != RS_OK) {
return RS_EIO;
@@ -59,8 +58,10 @@ rs_status_t rs_user_core_start(uint8_t core_id, rs_timeout_t timeout) {
if (result != RS_OK) {
return result;
}
reg_sysctrl_user_core_status = RS_USER_CORE_STATUS_CONFIG_ERROR;
reg_sysctrl_coresel = (uint32_t)core_id;
if ((rs_sysctrl_clear_user_core_config_error() != RS_OK) ||
(rs_sysctrl_set_core_select(core_id) != RS_OK)) {
return RS_EIO;
}
if (rs_user_core_get_status(&status) != RS_OK) {
return RS_EIO;
}
@@ -68,7 +69,9 @@ rs_status_t rs_user_core_start(uint8_t core_id, rs_timeout_t timeout) {
return RS_EIO;
}
reset_mask = rs_user_core_reset_mask_all() & ~(UINT32_C(1) << core_id);
reg_sysctrl_user_core_reset = reset_mask;
if (rs_sysctrl_set_user_core_reset(reset_mask) != RS_OK) {
return RS_EIO;
}
while (timeout-- != 0U) {
if (rs_user_core_get_status(&status) != RS_OK) {
return RS_EIO;
+12 -3
View File
@@ -4,6 +4,7 @@
#include <retrosoc/lib/printf.h>
#include <socver.h>
#include <retrosoc/hal/psram.h>
#include <retrosoc/hal/sysctrl.h>
#include <retrosoc/hal/timer.h>
#include <retrosoc/lib/console.h>
#include <retrosoc/lib/string.h>
@@ -12,6 +13,13 @@
#include <user_design_info.h>
void rs_app_info(void) {
uint8_t selected_core;
uint8_t selected_ip;
selected_core = 0U;
selected_ip = 0U;
(void)rs_sysctrl_get_core_select(&selected_core);
(void)rs_sysctrl_get_ip_select(&selected_ip);
printf("#############################################################\n");
printf("#############################################################\n");
printf("compile date: %s %s\n", __DATE__, __TIME__);
@@ -52,7 +60,7 @@ void rs_app_info(void) {
uint32_t core_size = sizeof(user_core_info) / sizeof(user_core_info[0]);
printf(" %-15s %-12s %-12s %s\n", "[name]", "[isa]", "[maintainer]", "[repo]");
for (uint32_t i = 0; i < core_size; ++i) {
if (reg_sysctrl_coresel == i)
if (selected_core == i)
printf("=>");
else
printf(" ");
@@ -64,7 +72,7 @@ void rs_app_info(void) {
uint32_t ip_size = sizeof(user_ip_info) / sizeof(user_ip_info[0]);
printf(" %-15s %-12s %-12s %s\n", "[name]", "[isa]", "[maintainer]", "[repo]");
for (uint32_t i = 0; i < ip_size; ++i) {
if (reg_sysctrl_ipsel == i)
if (selected_ip == i)
printf("=>");
else
printf(" ");
@@ -111,7 +119,8 @@ void rs_app_info(void) {
(void *)(uintptr_t)RS_SOC_RIBP_WS2812_BASE);
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 SYSCTRL @%p\n",
(void *)(uintptr_t)RS_SOC_RIBP_SYSCTRL_BASE);
printf(" 1 x CLINT @%p\n",
(void *)(uintptr_t)RS_SOC_RIBP_CLINT_BASE);
printf(" 1 x SDRAM @%p\n", (void *)&reg_sdram_clkdiv);
+12 -2
View File
@@ -5,6 +5,7 @@
#include <retrosoc/lib/string.h>
#include <retrosoc/service/shell.h>
#include <retrosoc/hal/lcd.h>
#include <retrosoc/hal/sysctrl.h>
#include <retrosoc/hal/timer.h>
#include <ff.h>
#include <retrosoc/media/video_player.h>
@@ -684,20 +685,29 @@ static void rs_shell_app_coremark_cmd(int argc, char **argv) {
}
static void rs_shell_app_userip_cmd(int argc, char **argv) {
uint8_t current_user_id;
if (argc != 1 && argc != 2) {
printf("[userip] cmd param error\n");
return;
}
if (argc == 1) {
printf("current user ip id: %03d\n", reg_sysctrl_ipsel);
if (rs_sysctrl_get_ip_select(&current_user_id) != RS_OK) {
printf("user ip selection read failed\n");
return;
}
printf("current user ip id: %03d\n", current_user_id);
userip_main(0, NULL);
} else if (argc == 2) {
int32_t user_id;
if ((rs_strtoi32(argv[1], &user_id) == RS_OK) && (user_id >= 0) && (user_id <= 255)) {
printf("switch to user ip id to [%03d...]\n", user_id);
reg_sysctrl_ipsel = (uint8_t)user_id;
if (rs_sysctrl_set_ip_select((uint8_t)user_id) != RS_OK) {
printf("user ip selection write failed\n");
return;
}
userip_main((int)user_id, NULL); // HACK:
} else {
printf("error use id: %d\n", user_id);
+2 -7
View File
@@ -1,13 +1,8 @@
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/sysctrl.h>
#include <retrosoc/service/test.h>
void rs_test_finish(rs_test_result_t result, uint8_t code) {
uint32_t status = RS_SOC_TEST_STATUS_VALID | ((uint32_t)code << RS_SOC_TEST_STATUS_CODE_SHIFT);
if (result == RS_TEST_PASSED) {
status |= RS_SOC_TEST_STATUS_PASS;
}
reg_sysctrl_test_status = status;
rs_sysctrl_write_test_status(result == RS_TEST_PASSED, code);
for (;;) {
}
}
+2
View File
@@ -34,6 +34,8 @@ the root README and subsystem guides.
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/sysctrl.md](ip/sysctrl.md) defines the SystemCtrl register ABI, user-core
lifecycle, PLL/fault/performance/RTC/test contracts, HAL, and verification.
- [ip/clint.md](ip/clint.md) defines the standard CLINT register map, fixed
timebase, RV32 access rules, interrupt behavior, and verification contract.
- [ip/gpio.md](ip/gpio.md) defines the GPIO dual-window ABI, pad ownership,
+1
View File
@@ -4,6 +4,7 @@ This directory owns architecture, register ABI, software contract, and
verification documentation for self-owned retroSoC peripheral IP.
- [timer.md](timer.md) defines the dual RIBP general timer.
- [sysctrl.md](sysctrl.md) defines the RIBP SystemCtrl register ABI, control-plane contracts, HAL, and verification.
- [ws2812.md](ws2812.md) defines the WS2812 transmitter.
- [clint.md](clint.md) defines the management-hart software and timer interrupt block.
- [gpio.md](gpio.md) defines the dual-window GPIO controller.
+86
View File
@@ -0,0 +1,86 @@
# RIBP System Control
SystemCtrl is the Mini SoC control-plane peripheral at
`0x1000B000`. It owns user-core/IP selection, the PLL request protocol,
bus-fault retention, performance-counter snapshots, RTC wake observation, and
the terminal simulation result. The integration wrapper is `ribp_sysctrl`;
the implementation is separated into `sysctrl_reg`, `sysctrl_core`, and
`sysctrl_if`.
## Integration
`sysctrl_if` is the SoC-facing contract. It drives the selected user core,
per-core reset mask, user-bus enable, selected user IP, performance
enable/clear, and sticky terminal test result. It receives user-bus idle,
fault metadata, eight wait counters, and asynchronous RTC wake. `sysctrl_core`
synchronizes RTC wake with the Common `cdc_sync` primitive before storing its
sticky state.
`pll_ctrl_if` carries a one-request PLL configuration handshake. SystemCtrl
asserts `req_valid_o` after a valid `PLL_CMD.APPLY`, holds `busy` until the
PLL response is accepted, and always asserts `rsp_ready_o`. See
[PLL Clock Control](../pll-clock-control.md) for the required software
quiesce sequence.
## RIBP contract
SystemCtrl accepts a RIBP request when `valid` is high and its registered
`ready` is low. It responds in the following cycle, holds `resp_err` low as
in the established ABI, and captures read data on accepted reads. Reads of an
unmapped register retain the previously captured read value. Writes use the
existing byte strobe qualification for each field; software must use full-word
writes for `TEST_STATUS`.
The offset map remains generated from
`rtl/mini/address_map/memory_map.json`. RTL aliases are in
`rtl/ip/peripheral/sysctrl_define.svh`; neither file changes the generated C
offset macros.
## Register ABI
| Offset | Register | Access | Semantics |
| --- | --- | --- | --- |
| `0x000` | `CORESEL` | RW | Selected user core. A write is accepted only while all user cores are reset, the user bus is idle, and it is not running. |
| `0x004` | `IPSEL` | RW | Selected user IP. |
| `0x008` | `PLL_CFG` | RW | Requested PLL profile, bits `[2:0]`. |
| `0x00C` | `PLL_CMD` | WO | Bit 0 applies `PLL_CFG`; bit 1 clears sticky PLL error. |
| `0x010` | `FAULT_STATUS` | RW1C | Bit 0 pending, bit 1 write, bits `[4:2]` normalized reason. Write one to bit 0 clears pending. |
| `0x014` | `FAULT_ADDR` | RO | First fault address while pending. |
| `0x018` | `FAULT_COUNT` | RO | Saturating count of observed faults. |
| `0x01C` | `PLL_STATUS` | RO | Active profile, valid, busy, error/error reason, safe clock, lock, and capability. |
| `0x020` | `USER_CORE_RESET` | RW | Per-user-core active-high reset mask. All ones stops the user bus; a one-hot deassertion starts the selected core. |
| `0x024` | `USER_CORE_STATUS` | RW1C/RO | Selected core, user-bus enabled/idle/draining, and bit 11 configuration-error W1C. |
| `0x028` | `FAULT_MASTER` | RO | First fault master. |
| `0x02C` | `FAULT_DETAIL` | RO | First raw RIB response code. |
| `0x040` | `PERF_CTRL` | RW | Bit 0 enable, bit 1 clear pulse, bit 2 snapshot pulse. |
| `0x044`-`0x080` | `PERF_*_WAIT_{LO,HI}` | RO | Snapshot of management, user, DMA, RIBP, APB, SDRAM, PSRAM, and flash wait counters. |
| `0x084` | `TEST_STATUS` | RW-once/RO | Full-word write with bit 31 set records sticky done, bit 0 pass, and bits `[15:8]` result code. |
| `0x088` | `RTC_WAKE_STATUS` | RW1C/RO | Bit 0 synchronized live wake; bit 1 sticky wake, cleared by writing one to bit 1. |
The first fault remains visible until software clears pending; later faults
increase only the saturating count. A hardware fault in the clear cycle
remains pending. `TEST_STATUS` accepts the first valid full-word write after
reset and ignores all later writes, allowing the simulator to use a stable
verdict.
## SDK contract
`<retrosoc/hal/sysctrl.h>` owns typed SystemCtrl access. It provides semantic
operations for user-core/IP selection, PLL configuration/status, fault
inspection and clear, performance control/counter reads, terminal status, and
RTC wake state. Legacy `reg_sysctrl_*` lvalue macros are intentionally absent
from `<retrosoc/core/soc.h>`.
Existing `<retrosoc/hal/clock.h>`, `<retrosoc/hal/user_core.h>`, and
`<retrosoc/hal/perf.h>` APIs retain their behavior and delegate their
SystemCtrl accesses to this HAL. `<retrosoc/service/test.h>` writes the
sticky terminal result through `rs_sysctrl_write_test_status()`.
## Verification
`tests/test_sysctrl.py` and `tests/rtl/sysctrl_tb.sv` check RIBP response
retention, reset values, user-core lifecycle errors, first-fault retention and
W1C behavior, performance snapshots, sticky terminal status, and RTC wake
live/sticky behavior. `sysctrl_formal` proves the user-core, PLL, fault, and
test-status invariants and covers normal/error paths. The separate PLL/RCU
test retains dynamic-clock and fallback coverage.
+6
View File
@@ -72,3 +72,9 @@ separate RIBP management plane across four independently isolated 8 MiB chips.
Its frozen architecture, register ABI, timing limits, model, formal target, and
verification evidence are documented in
[ESP-PSRAM64H Controller](../docs/ip/psram.md).
SystemCtrl uses `sysctrl_if.sv`, `sysctrl_define.svh`, `sysctrl_reg.sv`, and
`sysctrl_core.sv` behind the stable `ribp_sysctrl` integration wrapper. Its
generated register offsets, RIBP timing, control-plane behavior, and
verification contract are documented in
[RIBP System Control](../docs/ip/sysctrl.md).
+43 -767
View File
@@ -1,781 +1,57 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "user_extensions.svh"
`include "mmap_define.svh"
`include "rib_defs.svh"
interface sysctrl_if ();
logic [`USER_CORESEL_WIDTH-1:0] core_sel_o;
logic [ `USER_CORE_COUNT-1:0] core_reset_o;
logic user_bus_enable_o;
logic user_bus_idle_i;
logic fault_access_i;
logic [ 1:0] fault_master_i;
logic [ 2:0] fault_code_i;
logic perf_enable_o;
logic perf_clear_o;
logic [ 63:0] perf_mgmt_wait_i;
logic [ 63:0] perf_user_wait_i;
logic [ 63:0] perf_dma_wait_i;
logic [ 63:0] perf_ribp_wait_i;
logic [ 63:0] perf_apb_wait_i;
logic [ 63:0] perf_sdram_wait_i;
logic [ 63:0] perf_psram_wait_i;
logic [ 63:0] perf_flash_wait_i;
logic rtc_wake_i;
logic test_done_o;
logic test_pass_o;
logic [ 7:0] test_code_o;
logic [ `USER_IPSEL_WIDTH-1:0] ip_sel_o;
modport dut(
input user_bus_idle_i,
input fault_access_i,
input fault_master_i,
input fault_code_i,
input perf_mgmt_wait_i,
input perf_user_wait_i,
input perf_dma_wait_i,
input perf_ribp_wait_i,
input perf_apb_wait_i,
input perf_sdram_wait_i,
input perf_psram_wait_i,
input perf_flash_wait_i,
input rtc_wake_i,
output core_sel_o,
output core_reset_o,
output user_bus_enable_o,
output ip_sel_o,
output perf_enable_o,
output perf_clear_o,
output test_done_o,
output test_pass_o,
output test_code_o
);
endinterface
module ribp_sysctrl (
// verilog_format: off -- preserve reviewed column alignment
input logic clk_i,
input logic rst_n_i,
input logic fault_valid_i,
input logic [31:0] fault_addr_i,
input logic [3:0] fault_wstrb_i,
input logic fault_reserved_i,
ribp_if.slave ribp,
sysctrl_if.dut sysctrl,
pll_ctrl_if.sysctrl pll_ctrl
input logic clk_i,
input logic rst_n_i,
input logic fault_valid_i,
input logic [31:0] fault_addr_i,
input logic [3:0] fault_wstrb_i,
input logic fault_reserved_i,
ribp_if.slave ribp,
sysctrl_if.dut sysctrl,
pll_ctrl_if.sysctrl pll_ctrl
// verilog_format: on
);
typedef logic [7:0] sysctrl_offset_t;
logic s_write_valid;
logic [ 7:0] s_write_offset;
logic [31:0] s_write_data;
logic [ 3:0] s_write_strobe;
logic [ 7:0] s_read_offset;
logic s_read_data_valid;
logic [31:0] s_read_data;
localparam sysctrl_offset_t SYSCTRL_CORESEL_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_CORESEL_OFFSET);
localparam sysctrl_offset_t SYSCTRL_IPSEL_OFFSET = sysctrl_offset_t'(`SOC_SYSCTRL_IPSEL_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PLL_CFG_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PLL_CFG_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PLL_CMD_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PLL_CMD_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_STATUS_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_STATUS_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_ADDR_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_ADDR_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_COUNT_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_COUNT_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PLL_STATUS_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PLL_STATUS_OFFSET);
localparam sysctrl_offset_t SYSCTRL_USER_CORE_RESET_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_USER_CORE_RESET_OFFSET);
localparam sysctrl_offset_t SYSCTRL_USER_CORE_STATUS_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_USER_CORE_STATUS_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_MASTER_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_MASTER_OFFSET);
localparam sysctrl_offset_t SYSCTRL_FAULT_DETAIL_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_FAULT_DETAIL_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_CTRL_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_CTRL_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_USER_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_USER_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_USER_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_USER_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_DMA_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_DMA_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_DMA_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_DMA_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_APB_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_APB_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_APB_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_APB_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET);
localparam sysctrl_offset_t SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET);
localparam sysctrl_offset_t SYSCTRL_TEST_STATUS_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_TEST_STATUS_OFFSET);
localparam sysctrl_offset_t SYSCTRL_RTC_WAKE_STATUS_OFFSET =
sysctrl_offset_t'(`SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET);
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 [`USER_CORESEL_WIDTH-1:0] s_sysctrl_coresel_d, s_sysctrl_coresel_q;
logic s_sysctrl_coresel_en;
logic s_sysctrl_coresel_write_valid;
logic [`USER_CORE_COUNT-1:0] s_user_reset_d, s_user_reset_q;
logic s_user_reset_en;
logic s_user_running_d, s_user_running_q;
logic s_user_draining_d, s_user_draining_q;
logic s_user_config_err_d, s_user_config_err_q;
logic s_user_config_err_clear;
logic s_user_reset_write_legal;
logic [`USER_CORE_COUNT-1:0] s_user_reset_write_data;
logic s_sysctrl_ipsel_en;
logic [`USER_IPSEL_WIDTH-1:0] s_sysctrl_ipsel_d, s_sysctrl_ipsel_q;
logic [2:0] s_pll_cfg_d, s_pll_cfg_q;
logic s_pll_cfg_en;
logic s_pll_apply, s_pll_clear_err;
logic s_pll_req_valid_d, s_pll_req_valid_q;
logic s_pll_busy_d, s_pll_busy_q;
logic s_pll_rsp_accept;
logic s_pll_err_d, s_pll_err_q;
logic [1:0] s_pll_err_reason_d, s_pll_err_reason_q;
logic [2:0] s_pll_active_sel_d, s_pll_active_sel_q;
logic s_pll_active_valid_d, s_pll_active_valid_q;
logic s_pll_safe_clk_d, s_pll_safe_clk_q;
logic s_pll_lock_d, s_pll_lock_q;
logic s_fault_stat_clear;
logic s_fault_pending_d, s_fault_pending_q;
logic s_fault_write_d, s_fault_write_q;
logic [2:0] s_fault_reason_d, s_fault_reason_q;
logic [2:0] s_fault_detail_d, s_fault_detail_q;
logic [31:0] s_fault_addr_d, s_fault_addr_q;
logic [31:0] s_fault_count_d, s_fault_count_q;
logic [1:0] s_fault_master_d, s_fault_master_q;
logic s_perf_en_d, s_perf_en_q;
logic s_perf_en_en, s_perf_clear, s_perf_snapshot;
logic [63:0] s_perf_mgmt_wait_q;
logic [63:0] s_perf_user_wait_q;
logic [63:0] s_perf_dma_wait_q;
logic [63:0] s_perf_ribp_wait_q;
logic [63:0] s_perf_apb_wait_q;
logic [63:0] s_perf_sdram_wait_q;
logic [63:0] s_perf_psram_wait_q;
logic [63:0] s_perf_flash_wait_q;
logic s_test_done_d, s_test_done_q;
logic s_test_pass_d, s_test_pass_q;
logic [7:0] s_test_code_d, s_test_code_q;
logic s_test_stat_write;
logic s_rtc_wake_sync;
logic s_rtc_wake_clear;
logic s_rtc_wake_seen_d, s_rtc_wake_seen_q;
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && (|ribp.wstrb);
assign s_ribp_rd_hdshk = ribp.valid && (~s_ribp_ready_q) && (~(|ribp.wstrb));
assign ribp.ready = s_ribp_ready_q;
assign ribp.resp_err = 1'b0;
assign ribp.rdata = s_ribp_rdata_q;
assign sysctrl.ip_sel_o = s_sysctrl_ipsel_q;
assign sysctrl.core_sel_o = s_sysctrl_coresel_q;
assign sysctrl.core_reset_o = s_user_reset_q;
assign sysctrl.user_bus_enable_o = s_user_running_q;
assign sysctrl.perf_enable_o = s_perf_en_q;
assign sysctrl.perf_clear_o = s_perf_clear;
assign sysctrl.test_done_o = s_test_done_q;
assign sysctrl.test_pass_o = s_test_pass_q;
assign sysctrl.test_code_o = s_test_code_q;
assign pll_ctrl.req_sel_o = s_pll_cfg_q;
assign pll_ctrl.req_valid_o = s_pll_req_valid_q;
assign pll_ctrl.rsp_ready_o = 1'b1;
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_rtc_wake_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (sysctrl.rtc_wake_i),
.dat_o (s_rtc_wake_sync)
sysctrl_reg u_sysctrl_reg (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.ribp (ribp),
.write_valid_o (s_write_valid),
.write_offset_o (s_write_offset),
.write_data_o (s_write_data),
.write_strobe_o (s_write_strobe),
.read_offset_o (s_read_offset),
.read_data_valid_i(s_read_data_valid),
.read_data_i (s_read_data)
);
assign s_rtc_wake_clear = s_ribp_wr_hdshk &&
(ribp.addr[7:0] == SYSCTRL_RTC_WAKE_STATUS_OFFSET) && ribp.wstrb[0] && ribp.wdata[1];
always_comb begin
s_rtc_wake_seen_d = s_rtc_wake_seen_q;
if (s_rtc_wake_clear) begin
s_rtc_wake_seen_d = 1'b0;
end
if (s_rtc_wake_sync) begin
s_rtc_wake_seen_d = 1'b1;
end
end
dffr #(
.DATA_WIDTH(1)
) u_rtc_wake_seen_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_rtc_wake_seen_d),
.dat_o (s_rtc_wake_seen_q)
);
assign s_sysctrl_coresel_write_valid = ribp.wdata[`USER_CORESEL_WIDTH-1:0] < `USER_CORE_COUNT;
assign s_sysctrl_coresel_en = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_CORESEL_OFFSET &&
ribp.wstrb[0] && s_sysctrl_coresel_write_valid &&
(&s_user_reset_q) && sysctrl.user_bus_idle_i && ~s_user_running_q;
assign s_sysctrl_coresel_d = ribp.wdata[`USER_CORESEL_WIDTH-1:0];
dffer #(
.DATA_WIDTH(`USER_CORESEL_WIDTH)
) u_sysctrl_coresel_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_sysctrl_coresel_en),
.dat_i (s_sysctrl_coresel_d),
.dat_o (s_sysctrl_coresel_q)
);
assign s_user_reset_write_data = ribp.wdata[`USER_CORE_COUNT-1:0];
assign s_user_reset_write_legal = (&s_user_reset_write_data) ||
((s_sysctrl_coresel_q < `USER_CORE_COUNT) &&
((~s_user_reset_write_data) ==
({{(`USER_CORE_COUNT - 1){1'b0}}, 1'b1} << s_sysctrl_coresel_q)));
assign s_user_reset_en = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_USER_CORE_RESET_OFFSET &&
ribp.wstrb[0];
assign s_user_config_err_clear = s_ribp_wr_hdshk &&
ribp.addr[7:0] == SYSCTRL_USER_CORE_STATUS_OFFSET && ribp.wstrb[1] && ribp.wdata[11];
always_comb begin
s_user_reset_d = s_user_reset_q;
s_user_running_d = s_user_running_q;
s_user_draining_d = s_user_draining_q;
s_user_config_err_d = s_user_config_err_q;
if (s_user_config_err_clear) begin
s_user_config_err_d = 1'b0;
end
if (s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_CORESEL_OFFSET && ~s_sysctrl_coresel_en) begin
s_user_config_err_d = 1'b1;
end
if (s_user_reset_en) begin
if (~s_user_reset_write_legal) begin
s_user_config_err_d = 1'b1;
end else if (&s_user_reset_write_data) begin
s_user_running_d = 1'b0;
if (sysctrl.user_bus_idle_i) begin
s_user_reset_d = s_user_reset_write_data;
s_user_draining_d = 1'b0;
end else begin
s_user_draining_d = 1'b1;
end
end else if (sysctrl.user_bus_idle_i && (&s_user_reset_q) && ~s_user_running_q) begin
s_user_reset_d = s_user_reset_write_data;
s_user_running_d = 1'b1;
s_user_draining_d = 1'b0;
end else begin
s_user_config_err_d = 1'b1;
end
end
if (s_user_draining_q && sysctrl.user_bus_idle_i) begin
s_user_reset_d = '1;
s_user_draining_d = 1'b0;
end
end
dffrc #(
.DATA_WIDTH(`USER_CORE_COUNT),
.RESET_VAL ('1)
) u_user_reset_dffrc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_user_reset_d),
.dat_o (s_user_reset_q)
);
dffr #(
.DATA_WIDTH(1)
) u_user_running_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_user_running_d),
.dat_o (s_user_running_q)
);
dffr #(
.DATA_WIDTH(1)
) u_user_draining_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_user_draining_d),
.dat_o (s_user_draining_q)
);
dffr #(
.DATA_WIDTH(1)
) u_user_config_error_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_user_config_err_d),
.dat_o (s_user_config_err_q)
);
assign s_sysctrl_ipsel_en = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_IPSEL_OFFSET;
assign s_sysctrl_ipsel_d = ribp.wdata[`USER_IPSEL_WIDTH-1:0];
dffer #(
.DATA_WIDTH(`USER_IPSEL_WIDTH)
) u_sysctrl_ipsel_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_sysctrl_ipsel_en),
.dat_i (s_sysctrl_ipsel_d),
.dat_o (s_sysctrl_ipsel_q)
);
assign s_pll_cfg_en = s_ribp_wr_hdshk &&
(ribp.addr[7:0] == SYSCTRL_PLL_CFG_OFFSET) && ribp.wstrb[0];
assign s_pll_cfg_d = ribp.wdata[2:0];
dffer #(
.DATA_WIDTH(3)
) u_pll_cfg_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_pll_cfg_en),
.dat_i (s_pll_cfg_d),
.dat_o (s_pll_cfg_q)
);
assign s_pll_apply = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_PLL_CMD_OFFSET &&
ribp.wstrb[0] && ribp.wdata[0];
assign s_pll_clear_err = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_PLL_CMD_OFFSET &&
ribp.wstrb[0] && ribp.wdata[1];
assign s_pll_rsp_accept = pll_ctrl.rsp_valid_i && pll_ctrl.rsp_ready_o;
always_comb begin
s_pll_req_valid_d = s_pll_req_valid_q;
s_pll_busy_d = s_pll_busy_q;
if (s_pll_req_valid_q && pll_ctrl.req_ready_i) begin
s_pll_req_valid_d = 1'b0;
end
if (s_pll_apply && ~s_pll_busy_q && ~s_pll_req_valid_q) begin
s_pll_req_valid_d = 1'b1;
s_pll_busy_d = 1'b1;
end
if (s_pll_rsp_accept) begin
s_pll_busy_d = 1'b0;
end
end
dffr #(
.DATA_WIDTH(1)
) u_pll_req_valid_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_pll_req_valid_d),
.dat_o (s_pll_req_valid_q)
);
dffr #(
.DATA_WIDTH(1)
) u_pll_busy_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_pll_busy_d),
.dat_o (s_pll_busy_q)
);
always_comb begin
s_pll_err_d = s_pll_err_q;
s_pll_err_reason_d = s_pll_err_reason_q;
if (s_pll_clear_err) begin
s_pll_err_d = 1'b0;
s_pll_err_reason_d = 2'd0;
end
if (s_pll_apply && (s_pll_busy_q || s_pll_req_valid_q)) begin
s_pll_err_d = 1'b1;
s_pll_err_reason_d = 2'd3;
end
if (s_pll_rsp_accept && |pll_ctrl.rsp_error_i) begin
s_pll_err_d = 1'b1;
s_pll_err_reason_d = pll_ctrl.rsp_error_i;
end
end
dffr #(
.DATA_WIDTH(1)
) u_pll_error_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_pll_err_d),
.dat_o (s_pll_err_q)
);
dffr #(
.DATA_WIDTH(2)
) u_pll_error_reason_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_pll_err_reason_d),
.dat_o (s_pll_err_reason_q)
);
assign s_pll_active_sel_d = pll_ctrl.rsp_active_sel_i;
dffer #(
.DATA_WIDTH(3)
) u_pll_active_sel_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_pll_rsp_accept),
.dat_i (s_pll_active_sel_d),
.dat_o (s_pll_active_sel_q)
);
assign s_pll_active_valid_d = pll_ctrl.rsp_active_valid_i;
dffer #(
.DATA_WIDTH(1)
) u_pll_active_valid_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_pll_rsp_accept),
.dat_i (s_pll_active_valid_d),
.dat_o (s_pll_active_valid_q)
);
assign s_pll_safe_clk_d = pll_ctrl.rsp_safe_clk_i;
dfferc #(
.DATA_WIDTH(1),
.RESET_VAL (1'b1)
) u_pll_safe_clk_dfferc (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_pll_rsp_accept),
.dat_i (s_pll_safe_clk_d),
.dat_o (s_pll_safe_clk_q)
);
assign s_pll_lock_d = pll_ctrl.rsp_pll_lock_i;
dffer #(
.DATA_WIDTH(1)
) u_pll_lock_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_pll_rsp_accept),
.dat_i (s_pll_lock_d),
.dat_o (s_pll_lock_q)
);
assign s_perf_en_en = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_PERF_CTRL_OFFSET &&
ribp.wstrb[0];
assign s_perf_en_d = ribp.wdata[0];
assign s_perf_clear = s_perf_en_en && ribp.wdata[1];
assign s_perf_snapshot = s_perf_en_en && ribp.wdata[2];
dffer #(
.DATA_WIDTH(1)
) u_perf_enable_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_en_en),
.dat_i (s_perf_en_d),
.dat_o (s_perf_en_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_mgmt_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_mgmt_wait_i),
.dat_o (s_perf_mgmt_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_user_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_user_wait_i),
.dat_o (s_perf_user_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_dma_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_dma_wait_i),
.dat_o (s_perf_dma_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_ribp_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_ribp_wait_i),
.dat_o (s_perf_ribp_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_apb_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_apb_wait_i),
.dat_o (s_perf_apb_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_sdram_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_sdram_wait_i),
.dat_o (s_perf_sdram_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_psram_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_psram_wait_i),
.dat_o (s_perf_psram_wait_q)
);
dffer #(
.DATA_WIDTH(64)
) u_perf_flash_wait_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_perf_snapshot),
.dat_i (sysctrl.perf_flash_wait_i),
.dat_o (s_perf_flash_wait_q)
);
assign s_test_stat_write = s_ribp_wr_hdshk && ribp.addr[7:0] == SYSCTRL_TEST_STATUS_OFFSET &&
ribp.wstrb == 4'hF && ribp.wdata[31] && ~s_test_done_q;
assign s_test_done_d = 1'b1;
dffer #(
.DATA_WIDTH(1)
) u_test_done_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_test_stat_write),
.dat_i (s_test_done_d),
.dat_o (s_test_done_q)
);
assign s_test_pass_d = ribp.wdata[0];
dffer #(
.DATA_WIDTH(1)
) u_test_pass_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_test_stat_write),
.dat_i (s_test_pass_d),
.dat_o (s_test_pass_q)
);
assign s_test_code_d = ribp.wdata[15:8];
dffer #(
.DATA_WIDTH(8)
) u_test_code_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_test_stat_write),
.dat_i (s_test_code_d),
.dat_o (s_test_code_q)
);
assign s_fault_stat_clear = s_ribp_wr_hdshk &&
ribp.addr[7:0] == SYSCTRL_FAULT_STATUS_OFFSET &&
ribp.wstrb[0] && ribp.wdata[0];
always_comb begin
s_fault_pending_d = s_fault_pending_q;
s_fault_write_d = s_fault_write_q;
s_fault_reason_d = s_fault_reason_q;
s_fault_detail_d = s_fault_detail_q;
s_fault_addr_d = s_fault_addr_q;
s_fault_count_d = s_fault_count_q;
if (s_fault_stat_clear) begin
s_fault_pending_d = 1'b0;
end
if (fault_valid_i) begin
s_fault_pending_d = 1'b1;
if (~s_fault_pending_q || s_fault_stat_clear) begin
s_fault_write_d = |fault_wstrb_i;
s_fault_detail_d = |sysctrl.fault_code_i ? sysctrl.fault_code_i :
sysctrl.fault_access_i ? `RIB_RESP_PROTERR :
fault_reserved_i ? `RIB_RESP_RESERVED : `RIB_RESP_DECERR;
unique case (s_fault_detail_d)
`RIB_RESP_RESERVED: s_fault_reason_d = 3'd2;
`RIB_RESP_PROTERR: s_fault_reason_d = 3'd3;
`RIB_RESP_SLVERR: s_fault_reason_d = 3'd4;
`RIB_RESP_TIMEOUT: s_fault_reason_d = 3'd5;
default: s_fault_reason_d = 3'd1;
endcase
s_fault_addr_d = fault_addr_i;
end
if (~(&s_fault_count_q)) begin
s_fault_count_d = s_fault_count_q + 32'd1;
end
end
end
dffr #(
.DATA_WIDTH(1)
) u_fault_pending_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_pending_d),
.dat_o (s_fault_pending_q)
);
dffr #(
.DATA_WIDTH(1)
) u_fault_write_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_write_d),
.dat_o (s_fault_write_q)
);
dffr #(
.DATA_WIDTH(3)
) u_fault_reason_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_reason_d),
.dat_o (s_fault_reason_q)
);
dffr #(
.DATA_WIDTH(3)
) u_fault_detail_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_detail_d),
.dat_o (s_fault_detail_q)
);
dffr #(
.DATA_WIDTH(32)
) u_fault_addr_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_addr_d),
.dat_o (s_fault_addr_q)
);
dffr #(
.DATA_WIDTH(32)
) u_fault_count_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_count_d),
.dat_o (s_fault_count_q)
);
always_comb begin
s_fault_master_d = s_fault_master_q;
if (fault_valid_i && (~s_fault_pending_q || s_fault_stat_clear)) begin
s_fault_master_d = sysctrl.fault_master_i;
end
end
dffr #(
.DATA_WIDTH(2)
) u_fault_master_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_fault_master_d),
.dat_o (s_fault_master_q)
);
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q);
dffr #(
.DATA_WIDTH(1)
) u_ribp_ready_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_ribp_ready_d),
.dat_o (s_ribp_ready_q)
);
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
always_comb begin
s_ribp_rdata_d = s_ribp_rdata_q;
unique case (ribp.addr[7:0])
// verilog_format: off -- preserve reviewed column alignment
SYSCTRL_CORESEL_OFFSET:
s_ribp_rdata_d = {{(32 - `USER_CORESEL_WIDTH) {1'b0}}, s_sysctrl_coresel_q};
SYSCTRL_IPSEL_OFFSET:
s_ribp_rdata_d = {{(32 - `USER_IPSEL_WIDTH) {1'b0}}, s_sysctrl_ipsel_q};
SYSCTRL_PLL_CFG_OFFSET: s_ribp_rdata_d = {29'd0, s_pll_cfg_q};
SYSCTRL_FAULT_STATUS_OFFSET:
s_ribp_rdata_d = {27'd0, s_fault_reason_q, s_fault_write_q, s_fault_pending_q};
SYSCTRL_FAULT_ADDR_OFFSET: s_ribp_rdata_d = s_fault_addr_q;
SYSCTRL_FAULT_COUNT_OFFSET: s_ribp_rdata_d = s_fault_count_q;
SYSCTRL_PLL_STATUS_OFFSET: s_ribp_rdata_d = {
21'd0,
pll_ctrl.capable_i,
s_pll_lock_q,
s_pll_safe_clk_q,
s_pll_err_reason_q,
s_pll_err_q,
s_pll_busy_q,
s_pll_active_valid_q,
s_pll_active_sel_q
};
SYSCTRL_USER_CORE_RESET_OFFSET:
s_ribp_rdata_d = {{(32 - `USER_CORE_COUNT) {1'b0}}, s_user_reset_q};
SYSCTRL_USER_CORE_STATUS_OFFSET: s_ribp_rdata_d = {
20'd0,
s_user_config_err_q,
s_user_draining_q,
sysctrl.user_bus_idle_i,
s_user_running_q,
{ (8 - `USER_CORESEL_WIDTH) {1'b0} },
s_sysctrl_coresel_q
};
SYSCTRL_FAULT_MASTER_OFFSET: s_ribp_rdata_d = {30'd0, s_fault_master_q};
SYSCTRL_FAULT_DETAIL_OFFSET: s_ribp_rdata_d = {29'd0, s_fault_detail_q};
SYSCTRL_PERF_CTRL_OFFSET: s_ribp_rdata_d = {31'd0, s_perf_en_q};
SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_mgmt_wait_q[31:0];
SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_mgmt_wait_q[63:32];
SYSCTRL_PERF_USER_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_user_wait_q[31:0];
SYSCTRL_PERF_USER_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_user_wait_q[63:32];
SYSCTRL_PERF_DMA_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_dma_wait_q[31:0];
SYSCTRL_PERF_DMA_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_dma_wait_q[63:32];
SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_ribp_wait_q[31:0];
SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_ribp_wait_q[63:32];
SYSCTRL_PERF_APB_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_apb_wait_q[31:0];
SYSCTRL_PERF_APB_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_apb_wait_q[63:32];
SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_sdram_wait_q[31:0];
SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_sdram_wait_q[63:32];
SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_psram_wait_q[31:0];
SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_psram_wait_q[63:32];
SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET: s_ribp_rdata_d = s_perf_flash_wait_q[31:0];
SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET: s_ribp_rdata_d = s_perf_flash_wait_q[63:32];
SYSCTRL_TEST_STATUS_OFFSET: s_ribp_rdata_d = {
s_test_done_q, 15'd0, s_test_code_q, 7'd0, s_test_pass_q
};
SYSCTRL_RTC_WAKE_STATUS_OFFSET: s_ribp_rdata_d = {
30'd0, s_rtc_wake_seen_q, s_rtc_wake_sync
};
default: s_ribp_rdata_d = s_ribp_rdata_q;
endcase
// verilog_format: on
end
dffer #(
.DATA_WIDTH(32)
) u_ribp_rdata_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_ribp_rdata_en),
.dat_i (s_ribp_rdata_d),
.dat_o (s_ribp_rdata_q)
sysctrl_core u_sysctrl_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.write_valid_i (s_write_valid),
.write_offset_i (s_write_offset),
.write_data_i (s_write_data),
.write_strobe_i (s_write_strobe),
.read_offset_i (s_read_offset),
.fault_valid_i (fault_valid_i),
.fault_addr_i (fault_addr_i),
.fault_wstrb_i (fault_wstrb_i),
.fault_reserved_i (fault_reserved_i),
.sysctrl (sysctrl),
.pll_ctrl (pll_ctrl),
.read_data_valid_o(s_read_data_valid),
.read_data_o (s_read_data)
);
endmodule
+477
View File
@@ -0,0 +1,477 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "user_extensions.svh"
`include "rib_defs.svh"
`include "sysctrl_define.svh"
module sysctrl_core (
// verilog_format: off -- preserve reviewed column alignment
input logic clk_i,
input logic rst_n_i,
input logic write_valid_i,
input logic [7:0] write_offset_i,
input logic [31:0] write_data_i,
input logic [3:0] write_strobe_i,
input logic [7:0] read_offset_i,
input logic fault_valid_i,
input logic [31:0] fault_addr_i,
input logic [3:0] fault_wstrb_i,
input logic fault_reserved_i,
sysctrl_if.dut sysctrl,
pll_ctrl_if.sysctrl pll_ctrl,
output logic read_data_valid_o,
output logic [31:0] read_data_o
// verilog_format: on
);
typedef logic [7:0] sysctrl_offset_t;
localparam sysctrl_offset_t CoreSel = sysctrl_offset_t'(`RIBP_SYSCTRL__CORESEL);
localparam sysctrl_offset_t IpSel = sysctrl_offset_t'(`RIBP_SYSCTRL__IPSEL);
localparam sysctrl_offset_t PllCfg = sysctrl_offset_t'(`RIBP_SYSCTRL__PLL_CFG);
localparam sysctrl_offset_t PllCmd = sysctrl_offset_t'(`RIBP_SYSCTRL__PLL_CMD);
localparam sysctrl_offset_t FaultStatus = sysctrl_offset_t'(`RIBP_SYSCTRL__FAULT_STATUS);
localparam sysctrl_offset_t FaultAddr = sysctrl_offset_t'(`RIBP_SYSCTRL__FAULT_ADDR);
localparam sysctrl_offset_t FaultCount = sysctrl_offset_t'(`RIBP_SYSCTRL__FAULT_COUNT);
localparam sysctrl_offset_t PllStatus = sysctrl_offset_t'(`RIBP_SYSCTRL__PLL_STATUS);
localparam sysctrl_offset_t UserCoreReset = sysctrl_offset_t'(`RIBP_SYSCTRL__USER_CORE_RESET);
localparam sysctrl_offset_t UserCoreStatus = sysctrl_offset_t'(`RIBP_SYSCTRL__USER_CORE_STATUS);
localparam sysctrl_offset_t FaultMaster = sysctrl_offset_t'(`RIBP_SYSCTRL__FAULT_MASTER);
localparam sysctrl_offset_t FaultDetail = sysctrl_offset_t'(`RIBP_SYSCTRL__FAULT_DETAIL);
localparam sysctrl_offset_t PerfCtrl = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_CTRL);
localparam sysctrl_offset_t PerfMgmtWaitLo = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_MGMT_WAIT_LO);
localparam sysctrl_offset_t PerfMgmtWaitHi = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_MGMT_WAIT_HI);
localparam sysctrl_offset_t PerfUserWaitLo = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_USER_WAIT_LO);
localparam sysctrl_offset_t PerfUserWaitHi = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_USER_WAIT_HI);
localparam sysctrl_offset_t PerfDmaWaitLo = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_DMA_WAIT_LO);
localparam sysctrl_offset_t PerfDmaWaitHi = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_DMA_WAIT_HI);
localparam sysctrl_offset_t PerfRibpWaitLo = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_RIBP_WAIT_LO);
localparam sysctrl_offset_t PerfRibpWaitHi = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_RIBP_WAIT_HI);
localparam sysctrl_offset_t PerfApbWaitLo = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_APB_WAIT_LO);
localparam sysctrl_offset_t PerfApbWaitHi = sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_APB_WAIT_HI);
localparam sysctrl_offset_t PerfSdramWaitLo =
sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_SDRAM_WAIT_LO);
localparam sysctrl_offset_t PerfSdramWaitHi =
sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_SDRAM_WAIT_HI);
localparam sysctrl_offset_t PerfPsramWaitLo =
sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_PSRAM_WAIT_LO);
localparam sysctrl_offset_t PerfPsramWaitHi =
sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_PSRAM_WAIT_HI);
localparam sysctrl_offset_t PerfFlashWaitLo =
sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_FLASH_WAIT_LO);
localparam sysctrl_offset_t PerfFlashWaitHi =
sysctrl_offset_t'(`RIBP_SYSCTRL__PERF_FLASH_WAIT_HI);
localparam sysctrl_offset_t TestStatus = sysctrl_offset_t'(`RIBP_SYSCTRL__TEST_STATUS);
localparam sysctrl_offset_t RtcWakeStatus = sysctrl_offset_t'(`RIBP_SYSCTRL__RTC_WAKE_STATUS);
logic [`USER_CORESEL_WIDTH-1:0] s_sysctrl_coresel_d, s_sysctrl_coresel_q;
logic [`USER_CORE_COUNT-1:0] s_user_reset_d, s_user_reset_q;
logic s_user_running_d, s_user_running_q;
logic s_user_draining_d, s_user_draining_q;
logic s_user_config_err_d, s_user_config_err_q;
logic [`USER_IPSEL_WIDTH-1:0] s_sysctrl_ipsel_d, s_sysctrl_ipsel_q;
logic [2:0] s_pll_cfg_d, s_pll_cfg_q;
logic s_pll_req_valid_d, s_pll_req_valid_q;
logic s_pll_busy_d, s_pll_busy_q;
logic s_pll_err_d, s_pll_err_q;
logic [1:0] s_pll_err_reason_d, s_pll_err_reason_q;
logic [2:0] s_pll_active_sel_d, s_pll_active_sel_q;
logic s_pll_active_valid_d, s_pll_active_valid_q;
logic s_pll_safe_clk_d, s_pll_safe_clk_q;
logic s_pll_lock_d, s_pll_lock_q;
logic s_fault_pending_d, s_fault_pending_q;
logic s_fault_write_d, s_fault_write_q;
logic [2:0] s_fault_reason_d, s_fault_reason_q;
logic [2:0] s_fault_detail_d, s_fault_detail_q;
logic [31:0] s_fault_addr_d, s_fault_addr_q;
logic [31:0] s_fault_count_d, s_fault_count_q;
logic [1:0] s_fault_master_d, s_fault_master_q;
logic s_perf_en_d, s_perf_en_q;
logic [63:0] s_perf_mgmt_wait_d, s_perf_mgmt_wait_q;
logic [63:0] s_perf_user_wait_d, s_perf_user_wait_q;
logic [63:0] s_perf_dma_wait_d, s_perf_dma_wait_q;
logic [63:0] s_perf_ribp_wait_d, s_perf_ribp_wait_q;
logic [63:0] s_perf_apb_wait_d, s_perf_apb_wait_q;
logic [63:0] s_perf_sdram_wait_d, s_perf_sdram_wait_q;
logic [63:0] s_perf_psram_wait_d, s_perf_psram_wait_q;
logic [63:0] s_perf_flash_wait_d, s_perf_flash_wait_q;
logic s_test_done_d, s_test_done_q;
logic s_test_pass_d, s_test_pass_q;
logic [7:0] s_test_code_d, s_test_code_q;
logic s_rtc_wake_seen_d, s_rtc_wake_seen_q;
logic s_rtc_wake_sync;
logic s_core_sel_write_valid;
logic s_core_sel_write_en;
logic s_user_reset_write_en;
logic s_user_reset_write_legal;
logic s_user_config_err_clear;
logic s_pll_cfg_write_en;
logic s_pll_apply;
logic s_pll_clear_err;
logic s_pll_rsp_accept;
logic s_fault_stat_clear;
logic s_perf_write_en;
logic s_perf_clear;
logic s_perf_snapshot;
logic s_test_stat_write;
logic s_rtc_wake_clear;
logic [14:0] unused_write_data;
// TEST_STATUS[30:16] and the same bits on every other register are reserved.
assign unused_write_data = write_data_i[30:16];
assign sysctrl.ip_sel_o = s_sysctrl_ipsel_q;
assign sysctrl.core_sel_o = s_sysctrl_coresel_q;
assign sysctrl.core_reset_o = s_user_reset_q;
assign sysctrl.user_bus_enable_o = s_user_running_q;
assign sysctrl.perf_enable_o = s_perf_en_q;
assign sysctrl.perf_clear_o = s_perf_clear;
assign sysctrl.test_done_o = s_test_done_q;
assign sysctrl.test_pass_o = s_test_pass_q;
assign sysctrl.test_code_o = s_test_code_q;
assign pll_ctrl.req_sel_o = s_pll_cfg_q;
assign pll_ctrl.req_valid_o = s_pll_req_valid_q;
assign pll_ctrl.rsp_ready_o = 1'b1;
cdc_sync #(
.STAGE (2),
.DATA_WIDTH(1)
) u_rtc_wake_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (sysctrl.rtc_wake_i),
.dat_o (s_rtc_wake_sync)
);
assign s_core_sel_write_valid = write_data_i[`USER_CORESEL_WIDTH-1:0] < `USER_CORE_COUNT;
assign s_core_sel_write_en = write_valid_i && (write_offset_i == CoreSel) &&
write_strobe_i[0] && s_core_sel_write_valid &&
(&s_user_reset_q) && sysctrl.user_bus_idle_i && !s_user_running_q;
assign s_user_reset_write_en = write_valid_i && (write_offset_i == UserCoreReset) &&
write_strobe_i[0];
assign s_user_reset_write_legal = (&write_data_i[`USER_CORE_COUNT-1:0]) ||
((s_sysctrl_coresel_q < `USER_CORE_COUNT) &&
((~write_data_i[`USER_CORE_COUNT-1:0]) ==
({{(`USER_CORE_COUNT - 1){1'b0}}, 1'b1} << s_sysctrl_coresel_q)));
assign s_user_config_err_clear = write_valid_i && (write_offset_i == UserCoreStatus) &&
write_strobe_i[1] && write_data_i[11];
always_comb begin
s_sysctrl_coresel_d = s_sysctrl_coresel_q;
s_user_reset_d = s_user_reset_q;
s_user_running_d = s_user_running_q;
s_user_draining_d = s_user_draining_q;
s_user_config_err_d = s_user_config_err_q;
if (s_core_sel_write_en) begin
s_sysctrl_coresel_d = write_data_i[`USER_CORESEL_WIDTH-1:0];
end
if (s_user_config_err_clear) begin
s_user_config_err_d = 1'b0;
end
if (write_valid_i && (write_offset_i == CoreSel) && !s_core_sel_write_en) begin
s_user_config_err_d = 1'b1;
end
if (s_user_reset_write_en) begin
if (!s_user_reset_write_legal) begin
s_user_config_err_d = 1'b1;
end else if (&write_data_i[`USER_CORE_COUNT-1:0]) begin
s_user_running_d = 1'b0;
if (sysctrl.user_bus_idle_i) begin
s_user_reset_d = write_data_i[`USER_CORE_COUNT-1:0];
s_user_draining_d = 1'b0;
end else begin
s_user_draining_d = 1'b1;
end
end else if (sysctrl.user_bus_idle_i && (&s_user_reset_q) && !s_user_running_q) begin
s_user_reset_d = write_data_i[`USER_CORE_COUNT-1:0];
s_user_running_d = 1'b1;
s_user_draining_d = 1'b0;
end else begin
s_user_config_err_d = 1'b1;
end
end
if (s_user_draining_q && sysctrl.user_bus_idle_i) begin
s_user_reset_d = '1;
s_user_draining_d = 1'b0;
end
end
assign s_pll_cfg_write_en = write_valid_i && (write_offset_i == PllCfg) && write_strobe_i[0];
assign s_pll_apply = write_valid_i && (write_offset_i == PllCmd) && write_strobe_i[0] &&
write_data_i[`RIBP_SYSCTRL__PLL_CMD_APPLY];
assign s_pll_clear_err = write_valid_i && (write_offset_i == PllCmd) && write_strobe_i[0] &&
write_data_i[`RIBP_SYSCTRL__PLL_CMD_CLEAR_ERROR];
assign s_pll_rsp_accept = pll_ctrl.rsp_valid_i;
always_comb begin
s_sysctrl_ipsel_d = s_sysctrl_ipsel_q;
s_pll_cfg_d = s_pll_cfg_q;
s_pll_req_valid_d = s_pll_req_valid_q;
s_pll_busy_d = s_pll_busy_q;
s_pll_err_d = s_pll_err_q;
s_pll_err_reason_d = s_pll_err_reason_q;
s_pll_active_sel_d = s_pll_active_sel_q;
s_pll_active_valid_d = s_pll_active_valid_q;
s_pll_safe_clk_d = s_pll_safe_clk_q;
s_pll_lock_d = s_pll_lock_q;
if (write_valid_i && (write_offset_i == IpSel)) begin
s_sysctrl_ipsel_d = write_data_i[`USER_IPSEL_WIDTH-1:0];
end
if (s_pll_cfg_write_en) begin
s_pll_cfg_d = write_data_i[2:0];
end
if (s_pll_req_valid_q && pll_ctrl.req_ready_i) begin
s_pll_req_valid_d = 1'b0;
end
if (s_pll_apply && !s_pll_busy_q && !s_pll_req_valid_q) begin
s_pll_req_valid_d = 1'b1;
s_pll_busy_d = 1'b1;
end
if (s_pll_rsp_accept) begin
s_pll_busy_d = 1'b0;
s_pll_active_sel_d = pll_ctrl.rsp_active_sel_i;
s_pll_active_valid_d = pll_ctrl.rsp_active_valid_i;
s_pll_safe_clk_d = pll_ctrl.rsp_safe_clk_i;
s_pll_lock_d = pll_ctrl.rsp_pll_lock_i;
end
if (s_pll_clear_err) begin
s_pll_err_d = 1'b0;
s_pll_err_reason_d = 2'd0;
end
if (s_pll_apply && (s_pll_busy_q || s_pll_req_valid_q)) begin
s_pll_err_d = 1'b1;
s_pll_err_reason_d = 2'd3;
end
if (s_pll_rsp_accept && (|pll_ctrl.rsp_error_i)) begin
s_pll_err_d = 1'b1;
s_pll_err_reason_d = pll_ctrl.rsp_error_i;
end
end
assign s_fault_stat_clear = write_valid_i && (write_offset_i == FaultStatus) &&
write_strobe_i[0] &&
write_data_i[`RIBP_SYSCTRL__FAULT_STATUS_PENDING];
always_comb begin
s_fault_pending_d = s_fault_pending_q;
s_fault_write_d = s_fault_write_q;
s_fault_reason_d = s_fault_reason_q;
s_fault_detail_d = s_fault_detail_q;
s_fault_addr_d = s_fault_addr_q;
s_fault_count_d = s_fault_count_q;
s_fault_master_d = s_fault_master_q;
if (s_fault_stat_clear) begin
s_fault_pending_d = 1'b0;
end
if (fault_valid_i) begin
s_fault_pending_d = 1'b1;
if (!s_fault_pending_q || s_fault_stat_clear) begin
s_fault_write_d = |fault_wstrb_i;
s_fault_detail_d = |sysctrl.fault_code_i ? sysctrl.fault_code_i :
sysctrl.fault_access_i ? `RIB_RESP_PROTERR :
fault_reserved_i ? `RIB_RESP_RESERVED : `RIB_RESP_DECERR;
unique case (s_fault_detail_d)
`RIB_RESP_RESERVED: s_fault_reason_d = 3'd2;
`RIB_RESP_PROTERR: s_fault_reason_d = 3'd3;
`RIB_RESP_SLVERR: s_fault_reason_d = 3'd4;
`RIB_RESP_TIMEOUT: s_fault_reason_d = 3'd5;
default: s_fault_reason_d = 3'd1;
endcase
s_fault_addr_d = fault_addr_i;
s_fault_master_d = sysctrl.fault_master_i;
end
if (!(&s_fault_count_q)) begin
s_fault_count_d = s_fault_count_q + 32'd1;
end
end
end
assign s_perf_write_en = write_valid_i && (write_offset_i == PerfCtrl) && write_strobe_i[0];
assign s_perf_clear = s_perf_write_en && write_data_i[`RIBP_SYSCTRL__PERF_CTRL_CLEAR];
assign s_perf_snapshot = s_perf_write_en && write_data_i[`RIBP_SYSCTRL__PERF_CTRL_SNAPSHOT];
always_comb begin
s_perf_en_d = s_perf_en_q;
s_perf_mgmt_wait_d = s_perf_mgmt_wait_q;
s_perf_user_wait_d = s_perf_user_wait_q;
s_perf_dma_wait_d = s_perf_dma_wait_q;
s_perf_ribp_wait_d = s_perf_ribp_wait_q;
s_perf_apb_wait_d = s_perf_apb_wait_q;
s_perf_sdram_wait_d = s_perf_sdram_wait_q;
s_perf_psram_wait_d = s_perf_psram_wait_q;
s_perf_flash_wait_d = s_perf_flash_wait_q;
if (s_perf_write_en) begin
s_perf_en_d = write_data_i[`RIBP_SYSCTRL__PERF_CTRL_ENABLE];
end
if (s_perf_snapshot) begin
s_perf_mgmt_wait_d = sysctrl.perf_mgmt_wait_i;
s_perf_user_wait_d = sysctrl.perf_user_wait_i;
s_perf_dma_wait_d = sysctrl.perf_dma_wait_i;
s_perf_ribp_wait_d = sysctrl.perf_ribp_wait_i;
s_perf_apb_wait_d = sysctrl.perf_apb_wait_i;
s_perf_sdram_wait_d = sysctrl.perf_sdram_wait_i;
s_perf_psram_wait_d = sysctrl.perf_psram_wait_i;
s_perf_flash_wait_d = sysctrl.perf_flash_wait_i;
end
end
assign s_test_stat_write = write_valid_i && (write_offset_i == TestStatus) &&
(write_strobe_i == 4'hF) &&
write_data_i[`RIBP_SYSCTRL__TEST_STATUS_VALID] && !s_test_done_q;
assign s_rtc_wake_clear = write_valid_i && (write_offset_i == RtcWakeStatus) &&
write_strobe_i[0] &&
write_data_i[`RIBP_SYSCTRL__RTC_WAKE_STATUS_SEEN];
always_comb begin
s_test_done_d = s_test_done_q;
s_test_pass_d = s_test_pass_q;
s_test_code_d = s_test_code_q;
s_rtc_wake_seen_d = s_rtc_wake_seen_q;
if (s_test_stat_write) begin
s_test_done_d = 1'b1;
s_test_pass_d = write_data_i[`RIBP_SYSCTRL__TEST_STATUS_PASS];
s_test_code_d = write_data_i[`RIBP_SYSCTRL__TEST_STATUS_CODE+:8];
end
if (s_rtc_wake_clear) begin
s_rtc_wake_seen_d = 1'b0;
end
if (s_rtc_wake_sync) begin
s_rtc_wake_seen_d = 1'b1;
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_sysctrl_coresel_q <= '0;
s_user_reset_q <= '1;
s_user_running_q <= 1'b0;
s_user_draining_q <= 1'b0;
s_user_config_err_q <= 1'b0;
s_sysctrl_ipsel_q <= '0;
s_pll_cfg_q <= '0;
s_pll_req_valid_q <= 1'b0;
s_pll_busy_q <= 1'b0;
s_pll_err_q <= 1'b0;
s_pll_err_reason_q <= '0;
s_pll_active_sel_q <= '0;
s_pll_active_valid_q <= 1'b0;
s_pll_safe_clk_q <= 1'b1;
s_pll_lock_q <= 1'b0;
s_fault_pending_q <= 1'b0;
s_fault_write_q <= 1'b0;
s_fault_reason_q <= '0;
s_fault_detail_q <= '0;
s_fault_addr_q <= '0;
s_fault_count_q <= '0;
s_fault_master_q <= '0;
s_perf_en_q <= 1'b0;
s_perf_mgmt_wait_q <= '0;
s_perf_user_wait_q <= '0;
s_perf_dma_wait_q <= '0;
s_perf_ribp_wait_q <= '0;
s_perf_apb_wait_q <= '0;
s_perf_sdram_wait_q <= '0;
s_perf_psram_wait_q <= '0;
s_perf_flash_wait_q <= '0;
s_test_done_q <= 1'b0;
s_test_pass_q <= 1'b0;
s_test_code_q <= '0;
s_rtc_wake_seen_q <= 1'b0;
end else begin
s_sysctrl_coresel_q <= s_sysctrl_coresel_d;
s_user_reset_q <= s_user_reset_d;
s_user_running_q <= s_user_running_d;
s_user_draining_q <= s_user_draining_d;
s_user_config_err_q <= s_user_config_err_d;
s_sysctrl_ipsel_q <= s_sysctrl_ipsel_d;
s_pll_cfg_q <= s_pll_cfg_d;
s_pll_req_valid_q <= s_pll_req_valid_d;
s_pll_busy_q <= s_pll_busy_d;
s_pll_err_q <= s_pll_err_d;
s_pll_err_reason_q <= s_pll_err_reason_d;
s_pll_active_sel_q <= s_pll_active_sel_d;
s_pll_active_valid_q <= s_pll_active_valid_d;
s_pll_safe_clk_q <= s_pll_safe_clk_d;
s_pll_lock_q <= s_pll_lock_d;
s_fault_pending_q <= s_fault_pending_d;
s_fault_write_q <= s_fault_write_d;
s_fault_reason_q <= s_fault_reason_d;
s_fault_detail_q <= s_fault_detail_d;
s_fault_addr_q <= s_fault_addr_d;
s_fault_count_q <= s_fault_count_d;
s_fault_master_q <= s_fault_master_d;
s_perf_en_q <= s_perf_en_d;
s_perf_mgmt_wait_q <= s_perf_mgmt_wait_d;
s_perf_user_wait_q <= s_perf_user_wait_d;
s_perf_dma_wait_q <= s_perf_dma_wait_d;
s_perf_ribp_wait_q <= s_perf_ribp_wait_d;
s_perf_apb_wait_q <= s_perf_apb_wait_d;
s_perf_sdram_wait_q <= s_perf_sdram_wait_d;
s_perf_psram_wait_q <= s_perf_psram_wait_d;
s_perf_flash_wait_q <= s_perf_flash_wait_d;
s_test_done_q <= s_test_done_d;
s_test_pass_q <= s_test_pass_d;
s_test_code_q <= s_test_code_d;
s_rtc_wake_seen_q <= s_rtc_wake_seen_d;
end
end
always_comb begin
read_data_valid_o = 1'b1;
read_data_o = '0;
unique case (read_offset_i)
CoreSel: read_data_o = {{(32 - `USER_CORESEL_WIDTH) {1'b0}}, s_sysctrl_coresel_q};
IpSel: read_data_o = {{(32 - `USER_IPSEL_WIDTH) {1'b0}}, s_sysctrl_ipsel_q};
PllCfg: read_data_o = {29'd0, s_pll_cfg_q};
FaultStatus: read_data_o = {27'd0, s_fault_reason_q, s_fault_write_q, s_fault_pending_q};
FaultAddr: read_data_o = s_fault_addr_q;
FaultCount: read_data_o = s_fault_count_q;
PllStatus:
read_data_o = {
21'd0,
pll_ctrl.capable_i,
s_pll_lock_q,
s_pll_safe_clk_q,
s_pll_err_reason_q,
s_pll_err_q,
s_pll_busy_q,
s_pll_active_valid_q,
s_pll_active_sel_q
};
UserCoreReset: read_data_o = {{(32 - `USER_CORE_COUNT) {1'b0}}, s_user_reset_q};
UserCoreStatus:
read_data_o = {
20'd0,
s_user_config_err_q,
s_user_draining_q,
sysctrl.user_bus_idle_i,
s_user_running_q,
{(8 - `USER_CORESEL_WIDTH) {1'b0}},
s_sysctrl_coresel_q
};
FaultMaster: read_data_o = {30'd0, s_fault_master_q};
FaultDetail: read_data_o = {29'd0, s_fault_detail_q};
PerfCtrl: read_data_o = {31'd0, s_perf_en_q};
PerfMgmtWaitLo: read_data_o = s_perf_mgmt_wait_q[31:0];
PerfMgmtWaitHi: read_data_o = s_perf_mgmt_wait_q[63:32];
PerfUserWaitLo: read_data_o = s_perf_user_wait_q[31:0];
PerfUserWaitHi: read_data_o = s_perf_user_wait_q[63:32];
PerfDmaWaitLo: read_data_o = s_perf_dma_wait_q[31:0];
PerfDmaWaitHi: read_data_o = s_perf_dma_wait_q[63:32];
PerfRibpWaitLo: read_data_o = s_perf_ribp_wait_q[31:0];
PerfRibpWaitHi: read_data_o = s_perf_ribp_wait_q[63:32];
PerfApbWaitLo: read_data_o = s_perf_apb_wait_q[31:0];
PerfApbWaitHi: read_data_o = s_perf_apb_wait_q[63:32];
PerfSdramWaitLo: read_data_o = s_perf_sdram_wait_q[31:0];
PerfSdramWaitHi: read_data_o = s_perf_sdram_wait_q[63:32];
PerfPsramWaitLo: read_data_o = s_perf_psram_wait_q[31:0];
PerfPsramWaitHi: read_data_o = s_perf_psram_wait_q[63:32];
PerfFlashWaitLo: read_data_o = s_perf_flash_wait_q[31:0];
PerfFlashWaitHi: read_data_o = s_perf_flash_wait_q[63:32];
TestStatus: read_data_o = {s_test_done_q, 15'd0, s_test_code_q, 7'd0, s_test_pass_q};
RtcWakeStatus: read_data_o = {30'd0, s_rtc_wake_seen_q, s_rtc_wake_sync};
default: begin
read_data_valid_o = 1'b0;
end
endcase
end
endmodule
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`ifndef RETROSOC_SYSCTRL_DEFINE_SVH
`define RETROSOC_SYSCTRL_DEFINE_SVH
`include "mmap_define.svh"
// verilog_format: off -- preserve reviewed column alignment
`define RIBP_SYSCTRL__CORESEL `SOC_SYSCTRL_CORESEL_OFFSET
`define RIBP_SYSCTRL__IPSEL `SOC_SYSCTRL_IPSEL_OFFSET
`define RIBP_SYSCTRL__PLL_CFG `SOC_SYSCTRL_PLL_CFG_OFFSET
`define RIBP_SYSCTRL__PLL_CMD `SOC_SYSCTRL_PLL_CMD_OFFSET
`define RIBP_SYSCTRL__FAULT_STATUS `SOC_SYSCTRL_FAULT_STATUS_OFFSET
`define RIBP_SYSCTRL__FAULT_ADDR `SOC_SYSCTRL_FAULT_ADDR_OFFSET
`define RIBP_SYSCTRL__FAULT_COUNT `SOC_SYSCTRL_FAULT_COUNT_OFFSET
`define RIBP_SYSCTRL__PLL_STATUS `SOC_SYSCTRL_PLL_STATUS_OFFSET
`define RIBP_SYSCTRL__USER_CORE_RESET `SOC_SYSCTRL_USER_CORE_RESET_OFFSET
`define RIBP_SYSCTRL__USER_CORE_STATUS `SOC_SYSCTRL_USER_CORE_STATUS_OFFSET
`define RIBP_SYSCTRL__FAULT_MASTER `SOC_SYSCTRL_FAULT_MASTER_OFFSET
`define RIBP_SYSCTRL__FAULT_DETAIL `SOC_SYSCTRL_FAULT_DETAIL_OFFSET
`define RIBP_SYSCTRL__PERF_CTRL `SOC_SYSCTRL_PERF_CTRL_OFFSET
`define RIBP_SYSCTRL__PERF_MGMT_WAIT_LO `SOC_SYSCTRL_PERF_MGMT_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_MGMT_WAIT_HI `SOC_SYSCTRL_PERF_MGMT_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_USER_WAIT_LO `SOC_SYSCTRL_PERF_USER_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_USER_WAIT_HI `SOC_SYSCTRL_PERF_USER_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_DMA_WAIT_LO `SOC_SYSCTRL_PERF_DMA_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_DMA_WAIT_HI `SOC_SYSCTRL_PERF_DMA_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_RIBP_WAIT_LO `SOC_SYSCTRL_PERF_RIBP_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_RIBP_WAIT_HI `SOC_SYSCTRL_PERF_RIBP_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_APB_WAIT_LO `SOC_SYSCTRL_PERF_APB_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_APB_WAIT_HI `SOC_SYSCTRL_PERF_APB_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_SDRAM_WAIT_LO `SOC_SYSCTRL_PERF_SDRAM_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_SDRAM_WAIT_HI `SOC_SYSCTRL_PERF_SDRAM_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_PSRAM_WAIT_LO `SOC_SYSCTRL_PERF_PSRAM_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_PSRAM_WAIT_HI `SOC_SYSCTRL_PERF_PSRAM_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__PERF_FLASH_WAIT_LO `SOC_SYSCTRL_PERF_FLASH_WAIT_LO_OFFSET
`define RIBP_SYSCTRL__PERF_FLASH_WAIT_HI `SOC_SYSCTRL_PERF_FLASH_WAIT_HI_OFFSET
`define RIBP_SYSCTRL__TEST_STATUS `SOC_SYSCTRL_TEST_STATUS_OFFSET
`define RIBP_SYSCTRL__RTC_WAKE_STATUS `SOC_SYSCTRL_RTC_WAKE_STATUS_OFFSET
`define RIBP_SYSCTRL__PLL_CMD_APPLY 0
`define RIBP_SYSCTRL__PLL_CMD_CLEAR_ERROR 1
`define RIBP_SYSCTRL__FAULT_STATUS_PENDING 0
`define RIBP_SYSCTRL__PERF_CTRL_ENABLE 0
`define RIBP_SYSCTRL__PERF_CTRL_CLEAR 1
`define RIBP_SYSCTRL__PERF_CTRL_SNAPSHOT 2
`define RIBP_SYSCTRL__TEST_STATUS_PASS 0
`define RIBP_SYSCTRL__TEST_STATUS_CODE 8
`define RIBP_SYSCTRL__TEST_STATUS_VALID 31
`define RIBP_SYSCTRL__RTC_WAKE_STATUS_LIVE 0
`define RIBP_SYSCTRL__RTC_WAKE_STATUS_SEEN 1
// verilog_format: on
`endif
+54
View File
@@ -0,0 +1,54 @@
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
`include "user_extensions.svh"
interface sysctrl_if ();
logic [`USER_CORESEL_WIDTH-1:0] core_sel_o;
logic [ `USER_CORE_COUNT-1:0] core_reset_o;
logic user_bus_enable_o;
logic user_bus_idle_i;
logic fault_access_i;
logic [ 1:0] fault_master_i;
logic [ 2:0] fault_code_i;
logic perf_enable_o;
logic perf_clear_o;
logic [ 63:0] perf_mgmt_wait_i;
logic [ 63:0] perf_user_wait_i;
logic [ 63:0] perf_dma_wait_i;
logic [ 63:0] perf_ribp_wait_i;
logic [ 63:0] perf_apb_wait_i;
logic [ 63:0] perf_sdram_wait_i;
logic [ 63:0] perf_psram_wait_i;
logic [ 63:0] perf_flash_wait_i;
logic rtc_wake_i;
logic test_done_o;
logic test_pass_o;
logic [ 7:0] test_code_o;
logic [ `USER_IPSEL_WIDTH-1:0] ip_sel_o;
modport dut(
input user_bus_idle_i,
input fault_access_i,
input fault_master_i,
input fault_code_i,
input perf_mgmt_wait_i,
input perf_user_wait_i,
input perf_dma_wait_i,
input perf_ribp_wait_i,
input perf_apb_wait_i,
input perf_sdram_wait_i,
input perf_psram_wait_i,
input perf_flash_wait_i,
input rtc_wake_i,
output core_sel_o,
output core_reset_o,
output user_bus_enable_o,
output ip_sel_o,
output perf_enable_o,
output perf_clear_o,
output test_done_o,
output test_pass_o,
output test_code_o
);
endinterface
+58
View File
@@ -0,0 +1,58 @@
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
module sysctrl_reg (
// verilog_format: off -- preserve reviewed column alignment
input logic clk_i,
input logic rst_n_i,
ribp_if.slave ribp,
output logic write_valid_o,
output logic [7:0] write_offset_o,
output logic [31:0] write_data_o,
output logic [3:0] write_strobe_o,
output logic [7:0] read_offset_o,
input logic read_data_valid_i,
input logic [31:0] read_data_i
// verilog_format: on
);
logic s_req_accept;
logic s_read_accept;
logic s_ribp_ready_d;
logic s_ribp_ready_q;
logic [31:0] s_ribp_rdata_d;
logic [31:0] s_ribp_rdata_q;
assign s_req_accept = ribp.valid && !s_ribp_ready_q;
assign s_read_accept = s_req_accept && !(|ribp.wstrb);
assign write_valid_o = s_req_accept && (|ribp.wstrb);
assign write_offset_o = ribp.addr[7:0];
assign write_data_o = ribp.wdata;
assign write_strobe_o = ribp.wstrb;
assign read_offset_o = ribp.addr[7:0];
assign ribp.ready = s_ribp_ready_q;
assign ribp.resp_err = 1'b0;
assign ribp.rdata = s_ribp_rdata_q;
assign s_ribp_ready_d = s_req_accept;
assign s_ribp_rdata_d = read_data_valid_i ? read_data_i : s_ribp_rdata_q;
dffr #(
.DATA_WIDTH(1)
) u_ribp_ready_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_ribp_ready_d),
.dat_o (s_ribp_ready_q)
);
dffer #(
.DATA_WIDTH(32)
) u_ribp_rdata_dffer (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.en_i (s_read_accept),
.dat_i (s_ribp_rdata_d),
.dat_o (s_ribp_rdata_q)
);
endmodule
+4
View File
@@ -44,6 +44,10 @@
/ip/peripheral/dma_core.sv
/ip/peripheral/ribp_dma.sv
/ip/peripheral/pll_ctrl_if.sv
/ip/peripheral/sysctrl_if.sv
/ip/peripheral/sysctrl_define.svh
/ip/peripheral/sysctrl_reg.sv
/ip/peripheral/sysctrl_core.sv
/ip/peripheral/ribp_sysctrl.sv
/ip/peripheral/clint_if.sv
/ip/peripheral/clint_timebase.sv
@@ -68,6 +68,10 @@ def source_files(target: str) -> list[Path]:
*common,
COMMON_RTL / "cdc/cdc_sync.sv",
PERIPHERAL / "pll_ctrl_if.sv",
PERIPHERAL / "sysctrl_if.sv",
PERIPHERAL / "sysctrl_define.svh",
PERIPHERAL / "sysctrl_reg.sv",
PERIPHERAL / "sysctrl_core.sv",
PERIPHERAL / "ribp_sysctrl.sv",
SCRIPT_DIR / "sysctrl_formal.sv",
]
+55 -55
View File
@@ -59,63 +59,63 @@ module sysctrl_formal_design (
(* anyseq *)logic [ 3:0] f_fault_wstrb;
(* anyseq *)logic f_fault_reserved;
assign rib.valid = f_rib_valid;
assign rib.addr = f_rib_addr;
assign rib.wdata = f_rib_wdata;
assign rib.wstrb = f_rib_wstrb;
assign sysctrl.user_bus_idle_i = 1'b1;
assign sysctrl.fault_access_i = 1'b0;
assign sysctrl.fault_master_i = '0;
assign sysctrl.fault_code_i = f_fault_reserved ? `RIB_RESP_RESERVED : `RIB_RESP_DECERR;
assign sysctrl.perf_mgmt_wait_i = '0;
assign sysctrl.perf_user_wait_i = '0;
assign sysctrl.perf_dma_wait_i = '0;
assign sysctrl.perf_ribp_wait_i = '0;
assign sysctrl.perf_apb_wait_i = '0;
assign sysctrl.perf_sdram_wait_i = '0;
assign sysctrl.perf_psram_wait_i = '0;
assign sysctrl.perf_flash_wait_i = '0;
assign sysctrl.rtc_wake_i = 1'b0;
assign pll_ctrl.req_ready_i = f_pll_req_ready;
assign pll_ctrl.rsp_active_sel_i = f_pll_active_sel;
assign rib.valid = f_rib_valid;
assign rib.addr = f_rib_addr;
assign rib.wdata = f_rib_wdata;
assign rib.wstrb = f_rib_wstrb;
assign sysctrl.user_bus_idle_i = 1'b1;
assign sysctrl.fault_access_i = 1'b0;
assign sysctrl.fault_master_i = '0;
assign sysctrl.fault_code_i = f_fault_reserved ? `RIB_RESP_RESERVED : `RIB_RESP_DECERR;
assign sysctrl.perf_mgmt_wait_i = '0;
assign sysctrl.perf_user_wait_i = '0;
assign sysctrl.perf_dma_wait_i = '0;
assign sysctrl.perf_ribp_wait_i = '0;
assign sysctrl.perf_apb_wait_i = '0;
assign sysctrl.perf_sdram_wait_i = '0;
assign sysctrl.perf_psram_wait_i = '0;
assign sysctrl.perf_flash_wait_i = '0;
assign sysctrl.rtc_wake_i = 1'b0;
assign pll_ctrl.req_ready_i = f_pll_req_ready;
assign pll_ctrl.rsp_active_sel_i = f_pll_active_sel;
assign pll_ctrl.rsp_active_valid_i = f_pll_active_valid;
assign pll_ctrl.rsp_safe_clk_i = f_pll_safe_clk;
assign pll_ctrl.rsp_pll_lock_i = f_pll_lock;
assign pll_ctrl.rsp_error_i = f_pll_rsp_error;
assign pll_ctrl.rsp_valid_i = f_pll_rsp_valid;
assign pll_ctrl.capable_i = f_pll_capable;
assign pll_ctrl.rsp_safe_clk_i = f_pll_safe_clk;
assign pll_ctrl.rsp_pll_lock_i = f_pll_lock;
assign pll_ctrl.rsp_error_i = f_pll_rsp_error;
assign pll_ctrl.rsp_valid_i = f_pll_rsp_valid;
assign pll_ctrl.capable_i = f_pll_capable;
assign rib_valid = rib.valid;
assign rib_addr = rib.addr;
assign rib_wdata = rib.wdata;
assign rib_wstrb = rib.wstrb;
assign rib_ready = rib.ready;
assign ip_sel = sysctrl.ip_sel_o;
assign core_sel = u_dut.s_sysctrl_coresel_q;
assign user_reset = {{(32 - `USER_CORE_COUNT) {1'b0}}, u_dut.s_user_reset_q};
assign user_reset_mask = {{(32 - `USER_CORE_COUNT) {1'b0}}, {`USER_CORE_COUNT{1'b1}}};
assign user_core_count = `USER_CORE_COUNT;
assign user_bus_enable = u_dut.s_user_running_q;
assign user_config_error = u_dut.s_user_config_err_q;
assign pll_cfg = u_dut.s_pll_cfg_q;
assign pll_req_valid = pll_ctrl.req_valid_o;
assign pll_req_ready = pll_ctrl.req_ready_i;
assign pll_busy = u_dut.s_pll_busy_q;
assign pll_error = u_dut.s_pll_err_q;
assign pll_error_reason = u_dut.s_pll_err_reason_q;
assign pll_rsp_valid = pll_ctrl.rsp_valid_i;
assign fault_valid = f_fault_valid;
assign fault_addr = f_fault_addr;
assign fault_wstrb = f_fault_wstrb;
assign fault_reserved = f_fault_reserved;
assign fault_pending = u_dut.s_fault_pending_q;
assign fault_write = u_dut.s_fault_write_q;
assign fault_reason = u_dut.s_fault_reason_q;
assign fault_addr_q = u_dut.s_fault_addr_q;
assign fault_count = u_dut.s_fault_count_q;
assign test_done = sysctrl.test_done_o;
assign test_pass = sysctrl.test_pass_o;
assign test_code = sysctrl.test_code_o;
assign rib_valid = rib.valid;
assign rib_addr = rib.addr;
assign rib_wdata = rib.wdata;
assign rib_wstrb = rib.wstrb;
assign rib_ready = rib.ready;
assign ip_sel = sysctrl.ip_sel_o;
assign core_sel = u_dut.u_sysctrl_core.s_sysctrl_coresel_q;
assign user_reset = {{(32 - `USER_CORE_COUNT) {1'b0}}, u_dut.u_sysctrl_core.s_user_reset_q};
assign user_reset_mask = {{(32 - `USER_CORE_COUNT) {1'b0}}, {`USER_CORE_COUNT{1'b1}}};
assign user_core_count = `USER_CORE_COUNT;
assign user_bus_enable = u_dut.u_sysctrl_core.s_user_running_q;
assign user_config_error = u_dut.u_sysctrl_core.s_user_config_err_q;
assign pll_cfg = u_dut.u_sysctrl_core.s_pll_cfg_q;
assign pll_req_valid = pll_ctrl.req_valid_o;
assign pll_req_ready = pll_ctrl.req_ready_i;
assign pll_busy = u_dut.u_sysctrl_core.s_pll_busy_q;
assign pll_error = u_dut.u_sysctrl_core.s_pll_err_q;
assign pll_error_reason = u_dut.u_sysctrl_core.s_pll_err_reason_q;
assign pll_rsp_valid = pll_ctrl.rsp_valid_i;
assign fault_valid = f_fault_valid;
assign fault_addr = f_fault_addr;
assign fault_wstrb = f_fault_wstrb;
assign fault_reserved = f_fault_reserved;
assign fault_pending = u_dut.u_sysctrl_core.s_fault_pending_q;
assign fault_write = u_dut.u_sysctrl_core.s_fault_write_q;
assign fault_reason = u_dut.u_sysctrl_core.s_fault_reason_q;
assign fault_addr_q = u_dut.u_sysctrl_core.s_fault_addr_q;
assign fault_count = u_dut.u_sysctrl_core.s_fault_count_q;
assign test_done = sysctrl.test_done_o;
assign test_pass = sysctrl.test_pass_o;
assign test_code = sysctrl.test_code_o;
ribp_sysctrl u_dut (
.clk_i (clk_i),
@@ -172,7 +172,7 @@
"source": "audio",
"destination": "system",
"primitive": "cdc_sync",
"path": "rtl/ip/peripheral/ribp_sysctrl.sv",
"path": "rtl/ip/peripheral/sysctrl_core.sv",
"instance": "u_rtc_wake_sync"
},
{
+4
View File
@@ -56,6 +56,10 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
$(ROOT_PATH)/rtl/ip/peripheral/gpio_reg.sv \
$(ROOT_PATH)/rtl/ip/peripheral/ribp_gpio.sv \
$(ROOT_PATH)/rtl/ip/peripheral/pll_ctrl_if.sv \
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_if.sv \
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_define.svh \
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_reg.sv \
$(ROOT_PATH)/rtl/ip/peripheral/sysctrl_core.sv \
$(ROOT_PATH)/rtl/ip/peripheral/ribp_sysctrl.sv \
$(ROOT_PATH)/rtl/ip/serial/ws2812_if.sv \
$(ROOT_PATH)/rtl/ip/serial/ws2812_reg.sv \
+1
View File
@@ -77,6 +77,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
$(ROOT_PATH)/crt/src/service/test.c \
$(ROOT_PATH)/crt/src/hal/clint.c \
$(ROOT_PATH)/crt/src/hal/clock.c \
$(ROOT_PATH)/crt/src/hal/sysctrl.c \
$(ROOT_PATH)/crt/src/hal/uart_math.c \
$(ROOT_PATH)/crt/src/hal/uart.c \
$(ROOT_PATH)/crt/src/hal/gpio_math.c \
+4
View File
@@ -123,6 +123,10 @@
"ribp_gpio.sv",
"ribp_sysctrl.sv",
"ribp_timer.sv",
"sysctrl_core.sv",
"sysctrl_define.svh",
"sysctrl_if.sv",
"sysctrl_reg.sv",
"timer_core.sv",
"timer_define.svh",
"timer_reg.sv",
+1
View File
@@ -26,6 +26,7 @@ TEST_SOURCES = (
"crt/src/hal/uart_math.c",
"crt/src/hal/timer_math.c",
"crt/src/hal/psram_math.c",
"crt/src/hal/sysctrl.c",
"rtl/managed/clusterip/ps2/sw/src/ps2.c",
"rtl/managed/clusterip/ps2/sw/src/ps2_keyboard.c",
"rtl/managed/clusterip/ps2/sw/src/ps2_mouse.c",
@@ -1,6 +1,6 @@
`timescale 1ns / 1ps
module sysctrl_fault_tb;
module sysctrl_tb;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic fault_valid_i = 1'b0;
@@ -186,7 +186,7 @@ module sysctrl_fault_tb;
$fatal(1, "RTC wake sticky status W1C failed");
end
$display("sysctrl fault, user core control, and RTC wake test passed");
$display("SystemCtrl register, lifecycle, fault, performance, and RTC wake test passed");
$finish;
end
endmodule
+7 -51
View File
@@ -193,53 +193,6 @@ def test_bus_fault_responder_handles_reserved_and_unmapped_addresses(tmp_path: P
assert "bus fault responder test passed" in result.stdout
def test_sysctrl_fault_registers_record_and_clear_pending(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
if iverilog is None or vvp is None:
return
generate(tmp_path)
source_list = tmp_path / "sysctrl_fault.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{tmp_path / 'rtl'}",
f"+incdir+{tmp_path / 'user_extensions' / 'rtl'}",
f"+incdir+{ROOT / 'rtl/mini/top'}",
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv"),
str(ROOT / "rtl/ip/peripheral/pll_ctrl_if.sv"),
str(ROOT / "rtl/ip/peripheral/ribp_sysctrl.sv"),
str(ROOT / "tests/rtl/sysctrl_fault_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "sysctrl_fault_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 / "sysctrl_fault_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "sysctrl_fault_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "sysctrl fault, user core control, and RTC wake test passed" in result.stdout
def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path: Path) -> None:
iverilog = shutil.which("iverilog")
vvp = shutil.which("vvp")
@@ -267,6 +220,10 @@ def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path:
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/edge_det.sv"),
str(ROOT / "rtl/ip/peripheral/pll_ctrl_if.sv"),
str(ROOT / "rtl/ip/peripheral/clint_timebase.sv"),
str(ROOT / "rtl/ip/peripheral/sysctrl_if.sv"),
str(ROOT / "rtl/ip/peripheral/sysctrl_define.svh"),
str(ROOT / "rtl/ip/peripheral/sysctrl_reg.sv"),
str(ROOT / "rtl/ip/peripheral/sysctrl_core.sv"),
str(ROOT / "rtl/ip/peripheral/ribp_sysctrl.sv"),
str(ROOT / "rtl/tech/tc_clk.sv"),
str(ROOT / "rtl/tech/tc_pll.sv"),
@@ -339,8 +296,8 @@ def test_pll_controller_reconfigures_and_falls_back_to_the_safe_clock(tmp_path:
def test_sysctrl_does_not_expose_unused_i2c_or_qspi_select_registers() -> None:
rtl = (ROOT / "rtl/ip/peripheral/ribp_sysctrl.sv").read_text(encoding="utf-8")
header = (ROOT / "crt/include/retrosoc/core/soc.h").read_text(encoding="utf-8")
rtl = (ROOT / "rtl/ip/peripheral/sysctrl_core.sv").read_text(encoding="utf-8")
header = (ROOT / "crt/include/retrosoc/hal/sysctrl.h").read_text(encoding="utf-8")
for symbol in (
"SYSCTRL_I2CSEL",
@@ -351,5 +308,4 @@ def test_sysctrl_does_not_expose_unused_i2c_or_qspi_select_registers() -> None:
"s_sysctrl_qspisel",
):
assert symbol not in rtl
assert "reg_sysctrl_i2csel" not in header
assert "reg_sysctrl_qspicsel" not in header
assert "reg_sysctrl_" not in header
+4
View File
@@ -256,6 +256,10 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
assert ROOT / "rtl/mini/top/rib2apb.sv" in rib2apb.files
assert ROOT / "rtl/mini/formal/rib2apb_formal.sv" in rib2apb.files
assert ROOT / "rtl/managed/clusterip/common/rtl/interface/apb4_pure_if.sv" in rib2apb.files
assert ROOT / "rtl/ip/peripheral/sysctrl_if.sv" in sysctrl.files
assert ROOT / "rtl/ip/peripheral/sysctrl_define.svh" in sysctrl.files
assert ROOT / "rtl/ip/peripheral/sysctrl_reg.sv" in sysctrl.files
assert ROOT / "rtl/ip/peripheral/sysctrl_core.sv" in sysctrl.files
assert ROOT / "rtl/ip/peripheral/ribp_sysctrl.sv" in sysctrl.files
assert ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv" in sysctrl.files
assert ROOT / "rtl/mini/formal/sysctrl_formal.sv" in sysctrl.files
+93
View File
@@ -0,0 +1,93 @@
"""SystemCtrl 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/peripheral"
def test_sysctrl_registers_lifecycle_faults_and_wake(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"
generated = tmp_path / "generated"
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/address_map/generate_memory_map.py"),
"--map",
str(ROOT / "rtl/mini/address_map/memory_map.json"),
"--output-dir",
str(generated),
],
check=True,
)
subprocess.run(
[
sys.executable,
str(ROOT / "rtl/mini/integration/generate_user_extensions.py"),
"--map",
str(ROOT / "rtl/mini/integration/user_extensions.json"),
"--output-dir",
str(generated / "user_extensions"),
],
check=True,
)
source_list = tmp_path / "sysctrl.fl"
source_list.write_text(
"\n".join(
[
"+define+SV_ASSRT_DISABLE",
f"+incdir+{generated / 'rtl'}",
f"+incdir+{generated / 'user_extensions' / 'rtl'}",
f"+incdir+{ROOT / 'rtl/mini/top'}",
f"+incdir+{common}",
f"+incdir+{common / 'interface'}",
f"+incdir+{common / 'utils'}",
f"+incdir+{common / 'cdc'}",
f"+incdir+{PERIPHERAL}",
str(common / "interface/ribp_if.sv"),
str(common / "utils/register.sv"),
str(common / "cdc/cdc_sync.sv"),
str(PERIPHERAL / "pll_ctrl_if.sv"),
str(PERIPHERAL / "sysctrl_if.sv"),
str(PERIPHERAL / "sysctrl_define.svh"),
str(PERIPHERAL / "sysctrl_reg.sv"),
str(PERIPHERAL / "sysctrl_core.sv"),
str(PERIPHERAL / "ribp_sysctrl.sv"),
str(ROOT / "tests/rtl/sysctrl_tb.sv"),
"",
]
),
encoding="utf-8",
)
converted = tmp_path / "sysctrl_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 / "sysctrl_tb"
subprocess.run(
[iverilog, "-g2012", "-s", "sysctrl_tb", "-o", str(simulation), str(converted)],
check=True,
)
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
assert "SystemCtrl register, lifecycle, fault, performance, and RTC wake test passed" in (
result.stdout
)