mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
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:
31 files changed
+1441
-1025
No files matched your search
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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(®_sysctrl_perf_mgmt_wait_lo, ®_sysctrl_perf_mgmt_wait_hi);
|
||||
snapshot->user_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_user_wait_lo, ®_sysctrl_perf_user_wait_hi);
|
||||
snapshot->dma_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_dma_wait_lo, ®_sysctrl_perf_dma_wait_hi);
|
||||
snapshot->ribp_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_ribp_wait_lo, ®_sysctrl_perf_ribp_wait_hi);
|
||||
snapshot->apb_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_apb_wait_lo, ®_sysctrl_perf_apb_wait_hi);
|
||||
snapshot->sdram_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_sdram_wait_lo, ®_sysctrl_perf_sdram_wait_hi);
|
||||
snapshot->psram_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_psram_wait_lo, ®_sysctrl_perf_psram_wait_hi);
|
||||
snapshot->flash_wait =
|
||||
rs_perf_read_counter(®_sysctrl_perf_flash_wait_lo, ®_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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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 *)®_xpi_cfgidx);
|
||||
printf(" 1 x DMA @%p\n", (void *)®_dma_mode);
|
||||
printf(" 1 x SYSCTRL @%p\n", (void *)®_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 *)®_sdram_clkdiv);
|
||||
|
||||
+12
-2
@@ -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(¤t_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);
|
||||
|
||||
@@ -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 (;;) {
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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).
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
Reference in new issue
Block a user