|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  |  | 
|  | module tb; | 
|  | // dep packages | 
|  | import uvm_pkg::*; | 
|  | import dv_utils_pkg::*; | 
|  | import spi_host_env_pkg::*; | 
|  | import spi_host_test_pkg::*; | 
|  | import spi_host_reg_pkg::*; | 
|  | import lc_ctrl_pkg::*; | 
|  |  | 
|  | import spi_device_pkg::passthrough_req_t; | 
|  | import spi_device_pkg::passthrough_rsp_t; | 
|  |  | 
|  | // macro includes | 
|  | `include "uvm_macros.svh" | 
|  | `include "dv_macros.svh" | 
|  |  | 
|  | wire clk, rst_n; | 
|  | wire                          devmode; | 
|  | wire [NUM_MAX_INTERRUPTS-1:0] interrupts; | 
|  | wire [3:0]                    si_pulldown; | 
|  | wire [3:0]                    so_pulldown; | 
|  |  | 
|  | lc_tx_t                       scanmode_i; | 
|  | logic                         cio_sck_o; | 
|  | logic                         cio_sck_en_o; | 
|  | logic [NumCS-1:0]             cio_csb_o; | 
|  | logic [NumCS-1:0]             cio_csb_en_o; | 
|  | logic [3:0]                   cio_sd_o; | 
|  | logic [3:0]                   cio_sd_en_o; | 
|  | logic [3:0]                   cio_sd_i; | 
|  | logic                         intr_error; | 
|  | logic                         intr_event; | 
|  |  | 
|  | passthrough_req_t             passthrough_i; | 
|  | passthrough_rsp_t             passthrough_o; | 
|  |  | 
|  | // interfaces | 
|  | clk_rst_if   clk_rst_if(.clk(clk), .rst_n(rst_n)); | 
|  | pins_if #(1) devmode_if(devmode); | 
|  | pins_if #(NUM_MAX_INTERRUPTS) intr_if(.pins(interrupts)); | 
|  | tl_if        tl_if(.clk(clk), .rst_n(rst_n)); | 
|  | spi_if       spi_if(.rst_n(rst_n)); | 
|  | spi_passthrough_if       spi_passthrough_if(.rst_n(rst_n)); | 
|  |  | 
|  | `DV_ALERT_IF_CONNECT() | 
|  |  | 
|  | // dut | 
|  | spi_host dut ( | 
|  | .clk_i                (clk), | 
|  | .rst_ni               (rst_n), | 
|  |  | 
|  | // tl i/f | 
|  | .tl_i                 (tl_if.h2d), | 
|  | .tl_o                 (tl_if.d2h), | 
|  | // alerts | 
|  | .alert_rx_i           (alert_rx), | 
|  | .alert_tx_o           (alert_tx), | 
|  | // spi i/o | 
|  | .cio_sck_o            (cio_sck_o), | 
|  | .cio_sck_en_o         (cio_sck_en_o), | 
|  | .cio_csb_o            (cio_csb_o), | 
|  | .cio_csb_en_o         (cio_csb_en_o), | 
|  | .cio_sd_o             (cio_sd_o), | 
|  | .cio_sd_en_o          (cio_sd_en_o), | 
|  | .cio_sd_i             (cio_sd_i), | 
|  | // passthrough i/o | 
|  | .passthrough_i        (passthrough_i), | 
|  | .passthrough_o        (passthrough_o), | 
|  | // intr i/f | 
|  | .intr_error_o         (intr_error), | 
|  | .intr_spi_event_o     (intr_event) | 
|  | ); | 
|  |  | 
|  | assign passthrough_i.passthrough_en = spi_passthrough_if.passthrough_en; | 
|  | assign passthrough_i.sck_en         = spi_passthrough_if.sck_en; | 
|  | assign passthrough_i.csb_en         = spi_passthrough_if.csb_en; | 
|  | assign passthrough_i.s_en           = spi_passthrough_if.s_en; | 
|  | assign passthrough_i.csb            = spi_passthrough_if.csb; | 
|  | assign passthrough_i.sck            = spi_passthrough_if.sck; | 
|  |  | 
|  | assign passthrough_i.s                 = spi_passthrough_if.is; | 
|  | assign spi_passthrough_if.os           = passthrough_o.s; | 
|  | assign spi_passthrough_if.cio_sck_o    = cio_sck_o; | 
|  | assign spi_passthrough_if.cio_sck_en_o = cio_sck_en_o; | 
|  | assign spi_passthrough_if.cio_csb_o    = cio_csb_o; | 
|  | assign spi_passthrough_if.cio_csb_en_o = cio_csb_en_o; | 
|  | assign spi_passthrough_if.cio_sd_en_o  = cio_sd_en_o; | 
|  | assign spi_passthrough_if.cio_sd_o     = cio_sd_o; | 
|  |  | 
|  | assign cio_sd_i = spi_passthrough_if.passthrough_en ? spi_passthrough_if.cio_sd_i : si_pulldown; | 
|  |  | 
|  | // configure spi_if i/o | 
|  | assign spi_if.sck = (cio_sck_en_o) ? cio_sck_o : 1'bz; | 
|  | for (genvar i = 0; i < 4; i++) begin : gen_tri_state | 
|  | pullup (weak1) pd_in_i (si_pulldown[i]); | 
|  | pullup (weak1) pd_out_i (so_pulldown[i]); | 
|  | assign spi_if.sio[i]  = (cio_sd_en_o[i]) ? cio_sd_o[i] : 'z; | 
|  | assign (highz0, pull1) spi_if.sio[i] = !cio_sd_en_o[i]; | 
|  | assign si_pulldown[i] = spi_if.sio[i]; | 
|  |  | 
|  | assign spi_if.csb[i] = (i < NumCS && cio_csb_en_o[i]) ? cio_csb_o[i] : 1'b1; | 
|  | end | 
|  |  | 
|  | assign interrupts[SpiHostError] = intr_error; | 
|  | assign interrupts[SpiHostEvent] = intr_event; | 
|  |  | 
|  | initial begin | 
|  | // drive clk and rst_n from clk_if | 
|  | clk_rst_if.set_active(); | 
|  | uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "clk_rst_vif", clk_rst_if); | 
|  | uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if); | 
|  | uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if); | 
|  | uvm_config_db#(virtual spi_passthrough_if)::set(null, "*.env", "spi_passthrough_vif", | 
|  | spi_passthrough_if); | 
|  | uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if); | 
|  | uvm_config_db#(virtual spi_if)::set(null, "*.env.m_spi_agent*", "vif", spi_if); | 
|  | $timeformat(-12, 0, " ps", 12); | 
|  | run_test(); | 
|  | end | 
|  |  | 
|  | `ASSERT(Sck_A,   passthrough_i.passthrough_en -> passthrough_i.sck == cio_sck_o, clk, !rst_n) | 
|  | `ASSERT(Sck_En_A,passthrough_i.passthrough_en -> passthrough_i.sck_en == cio_sck_en_o, | 
|  | clk, !rst_n) | 
|  | `ASSERT(Csb_A,   passthrough_i.passthrough_en -> passthrough_i.csb == cio_csb_o, clk, !rst_n) | 
|  | `ASSERT(Csb_En_A,passthrough_i.passthrough_en -> passthrough_i.csb_en == cio_csb_en_o, | 
|  | clk, !rst_n) | 
|  | `ASSERT(S_En_A,  passthrough_i.passthrough_en -> passthrough_i.s_en == cio_sd_en_o, clk, !rst_n) | 
|  | `ASSERT(Sd_O_A,  passthrough_i.passthrough_en -> passthrough_i.s == cio_sd_o, clk, !rst_n) | 
|  | `ASSERT(Sd_I_A,  passthrough_i.passthrough_en -> passthrough_o.s == cio_sd_i, clk, !rst_n) | 
|  |  | 
|  | endmodule |