mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- 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.
438 lines
14 KiB
Systemverilog
438 lines
14 KiB
Systemverilog
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
|
// retroSoC is licensed under Mulan PSL v2.
|
|
// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
// You may obtain a copy of Mulan PSL v2 at:
|
|
// http://license.coscl.org.cn/MulanPSL2
|
|
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
// See the Mulan PSL v2 for more details.
|
|
|
|
// addr range: [31:28]: 4'h1(reg), 4'h4(psram), 4'h5(spisd)
|
|
`include "mmap_define.svh"
|
|
|
|
module ip_nmi_wrapper (
|
|
// verilog_format: off
|
|
input logic clk_i,
|
|
input logic rst_n_i,
|
|
input logic clk_aud_i,
|
|
input logic rst_aud_n_i,
|
|
// natv if
|
|
nmi_if.slave nmi,
|
|
gpio_if.dut gpio,
|
|
uart_if.dut uart,
|
|
psram_if.dut psram,
|
|
spi_if.dut spisd,
|
|
i2c_if.dut i2c0,
|
|
i2s_if.dut i2s,
|
|
onewire_if.dut onewire,
|
|
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,
|
|
opipsram_if.dut opipsram,
|
|
i2c_if.dut i2c1,
|
|
input logic fault_valid_i,
|
|
input logic [31:0] fault_addr_i,
|
|
input logic [3:0] fault_wstrb_i,
|
|
input logic fault_reserved_i,
|
|
// irq
|
|
output logic [9:0] irq_o
|
|
// verilog_format: on
|
|
);
|
|
|
|
// bus interface
|
|
nmi_if u_uart_nmi_if ();
|
|
nmi_if u_gpio_nmi_if ();
|
|
nmi_if u_tim0_nmi_if ();
|
|
nmi_if u_tim1_nmi_if ();
|
|
nmi_if u_psram_nmi_if ();
|
|
nmi_if u_spisd_nmi_if ();
|
|
nmi_if u_i2c0_nmi_if ();
|
|
nmi_if u_i2s_nmi_if ();
|
|
nmi_if u_onewire_nmi_if ();
|
|
nmi_if u_xpi_nmi_if ();
|
|
nmi_if u_dma_nmi_if ();
|
|
nmi_if u_sysctrl_nmi_if ();
|
|
nmi_if u_clint_nmi_if ();
|
|
nmi_if u_sdram_nmi_if ();
|
|
nmi_if u_dvp_nmi_if ();
|
|
nmi_if u_sdio_nmi_if ();
|
|
nmi_if u_opipsram_nmi_if ();
|
|
nmi_if u_i2c1_nmi_if ();
|
|
|
|
// ip interface
|
|
simp_clint_if u_clint_if ();
|
|
dma_hw_trg_if u_dma_hw_trg_if ();
|
|
|
|
// cfg or mem
|
|
logic s_psram_cfg_sel, s_psram_mem_sel;
|
|
logic s_opipsram_cfg_sel, s_opipsram_mem_sel;
|
|
logic s_spisd_cfg_sel;
|
|
logic s_sdram_cfg_sel, s_sdram_mem_sel;
|
|
logic s_xpi_cfg_sel, s_xpi_mem_sel;
|
|
// dma
|
|
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
|
|
logic s_dma_xpi_tx_stall, s_dma_xpi_rx_stall;
|
|
logic s_dma_xfer_done;
|
|
// irq
|
|
logic s_tim0_irq, s_tim1_irq;
|
|
|
|
|
|
// dma channel
|
|
assign u_dma_hw_trg_if.i2s_tx_proc = ~s_dma_i2s_tx_stall;
|
|
assign u_dma_hw_trg_if.i2s_rx_proc = ~s_dma_i2s_rx_stall;
|
|
assign u_dma_hw_trg_if.qspi_tx_proc = ~s_dma_xpi_tx_stall;
|
|
assign u_dma_hw_trg_if.qspi_rx_proc = ~s_dma_xpi_rx_stall;
|
|
// gpio
|
|
assign u_gpio_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_GPIO(nmi.addr);
|
|
assign u_gpio_nmi_if.addr = nmi.addr;
|
|
assign u_gpio_nmi_if.wdata = nmi.wdata;
|
|
assign u_gpio_nmi_if.wstrb = nmi.wstrb;
|
|
// uart
|
|
assign u_uart_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_UART0(nmi.addr);
|
|
assign u_uart_nmi_if.addr = nmi.addr;
|
|
assign u_uart_nmi_if.wdata = nmi.wdata;
|
|
assign u_uart_nmi_if.wstrb = nmi.wstrb;
|
|
// tim0
|
|
assign u_tim0_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_TIM0(nmi.addr);
|
|
assign u_tim0_nmi_if.addr = nmi.addr;
|
|
assign u_tim0_nmi_if.wdata = nmi.wdata;
|
|
assign u_tim0_nmi_if.wstrb = nmi.wstrb;
|
|
// tim1
|
|
assign u_tim1_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_TIM1(nmi.addr);
|
|
assign u_tim1_nmi_if.addr = nmi.addr;
|
|
assign u_tim1_nmi_if.wdata = nmi.wdata;
|
|
assign u_tim1_nmi_if.wstrb = nmi.wstrb;
|
|
// psram
|
|
assign s_psram_cfg_sel = `SOC_ADDR_IS_NMI_PSRAM(nmi.addr);
|
|
assign s_psram_mem_sel = `SOC_ADDR_IS_PSRAM(nmi.addr);
|
|
assign u_psram_nmi_if.valid = nmi.valid && (s_psram_mem_sel || s_psram_cfg_sel);
|
|
assign u_psram_nmi_if.addr = nmi.addr;
|
|
assign u_psram_nmi_if.wdata = nmi.wdata;
|
|
assign u_psram_nmi_if.wstrb = nmi.wstrb;
|
|
// spisd
|
|
assign s_spisd_cfg_sel = `SOC_ADDR_IS_NMI_SPISD(nmi.addr);
|
|
assign u_spisd_nmi_if.valid = nmi.valid && (`SOC_ADDR_IS_SPISD(nmi.addr) || s_spisd_cfg_sel);
|
|
assign u_spisd_nmi_if.addr = nmi.addr;
|
|
assign u_spisd_nmi_if.wdata = nmi.wdata;
|
|
assign u_spisd_nmi_if.wstrb = nmi.wstrb;
|
|
// i2c0
|
|
assign u_i2c0_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_I2C0(nmi.addr);
|
|
assign u_i2c0_nmi_if.addr = nmi.addr;
|
|
assign u_i2c0_nmi_if.wdata = nmi.wdata;
|
|
assign u_i2c0_nmi_if.wstrb = nmi.wstrb;
|
|
// i2s
|
|
assign u_i2s_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_I2S(nmi.addr);
|
|
assign u_i2s_nmi_if.addr = nmi.addr;
|
|
assign u_i2s_nmi_if.wdata = nmi.wdata;
|
|
assign u_i2s_nmi_if.wstrb = nmi.wstrb;
|
|
// onewire
|
|
assign u_onewire_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_ONEWIRE(nmi.addr);
|
|
assign u_onewire_nmi_if.addr = nmi.addr;
|
|
assign u_onewire_nmi_if.wdata = nmi.wdata;
|
|
assign u_onewire_nmi_if.wstrb = nmi.wstrb;
|
|
// xpi
|
|
assign s_xpi_cfg_sel = `SOC_ADDR_IS_NMI_XPI(nmi.addr);
|
|
assign s_xpi_mem_sel = `SOC_ADDR_IS_FLASH(nmi.addr) || `SOC_ADDR_IS_XPI(nmi.addr);
|
|
assign u_xpi_nmi_if.valid = nmi.valid && (s_xpi_cfg_sel || s_xpi_mem_sel);
|
|
assign u_xpi_nmi_if.addr = nmi.addr;
|
|
assign u_xpi_nmi_if.wdata = nmi.wdata;
|
|
assign u_xpi_nmi_if.wstrb = nmi.wstrb;
|
|
// dma
|
|
assign u_dma_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_DMA(nmi.addr);
|
|
assign u_dma_nmi_if.addr = nmi.addr;
|
|
assign u_dma_nmi_if.wdata = nmi.wdata;
|
|
assign u_dma_nmi_if.wstrb = nmi.wstrb;
|
|
// sysctrl
|
|
assign u_sysctrl_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_SYSCTRL(nmi.addr);
|
|
assign u_sysctrl_nmi_if.addr = nmi.addr;
|
|
assign u_sysctrl_nmi_if.wdata = nmi.wdata;
|
|
assign u_sysctrl_nmi_if.wstrb = nmi.wstrb;
|
|
// clint
|
|
assign u_clint_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_CLINT(nmi.addr);
|
|
assign u_clint_nmi_if.addr = nmi.addr;
|
|
assign u_clint_nmi_if.wdata = nmi.wdata;
|
|
assign u_clint_nmi_if.wstrb = nmi.wstrb;
|
|
// sdram
|
|
assign s_sdram_cfg_sel = `SOC_ADDR_IS_NMI_SDRAM(nmi.addr);
|
|
assign s_sdram_mem_sel = `SOC_ADDR_IS_SDRAM(nmi.addr);
|
|
assign u_sdram_nmi_if.valid = nmi.valid && (s_sdram_cfg_sel || s_sdram_mem_sel);
|
|
assign u_sdram_nmi_if.addr = nmi.addr;
|
|
assign u_sdram_nmi_if.wdata = nmi.wdata;
|
|
assign u_sdram_nmi_if.wstrb = nmi.wstrb;
|
|
// dvp
|
|
assign u_dvp_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_DVP(nmi.addr);
|
|
assign u_dvp_nmi_if.addr = nmi.addr;
|
|
assign u_dvp_nmi_if.wdata = nmi.wdata;
|
|
assign u_dvp_nmi_if.wstrb = nmi.wstrb;
|
|
// sdio
|
|
assign u_sdio_nmi_if.valid = 1'b0;
|
|
assign u_sdio_nmi_if.addr = nmi.addr;
|
|
assign u_sdio_nmi_if.wdata = nmi.wdata;
|
|
assign u_sdio_nmi_if.wstrb = nmi.wstrb;
|
|
// opipsram
|
|
assign s_opipsram_cfg_sel = 1'b0;
|
|
assign s_opipsram_mem_sel = 1'b0;
|
|
assign u_opipsram_nmi_if.valid = 1'b0;
|
|
assign u_opipsram_nmi_if.addr = nmi.addr;
|
|
assign u_opipsram_nmi_if.wdata = nmi.wdata;
|
|
assign u_opipsram_nmi_if.wstrb = nmi.wstrb;
|
|
// i2c1
|
|
assign u_i2c1_nmi_if.valid = nmi.valid && `SOC_ADDR_IS_NMI_I2C1(nmi.addr);
|
|
assign u_i2c1_nmi_if.addr = nmi.addr;
|
|
assign u_i2c1_nmi_if.wdata = nmi.wdata;
|
|
assign u_i2c1_nmi_if.wstrb = nmi.wstrb;
|
|
|
|
// verilog_format: off
|
|
// Registered one-hot slave select for response mux (breaks comb fanin)
|
|
logic [17:0] s_slv_sel_d, s_slv_sel_q;
|
|
assign s_slv_sel_d = { u_i2c1_nmi_if.valid,
|
|
u_opipsram_nmi_if.valid,
|
|
u_sdio_nmi_if.valid,
|
|
u_dvp_nmi_if.valid,
|
|
u_sdram_nmi_if.valid,
|
|
u_clint_nmi_if.valid,
|
|
u_sysctrl_nmi_if.valid,
|
|
u_dma_nmi_if.valid,
|
|
u_xpi_nmi_if.valid,
|
|
u_onewire_nmi_if.valid,
|
|
u_i2s_nmi_if.valid,
|
|
u_i2c0_nmi_if.valid,
|
|
u_spisd_nmi_if.valid,
|
|
u_psram_nmi_if.valid,
|
|
u_tim1_nmi_if.valid,
|
|
u_tim0_nmi_if.valid,
|
|
u_gpio_nmi_if.valid,
|
|
u_uart_nmi_if.valid };
|
|
dffr #(18) u_slv_sel_dffr (
|
|
clk_i,
|
|
rst_n_i,
|
|
s_slv_sel_d,
|
|
s_slv_sel_q
|
|
);
|
|
|
|
// Collect per-slave ready signals into a vector
|
|
logic [17:0] s_slv_ready;
|
|
assign s_slv_ready = { u_i2c1_nmi_if.ready,
|
|
u_opipsram_nmi_if.ready,
|
|
u_sdio_nmi_if.ready,
|
|
u_dvp_nmi_if.ready,
|
|
u_sdram_nmi_if.ready,
|
|
u_clint_nmi_if.ready,
|
|
u_sysctrl_nmi_if.ready,
|
|
u_dma_nmi_if.ready,
|
|
u_xpi_nmi_if.ready,
|
|
u_onewire_nmi_if.ready,
|
|
u_i2s_nmi_if.ready,
|
|
u_i2c0_nmi_if.ready,
|
|
u_spisd_nmi_if.ready,
|
|
u_psram_nmi_if.ready,
|
|
u_tim1_nmi_if.ready,
|
|
u_tim0_nmi_if.ready,
|
|
u_gpio_nmi_if.ready,
|
|
u_uart_nmi_if.ready };
|
|
|
|
assign nmi.ready = |(s_slv_sel_q & s_slv_ready);
|
|
|
|
// Registered select mux for rdata (reduces fanin from 18 to a clean one-hot mux)
|
|
logic [31:0] s_slv_rdata [0:17];
|
|
assign s_slv_rdata[0] = u_uart_nmi_if.rdata;
|
|
assign s_slv_rdata[1] = u_gpio_nmi_if.rdata;
|
|
assign s_slv_rdata[2] = u_tim0_nmi_if.rdata;
|
|
assign s_slv_rdata[3] = u_tim1_nmi_if.rdata;
|
|
assign s_slv_rdata[4] = u_psram_nmi_if.rdata;
|
|
assign s_slv_rdata[5] = u_spisd_nmi_if.rdata;
|
|
assign s_slv_rdata[6] = u_i2c0_nmi_if.rdata;
|
|
assign s_slv_rdata[7] = u_i2s_nmi_if.rdata;
|
|
assign s_slv_rdata[8] = u_onewire_nmi_if.rdata;
|
|
assign s_slv_rdata[9] = u_xpi_nmi_if.rdata;
|
|
assign s_slv_rdata[10] = u_dma_nmi_if.rdata;
|
|
assign s_slv_rdata[11] = u_sysctrl_nmi_if.rdata;
|
|
assign s_slv_rdata[12] = u_clint_nmi_if.rdata;
|
|
assign s_slv_rdata[13] = u_sdram_nmi_if.rdata;
|
|
assign s_slv_rdata[14] = u_dvp_nmi_if.rdata;
|
|
assign s_slv_rdata[15] = u_sdio_nmi_if.rdata;
|
|
assign s_slv_rdata[16] = u_opipsram_nmi_if.rdata;
|
|
assign s_slv_rdata[17] = u_i2c1_nmi_if.rdata;
|
|
|
|
// One-hot mux using registered slave select
|
|
always_comb begin
|
|
nmi.rdata = '0;
|
|
for (int i = 0; i < 18; i++) begin
|
|
if (s_slv_sel_q[i]) nmi.rdata = nmi.rdata | s_slv_rdata[i];
|
|
end
|
|
end
|
|
// verilog_format: on
|
|
|
|
// irq
|
|
assign irq_o[0] = u_clint_if.sfr_irq_o;
|
|
assign irq_o[1] = u_clint_if.tmr_irq_o;
|
|
assign irq_o[2] = uart.irq_o;
|
|
assign irq_o[3] = s_tim0_irq;
|
|
assign irq_o[4] = s_tim1_irq;
|
|
assign irq_o[5] = psram.irq_o;
|
|
assign irq_o[6] = spisd.irq_o;
|
|
assign irq_o[7] = i2c0.irq_o;
|
|
assign irq_o[8] = i2s.irq_o;
|
|
assign irq_o[9] = xpi.irq_o;
|
|
|
|
|
|
nmi_gpio u_nmi_gpio (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_gpio_nmi_if),
|
|
.gpio (gpio)
|
|
);
|
|
|
|
|
|
nmi_uart u_nmi_uart (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_uart_nmi_if),
|
|
.uart (uart)
|
|
);
|
|
|
|
|
|
nmi_timer u_nmi_timer0 (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_tim0_nmi_if),
|
|
.irq_o (s_tim0_irq)
|
|
);
|
|
|
|
|
|
nmi_timer u_nmi_timer1 (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_tim1_nmi_if),
|
|
.irq_o (s_tim1_irq)
|
|
);
|
|
|
|
|
|
nmi_psram u_nmi_psram (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_psram_nmi_if),
|
|
.psram (psram)
|
|
);
|
|
|
|
|
|
nmi_spisd u_nmi_spisd (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_spisd_nmi_if),
|
|
.spi (spisd)
|
|
);
|
|
|
|
|
|
nmi_i2c u_nmi_i2c0 (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_i2c0_nmi_if),
|
|
.i2c (i2c0)
|
|
);
|
|
|
|
|
|
nmi_i2s u_nmi_i2s (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.clk_aud_i (clk_aud_i),
|
|
.rst_aud_n_i (rst_aud_n_i),
|
|
.dma_tx_stall_o(s_dma_i2s_tx_stall),
|
|
.dma_rx_stall_o(s_dma_i2s_rx_stall),
|
|
.nmi (u_i2s_nmi_if),
|
|
.i2s (i2s)
|
|
);
|
|
|
|
|
|
nmi_onewire u_nmi_onewire (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_onewire_nmi_if),
|
|
.onewire(onewire)
|
|
);
|
|
|
|
nmi_xpi u_nmi_xpi (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.dma_xfer_done_i(s_dma_xfer_done),
|
|
.dma_tx_stall_o (s_dma_xpi_tx_stall),
|
|
.dma_rx_stall_o (s_dma_xpi_rx_stall),
|
|
.nmi (u_xpi_nmi_if),
|
|
.xpi (xpi)
|
|
);
|
|
|
|
nmi_dma u_nmi_dma (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.dma_xfer_done_o(s_dma_xfer_done),
|
|
.hw_trg (u_dma_hw_trg_if),
|
|
.nmi (u_dma_nmi_if),
|
|
.nmi_dma (dma_nmi)
|
|
);
|
|
|
|
nmi_sysctrl u_nmi_sysctrl (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.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 (u_sysctrl_nmi_if),
|
|
.sysctrl (sysctrl),
|
|
.pll_ctrl (pll_ctrl)
|
|
);
|
|
|
|
nmi_clint u_nmi_clint (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_clint_nmi_if),
|
|
.clint (u_clint_if)
|
|
);
|
|
|
|
|
|
nmi_sdram u_nmi_sdram (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_sdram_nmi_if),
|
|
.sdram (sdram)
|
|
);
|
|
|
|
|
|
nmi_dvp u_nmi_dvp (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_dvp_nmi_if),
|
|
.dvp (dvp)
|
|
);
|
|
|
|
|
|
nmi_sdio u_nmi_sdio (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_sdio_nmi_if),
|
|
.sdio (sdio)
|
|
);
|
|
|
|
|
|
nmi_opipsram u_nmi_opipsram (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_opipsram_nmi_if),
|
|
.psram (opipsram)
|
|
);
|
|
|
|
|
|
nmi_i2c u_nmi_i2c1 (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.nmi (u_i2c1_nmi_if),
|
|
.i2c (i2c1)
|
|
);
|
|
|
|
endmodule
|