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.
This commit is contained in:
maksyuki committed 2026-07-20 22:12:17 +08:00
1 parent f5559ce784
commit fc898bc4ab
28 files changed
+1066 -431

No files matched your search

+12 -1
View File
@@ -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
--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
-2
View File
@@ -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)
+3
View File
@@ -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)
+34
View File
@@ -0,0 +1,34 @@
#ifndef RETROSOC_HAL_CLOCK_H
#define RETROSOC_HAL_CLOCK_H
#include <stdbool.h>
#include <stdint.h>
#include <retrosoc/core/status.h>
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
+79
View File
@@ -0,0 +1,79 @@
#include <stddef.h>
#include <retrosoc/core/soc.h>
#include <retrosoc/hal/clock.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
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;
}
+2
View File
@@ -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
+34
View File
@@ -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
`<retrosoc/hal/clock.h>`; 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.
-4
View File
@@ -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),
+52
View File
@@ -0,0 +1,52 @@
// 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 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
+137 -1
View File
@@ -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;
@@ -65,6 +81,9 @@ module nmi_sysctrl (
assign nmi.rdata = s_nmi_rdata_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;
dffr #(`USER_CORESEL_WIDTH) u_sysctrl_coresel_dffr (
@@ -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
@@ -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",
"",
+1 -33
View File
@@ -27,10 +27,6 @@ module retrosoc_tb;
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;
`endif
reg [ 4:0] r_core_sel;
wire [ 4:0] s_core_sel;
@@ -91,10 +87,6 @@ module retrosoc_tb;
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_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
@@ -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;
@@ -46,7 +45,6 @@ module retrosoc_top (
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;
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]),
+1
View File
@@ -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
+1 -2
View File
@@ -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)
+1
View File
@@ -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 \
+1 -2
View File
@@ -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
+3 -1
View File
@@ -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 (
+281 -113
View File
@@ -5,7 +5,7 @@
// 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 (
@@ -14,65 +14,113 @@ module rcu (
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,
`endif
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
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
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;
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_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
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;
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_APPLY: begin
s_lock_count_d = '0;
s_state_d = PLL_WAIT_LOCK;
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_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
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;
PLL_SWITCH: begin
s_select_ext_clk_d = 1'b0;
s_state_d = PLL_RESPOND;
end
default: begin //bypass
s_pll_bp = 1'b1;
s_pll_M = 8'd20;
s_pll_N = 4'd2;
s_pll_OD = 2'd1;
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
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
+2
View File
@@ -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),
+3 -12
View File
@@ -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,
@@ -143,8 +139,6 @@ module retrosoc_asic (
logic s_sys_clkdiv4;
`ifdef HAVE_PLL
logic s_xtal_io;
logic s_clk_bypass;
logic [2:0] s_pll_cfg;
`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
+22
View File
@@ -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,
+94 -52
View File
@@ -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,
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
+9 -161
View File
@@ -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_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 -setup 0.2 [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
# ###############################################################################
+10 -40
View File
@@ -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]
# 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.
+170
View File
@@ -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
+11 -1
View File
@@ -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);
@@ -59,6 +61,14 @@ module sysctrl_fault_tb;
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;
+97
View File
@@ -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")