blob: e1068122e9914bb79eeb4c01944d086834273a37 [file] [log] [blame]
// Copyright 2023 Google LLC
// Copyright lowRISC contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
module chip_sim_tb (
// Clock and Reset
input clk_i,
input rst_ni
);
logic [31:0] cio_gpio_p2d, cio_gpio_d2p, cio_gpio_en_d2p;
logic [31:0] cio_gpio_pull_en, cio_gpio_pull_select;
logic cio_uart_rx_p2d, cio_uart_tx_d2p, cio_uart_tx_en_d2p;
logic cio_smc_uart_rx_p2d, cio_smc_uart_tx_d2p;
logic cio_spi_device_sck_p2d, cio_spi_device_csb_p2d;
logic cio_spi_device_sdi_p2d;
logic cio_spi_device_sdo_d2p, cio_spi_device_sdo_en_d2p;
logic cio_usbdev_sense_p2d;
logic cio_usbdev_se0_d2p;
logic cio_usbdev_dp_pullup_d2p;
logic cio_usbdev_dn_pullup_d2p;
logic cio_usbdev_rx_enable_d2p;
logic cio_usbdev_tx_use_d_se0_d2p;
logic cio_usbdev_d_p2d, cio_usbdev_d_d2p, cio_usbdev_d_en_d2p;
logic cio_usbdev_dp_p2d, cio_usbdev_dp_d2p, cio_usbdev_dp_en_d2p;
logic cio_usbdev_dn_p2d, cio_usbdev_dn_d2p, cio_usbdev_dn_en_d2p;
chip_matcha_verilator u_dut (
.clk_i,
.rst_ni,
// communication with GPIO
.cio_gpio_p2d_i(cio_gpio_p2d),
.cio_gpio_d2p_o(cio_gpio_d2p),
.cio_gpio_en_d2p_o(cio_gpio_en_d2p),
.cio_gpio_pull_en_o(cio_gpio_pull_en),
.cio_gpio_pull_select_o(cio_gpio_pull_select),
// communication with UART
.cio_uart_rx_p2d_i(cio_uart_rx_p2d),
.cio_uart_tx_d2p_o(cio_uart_tx_d2p),
// communication with SMC UART
.cio_uart_smc_rx_p2d_i(cio_smc_uart_rx_p2d),
.cio_uart_smc_tx_d2p_o(cio_smc_uart_tx_d2p),
// communication with SPI
.cio_spi_device_sck_p2d_i(cio_spi_device_sck_p2d),
.cio_spi_device_csb_p2d_i(cio_spi_device_csb_p2d),
.cio_spi_device_sdi_p2d_i(cio_spi_device_sdi_p2d),
.cio_spi_device_sdo_d2p_o(cio_spi_device_sdo_d2p),
.cio_spi_device_sdo_en_d2p_o(cio_spi_device_sdo_en_d2p),
// communication with USB
.cio_usbdev_sense_p2d_i(cio_usbdev_sense_p2d),
.cio_usbdev_dp_pullup_d2p_o(cio_usbdev_dp_pullup_d2p),
.cio_usbdev_dn_pullup_d2p_o(cio_usbdev_dn_pullup_d2p),
.cio_usbdev_dp_p2d_i(cio_usbdev_dp_p2d),
.cio_usbdev_dp_d2p_o(cio_usbdev_dp_d2p),
.cio_usbdev_dp_en_d2p_o(cio_usbdev_dp_en_d2p),
.cio_usbdev_dn_p2d_i(cio_usbdev_dn_p2d),
.cio_usbdev_dn_d2p_o(cio_usbdev_dn_d2p),
.cio_usbdev_dn_en_d2p_o(cio_usbdev_dn_en_d2p),
.cio_usbdev_d_p2d_i(cio_usbdev_d_p2d),
.cio_usbdev_d_d2p_o(cio_usbdev_d_d2p),
.cio_usbdev_d_en_d2p_o(cio_usbdev_d_en_d2p),
.cio_usbdev_se0_d2p_o(cio_usbdev_se0_d2p),
.cio_usbdev_rx_enable_d2p_o(cio_usbdev_rx_enable_d2p),
.cio_usbdev_tx_use_d_se0_d2p_o(cio_usbdev_tx_use_d_se0_d2p),
//Communication with I2S
.cio_i2s_rx_sd_p2d_i(cio_i2s_rx_sd_p2d),
.cio_i2s_rx_sclk_d2p_o(cio_i2s_rx_sclk_d2p),
.cio_i2s_rx_ws_d2p_o(cio_i2s_rx_ws_d2p),
.cio_i2s_tx_ws_d2p_o(cio_i2s_tx_ws_d2p),
.cio_i2s_tx_sd_d2p_o(cio_i2s_tx_sd_d2p_o),
.cio_i2s_tx_sclk_d2p_o(cio_i2s_tx_sclk_d2p)
);
// GPIO DPI
gpiodpi #(.N_GPIO(32)) u_gpiodpi (
.clk_i (clk_i),
.rst_ni (rst_ni),
.gpio_p2d (cio_gpio_p2d),
.gpio_d2p (cio_gpio_d2p),
.gpio_en_d2p(cio_gpio_en_d2p),
.gpio_pull_en(cio_gpio_pull_en),
.gpio_pull_sel(cio_gpio_pull_select)
);
// UART DPI
// The baud rate set to match FPGA implementation; the frequency is "artificial". Both baud rate
// frequency must match the settings used in the on-chip software at
// `sw/device/lib/arch/device_sim_verilator.c`.
uartdpi #(
.BAUD('d7_200),
.FREQ('d500_000)
) u_uart (
.clk_i (clk_i),
.rst_ni (rst_ni),
.tx_o (cio_uart_rx_p2d),
.rx_i (cio_uart_tx_d2p)
);
uartdpi #(
.BAUD('d7_200),
.FREQ('d500_000),
.NAME("smc_uart")
) u_smc_uart (
.clk_i (clk_i),
.rst_ni (rst_ni),
.tx_o (cio_smc_uart_rx_p2d),
.rx_i (cio_smc_uart_tx_d2p)
);
//////////////////////////////////
/// I2S Temporary Test Pattern ///
//////////////////////////////////
wire sd;
wire sclk_i;
reg [DATA_WIDTH-1:0] data_tx; //Oversized 1x bit
integer indx_tx;
reg ws_rx_lag, ws_rx_reg;
wire ws_rx;
wire data_incr;
//SCLK get from ip
assign sclk_i = cio_i2s_rx_sclk_d2p;
assign ws_rx = cio_i2s_rx_ws_d2p;
assign cio_i2s_rx_sd_p2d = sd;
assign data_incr = (ws_rx != ws_rx_reg) && rst_ni;
assign sd = (indx_tx >= 0) ? data_tx[indx_tx]: 0;
parameter int unsigned DATA_WIDTH = 16;
//Transmit data buffer then switch to sending zeros. Real mic will be HI-Z after data.
always @(posedge sclk_i or negedge rst_ni) begin
if (!rst_ni) begin
indx_tx <= DATA_WIDTH-1;
ws_rx_reg <= 0;
end else begin
indx_tx <= (data_incr) ? DATA_WIDTH-1 : indx_tx - 1;
ws_rx_reg <= ws_rx;
end
end
always @(posedge sclk_i or negedge rst_ni) begin
if (!rst_ni) begin
data_tx <= 16'hff_ff;
end else begin
if (data_incr) begin
data_tx <= data_tx - 1;
end
end
end
//////////////////////////////////////
/// END I2S Temporary Test Pattern ///
//////////////////////////////////////
`ifdef DMIDirectTAP
// OpenOCD direct DMI TAP
bind rv_dm dmidpi u_dmidpi (
.clk_i,
.rst_ni,
.dmi_req_valid,
.dmi_req_ready,
.dmi_req_addr (dmi_req.addr),
.dmi_req_op (dmi_req.op),
.dmi_req_data (dmi_req.data),
.dmi_rsp_valid,
.dmi_rsp_ready,
.dmi_rsp_data (dmi_rsp.data),
.dmi_rsp_resp (dmi_rsp.resp),
.dmi_rst_n (dmi_rst_n)
);
`else
// TODO: this is currently not supported.
// connect this to the correct pins once pinout is final and once the
// verilator testbench supports DFT/Debug strap sampling.
// See also #5221.
//
// jtagdpi u_jtagdpi (
// .clk_i,
// .rst_ni,
// .jtag_tck (cio_jtag_tck),
// .jtag_tms (cio_jtag_tms),
// .jtag_tdi (cio_jtag_tdi),
// .jtag_tdo (cio_jtag_tdo),
// .jtag_trst_n (cio_jtag_trst_n),
// .jtag_srst_n (cio_jtag_srst_n)
// );
`endif
// SPI DPI
spidpi u_spi (
.clk_i (clk_i),
.rst_ni (rst_ni),
.spi_device_sck_o (cio_spi_device_sck_p2d),
.spi_device_csb_o (cio_spi_device_csb_p2d),
.spi_device_sdi_o (cio_spi_device_sdi_p2d),
.spi_device_sdo_i (cio_spi_device_sdo_d2p),
.spi_device_sdo_en_i (cio_spi_device_sdo_en_d2p)
);
// USB DPI
usbdpi u_usbdpi (
.clk_i (clk_i),
.rst_ni (rst_ni),
.clk_48MHz_i (clk_i),
.sense_p2d (cio_usbdev_sense_p2d),
.pullupdp_d2p (cio_usbdev_dp_pullup_d2p),
.pullupdn_d2p (cio_usbdev_dn_pullup_d2p),
.dp_p2d (cio_usbdev_dp_p2d),
.dp_d2p (cio_usbdev_dp_d2p),
.dp_en_d2p (cio_usbdev_dp_en_d2p),
.dn_p2d (cio_usbdev_dn_p2d),
.dn_d2p (cio_usbdev_dn_d2p),
.dn_en_d2p (cio_usbdev_dn_en_d2p),
.d_p2d (cio_usbdev_d_p2d),
.d_d2p (cio_usbdev_d_d2p),
.d_en_d2p (cio_usbdev_d_en_d2p),
.se0_d2p (cio_usbdev_se0_d2p),
.rx_enable_d2p (cio_usbdev_rx_enable_d2p),
.tx_use_d_se0_d2p(cio_usbdev_tx_use_d_se0_d2p)
);
`define RV_CORE_IBEX u_dut.top_matcha.u_rv_core_ibex_sec
`define RV_CORE_SMC u_dut.top_matcha.u_rv_core_ibex_smc
`define SIM_SRAM_IF u_sim_sram.u_sim_sram_if
`define TEST_DONE_SEC u_sw_test_status_if.sw_test_done
// Detect SW test termination.
sim_sram u_sim_sram (
.clk_i (`RV_CORE_IBEX.clk_i),
.rst_ni (`RV_CORE_IBEX.rst_ni),
.tl_in_i (tlul_pkg::tl_h2d_t'(`RV_CORE_IBEX.u_tlul_req_buf.out_o)),
.tl_in_o (),
.tl_out_o (),
.tl_out_i ()
);
// Connect the sim SRAM directly inside rv_core_ibex.
assign `RV_CORE_IBEX.tl_win_d2h = u_sim_sram.tl_in_o;
// Instantiate the SW test status interface & connect signals from sim_sram_if instance
// instantiated inside sim_sram. Bind would have worked nicely here, but Verilator segfaults
// when trace is enabled (#3951).
sw_test_status_if u_sw_test_status_if (
.clk_i (`SIM_SRAM_IF.clk_i),
.rst_ni (`SIM_SRAM_IF.rst_ni),
.fetch_en (1'b0),
.wr_valid (`SIM_SRAM_IF.wr_valid),
.addr (`SIM_SRAM_IF.tl_h2d.a_address),
.data (`SIM_SRAM_IF.tl_h2d.a_data[15:0])
);
// Connect the SMC SRAM directly inside rv_core_smc.
assign `RV_CORE_SMC.tl_win_d2h = u_dut.top_matcha.u_tl_adapter_ram_smc.tl_o;
// Instantiate an interface to the SMC wrapper to monitor SW test termination.
sim_sram_if #(
.AddrWidth(32)
) u_sim_sram_smc_if (
.clk_i (`RV_CORE_SMC.clk_i),
.rst_ni (`RV_CORE_SMC.rst_ni),
.tl_h2d (tlul_pkg::tl_h2d_t'(`RV_CORE_SMC.u_tlul_req_buf.out_o)),
.tl_d2h (tlul_pkg::tl_d2h_t'(`RV_CORE_SMC.tl_win_d2h))
);
// Instantiate separate sw_test_status_if for the SMC since we don't use address
// arbitration here.
sw_test_status_if u_sw_test_status_smc_if (
.clk_i (u_sim_sram_smc_if.clk_i),
.rst_ni (u_sim_sram_smc_if.rst_ni),
.fetch_en (1'b0),
.wr_valid (u_sim_sram_smc_if.wr_valid),
.addr (u_sim_sram_smc_if.tl_h2d.a_address),
.data (u_sim_sram_smc_if.tl_h2d.a_data[15:0])
);
// Set the start address of the simulation SRAM.
// Use offset 0 within both sim SRAM interfaces for SW test status indication.
initial begin
`SIM_SRAM_IF.start_addr = `VERILATOR_TEST_STATUS_ADDR;
u_sw_test_status_if.sw_test_status_addr = `SIM_SRAM_IF.start_addr;
u_sim_sram_smc_if.start_addr = `SMC_VERILATOR_TEST_STATUS_ADDR;
u_sw_test_status_smc_if.sw_test_status_addr = u_sim_sram_smc_if.start_addr;
end
always @(posedge clk_i) begin
if (u_sw_test_status_if.sw_test_done || u_sw_test_status_smc_if.sw_test_done) begin
$display("Verilator sim termination requested");
$display("Your simulation wrote to 0x%h", (`TEST_DONE_SEC ?
u_sw_test_status_if.sw_test_status_addr :
u_sw_test_status_smc_if.sw_test_status_addr));
dv_test_status_pkg::dv_test_status((`TEST_DONE_SEC ?
u_sw_test_status_if.sw_test_passed :
u_sw_test_status_smc_if.sw_test_passed));
$finish;
end
end
`undef RV_CORE_IBEX
`undef RV_CORE_SMC
`undef SIM_SRAM_IF
`undef TEST_DONE_SEC
endmodule // chip_sim_tb