From fc898bc4ab5ca96cc6192cf48d7c29c496fb63b4 Mon Sep 17 00:00:00 2001 From: maksyuki Date: Mon, 20 Jul 2026 22:12:17 +0800 Subject: [PATCH] feat: add PLL controller and related testbench functionality - Removed legacy clock definitions and added a dynamic PLL timing template in retrosoc_pll.sdc. - Introduced a new SystemVerilog testbench (pll_ctrl_tb.sv) for the PLL controller, including clock generation, register read/write tasks, and validation of PLL configuration and timing. - Updated sysctrl_fault_tb.sv to include PLL controller interface and initialization. - Enhanced memory map tests to verify PLL configuration and status offsets. - Added tests for PLL controller dynamic reconfiguration and fallback to safe clock. --- .verible-format | 13 +- Makefile | 2 - crt/include/retrosoc/core/soc.h | 3 + crt/include/retrosoc/hal/clock.h | 34 ++ crt/src/hal/clock.c | 79 ++++ docs/README.md | 2 + docs/pll-clock-control.md | 34 ++ fpga/mini/retrosoc_top.sv | 4 - rtl/ip/native/peripheral/pll_ctrl_if.sv | 52 +++ rtl/ip/native/peripheral/sysctrl.sv | 150 ++++++- rtl/mini/address_map/generate_memory_map.py | 6 + rtl/mini/dv/tb/retrosoc_tb.sv | 54 +-- rtl/mini/dv/verilator/rtl/retrosoc_top.sv | 12 +- rtl/mini/filelist/ip.fl | 1 + rtl/mini/mk/iverilog.mk | 3 +- rtl/mini/mk/software.mk | 1 + rtl/mini/mk/vcs.mk | 3 +- rtl/mini/top/ip_nmi_wrapper.sv | 4 +- rtl/mini/top/rcu.sv | 416 ++++++++++++++------ rtl/mini/top/retrosoc.sv | 2 + rtl/mini/top/retrosoc_asic.sv | 17 +- rtl/tech/tc_clk.sv | 22 ++ rtl/tech/tc_pll.sv | 154 +++++--- sta/opensta/gen2.sdc | 182 +-------- sta/opensta/retrosoc_pll.sdc | 50 +-- tests/rtl/pll_ctrl_tb.sv | 170 ++++++++ tests/rtl/sysctrl_fault_tb.sv | 22 +- tests/test_memory_map.py | 97 +++++ 28 files changed, 1112 insertions(+), 477 deletions(-) create mode 100644 crt/include/retrosoc/hal/clock.h create mode 100644 crt/src/hal/clock.c create mode 100644 docs/pll-clock-control.md create mode 100644 rtl/ip/native/peripheral/pll_ctrl_if.sv create mode 100644 tests/rtl/pll_ctrl_tb.sv diff --git a/.verible-format b/.verible-format index 11a27d22..b24d8c9d 100644 --- a/.verible-format +++ b/.verible-format @@ -1 +1,12 @@ ---assignment_statement_alignment align --case_items_alignment align --class_member_variable_alignment align --distribution_items_alignment align --enum_assignment_statement_alignment align --formal_parameters_alignment align --module_net_variable_alignment align --named_parameter_alignment align --named_port_alignment align --port_declarations_alignment align --struct_union_members_alignment align --inplace \ No newline at end of file +--assignment_statement_alignment=align +--case_items_alignment=align +--class_member_variable_alignment=align +--distribution_items_alignment=align +--enum_assignment_statement_alignment=align +--formal_parameters_alignment=align +--module_net_variable_alignment=align +--named_parameter_alignment=align +--named_port_alignment=align +--port_declarations_alignment=align +--struct_union_members_alignment=align +--inplace diff --git a/Makefile b/Makefile index 6cd9070f..32800f5b 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,6 @@ HAVE_SRAM_MACRO ?= NO HAVE_SVA ?= NO WAVE ?= NO -RTL_SIM_PLLEN ?= NONE -RTL_SIM_PLLCFG ?= NONE RTL_SIM_CORESEL ?= 0 RTL_SIM_TIMEOUT ?= -1 SIM_FIRMWARE_NAME ?= $(FIRMWARE_NAME) diff --git a/crt/include/retrosoc/core/soc.h b/crt/include/retrosoc/core/soc.h index 94cd4448..b15ce61f 100644 --- a/crt/include/retrosoc/core/soc.h +++ b/crt/include/retrosoc/core/soc.h @@ -148,10 +148,13 @@ #define RS_SOC_SYSCTRL_REG32(offset) RS_SOC_REG32(RS_SOC_NMI_SYSCTRL_BASE, (offset)) #define reg_sysctrl_coresel RS_SOC_REG32(RS_SOC_NMI_SYSCTRL_BASE, UINT32_C(0x00)) #define reg_sysctrl_ipsel RS_SOC_REG32(RS_SOC_NMI_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 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) diff --git a/crt/include/retrosoc/hal/clock.h b/crt/include/retrosoc/hal/clock.h new file mode 100644 index 00000000..2bee1d74 --- /dev/null +++ b/crt/include/retrosoc/hal/clock.h @@ -0,0 +1,34 @@ +#ifndef RETROSOC_HAL_CLOCK_H +#define RETROSOC_HAL_CLOCK_H + +#include +#include + +#include + +typedef enum { + RS_CLOCK_FREQ_24MHZ = 0, + RS_CLOCK_FREQ_48MHZ = 1, + RS_CLOCK_FREQ_72MHZ = 2, + RS_CLOCK_FREQ_96MHZ = 3, + RS_CLOCK_FREQ_120MHZ = 4, + RS_CLOCK_FREQ_144MHZ = 5, + RS_CLOCK_FREQ_168MHZ = 6, + RS_CLOCK_FREQ_192MHZ = 7, +} rs_clock_frequency_t; + +typedef struct { + rs_clock_frequency_t requested_frequency; + rs_clock_frequency_t active_frequency; + uint8_t error_reason; + bool active_valid; + bool busy; + bool safe_clock; + bool pll_locked; + bool capable; +} rs_clock_status_t; + +rs_status_t rs_clock_get_status(rs_clock_status_t *status); +rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t timeout); + +#endif diff --git a/crt/src/hal/clock.c b/crt/src/hal/clock.c new file mode 100644 index 00000000..ba79a8e6 --- /dev/null +++ b/crt/src/hal/clock.c @@ -0,0 +1,79 @@ +#include + +#include +#include + +#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 + +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; + + 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; + return RS_OK; +} + +rs_status_t rs_clock_set_frequency(rs_clock_frequency_t frequency, rs_timeout_t timeout) { + rs_clock_status_t status; + bool busy_observed = false; + + if (!rs_clock_frequency_valid(frequency)) { + return RS_EINVAL; + } + if (rs_clock_get_status(&status) != RS_OK) { + return RS_EIO; + } + if (!status.capable) { + return RS_ENOTSUP; + } + if (status.busy) { + 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; + + while (timeout-- != 0U) { + if (rs_clock_get_status(&status) != RS_OK) { + return RS_EIO; + } + busy_observed = busy_observed || status.busy; + if (busy_observed && !status.busy) { + if (status.error_reason == RS_CLOCK_ERROR_UNSUPPORTED) { + return RS_ENOTSUP; + } + if (status.error_reason == RS_CLOCK_ERROR_LOCK_TIMEOUT) { + return RS_ETIMEOUT; + } + return status.error_reason == 0U ? RS_OK : RS_EIO; + } + } + + return RS_ETIMEOUT; +} diff --git a/docs/README.md b/docs/README.md index 4a8f4f46..f39fa35f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,8 @@ the root README and subsystem guides. artifacts, result policy, warning baselines, metrics, CI, and releases. - [misra-c-2012.md](misra-c-2012.md) defines the MISRA C:2012 Amendment 2 baseline, scope, partial automation, and deviation process. +- [pll-clock-control.md](pll-clock-control.md) describes the SYSCTRL PLL + register protocol and software quiesce contract. Keep policy descriptions here concise and link to executable configuration as the source of truth. Changes that alter process requirements must also update diff --git a/docs/pll-clock-control.md b/docs/pll-clock-control.md new file mode 100644 index 00000000..32c68018 --- /dev/null +++ b/docs/pll-clock-control.md @@ -0,0 +1,34 @@ +# PLL Dynamic Clock Control + +The system powers up on the `extclk_i_pad` external safe clock. After software +submits a PLL frequency request through SYSCTRL, the RCU switches to the safe +source, configures the PLL, waits for lock, and switches back in the external +reference-clock domain. PLL lock transitions do not reset the system. A failed +configuration leaves the system on the safe clock. + +## Registers + +| Offset | Name | Access | Description | +| --- | --- | --- | --- | +| `0x08` | `PLL_CFG` | RW | `FREQ_SEL[2:0]`: 24, 48, 72, 96, 120, 144, 168, or 192 MHz. | +| `0x0c` | `PLL_CMD` | WO | bit 0 is `APPLY`; bit 1 is `CLEAR_ERROR`. | +| `0x1c` | `PLL_STATUS` | RO | Active profile, validity, busy state, error and cause, safe-clock source, lock state, and capability. | + +Applications use `rs_clock_set_frequency()` and `rs_clock_get_status()` from +``; PDK-specific PLL divider settings are not exposed. + +## Software Flow + +1. Run the transition routine from SRAM, disable interrupts, and quiesce DMA, + serial transfers, and other frequency-sensitive transactions. +2. Call `rs_clock_set_frequency()` and wait with a bounded timeout. +3. On success, reprogram UART, SPI, I2C, timer, and other divider-dependent + peripherals for the new frequency before restoring normal operation. +4. `RS_ENOTSUP` means the current PDK has no integrated dynamic PLL or + glitch-free clock-switch backend. The system remains on the external safe + clock. + +`PDK_BEHAV` provides a dynamic-frequency and lock behavior model. A real PDK +must integrate a characterized PLL macro, lock timing, and glitch-free clock +switch before setting capability to 1. The current IHP130 and ICS55 backends +do not advertise this capability. diff --git a/fpga/mini/retrosoc_top.sv b/fpga/mini/retrosoc_top.sv index f1acdb44..88cc7dea 100644 --- a/fpga/mini/retrosoc_top.sv +++ b/fpga/mini/retrosoc_top.sv @@ -91,10 +91,6 @@ module retrosoc_top ( `ifdef HAVE_PLL .xi_i_pad (s_sys_clk), .xo_o_pad (), - .clk_bypass_i_pad (1'b1), - .pll_cfg_0_i_pad (1'b0), - .pll_cfg_1_i_pad (1'b0), - .pll_cfg_2_i_pad (1'b0), `endif `ifdef CORE_MDD .core_sel_0_i_pad (1'b0), diff --git a/rtl/ip/native/peripheral/pll_ctrl_if.sv b/rtl/ip/native/peripheral/pll_ctrl_if.sv new file mode 100644 index 00000000..100e126e --- /dev/null +++ b/rtl/ip/native/peripheral/pll_ctrl_if.sv @@ -0,0 +1,52 @@ +// Copyright (c) 2023-2026 Yuchi Miao +// 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 FITNESS FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +interface pll_ctrl_if (); + logic [2:0] req_sel_o; + logic req_valid_o; + logic req_ready_i; + + logic [2:0] rsp_active_sel_i; + logic rsp_active_valid_i; + logic rsp_safe_clk_i; + logic rsp_pll_lock_i; + logic [1:0] rsp_error_i; + logic rsp_valid_i; + logic rsp_ready_o; + logic capable_i; + + modport sysctrl( + output req_sel_o, + output req_valid_o, + output rsp_ready_o, + input req_ready_i, + input rsp_active_sel_i, + input rsp_active_valid_i, + input rsp_safe_clk_i, + input rsp_pll_lock_i, + input rsp_error_i, + input rsp_valid_i, + input capable_i + ); + + modport rcu( + input req_sel_o, + input req_valid_o, + input rsp_ready_o, + output req_ready_i, + output rsp_active_sel_i, + output rsp_active_valid_i, + output rsp_safe_clk_i, + output rsp_pll_lock_i, + output rsp_error_i, + output rsp_valid_i, + output capable_i + ); +endinterface diff --git a/rtl/ip/native/peripheral/sysctrl.sv b/rtl/ip/native/peripheral/sysctrl.sv index 729b8113..091d89e0 100644 --- a/rtl/ip/native/peripheral/sysctrl.sv +++ b/rtl/ip/native/peripheral/sysctrl.sv @@ -14,9 +14,12 @@ // verilog_format: off `define NATV_SYSCTRL_CORESEL 8'h00 // RO `define NATV_SYSCTRL_IPSEL 8'h04 // WR/RD +`define NATV_SYSCTRL_PLL_CFG `SOC_SYSCTRL_PLL_CFG_OFFSET // WR/RD +`define NATV_SYSCTRL_PLL_CMD `SOC_SYSCTRL_PLL_CMD_OFFSET // WO `define NATV_SYSCTRL_FAULT_STATUS `SOC_SYSCTRL_FAULT_STATUS_OFFSET // W1C/RD `define NATV_SYSCTRL_FAULT_ADDR `SOC_SYSCTRL_FAULT_ADDR_OFFSET // RD `define NATV_SYSCTRL_FAULT_COUNT `SOC_SYSCTRL_FAULT_COUNT_OFFSET // RD +`define NATV_SYSCTRL_PLL_STATUS `SOC_SYSCTRL_PLL_STATUS_OFFSET // RD // verilog_format: on `endif @@ -40,7 +43,8 @@ module nmi_sysctrl ( input logic [3:0] fault_wstrb_i, input logic fault_reserved_i, nmi_if.slave nmi, - sysctrl_if.dut sysctrl + sysctrl_if.dut sysctrl, + pll_ctrl_if.sysctrl pll_ctrl // verilog_format: on ); @@ -52,6 +56,18 @@ module nmi_sysctrl ( logic [`USER_CORESEL_WIDTH-1:0] s_sysctrl_coresel_d, s_sysctrl_coresel_q; 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_error; + 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_error_d, s_pll_error_q; + logic [1:0] s_pll_error_reason_d, s_pll_error_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_status_clear; logic s_fault_pending_d, s_fault_pending_q; logic s_fault_write_d, s_fault_write_q; @@ -59,14 +75,17 @@ module nmi_sysctrl ( logic [31:0] s_fault_addr_d, s_fault_addr_q; logic [31:0] s_fault_count_d, s_fault_count_q; - assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb); - assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb)); - assign nmi.ready = s_nmi_ready_q; - assign nmi.rdata = s_nmi_rdata_q; + assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb); + assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb)); + assign nmi.ready = s_nmi_ready_q; + assign nmi.rdata = s_nmi_rdata_q; - assign sysctrl.ip_sel_o = s_sysctrl_ipsel_q; + assign sysctrl.ip_sel_o = s_sysctrl_ipsel_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; - assign s_sysctrl_coresel_d = sysctrl.core_sel_i; + assign s_sysctrl_coresel_d = sysctrl.core_sel_i; dffr #(`USER_CORESEL_WIDTH) u_sysctrl_coresel_dffr ( clk_i, rst_n_i, @@ -84,6 +103,111 @@ module nmi_sysctrl ( s_sysctrl_ipsel_q ); + assign s_pll_cfg_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_SYSCTRL_PLL_CFG && nmi.wstrb[0]; + assign s_pll_cfg_d = nmi.wdata[2:0]; + dffer #(3) u_pll_cfg_dffer ( + clk_i, + rst_n_i, + s_pll_cfg_en, + s_pll_cfg_d, + s_pll_cfg_q + ); + + assign s_pll_apply = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_SYSCTRL_PLL_CMD && + nmi.wstrb[0] && nmi.wdata[0]; + assign s_pll_clear_error = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_SYSCTRL_PLL_CMD && + nmi.wstrb[0] && nmi.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 #(1) u_pll_req_valid_dffr ( + clk_i, + rst_n_i, + s_pll_req_valid_d, + s_pll_req_valid_q + ); + dffr #(1) u_pll_busy_dffr ( + clk_i, + rst_n_i, + s_pll_busy_d, + s_pll_busy_q + ); + + always_comb begin + s_pll_error_d = s_pll_error_q; + s_pll_error_reason_d = s_pll_error_reason_q; + if (s_pll_clear_error) begin + s_pll_error_d = 1'b0; + s_pll_error_reason_d = 2'd0; + end + if (s_pll_apply && (s_pll_busy_q || s_pll_req_valid_q)) begin + s_pll_error_d = 1'b1; + s_pll_error_reason_d = 2'd3; + end + if (s_pll_rsp_accept && |pll_ctrl.rsp_error_i) begin + s_pll_error_d = 1'b1; + s_pll_error_reason_d = pll_ctrl.rsp_error_i; + end + end + dffr #(1) u_pll_error_dffr ( + clk_i, + rst_n_i, + s_pll_error_d, + s_pll_error_q + ); + dffr #(2) u_pll_error_reason_dffr ( + clk_i, + rst_n_i, + s_pll_error_reason_d, + s_pll_error_reason_q + ); + + assign s_pll_active_sel_d = pll_ctrl.rsp_active_sel_i; + dffer #(3) u_pll_active_sel_dffer ( + clk_i, + rst_n_i, + s_pll_rsp_accept, + s_pll_active_sel_d, + s_pll_active_sel_q + ); + assign s_pll_active_valid_d = pll_ctrl.rsp_active_valid_i; + dffer #(1) u_pll_active_valid_dffer ( + clk_i, + rst_n_i, + s_pll_rsp_accept, + s_pll_active_valid_d, + s_pll_active_valid_q + ); + assign s_pll_safe_clk_d = pll_ctrl.rsp_safe_clk_i; + dfferc #(1, 1'b1) u_pll_safe_clk_dfferc ( + clk_i, + rst_n_i, + s_pll_rsp_accept, + s_pll_safe_clk_d, + s_pll_safe_clk_q + ); + assign s_pll_lock_d = pll_ctrl.rsp_pll_lock_i; + dffer #(1) u_pll_lock_dffer ( + clk_i, + rst_n_i, + s_pll_rsp_accept, + s_pll_lock_d, + s_pll_lock_q + ); + assign s_fault_status_clear = s_nmi_wr_hdshk && nmi.addr[7:0] == `NATV_SYSCTRL_FAULT_STATUS && nmi.wstrb[0] && nmi.wdata[0]; @@ -152,9 +276,21 @@ module nmi_sysctrl ( // verilog_format: off `NATV_SYSCTRL_CORESEL: s_nmi_rdata_d = {{(32 - `USER_CORESEL_WIDTH) {1'b0}}, s_sysctrl_coresel_q}; `NATV_SYSCTRL_IPSEL: s_nmi_rdata_d = {{(32 - `USER_IPSEL_WIDTH) {1'b0}}, s_sysctrl_ipsel_q}; + `NATV_SYSCTRL_PLL_CFG: s_nmi_rdata_d = {29'd0, s_pll_cfg_q}; `NATV_SYSCTRL_FAULT_STATUS: s_nmi_rdata_d = {28'd0, s_fault_reason_q, s_fault_write_q, s_fault_pending_q}; `NATV_SYSCTRL_FAULT_ADDR: s_nmi_rdata_d = s_fault_addr_q; `NATV_SYSCTRL_FAULT_COUNT: s_nmi_rdata_d = s_fault_count_q; + `NATV_SYSCTRL_PLL_STATUS: s_nmi_rdata_d = { + 21'd0, + pll_ctrl.capable_i, + s_pll_lock_q, + s_pll_safe_clk_q, + s_pll_error_reason_q, + s_pll_error_q, + s_pll_busy_q, + s_pll_active_valid_q, + s_pll_active_sel_q + }; default: s_nmi_rdata_d = s_nmi_rdata_q; endcase // verilog_format: on diff --git a/rtl/mini/address_map/generate_memory_map.py b/rtl/mini/address_map/generate_memory_map.py index f4c0432c..db97bfc7 100644 --- a/rtl/mini/address_map/generate_memory_map.py +++ b/rtl/mini/address_map/generate_memory_map.py @@ -129,9 +129,12 @@ def render_rtl(cpu_reset: int, regions: list[dict[str, Any]]) -> str: lines.append(f"`define SOC_ADDR_IS_{route.upper()}(addr) ({join_or(selected)})") lines += [ "", + "`define SOC_SYSCTRL_PLL_CFG_OFFSET 32'h00000008", + "`define SOC_SYSCTRL_PLL_CMD_OFFSET 32'h0000000C", "`define SOC_SYSCTRL_FAULT_STATUS_OFFSET 32'h00000010", "`define SOC_SYSCTRL_FAULT_ADDR_OFFSET 32'h00000014", "`define SOC_SYSCTRL_FAULT_COUNT_OFFSET 32'h00000018", + "`define SOC_SYSCTRL_PLL_STATUS_OFFSET 32'h0000001C", "", "`endif", "", @@ -162,9 +165,12 @@ def render_c(cpu_reset: int, regions: list[dict[str, Any]], have_sram_if: str) - ] lines += [ "", + "#define RS_SOC_SYSCTRL_PLL_CFG_OFFSET UINT32_C(0x00000008)", + "#define RS_SOC_SYSCTRL_PLL_CMD_OFFSET UINT32_C(0x0000000C)", "#define RS_SOC_SYSCTRL_FAULT_STATUS_OFFSET UINT32_C(0x00000010)", "#define RS_SOC_SYSCTRL_FAULT_ADDR_OFFSET UINT32_C(0x00000014)", "#define RS_SOC_SYSCTRL_FAULT_COUNT_OFFSET UINT32_C(0x00000018)", + "#define RS_SOC_SYSCTRL_PLL_STATUS_OFFSET UINT32_C(0x0000001C)", "", "#endif", "", diff --git a/rtl/mini/dv/tb/retrosoc_tb.sv b/rtl/mini/dv/tb/retrosoc_tb.sv index 72335c86..cb2868fc 100644 --- a/rtl/mini/dv/tb/retrosoc_tb.sv +++ b/rtl/mini/dv/tb/retrosoc_tb.sv @@ -19,18 +19,14 @@ module retrosoc_tb; integer sim_runtime; - reg r_ext_clk; - wire s_ext_clk; - reg r_aud_clk; - wire s_aud_clk; - reg r_rst_n; - wire s_rst_n; + reg r_ext_clk; + wire s_ext_clk; + reg r_aud_clk; + wire s_aud_clk; + reg r_rst_n; + wire s_rst_n; `ifdef HAVE_PLL - reg r_xtal_clk; - reg r_pll_en; - wire s_clk_bypass; - reg [2:0] r_pll_cfg; - wire [2:0] s_pll_cfg; + reg r_xtal_clk; `endif reg [ 4:0] r_core_sel; wire [ 4:0] s_core_sel; @@ -88,13 +84,9 @@ module retrosoc_tb; always #(1000 / AUD_CPU_FREQ / 2) r_aud_clk = (r_aud_clk === 1'b0); // connect inout pad - assign s_ext_clk = r_ext_clk; - assign s_aud_clk = r_aud_clk; - assign s_rst_n = r_rst_n; -`ifdef HAVE_PLL - assign s_clk_bypass = ~r_pll_en; - assign s_pll_cfg = r_pll_cfg; -`endif + assign s_ext_clk = r_ext_clk; + assign s_aud_clk = r_aud_clk; + assign s_rst_n = r_rst_n; assign s_core_sel = r_core_sel; assign s_user_gpio_0_io = r_user_gpio_0_io; @@ -105,10 +97,6 @@ module retrosoc_tb; `ifdef HAVE_PLL .xi_i_pad (r_xtal_clk), .xo_o_pad (), - .clk_bypass_i_pad (s_clk_bypass), - .pll_cfg_0_i_pad (s_pll_cfg[0]), - .pll_cfg_1_i_pad (s_pll_cfg[1]), - .pll_cfg_2_i_pad (s_pll_cfg[2]), `endif `ifdef CORE_MDD .core_sel_0_i_pad (s_core_sel[0]), @@ -412,27 +400,7 @@ module retrosoc_tb; `endif `ifdef HAVE_PLL - if ($test$plusargs("pll_en")) r_pll_en = 1'b1; - else r_pll_en = 1'b0; - - if ($test$plusargs("pll_cfg0")) r_pll_cfg = 3'd0; // 24M - else if ($test$plusargs("pll_cfg1")) r_pll_cfg = 3'd1; // 48M - else if ($test$plusargs("pll_cfg2")) r_pll_cfg = 3'd2; // 72M - else if ($test$plusargs("pll_cfg3")) r_pll_cfg = 3'd3; // 96M - else if ($test$plusargs("pll_cfg4")) r_pll_cfg = 3'd4; // 120M - else if ($test$plusargs("pll_cfg5")) r_pll_cfg = 3'd5; // 144M - else if ($test$plusargs("pll_cfg6")) r_pll_cfg = 3'd6; // 168M - else if ($test$plusargs("pll_cfg7")) r_pll_cfg = 3'd7; // 192M - else r_pll_cfg = 3'd0; // 24M - - if (r_pll_en == 1'b0) begin - $display("pll_en: %0d pll_cfg: %0d clk_freq: %0dMHz", r_pll_en, r_pll_cfg, EXT_CPU_FREQ); - end else if (r_pll_cfg == 3'd0 || r_pll_cfg == 3'd1) begin - $display("pll_en: %0d pll_cfg: %0d clk_freq: %0dMHz", r_pll_en, r_pll_cfg, XTAL_CPU_FREQ); - end else begin - $display("pll_en: %0d pll_cfg: %0d clk_freq: %0dMHz", r_pll_en, r_pll_cfg, - (r_pll_cfg + 1) * 24); - end + $display("pll clock control: sysctrl"); `else $display("ext clk_freq: %0dMHz", EXT_CPU_FREQ); `endif diff --git a/rtl/mini/dv/verilator/rtl/retrosoc_top.sv b/rtl/mini/dv/verilator/rtl/retrosoc_top.sv index e7df7582..824a714b 100644 --- a/rtl/mini/dv/verilator/rtl/retrosoc_top.sv +++ b/rtl/mini/dv/verilator/rtl/retrosoc_top.sv @@ -29,7 +29,6 @@ module retrosoc_top ( wire s_clk; wire s_rst_n; wire [4:0] s_core_sel; - wire s_clk_bypass; wire s_psram_sck; wire s_psram_nss0; wire s_psram_dat0; @@ -43,10 +42,9 @@ module retrosoc_top ( wire s_xpi_dat2_io; wire s_xpi_dat3_io; - assign s_clk = ext_clk_i; - assign s_rst_n = rst_n_i; - assign s_core_sel = core_sel_i; - assign s_clk_bypass = 1'b1; + assign s_clk = ext_clk_i; + assign s_rst_n = rst_n_i; + assign s_core_sel = core_sel_i; retrosoc_asic u_retrosoc_asic ( .extclk_i_pad (s_clk), .audclk_i_pad (), @@ -54,10 +52,6 @@ module retrosoc_top ( `ifdef HAVE_PLL .xi_i_pad (), .xo_o_pad (), - .clk_bypass_i_pad (s_clk_bypass), - .pll_cfg_0_i_pad (), - .pll_cfg_1_i_pad (), - .pll_cfg_2_i_pad (), `endif `ifdef CORE_MDD .core_sel_0_i_pad (s_core_sel[0]), diff --git a/rtl/mini/filelist/ip.fl b/rtl/mini/filelist/ip.fl index ba9b2cad..520300e9 100644 --- a/rtl/mini/filelist/ip.fl +++ b/rtl/mini/filelist/ip.fl @@ -28,6 +28,7 @@ /ip/native/storage/xpi.sv /ip/native/peripheral/dma_core.sv /ip/native/peripheral/dma.sv +/ip/native/peripheral/pll_ctrl_if.sv /ip/native/peripheral/sysctrl.sv /ip/native/peripheral/clint.sv /ip/native/memory/sdram_clkgen.sv diff --git a/rtl/mini/mk/iverilog.mk b/rtl/mini/mk/iverilog.mk index 4b744c2b..ac623176 100644 --- a/rtl/mini/mk/iverilog.mk +++ b/rtl/mini/mk/iverilog.mk @@ -28,8 +28,7 @@ IVERILOG_POST_DEPFILE := $(IVERILOG_POST_DIR)/simv.d IVERILOG_COMMON_OPTS := -g2012 IVERILOG_TIME_OPTS := -gno-specify IVERILOG_POST_OPTS := -gspecify -Tmin -IVERILOG_SIM_OPTS := +$(RTL_SIM_PLLEN) +$(RTL_SIM_PLLCFG) \ - +core_sel=$(RTL_SIM_CORESEL) +sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE) +IVERILOG_SIM_OPTS := +core_sel=$(RTL_SIM_CORESEL) +sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE) $(CONVERTED_SOC): $(MPW_VARIANT_STAMP) $(FILELIST_STAMP) @mkdir -p $(@D) diff --git a/rtl/mini/mk/software.mk b/rtl/mini/mk/software.mk index 501976ba..401b2bbb 100644 --- a/rtl/mini/mk/software.mk +++ b/rtl/mini/mk/software.mk @@ -65,6 +65,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \ $(ROOT_PATH)/crt/src/core/archinfo.c \ $(ROOT_PATH)/crt/src/service/bench.c \ $(ROOT_PATH)/crt/src/service/booter.c \ + $(ROOT_PATH)/crt/src/hal/clock.c \ $(ROOT_PATH)/crt/src/hal/uart.c \ $(ROOT_PATH)/crt/src/hal/gpio.c \ $(ROOT_PATH)/crt/src/hal/timer.c \ diff --git a/rtl/mini/mk/vcs.mk b/rtl/mini/mk/vcs.mk index b505e5df..e72b8fc4 100644 --- a/rtl/mini/mk/vcs.mk +++ b/rtl/mini/mk/vcs.mk @@ -46,8 +46,7 @@ POST_OPTS := -sdf min:retrosoc_tb.u_retrosoc_asic:$(SDF_PATH) \ TIME_OPTION := +notimingcheck +nospecify SIM_OPTS := +vcs+loopreport+1000 -suppress=ASLR_DETECTED_INFO \ - +$(RTL_SIM_PLLEN) +$(RTL_SIM_PLLCFG) +core_sel=$(RTL_SIM_CORESEL) +sim_timeout=$(RTL_SIM_TIMEOUT) \ - +wave_$(WAVE) + +core_sel=$(RTL_SIM_CORESEL) +sim_timeout=$(RTL_SIM_TIMEOUT) +wave_$(WAVE) VCS_BEHV_DIR := $(SIM_BUILD_ROOT)/behv VCS_NETL_DIR := $(SIM_BUILD_ROOT)/netl diff --git a/rtl/mini/top/ip_nmi_wrapper.sv b/rtl/mini/top/ip_nmi_wrapper.sv index 7da63594..73755a74 100644 --- a/rtl/mini/top/ip_nmi_wrapper.sv +++ b/rtl/mini/top/ip_nmi_wrapper.sv @@ -29,6 +29,7 @@ module ip_nmi_wrapper ( xpi_if.dut xpi, nmi_if.master dma_nmi, sysctrl_if.dut sysctrl, + pll_ctrl_if.sysctrl pll_ctrl, sdram_if.dut sdram, dvp_if.dut dvp, sdio_if.dut sdio, @@ -382,7 +383,8 @@ module ip_nmi_wrapper ( .fault_wstrb_i (fault_wstrb_i), .fault_reserved_i(fault_reserved_i), .nmi (u_sysctrl_nmi_if), - .sysctrl (sysctrl) + .sysctrl (sysctrl), + .pll_ctrl (pll_ctrl) ); nmi_clint u_nmi_clint ( diff --git a/rtl/mini/top/rcu.sv b/rtl/mini/top/rcu.sv index b868090f..cc7da73d 100644 --- a/rtl/mini/top/rcu.sv +++ b/rtl/mini/top/rcu.sv @@ -5,74 +5,122 @@ // 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. +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. module rcu ( - input logic ext_clk_i, - input logic aud_clk_i, - input logic ext_rst_n_i, + input logic ext_clk_i, + input logic aud_clk_i, + input logic ext_rst_n_i, `ifdef HAVE_PLL - input logic xtal_clk_i, - input logic clk_bypass_i, - input logic [2:0] pll_cfg_i, + input logic xtal_clk_i, `endif - output logic sys_clk_o, - output logic sys_rst_n_o, - output logic aud_rst_n_o, - output logic sys_clkdiv4_o + pll_ctrl_if.rcu pll_ctrl, + output logic sys_clk_o, + output logic sys_rst_n_o, + output logic aud_rst_n_o, + output logic sys_clkdiv4_o ); -`ifdef HAVE_PLL - logic s_xtal_clk_buf; - logic s_pll_clk_buf; - logic s_pll_clk; - logic s_pll_lock; - logic s_pll_bp, s_pll_bp_q; - logic [3:0] s_pll_N, s_pll_N_q; - logic [7:0] s_pll_M, s_pll_M_q; - logic [1:0] s_pll_OD, s_pll_OD_q; -`endif logic s_ext_clk_buf; - logic s_sys_clk; logic s_aud_clk_buf; + logic s_sys_clk; logic s_ext_rst_n_sync; + logic s_sys_rst_n_sync; logic s_aud_rst_n_sync; - logic [3:0] s_div_cnt_d, s_div_cnt_q; logic s_sys_clkdiv4_d, s_sys_clkdiv4_q; - - // ext buffer tc_clk_buf u_ext_clk_buf ( .clk_i(ext_clk_i), .clk_o(s_ext_clk_buf) ); - // aud buffer tc_clk_buf u_aud_clk_buf ( .clk_i(aud_clk_i), .clk_o(s_aud_clk_buf) ); + rst_sync #( + .STAGE(5) + ) u_ext_rst_sync ( + .clk_i (s_ext_clk_buf), + .rst_n_i(ext_rst_n_i), + .rst_n_o(s_ext_rst_n_sync) + ); + `ifdef HAVE_PLL + logic s_xtal_clk_buf; + logic s_pll_clk; + logic s_pll_clk_buf; + logic s_pll_lock; + logic s_pll_capable; + logic [2:0] s_pll_sel; + logic s_pll_apply; + logic s_select_ext_clk; + tc_clk_buf u_xtal_buf ( .clk_i(xtal_clk_i), .clk_o(s_xtal_clk_buf) ); - + tc_pll u_tc_pll ( + .fref_i (s_xtal_clk_buf), + .rst_n_i (s_ext_rst_n_sync), + .cfg_sel_i (s_pll_sel), + .cfg_apply_i (s_pll_apply), + .pll_capable_o(s_pll_capable), + .pll_lock_o (s_pll_lock), + .pll_clk_o (s_pll_clk) + ); tc_clk_buf u_pll_clk_buf ( .clk_i(s_pll_clk), .clk_o(s_pll_clk_buf) ); - - // select system clock from pll or ext - tc_clk_mux2 u_sys_mux ( + tc_clk_switch2 u_sys_clk_switch ( .clk0_i (s_pll_clk_buf), .clk1_i (s_ext_clk_buf), - .clk_sel_i(clk_bypass_i), + .clk_sel_i(s_select_ext_clk), .clk_o (s_sys_clk) ); + + pll_rcu_controller u_pll_rcu_controller ( + .sys_clk_i (s_sys_clk), + .sys_rst_n_i (s_sys_rst_n_sync), + .ext_clk_i (s_ext_clk_buf), + .ext_rst_n_i (s_ext_rst_n_sync), + .pll_lock_i (s_pll_lock), + .pll_capable_i (s_pll_capable), + .pll_sel_o (s_pll_sel), + .pll_apply_o (s_pll_apply), + .select_ext_clk_o(s_select_ext_clk), + .pll_ctrl (pll_ctrl) + ); `else - assign s_sys_clk = s_ext_clk_buf; + logic s_no_pll_rsp_valid_d, s_no_pll_rsp_valid_q; + + assign s_sys_clk = s_ext_clk_buf; + assign pll_ctrl.req_ready_i = ~s_no_pll_rsp_valid_q; + assign pll_ctrl.rsp_active_sel_i = '0; + assign pll_ctrl.rsp_active_valid_i = 1'b0; + assign pll_ctrl.rsp_safe_clk_i = 1'b1; + assign pll_ctrl.rsp_pll_lock_i = 1'b0; + assign pll_ctrl.rsp_error_i = 2'd1; + assign pll_ctrl.rsp_valid_i = s_no_pll_rsp_valid_q; + assign pll_ctrl.capable_i = 1'b0; + + always_comb begin + s_no_pll_rsp_valid_d = s_no_pll_rsp_valid_q; + if (pll_ctrl.req_valid_o && pll_ctrl.req_ready_i) begin + s_no_pll_rsp_valid_d = 1'b1; + end + if (s_no_pll_rsp_valid_q && pll_ctrl.rsp_ready_o) begin + s_no_pll_rsp_valid_d = 1'b0; + end + end + dffr #(1) u_no_pll_rsp_valid_dffr ( + s_ext_clk_buf, + s_ext_rst_n_sync, + s_no_pll_rsp_valid_d, + s_no_pll_rsp_valid_q + ); `endif tc_clk_buf u_sys_clk_buf ( @@ -80,16 +128,13 @@ module rcu ( .clk_o(sys_clk_o) ); - - // reset sync logic rst_sync #( .STAGE(5) - ) u_ext_rst_sync ( + ) u_sys_rst_sync ( .clk_i (sys_clk_o), .rst_n_i(ext_rst_n_i), - .rst_n_o(s_ext_rst_n_sync) + .rst_n_o(s_sys_rst_n_sync) ); - rst_sync #( .STAGE(5) ) u_aud_rst_sync ( @@ -98,12 +143,7 @@ module rcu ( .rst_n_o(s_aud_rst_n_sync) ); -`ifdef HAVE_PLL - assign sys_rst_n_o = clk_bypass_i ? s_ext_rst_n_sync : s_pll_lock; -`else - assign sys_rst_n_o = s_ext_rst_n_sync; -`endif - + assign sys_rst_n_o = s_sys_rst_n_sync; assign aud_rst_n_o = s_aud_rst_n_sync; assign sys_clkdiv4_o = s_sys_clkdiv4_q; @@ -114,7 +154,6 @@ module rcu ( s_div_cnt_d, s_div_cnt_q ); - assign s_sys_clkdiv4_d = (s_div_cnt_q == 4'd1) ? ~s_sys_clkdiv4_q : s_sys_clkdiv4_q; dffr #(1) u_sys_clkdiv4_dffr ( sys_clk_o, @@ -122,97 +161,226 @@ module rcu ( s_sys_clkdiv4_d, s_sys_clkdiv4_q ); +endmodule + +module pll_rcu_controller #( + parameter int LOCK_TIMEOUT = 1024 +) ( + input logic sys_clk_i, + input logic sys_rst_n_i, + input logic ext_clk_i, + input logic ext_rst_n_i, + input logic pll_lock_i, + input logic pll_capable_i, + output logic [2:0] pll_sel_o, + output logic pll_apply_o, + output logic select_ext_clk_o, + pll_ctrl_if.rcu pll_ctrl +); + localparam logic [2:0] PLL_IDLE = 3'd0; + localparam logic [2:0] PLL_SAFE = 3'd1; + localparam logic [2:0] PLL_APPLY = 3'd2; + localparam logic [2:0] PLL_WAIT_LOCK = 3'd3; + localparam logic [2:0] PLL_SWITCH = 3'd4; + localparam logic [2:0] PLL_RESPOND = 3'd5; + + logic [2:0] s_req_sel; + logic s_req_valid, s_req_ready; + logic [7:0] s_rsp_data; + logic s_rsp_valid, s_rsp_ready; + logic [7:0] s_rsp_sys_data; + logic s_rsp_sys_valid; + logic [2:0] s_state_d, s_state_q; + logic [2:0] s_pll_sel_d, s_pll_sel_q; + logic s_pll_apply_d, s_pll_apply_q; + logic s_select_ext_clk_d, s_select_ext_clk_q; + logic [15:0] s_lock_count_d, s_lock_count_q; + logic [2:0] s_active_sel_d, s_active_sel_q; + logic s_active_valid_d, s_active_valid_q; + logic s_safe_clk_d, s_safe_clk_q; + logic s_lock_d, s_lock_q; + logic [1:0] s_error_d, s_error_q; + logic s_rsp_valid_d, s_rsp_valid_q; + + cdc_2phase #( + .DATA_WIDTH(3) + ) u_pll_request_cdc ( + .src_clk_i (sys_clk_i), + .src_rst_n_i(sys_rst_n_i), + .src_data_i (pll_ctrl.req_sel_o), + .src_valid_i(pll_ctrl.req_valid_o), + .src_ready_o(pll_ctrl.req_ready_i), + .dst_clk_i (ext_clk_i), + .dst_rst_n_i(ext_rst_n_i), + .dst_data_o (s_req_sel), + .dst_valid_o(s_req_valid), + .dst_ready_i(s_req_ready) + ); + cdc_2phase #( + .DATA_WIDTH(8) + ) u_pll_response_cdc ( + .src_clk_i (ext_clk_i), + .src_rst_n_i(ext_rst_n_i), + .src_data_i (s_rsp_data), + .src_valid_i(s_rsp_valid_q), + .src_ready_o(s_rsp_ready), + .dst_clk_i (sys_clk_i), + .dst_rst_n_i(sys_rst_n_i), + .dst_data_o (s_rsp_sys_data), + .dst_valid_o(s_rsp_sys_valid), + .dst_ready_i(pll_ctrl.rsp_ready_o) + ); + + assign pll_ctrl.rsp_active_sel_i = s_rsp_sys_data[2:0]; + assign pll_ctrl.rsp_active_valid_i = s_rsp_sys_data[3]; + assign pll_ctrl.rsp_safe_clk_i = s_rsp_sys_data[4]; + assign pll_ctrl.rsp_pll_lock_i = s_rsp_sys_data[5]; + assign pll_ctrl.rsp_error_i = s_rsp_sys_data[7:6]; + assign pll_ctrl.rsp_valid_i = s_rsp_sys_valid; + assign pll_ctrl.capable_i = pll_capable_i; + assign s_req_ready = s_state_q == PLL_IDLE; + assign s_rsp_data = {s_error_q, s_lock_q, s_safe_clk_q, s_active_valid_q, s_active_sel_q}; + assign pll_sel_o = s_pll_sel_q; + assign pll_apply_o = s_pll_apply_q; + assign select_ext_clk_o = s_select_ext_clk_q; - // 24(bypass) 48(ext clk) 72 96 - // 120 144 168 192 - // 2 <= N <= 4 - // 7 <= M -`ifdef HAVE_PLL always_comb begin - unique case (pll_cfg_i) - 3'b000: begin //bypass 24MHz - s_pll_bp = 1'b1; - s_pll_M = 8'd20; - s_pll_N = 4'd2; - s_pll_OD = 2'd1; + s_state_d = s_state_q; + s_pll_sel_d = s_pll_sel_q; + s_pll_apply_d = (s_state_q == PLL_APPLY) || (s_state_q == PLL_WAIT_LOCK); + s_select_ext_clk_d = s_select_ext_clk_q; + s_lock_count_d = s_lock_count_q; + s_active_sel_d = s_active_sel_q; + s_active_valid_d = s_active_valid_q; + s_safe_clk_d = s_safe_clk_q; + s_lock_d = s_lock_q; + s_error_d = s_error_q; + s_rsp_valid_d = s_rsp_valid_q; + + unique case (s_state_q) + PLL_IDLE: begin + if (s_req_valid) begin + s_pll_sel_d = s_req_sel; + s_select_ext_clk_d = 1'b1; + s_error_d = 2'd0; + s_state_d = PLL_SAFE; + end end - 3'b001: begin //bypass 24MHz - s_pll_bp = 1'b1; - s_pll_M = 8'd20; - s_pll_N = 4'd2; - s_pll_OD = 2'd1; + PLL_SAFE: begin + s_select_ext_clk_d = 1'b1; + s_safe_clk_d = 1'b1; + s_lock_d = 1'b0; + if (pll_capable_i) begin + s_state_d = PLL_APPLY; + end else begin + s_active_valid_d = 1'b0; + s_error_d = 2'd1; + s_state_d = PLL_RESPOND; + end end - 3'b010: begin //3*clk 72MHz - s_pll_bp = 1'b0; - s_pll_M = 8'd24; - s_pll_N = 4'd2; - s_pll_OD = 2'd2; + PLL_APPLY: begin + s_lock_count_d = '0; + s_state_d = PLL_WAIT_LOCK; end - 3'b011: begin //4*clk 96MHz - s_pll_bp = 1'b0; - s_pll_M = 8'd32; - s_pll_N = 4'd2; - s_pll_OD = 2'd2; + PLL_WAIT_LOCK: begin + if (pll_lock_i) begin + s_active_sel_d = s_pll_sel_q; + s_active_valid_d = 1'b1; + s_safe_clk_d = 1'b0; + s_lock_d = 1'b1; + s_error_d = 2'd0; + s_state_d = PLL_SWITCH; + end else if (s_lock_count_q == LOCK_TIMEOUT - 1) begin + s_active_valid_d = 1'b0; + s_safe_clk_d = 1'b1; + s_lock_d = 1'b0; + s_error_d = 2'd2; + s_state_d = PLL_RESPOND; + end else begin + s_lock_count_d = s_lock_count_q + 1'b1; + end end - 3'b100: begin //5*clk 120MHz - s_pll_bp = 1'b0; - s_pll_M = 8'd40; - s_pll_N = 4'd2; - s_pll_OD = 2'd2; + PLL_SWITCH: begin + s_select_ext_clk_d = 1'b0; + s_state_d = PLL_RESPOND; end - 3'b101: begin //6*clk 144MHz - s_pll_bp = 1'b0; - s_pll_M = 8'd48; - s_pll_N = 4'd2; - s_pll_OD = 2'd2; + PLL_RESPOND: begin + s_rsp_valid_d = 1'b1; + if (s_rsp_valid_q && s_rsp_ready) begin + s_rsp_valid_d = 1'b0; + s_state_d = PLL_IDLE; + end end - 3'b110: begin //7*clk 168MHz - s_pll_bp = 1'b0; - s_pll_M = 8'd56; - s_pll_N = 4'd2; - s_pll_OD = 2'd2; - end - 3'b111: begin //8*clk 192MHz - s_pll_bp = 1'b0; - s_pll_M = 8'd64; - s_pll_N = 4'd4; - s_pll_OD = 2'd1; - end - default: begin //bypass - s_pll_bp = 1'b1; - s_pll_M = 8'd20; - s_pll_N = 4'd2; - s_pll_OD = 2'd1; + default: begin + s_state_d = PLL_IDLE; end endcase end - // Register PLL config outputs to break the comb path to PLL macro - always_ff @(posedge s_ext_clk_buf or negedge ext_rst_n_i) begin - if (~ext_rst_n_i) begin - s_pll_bp_q <= 1'b1; - s_pll_M_q <= 8'd20; - s_pll_N_q <= 4'd2; - s_pll_OD_q <= 2'd1; - end else begin - s_pll_bp_q <= s_pll_bp; - s_pll_M_q <= s_pll_M; - s_pll_N_q <= s_pll_N; - s_pll_OD_q <= s_pll_OD; - end - end - - tc_pll u_tc_pll ( - .fref_i (s_xtal_clk_buf), - .rst_n_i (s_ext_rst_n_sync), - .refdiv_i (s_pll_M_q), - .fbdiv_i (), - .postdiv1_i(s_pll_N_q), - .postdiv2_i(s_pll_OD_q), - .bp_i (clk_bypass_i || s_pll_bp_q), - .pll_lock_o(s_pll_lock), - .pll_clk_o (s_pll_clk) + dffrc #(3, PLL_IDLE) u_state_dffrc ( + ext_clk_i, + ext_rst_n_i, + s_state_d, + s_state_q + ); + dffr #(3) u_pll_sel_dffr ( + ext_clk_i, + ext_rst_n_i, + s_pll_sel_d, + s_pll_sel_q + ); + dffr #(1) u_pll_apply_dffr ( + ext_clk_i, + ext_rst_n_i, + s_pll_apply_d, + s_pll_apply_q + ); + dffrc #(1, 1'b1) u_select_ext_clk_dffrc ( + ext_clk_i, + ext_rst_n_i, + s_select_ext_clk_d, + s_select_ext_clk_q + ); + dffr #(16) u_lock_count_dffr ( + ext_clk_i, + ext_rst_n_i, + s_lock_count_d, + s_lock_count_q + ); + dffr #(3) u_active_sel_dffr ( + ext_clk_i, + ext_rst_n_i, + s_active_sel_d, + s_active_sel_q + ); + dffr #(1) u_active_valid_dffr ( + ext_clk_i, + ext_rst_n_i, + s_active_valid_d, + s_active_valid_q + ); + dffrc #(1, 1'b1) u_safe_clk_dffrc ( + ext_clk_i, + ext_rst_n_i, + s_safe_clk_d, + s_safe_clk_q + ); + dffr #(1) u_lock_dffr ( + ext_clk_i, + ext_rst_n_i, + s_lock_d, + s_lock_q + ); + dffr #(2) u_error_dffr ( + ext_clk_i, + ext_rst_n_i, + s_error_d, + s_error_q + ); + dffr #(1) u_rsp_valid_dffr ( + ext_clk_i, + ext_rst_n_i, + s_rsp_valid_d, + s_rsp_valid_q ); -`endif - endmodule diff --git a/rtl/mini/top/retrosoc.sv b/rtl/mini/top/retrosoc.sv index 7916628c..4deb882c 100644 --- a/rtl/mini/top/retrosoc.sv +++ b/rtl/mini/top/retrosoc.sv @@ -18,6 +18,7 @@ module retrosoc ( input logic clk_aud_i, input logic rst_aud_n_i, input logic clkdiv4_i, + pll_ctrl_if.sysctrl pll_ctrl, `ifdef CORE_MDD input logic [`USER_CORESEL_WIDTH-1:0] core_sel_i, `endif @@ -409,6 +410,7 @@ module retrosoc ( .xpi (xpi), .dma_nmi (u_dma_nmi_if), .sysctrl (u_sysctrl_if), + .pll_ctrl (pll_ctrl), .sdram (sdram), .dvp (u_dvp_if), .sdio (u_sdio_if), diff --git a/rtl/mini/top/retrosoc_asic.sv b/rtl/mini/top/retrosoc_asic.sv index 51ecf9d7..18ea996e 100644 --- a/rtl/mini/top/retrosoc_asic.sv +++ b/rtl/mini/top/retrosoc_asic.sv @@ -20,10 +20,6 @@ module retrosoc_asic ( `ifdef HAVE_PLL input xi_i_pad, output xo_o_pad, - inout clk_bypass_i_pad, - inout pll_cfg_0_i_pad, - inout pll_cfg_1_i_pad, - inout pll_cfg_2_i_pad, `endif `ifdef CORE_MDD inout core_sel_0_i_pad, @@ -142,9 +138,7 @@ module retrosoc_asic ( logic s_aud_clk; logic s_sys_clkdiv4; `ifdef HAVE_PLL - logic s_xtal_io; - logic s_clk_bypass; - logic [2:0] s_pll_cfg; + logic s_xtal_io; `endif logic s_sys_clk; logic s_ext_rst_n; @@ -174,6 +168,7 @@ module retrosoc_asic ( uart_if u_uart0_if (); xpi_if u_xpi_if (); sdram_if u_sdram_if (); + pll_ctrl_if u_pll_ctrl_if (); tc_io_tri_pad u_extclk_i_pad (.pad(extclk_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_ext_clk)); @@ -181,10 +176,6 @@ module retrosoc_asic ( tc_io_tri_schmitt_pad u_ext_rst_n_i_pad (.pad(ext_rst_n_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_ext_rst_n)); `ifdef HAVE_PLL tc_io_xtl_pad u_xtal_io_pad (.xi_pad(xi_i_pad), .xo_pad(xo_o_pad), .en(1'b1), .clk(s_xtal_io)); - tc_io_tri_pad u_clk_bypass_i_pad (.pad(clk_bypass_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_clk_bypass)); - tc_io_tri_pad u_pll_cfg_0_i_pad (.pad(pll_cfg_0_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_pll_cfg[0])); - tc_io_tri_pad u_pll_cfg_1_i_pad (.pad(pll_cfg_1_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_pll_cfg[1])); - tc_io_tri_pad u_pll_cfg_2_i_pad (.pad(pll_cfg_2_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_pll_cfg[2])); `endif `ifdef CORE_MDD tc_io_tri_pad u_core_sel_0_i_pad (.pad(core_sel_0_i_pad), .c2p(1'b0), .c2p_en(1'b0), .p2c(s_core_sel[0])); @@ -307,9 +298,8 @@ module retrosoc_asic ( .ext_rst_n_i (s_ext_rst_n), `ifdef HAVE_PLL .xtal_clk_i (s_xtal_io), - .clk_bypass_i (s_clk_bypass), - .pll_cfg_i (s_pll_cfg), `endif + .pll_ctrl (u_pll_ctrl_if), .sys_clk_o (s_sys_clk), .sys_rst_n_o (s_sys_rst_n), .aud_rst_n_o (s_aud_rst_n), @@ -329,6 +319,7 @@ module retrosoc_asic ( .clk_aud_i (s_aud_clk), .rst_aud_n_i(s_aud_rst_n), .clkdiv4_i (s_sys_clkdiv4), + .pll_ctrl (u_pll_ctrl_if), `ifdef CORE_MDD .core_sel_i (s_core_sel), `endif diff --git a/rtl/tech/tc_clk.sv b/rtl/tech/tc_clk.sv index fca85b88..8a5cd86e 100644 --- a/rtl/tech/tc_clk.sv +++ b/rtl/tech/tc_clk.sv @@ -118,6 +118,28 @@ module tc_clk_mux2 ( `endif endmodule +// Dynamic clock switching is enabled only with the behavioral PLL backend. +// Silicon backends keep capability low until this wrapper is replaced by a +// characterized, glitch-free clock-switch cell. +module tc_clk_switch2 ( + input logic clk0_i, + input logic clk1_i, + input logic clk_sel_i, + output logic clk_o +); + +`ifdef PDK_BEHAV + assign clk_o = clk_sel_i ? clk1_i : clk0_i; +`else + tc_clk_mux2 u_tc_clk_mux2 ( + .clk0_i (clk0_i), + .clk1_i (clk1_i), + .clk_sel_i(clk_sel_i), + .clk_o (clk_o) + ); +`endif +endmodule + module tc_clk_xor2 ( input logic clk0_i, input logic clk1_i, diff --git a/rtl/tech/tc_pll.sv b/rtl/tech/tc_pll.sv index e143f9ac..d5146f31 100644 --- a/rtl/tech/tc_pll.sv +++ b/rtl/tech/tc_pll.sv @@ -5,77 +5,119 @@ // 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. +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. - module tc_pll ( - input logic fref_i, - input logic rst_n_i, - input logic [ 7:0] refdiv_i, - input logic [11:0] fbdiv_i, - input logic [ 3:0] postdiv1_i, - input logic [ 1:0] postdiv2_i, - input logic bp_i, - output logic pll_lock_o, - output logic pll_clk_o + input logic fref_i, + input logic rst_n_i, + input logic [2:0] cfg_sel_i, + input logic cfg_apply_i, + output logic pll_capable_o, + output logic pll_lock_o, + output logic pll_clk_o ); `ifdef PDK_BEHAV - assign pll_lock_o = 1'b1; - assign pll_clk_o = fref_i; -`elsif PDK_IHP130 - assign pll_lock_o = 1'b1; - assign pll_clk_o = fref_i; -`elsif PDK_ICS55 -`ifndef HAVE_PLL - assign pll_lock_o = 1'b1; - assign pll_clk_o = fref_i; -`else + localparam logic [2:0] PLL_LOCK_CYCLES = 3'd4; -`endif -`elsif PDK_S110 + logic [2:0] s_cfg_sel_d, s_cfg_sel_q; + logic [2:0] s_lock_count_d, s_lock_count_q; + logic s_lock_d, s_lock_q; + logic s_apply_seen_d, s_apply_seen_q; + logic s_cfg_apply; + logic s_force_lock_fail; + time s_last_ref_edge; + time s_ref_period; -`ifndef HAVE_PLL - assign pll_lock_o = 1'b1; - assign pll_clk_o = fref_i; -`else - `define LOCK_CNT_END 20'h1FFFF + function automatic int pll_multiplier(input logic [2:0] cfg_sel); + case (cfg_sel) + 3'd0: pll_multiplier = 1; + 3'd1: pll_multiplier = 2; + 3'd2: pll_multiplier = 3; + 3'd3: pll_multiplier = 4; + 3'd4: pll_multiplier = 5; + 3'd5: pll_multiplier = 6; + 3'd6: pll_multiplier = 7; + default: pll_multiplier = 8; + endcase + endfunction - logic [19:0] s_lock_cnt_d, s_lock_cnt_q; + initial begin + s_force_lock_fail = $test$plusargs("pll_lock_fail"); + s_last_ref_edge = 0; + s_ref_period = 0; + pll_clk_o = 1'b0; + end - assign pll_lock_o = s_lock_cnt_q == `LOCK_CNT_END; - //lock Time Max 0.5ms(500us, 500*1000ns) - assign s_lock_cnt_d = s_lock_cnt_q + 20'h1; - dffer #(20) u_lock_cnt_dffer ( + always @(posedge fref_i) begin + if (s_last_ref_edge != 0) begin + s_ref_period = $time - s_last_ref_edge; + end + s_last_ref_edge = $time; + end + + always begin + @(posedge fref_i); + wait (pll_lock_o); + while (pll_lock_o) begin + #(s_ref_period / (2 * pll_multiplier(s_cfg_sel_q))); + if (pll_lock_o) begin + pll_clk_o = ~pll_clk_o; + end + end + pll_clk_o = 1'b0; + end + + assign pll_capable_o = 1'b1; + assign pll_lock_o = s_lock_q; + assign s_cfg_apply = cfg_apply_i && !s_apply_seen_q; + assign s_cfg_sel_d = cfg_sel_i; + dffer #(3) u_cfg_sel_dffer ( fref_i, rst_n_i, - s_lock_cnt_q < `LOCK_CNT_END, - s_lock_cnt_d, - s_lock_cnt_q + s_cfg_apply, + s_cfg_sel_d, + s_cfg_sel_q ); - S013PLLFN u0_pll ( - // .A2VDD33 (), - // .A2VSS33 (), - // .AVDD33 (), - // .AVSS33 (), - // .DVDD12 (), - // .DVSS12 (), - .XIN (fref_i), - .CLK_OUT (pll_clk_o), - .N (postdiv1_i), - .M (refdiv_i), - .RESET ('0), - .SLEEP12 ('0), - .OD (postdiv2_i), - .BP (bp_i), - .SELECT (1'b1), - .FS ('0), - .FRAC_N_in('0), - .LKDT () + assign s_apply_seen_d = cfg_apply_i; + dffr #(1) u_apply_seen_dffr ( + fref_i, + rst_n_i, + s_apply_seen_d, + s_apply_seen_q ); -`endif + always_comb begin + s_lock_count_d = s_lock_count_q; + s_lock_d = s_lock_q; + if (s_cfg_apply) begin + s_lock_count_d = '0; + s_lock_d = 1'b0; + end else if (!s_lock_q && !s_force_lock_fail) begin + if (s_lock_count_q == PLL_LOCK_CYCLES - 1'b1) begin + s_lock_d = 1'b1; + end else begin + s_lock_count_d = s_lock_count_q + 1'b1; + end + end + end + dffr #(3) u_lock_count_dffr ( + fref_i, + rst_n_i, + s_lock_count_d, + s_lock_count_q + ); + dffr #(1) u_lock_dffr ( + fref_i, + rst_n_i, + s_lock_d, + s_lock_q + ); +`else + assign pll_capable_o = 1'b0; + assign pll_lock_o = 1'b0; + assign pll_clk_o = fref_i; `endif endmodule diff --git a/sta/opensta/gen2.sdc b/sta/opensta/gen2.sdc index 9479aae4..76ce87d8 100644 --- a/sta/opensta/gen2.sdc +++ b/sta/opensta/gen2.sdc @@ -1,184 +1,32 @@ -# mini gen2 plus -# set_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm +# Mini SoC default external-safe-clock timing mode. +# Dynamic PLL timing modes are enabled only after a PDK backend supplies a +# characterized PLL macro and a glitch-free switch cell. -# unit: MHz -set clk_xtal_freq 24.0 -set clk_ext_freq 72.0 -set clk_aud_freq 18.432 +set clk_ext_freq 72.0 +set clk_aud_freq 18.432 +set clk_ext_period [expr 1000.0 / $clk_ext_freq] +set clk_aud_period [expr 1000.0 / $clk_aud_freq] -set clk_xtal_period [expr 1000.0 / $clk_xtal_freq] -set clk_ext_period [expr 1000.0 / $clk_ext_freq] -set clk_aud_period [expr 1000.0 / $clk_aud_freq] - -set clk_period_factor .2 - -# set_operating_conditions -analysis_type on_chip_variation -library [get_libs {ETSCA_N55_H7BH_DSS_PRCMAX_V1P0_T125.db:ETSCA_N55_H7BH_DSS_PRCMAX_V1P0_T125}] -############################################################################### -# Clock Related Information -############################################################################### create_clock -name clk_ext -period $clk_ext_period [get_ports extclk_i_pad] create_clock -name clk_aud -period $clk_aud_period [get_ports audclk_i_pad] -############################################################################### -# Derived Clock related information -############################################################################### -create_generated_clock -name clk_i2s_mclk_o -source [get_pins \u_rcu.u_aud_clk_buf/clk_o] -divide_by 1 [get_ports gpio_10_io_pad] -set_clock_uncertainty -setup 0.2 [get_clocks clk_i2s_mclk_o] -set_clock_uncertainty -hold 0.1 [get_clocks clk_i2s_mclk_o] -############################################################################### -# Point to Point exceptions -############################################################################### -# group_path -name CLK_u_xtal_io_pad_u_P65_1233_PWE_XC_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {CLK_u_xtal_io_pad_u_P65_1233_PWE_XC}] -# group_path -name CLK_u_xtal_io_pad_u_P65_1233_PWE_XC_reg2out -from [get_clocks {CLK_u_xtal_io_pad_u_P65_1233_PWE_XC}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name CLK_u_extclk_i_pad_u_P65_1233_PBMUX_C_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {clk_ext}] -# group_path -name CLK_u_extclk_i_pad_u_P65_1233_PBMUX_C_reg2out -from [get_clocks {clk_ext}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y}] -# group_path -name CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y_reg2out -from [get_clocks {CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name CLK_sys_clk_buf_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {CLK_sys_clk_buf}] -# group_path -name CLK_sys_clk_buf_reg2out -from [get_clocks {CLK_sys_clk_buf}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name CLK_cust_qspi_spi_clk_o_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {CLK_cust_qspi_spi_clk_o}] -# group_path -name CLK_cust_qspi_spi_clk_o_reg2out -from [get_clocks {CLK_cust_qspi_spi_clk_o}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name CLK_cust_psram_sclk_o_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {CLK_cust_psram_sclk_o}] -# group_path -name CLK_cust_psram_sclk_o_reg2out -from [get_clocks {CLK_cust_psram_sclk_o}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name CLK_cust_spfs_clk_o_in2reg -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_clocks {CLK_cust_spfs_clk_o}] -# group_path -name CLK_cust_spfs_clk_o_reg2out -from [get_clocks {CLK_cust_spfs_clk_o}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# group_path -name all_in2out -from [get_ports {xi_i_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_rx_i_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_miso_i_pad}] -to [get_ports {xo_o_pad extclk_i_pad pll_cfg_0_i_pad pll_cfg_1_i_pad pll_cfg_2_i_pad clk_bypass_i_pad ext_rst_n_i_pad sys_clkdiv4_o_pad uart_tx_o_pad uart_rx_i_pad gpio_0_io_pad gpio_1_io_pad gpio_2_io_pad gpio_3_io_pad gpio_4_io_pad gpio_5_io_pad gpio_6_io_pad gpio_7_io_pad gpio_8_io_pad gpio_9_io_pad gpio_10_io_pad gpio_11_io_pad gpio_12_io_pad gpio_13_io_pad gpio_14_io_pad gpio_15_io_pad irq_pin_i_pad cust_uart_tx_o_pad cust_uart_rx_i_pad cust_pwm_pwm_0_o_pad cust_pwm_pwm_1_o_pad cust_pwm_pwm_2_o_pad cust_pwm_pwm_3_o_pad cust_ps2_ps2_clk_i_pad cust_ps2_ps2_dat_i_pad cust_i2c_scl_io_pad cust_i2c_sda_io_pad cust_qspi_spi_clk_o_pad cust_qspi_spi_csn_0_o_pad cust_qspi_spi_csn_1_o_pad cust_qspi_spi_csn_2_o_pad cust_qspi_spi_csn_3_o_pad cust_qspi_dat_0_io_pad cust_qspi_dat_1_io_pad cust_qspi_dat_2_io_pad cust_qspi_dat_3_io_pad cust_psram_sclk_o_pad cust_psram_ce_o_pad cust_psram_sio0_io_pad cust_psram_sio1_io_pad cust_psram_sio2_io_pad cust_psram_sio3_io_pad cust_spfs_clk_o_pad cust_spfs_cs_o_pad cust_spfs_mosi_o_pad cust_spfs_miso_i_pad}] -# set_case_analysis 1 [get_pins {u_rcu.u_sys_mux.u_MUX2X0P5H7L/S0}] +create_generated_clock -name clk_i2s_mclk_o -source [get_pins \u_rcu.u_aud_clk_buf/clk_o] \ + -divide_by 1 [get_ports gpio_10_io_pad] set_input_transition .1 [all_inputs] set_clock_uncertainty -setup 0.2 [get_clocks clk_ext] -set_clock_uncertainty -hold 0.1 [get_clocks clk_ext] +set_clock_uncertainty -hold 0.1 [get_clocks clk_ext] set_clock_uncertainty -setup 0.2 [get_clocks clk_aud] -set_clock_uncertainty -hold 0.1 [get_clocks clk_aud] +set_clock_uncertainty -hold 0.1 [get_clocks clk_aud] +set_clock_uncertainty -setup 0.2 [get_clocks clk_i2s_mclk_o] +set_clock_uncertainty -hold 0.1 [get_clocks clk_i2s_mclk_o] set_timing_derate -cell_delay -net_delay -late 1 set_timing_derate -net_delay -clock -early 0.95 set_timing_derate -net_delay -data -early 1 -set_timing_derate -net_delay -clock -early 0.95 -set_timing_derate -net_delay -data -early 1 set_timing_derate -cell_delay -clock -early 0.95 set_timing_derate -cell_delay -data -early 1 -# Clock Group -############################################################################### -set_clock_groups -name cgp_async -asynchronous -group [get_clocks clk_ext] -group [get_clocks clk_aud] -############################################################################### -# Input/Output Delay -############################################################################### +set_clock_groups -name cgp_async -asynchronous -group [get_clocks clk_ext] \ + -group [get_clocks clk_aud] -############################################################################### -# Pin drive/load -############################################################################### -# set_load -pin_load 8 [get_ports extclk_i_pad] -# set_load -pin_load 8 [get_ports audclk_i_pad] -# set_load -pin_load 8 [get_ports ext_rst_n_i_pad] -# set_load -pin_load 8 [get_ports gpio_0_io_pad] -# set_load -pin_load 8 [get_ports gpio_1_io_pad] -# set_load -pin_load 8 [get_ports gpio_2_io_pad] -# set_load -pin_load 8 [get_ports gpio_3_io_pad] -# set_load -pin_load 8 [get_ports gpio_4_io_pad] -# set_load -pin_load 8 [get_ports gpio_5_io_pad] -# set_load -pin_load 8 [get_ports gpio_6_io_pad] -# set_load -pin_load 8 [get_ports gpio_7_io_pad] -# set_load -pin_load 8 [get_ports gpio_8_io_pad] -# set_load -pin_load 8 [get_ports gpio_9_io_pad] -# set_load -pin_load 8 [get_ports gpio_10_io_pad] -# set_load -pin_load 8 [get_ports gpio_11_io_pad] -# set_load -pin_load 8 [get_ports gpio_12_io_pad] -# set_load -pin_load 8 [get_ports gpio_13_io_pad] -# set_load -pin_load 8 [get_ports gpio_14_io_pad] -# set_load -pin_load 8 [get_ports gpio_15_io_pad] -# set_load -pin_load 8 [get_ports gpio_16_io_pad] -# set_load -pin_load 8 [get_ports gpio_17_io_pad] -# set_load -pin_load 8 [get_ports gpio_18_io_pad] -# set_load -pin_load 8 [get_ports gpio_19_io_pad] -# set_load -pin_load 8 [get_ports gpio_20_io_pad] -# set_load -pin_load 8 [get_ports gpio_21_io_pad] -# set_load -pin_load 8 [get_ports gpio_22_io_pad] -# set_load -pin_load 8 [get_ports gpio_23_io_pad] -# set_load -pin_load 8 [get_ports gpio_24_io_pad] -# set_load -pin_load 8 [get_ports gpio_25_io_pad] -# set_load -pin_load 8 [get_ports gpio_26_io_pad] -# set_load -pin_load 8 [get_ports gpio_27_io_pad] -# set_load -pin_load 8 [get_ports gpio_28_io_pad] -# set_load -pin_load 8 [get_ports gpio_29_io_pad] -# set_load -pin_load 8 [get_ports gpio_30_io_pad] -# set_load -pin_load 8 [get_ports gpio_31_io_pad] -# set_load -pin_load 8 [get_ports uart0_tx_o_pad] -# set_load -pin_load 8 [get_ports uart0_rx_i_pad] -# set_load -pin_load 8 [get_ports xpi_sck_o_pad] -# set_load -pin_load 8 [get_ports xpi_nss0_o_pad] -# set_load -pin_load 8 [get_ports xpi_nss1_o_pad] -# set_load -pin_load 8 [get_ports xpi_nss2_o_pad] -# set_load -pin_load 8 [get_ports xpi_nss3_o_pad] -# set_load -pin_load 8 [get_ports xpi_dat0_io_pad] -# set_load -pin_load 8 [get_ports xpi_dat1_io_pad] -# set_load -pin_load 8 [get_ports xpi_dat2_io_pad] -# set_load -pin_load 8 [get_ports xpi_dat3_io_pad] -# set_load -pin_load 8 [get_ports sdram_clk_o_pad] -# set_load -pin_load 8 [get_ports sdram_cke_o_pad] -# set_load -pin_load 8 [get_ports sdram_cs_n_o_pad] -# set_load -pin_load 8 [get_ports sdram_ras_n_o_pad] -# set_load -pin_load 8 [get_ports sdram_cas_n_o_pad] -# set_load -pin_load 8 [get_ports sdram_we_n_o_pad] -# set_load -pin_load 8 [get_ports sdram_ba0_o_pad] -# set_load -pin_load 8 [get_ports sdram_ba1_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr0_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr1_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr2_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr3_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr4_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr5_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr6_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr7_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr8_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr9_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr10_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr11_o_pad] -# set_load -pin_load 8 [get_ports sdram_addr12_o_pad] -# set_load -pin_load 8 [get_ports sdram_dqm0_o_pad] -# set_load -pin_load 8 [get_ports sdram_dqm1_o_pad] -# set_load -pin_load 8 [get_ports sdram_dq0_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq1_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq2_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq3_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq4_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq5_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq6_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq7_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq8_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq9_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq10_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq11_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq12_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq13_io_pad] -# set_load -pin_load 8 [get_ports sdram_dq14_io_pad] -############################################################################### -# False Path -############################################################################### set_false_path -from [get_cells \u_rcu.u_ext_rst_sync*] -set_false_path -from [get_cells s_sys_rst_n_reg] set_false_path -from [get_cells \u_rcu.u_aud_rst_sync*] -set_false_path -from [get_cells s_aud_rst_n_reg] - -############################################################################### - -# set_wire_load_mode top -# set_max_fanout 32 [current_design] -# set_max_transition 1.7 [get_clocks {CLK_sys_clk_buf}] -clock_path -rise -# set_max_transition 1.7 [get_clocks {CLK_sys_clk_buf}] -clock_path -fall -# set_max_transition 3.4 [get_clocks {CLK_sys_clk_buf}] -data_path -rise -# set_max_transition 3.4 [get_clocks {CLK_sys_clk_buf}] -data_path -fall -# set_max_transition 7.083333 [get_clocks {CLK_u_xtal_io_pad_u_P65_1233_PWE_XC}] -clock_path -rise -# set_max_transition 7.083333 [get_clocks {CLK_u_xtal_io_pad_u_P65_1233_PWE_XC}] -clock_path -fall -# set_max_transition 14.166667 [get_clocks {CLK_u_xtal_io_pad_u_P65_1233_PWE_XC}] -data_path -rise -# set_max_transition 14.166667 [get_clocks {CLK_u_xtal_io_pad_u_P65_1233_PWE_XC}] -data_path -fall -# set_max_transition 1.7 [get_clocks {clk_ext}] -clock_path -rise -# set_max_transition 1.7 [get_clocks {clk_ext}] -clock_path -fall -# set_max_transition 3.4 [get_clocks {clk_ext}] -data_path -rise -# set_max_transition 3.4 [get_clocks {clk_ext}] -data_path -fall -# set_max_transition 7.083333 [get_clocks {CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y}] -clock_path -rise -# set_max_transition 7.083333 [get_clocks {CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y}] -clock_path -fall -# set_max_transition 14.166667 [get_clocks {CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y}] -data_path -rise -# set_max_transition 14.166667 [get_clocks {CLK_u_rcu_u_pll_clk_buf_u_BUFX0P7H7L_Y}] -data_path -fall -# ############################################################################### -# # POCV Information -# ############################################################################### diff --git a/sta/opensta/retrosoc_pll.sdc b/sta/opensta/retrosoc_pll.sdc index f9aab04c..7fe7fd6c 100644 --- a/sta/opensta/retrosoc_pll.sdc +++ b/sta/opensta/retrosoc_pll.sdc @@ -1,40 +1,10 @@ -#24MHz -set clk_xtal_period 41.67 -#120MHz -set clk_ext_period 8.33 -set clk_period_factor .2 -# clk src -create_clock -name CLK_src_xtal -period $clk_xtal_period xi_i_pad -create_clock -name CLK_src_ext -period $clk_ext_period extclk_i_pad -# clk buf -create_generated_clock -name CLK_xtal_buf -source \u_rcu.u_xtal_buf.i_buf/I -master_clock CLK_src_xtal -divide_by 1 \u_rcu.u_xtal_buf.i_buf/Z -create_generated_clock -name CLK_ext_buf -source \u_rcu.u_ext_clk_buf.i_buf/I -master_clock CLK_src_ext -divide_by 1 \u_rcu.u_ext_clk_buf.i_buf/Z -create_generated_clock -name CLK_pll -source \u_rcu.u_tc_pll.u0_pll/XIN -master_clock CLK_xtal_buf -multiply_by 4 \u_rcu.u_tc_pll.u0_pll/CLK_OUT -create_generated_clock -name CLK_pll_buf -source \u_rcu.u_pll_clk_buf.i_buf/I -master_clock CLK_pll -divide_by 1 \u_rcu.u_pll_clk_buf.i_buf/Z -set_clock_groups -logically_exclusive -group {CLK_pll_buf} -group {CLK_ext_buf} -set_clock_groups -asynchronous -group {CLK_pll_buf} -group {CLK_ext_buf} -# clk mux -create_generated_clock -name CLK_sys_mux_pll -source \u_rcu.u_sys_mux.u_LVT_CKMUX2HDV4/I0 -master_clock CLK_pll_buf -divide_by 1 \u_rcu.u_sys_mux.u_LVT_CKMUX2HDV4/Z -add -create_generated_clock -name CLK_sys_mux_ext -source \u_rcu.u_sys_mux.u_LVT_CKMUX2HDV4/I1 -master_clock CLK_ext_buf -divide_by 1 \u_rcu.u_sys_mux.u_LVT_CKMUX2HDV4/Z -add -create_generated_clock -name CLK_sys_clk_buf -source \u_rcu.u_sys_clk_buf.i_buf/I -master_clock CLK_src_ext -divide_by 1 \u_rcu.u_sys_clk_buf.i_buf/Z -set_clock_groups -physically_exclusive -group {CLK_sys_mux_pll} -group {CLK_sys_mux_ext} -# set bypass mode -set_case_analysis 0 \u_rcu.u_sys_mux.u_LVT_CKMUX2HDV4/S -# when bypass xtal_buf -# set_clock_groups -asynchronous -group {CLK_xtal_buf} -group {CLK_sys_clk_buf} -# ip -create_generated_clock -name CLK_flash_clk_o -source \u_retrosoc.u_spimemio.xfer.flash_clk_reg/Q -master_clock CLK_sys_clk_buf -divide_by 2 flash_clk_o_pad -create_generated_clock -name CLK_cust_qspi_spi_clk_o -source s_cust_qspi_spi_clk_o_reg/Q -master_clock CLK_sys_clk_buf -divide_by 2 cust_qspi_spi_clk_o_pad -create_generated_clock -name CLK_cust_psram_sclk_o -source s_cust_psram_sclk_o_reg/Q -master_clock CLK_sys_clk_buf -divide_by 2 cust_psram_sclk_o_pad -create_generated_clock -name CLK_cust_spfs_clk_o -source s_cust_spfs_clk_o_reg/Q -master_clock CLK_sys_clk_buf -divide_by 2 cust_spfs_clk_o_pad -# async rst -set_false_path -from \u_rcu.s_ext_rst_n_sync_reg -set_false_path -from [get_cells \u_rcu.u_tc_pll.s_lock_cnt_*__reg] -# in/out -# set clk_delay [expr $clk_ext_period * $clk_period_factor] -# set_input_delay $clk_delay -clock clk {req_val reset resp_rdy req_msg[*]} -# set_input_delay $clk_delay -clock xi_i_pad {} -# set_output_delay $clk_delay -clock xi_i_pad [all_outputs] -set_input_transition .1 [all_inputs] -set_clock_uncertainty -setup .1 [all_clocks] -set_clock_uncertainty -hold .1 [all_clocks] \ No newline at end of file +# Dynamic PLL timing template. +# +# This file is intentionally not selected by the default OpenSTA flow. It may +# be enabled only after a PDK backend supplies the concrete PLL and +# glitch-free clock-switch cell pin names. Sign off every selector mode with +# its own generated-clock period (24, 48, 72, 96, 120, 144, 168, 192 MHz), +# and declare the external safe clock and PLL clock physically exclusive. +# +# The current IHP130 and ICS55 wrappers report PLL capability disabled, so +# their valid signoff mode is sta/opensta/gen2.sdc. diff --git a/tests/rtl/pll_ctrl_tb.sv b/tests/rtl/pll_ctrl_tb.sv new file mode 100644 index 00000000..e8a616a2 --- /dev/null +++ b/tests/rtl/pll_ctrl_tb.sv @@ -0,0 +1,170 @@ +`timescale 1ns / 1ps + +module pll_ctrl_tb; + logic ext_clk_i = 1'b0; + logic xtal_clk_i = 1'b0; + logic aud_clk_i = 1'b0; + logic rst_n_i = 1'b0; + logic fault_valid_i = 1'b0; + logic [31:0] fault_addr_i = '0; + logic [ 3:0] fault_wstrb_i = '0; + logic fault_reserved_i = 1'b0; + nmi_if nmi (); + sysctrl_if sysctrl (); + pll_ctrl_if pll_ctrl (); + logic sys_clk_o; + logic sys_rst_n_o; + logic aud_rst_n_o; + logic sys_clkdiv4_o; + logic [31:0] read_data; + time edge_start; + time edge_end; + + always #7 ext_clk_i = ~ext_clk_i; + always #21 xtal_clk_i = ~xtal_clk_i; + always #27 aud_clk_i = ~aud_clk_i; + + rcu u_rcu ( + .ext_clk_i (ext_clk_i), + .aud_clk_i (aud_clk_i), + .ext_rst_n_i (rst_n_i), +`ifdef HAVE_PLL + .xtal_clk_i (xtal_clk_i), +`endif + .pll_ctrl (pll_ctrl), + .sys_clk_o (sys_clk_o), + .sys_rst_n_o (sys_rst_n_o), + .aud_rst_n_o (aud_rst_n_o), + .sys_clkdiv4_o(sys_clkdiv4_o) + ); + + nmi_sysctrl u_sysctrl ( + .clk_i (sys_clk_o), + .rst_n_i (sys_rst_n_o), + .fault_valid_i (fault_valid_i), + .fault_addr_i (fault_addr_i), + .fault_wstrb_i (fault_wstrb_i), + .fault_reserved_i(fault_reserved_i), + .nmi (nmi), + .sysctrl (sysctrl), + .pll_ctrl (pll_ctrl) + ); + + task automatic read_register(input logic [31:0] address, output logic [31:0] data); + begin + @(negedge sys_clk_o); + nmi.addr = address; + nmi.wdata = '0; + nmi.wstrb = '0; + nmi.valid = 1'b1; + while (!nmi.ready) @(posedge sys_clk_o); + data = nmi.rdata; + @(negedge sys_clk_o); + nmi.valid = 1'b0; + while (nmi.ready) @(posedge sys_clk_o); + end + endtask + + task automatic write_register(input logic [31:0] address, input logic [31:0] data); + begin + @(negedge sys_clk_o); + nmi.addr = address; + nmi.wdata = data; + nmi.wstrb = 4'hF; + nmi.valid = 1'b1; + while (!nmi.ready) @(posedge sys_clk_o); + @(negedge sys_clk_o); + nmi.valid = 1'b0; + while (nmi.ready) @(posedge sys_clk_o); + end + endtask + + task automatic wait_for_completion(output logic [31:0] status); + integer index; + logic complete; + begin + status = '0; + complete = 1'b0; + for (index = 0; index < 3000; index = index + 1) begin + if (!complete) begin + read_register(32'h1000_B01C, status); + complete = !status[4]; + end + end + if (!complete) begin + $fatal(1, "pll configuration did not complete"); + end + end + endtask + + initial begin + nmi.valid = 1'b0; + nmi.addr = '0; + nmi.wdata = '0; + nmi.wstrb = '0; + sysctrl.core_sel_i = '0; + #100; + rst_n_i = 1'b1; + repeat (12) @(posedge sys_clk_o); + + read_register(32'h1000_B01C, read_data); +`ifdef HAVE_PLL + if (read_data !== 32'h0000_0500) begin + $fatal(1, "pll reset status is not the external safe clock"); + end +`else + if (read_data !== 32'h0000_0100) begin + $fatal(1, "unsupported pll reset status is not the external safe clock"); + end +`endif + + write_register(32'h1000_B008, 32'd4); + write_register(32'h1000_B00C, 32'd1); + wait_for_completion(read_data); + +`ifdef HAVE_PLL + if ($test$plusargs("pll_lock_fail")) begin + if (read_data !== 32'h0000_05A0) begin + $fatal(1, "pll lock timeout did not keep the external safe clock"); + end + $display("pll controller timeout test passed"); + $finish; + end + + if (read_data !== 32'h0000_060C) begin + $fatal(1, "pll configuration did not select the requested frequency"); + end + repeat (4) @(posedge sys_clk_o); + @(posedge sys_clk_o); + edge_start = $time; + @(posedge sys_clk_o); + edge_end = $time; + if ((edge_end - edge_start) > 9) begin + $fatal(1, "pll behavioral output is slower than 120MHz"); + end + + write_register(32'h1000_B008, 32'd0); + write_register(32'h1000_B00C, 32'd1); + wait_for_completion(read_data); + if (read_data !== 32'h0000_0608) begin + $fatal(1, "pll did not select the 24MHz profile"); + end + repeat (4) @(posedge sys_clk_o); + @(posedge sys_clk_o); + edge_start = $time; + @(posedge sys_clk_o); + edge_end = $time; + if ((edge_end - edge_start) < 35) begin + $fatal(1, "pll behavioral output is faster than the 24MHz profile"); + end + + $display("pll controller dynamic configuration test passed"); +`else + if (read_data !== 32'h0000_0160) begin + $fatal(1, "unsupported pll backend did not report the safe-clock error"); + end + $display("pll controller capability gate test passed"); +`endif + $finish; + end +endmodule diff --git a/tests/rtl/sysctrl_fault_tb.sv b/tests/rtl/sysctrl_fault_tb.sv index 53bafa6d..40179903 100644 --- a/tests/rtl/sysctrl_fault_tb.sv +++ b/tests/rtl/sysctrl_fault_tb.sv @@ -9,6 +9,7 @@ module sysctrl_fault_tb; logic fault_reserved_i = 1'b0; nmi_if nmi (); sysctrl_if sysctrl (); + pll_ctrl_if pll_ctrl (); always #5 clk_i = ~clk_i; @@ -20,7 +21,8 @@ module sysctrl_fault_tb; .fault_wstrb_i (fault_wstrb_i), .fault_reserved_i(fault_reserved_i), .nmi (nmi), - .sysctrl (sysctrl) + .sysctrl (sysctrl), + .pll_ctrl (pll_ctrl) ); task automatic read_register(input logic [31:0] address, output logic [31:0] data); @@ -54,11 +56,19 @@ module sysctrl_fault_tb; logic [31:0] read_data; initial begin - nmi.valid = 1'b0; - nmi.addr = '0; - nmi.wdata = '0; - nmi.wstrb = '0; - sysctrl.core_sel_i = '0; + nmi.valid = 1'b0; + nmi.addr = '0; + nmi.wdata = '0; + nmi.wstrb = '0; + sysctrl.core_sel_i = '0; + pll_ctrl.req_ready_i = 1'b1; + pll_ctrl.rsp_active_sel_i = '0; + pll_ctrl.rsp_active_valid_i = 1'b0; + pll_ctrl.rsp_safe_clk_i = 1'b1; + pll_ctrl.rsp_pll_lock_i = 1'b0; + pll_ctrl.rsp_error_i = '0; + pll_ctrl.rsp_valid_i = 1'b0; + pll_ctrl.capable_i = 1'b0; repeat (2) @(posedge clk_i); rst_n_i = 1'b1; diff --git a/tests/test_memory_map.py b/tests/test_memory_map.py index 9d34d778..9fd4a295 100644 --- a/tests/test_memory_map.py +++ b/tests/test_memory_map.py @@ -49,6 +49,10 @@ def test_generated_artifacts_share_the_capacity_baseline(tmp_path: Path) -> None assert "RS_SOC_NMI_SDIO_BASE" not in header assert "RS_SOC_OPIPSRAM_BASE" not in header assert "RS_SOC_HAS_SRAM 1U" in header + assert "SOC_SYSCTRL_PLL_CFG_OFFSET 32'h00000008" in rtl + assert "SOC_SYSCTRL_PLL_STATUS_OFFSET 32'h0000001C" in rtl + assert "RS_SOC_SYSCTRL_PLL_CFG_OFFSET UINT32_C(0x00000008)" in header + assert "RS_SOC_SYSCTRL_PLL_STATUS_OFFSET UINT32_C(0x0000001C)" in header assert "PSRAM (wxa!ri) : ORIGIN = 0x40000000, LENGTH = 0x00800000" in linker @@ -151,6 +155,7 @@ def test_sysctrl_fault_registers_record_and_clear_pending(tmp_path: Path) -> Non f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}", str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_if.sv"), str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"), + str(ROOT / "rtl/ip/native/peripheral/pll_ctrl_if.sv"), str(ROOT / "rtl/ip/native/peripheral/sysctrl.sv"), str(ROOT / "tests/rtl/sysctrl_fault_tb.sv"), "", @@ -179,6 +184,98 @@ def test_sysctrl_fault_registers_record_and_clear_pending(tmp_path: Path) -> Non assert "sysctrl fault registers 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") + if iverilog is None or vvp is None: + return + generate(tmp_path) + source_list = tmp_path / "pll_ctrl.fl" + source_list.write_text( + "\n".join( + [ + "+define+SV_ASSRT_DISABLE", + "+define+PDK_BEHAV", + "+define+HAVE_PLL", + f"+incdir+{tmp_path / 'rtl'}", + f"+incdir+{ROOT / 'rtl/mini/top'}", + f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}", + str(ROOT / "rtl/managed/clusterip/common/rtl/interface/nmi_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/managed/clusterip/common/rtl/cdc/cdc_2phase.sv"), + str(ROOT / "rtl/managed/clusterip/common/rtl/clkrst/rst_sync.sv"), + str(ROOT / "rtl/ip/native/peripheral/pll_ctrl_if.sv"), + str(ROOT / "rtl/ip/native/peripheral/sysctrl.sv"), + str(ROOT / "rtl/tech/tc_clk.sv"), + str(ROOT / "rtl/tech/tc_pll.sv"), + str(ROOT / "rtl/mini/top/rcu.sv"), + str(ROOT / "tests/rtl/pll_ctrl_tb.sv"), + "", + ] + ), + encoding="utf-8", + ) + converted = tmp_path / "pll_ctrl_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 / "pll_ctrl_tb" + subprocess.run( + [iverilog, "-g2012", "-s", "pll_ctrl_tb", "-o", str(simulation), str(converted)], + check=True, + ) + result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True) + assert "pll controller dynamic configuration test passed" in result.stdout + result = subprocess.run( + [vvp, str(simulation), "+pll_lock_fail"], text=True, capture_output=True, check=True + ) + assert "pll controller timeout test passed" in result.stdout + + unsupported_list = tmp_path / "pll_unsupported.fl" + unsupported_list.write_text( + source_list.read_text(encoding="utf-8").replace("+define+HAVE_PLL\n", ""), + encoding="utf-8", + ) + unsupported_converted = tmp_path / "pll_unsupported_tb.v" + subprocess.run( + [ + sys.executable, + str(ROOT / "rtl/mini/script/convt_sv2v.py"), + "-f", + str(unsupported_list), + "--output", + str(unsupported_converted), + ], + check=True, + ) + unsupported_simulation = tmp_path / "pll_unsupported_tb" + subprocess.run( + [ + iverilog, + "-g2012", + "-s", + "pll_ctrl_tb", + "-o", + str(unsupported_simulation), + str(unsupported_converted), + ], + check=True, + ) + result = subprocess.run( + [vvp, str(unsupported_simulation)], text=True, capture_output=True, check=True + ) + assert "pll controller capability gate test passed" in result.stdout + + def test_sysctrl_does_not_expose_unused_i2c_or_qspi_select_registers() -> None: rtl = (ROOT / "rtl/ip/native/peripheral/sysctrl.sv").read_text(encoding="utf-8") header = (ROOT / "crt/include/retrosoc/core/soc.h").read_text(encoding="utf-8")