| // 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 otp_ctrl_env_pkg::*; | 
 |   import otp_ctrl_test_pkg::*; | 
 |   import otp_ctrl_reg_pkg::*; | 
 |   import mem_bkdr_util_pkg::mem_bkdr_util; | 
 |  | 
 |   // macro includes | 
 |   `include "uvm_macros.svh" | 
 |   `include "dv_macros.svh" | 
 |  | 
 |   // TB base test ENV_T & CFG_T specification | 
 |   // | 
 |   // Specify the parameters for the otp_ctrl_base_test | 
 |   // This will invoke the UVM registry and link this test type to | 
 |   // the name 'otp_ctrl_base_test' as a test name passed by UVM_TESTNAME | 
 |   // | 
 |   // This is done explicitly only for the prim_pkg::ImplGeneric implementation | 
 |   // since partner base tests inherit from otp_ctrl_base_test#(CFG_T, ENV_T) and | 
 |   // specify directly (CFG_T, ENV_T) via the class extension and use a different | 
 |   // UVM_TESTNAME | 
 |   if (`PRIM_DEFAULT_IMPL == prim_pkg::ImplGeneric) begin : gen_spec_base_test_params | 
 |     typedef otp_ctrl_base_test #(.CFG_T(otp_ctrl_env_cfg), | 
 |                                  .ENV_T(otp_ctrl_env)) otp_ctrl_base_test_t; | 
 |   end | 
 |  | 
 |   wire clk, rst_n; | 
 |   wire devmode; | 
 |   wire otp_ctrl_pkg::flash_otp_key_req_t flash_req; | 
 |   wire otp_ctrl_pkg::flash_otp_key_rsp_t flash_rsp; | 
 |   wire otp_ctrl_pkg::otbn_otp_key_req_t  otbn_req; | 
 |   wire otp_ctrl_pkg::otbn_otp_key_rsp_t  otbn_rsp; | 
 |   wire otp_ctrl_pkg::sram_otp_key_req_t[NumSramKeyReqSlots-1:0] sram_req; | 
 |   wire otp_ctrl_pkg::sram_otp_key_rsp_t[NumSramKeyReqSlots-1:0] sram_rsp; | 
 |  | 
 |   wire [NUM_MAX_INTERRUPTS-1:0] interrupts; | 
 |   wire intr_otp_operation_done, intr_otp_error; | 
 |  | 
 |   // Output from close-source OTP, not checked in open-source env. | 
 |   wire otp_ctrl_pkg::otp_ast_req_t ast_req; | 
 |   wire [7:0] otp_obs_o; | 
 |  | 
 |   tlul_pkg::tl_d2h_t prim_tl_o; | 
 |  | 
 |   // interfaces | 
 |   clk_rst_if clk_rst_if(.clk(clk), .rst_n(rst_n)); | 
 |   pins_if #(NUM_MAX_INTERRUPTS) intr_if(interrupts); | 
 |   pins_if #(1) devmode_if(devmode); | 
 |  | 
 |   // lc_otp interfaces | 
 |   push_pull_if #(.HostDataWidth(LC_PROG_DATA_SIZE), .DeviceDataWidth(1)) | 
 |                lc_prog_if(.clk(clk), .rst_n(rst_n)); | 
 |   push_pull_if #(.DeviceDataWidth(SRAM_DATA_SIZE)) | 
 |                sram_if[NumSramKeyReqSlots](.clk(clk), .rst_n(rst_n)); | 
 |   push_pull_if #(.DeviceDataWidth(OTBN_DATA_SIZE)) otbn_if(.clk(clk), .rst_n(rst_n)); | 
 |   push_pull_if #(.DeviceDataWidth(FLASH_DATA_SIZE)) flash_addr_if(.clk(clk), .rst_n(rst_n)); | 
 |   push_pull_if #(.DeviceDataWidth(FLASH_DATA_SIZE)) flash_data_if(.clk(clk), .rst_n(rst_n)); | 
 |  | 
 |   tl_if tl_if(.clk(clk), .rst_n(rst_n)); | 
 |   tl_if prim_tl_if(.clk(clk), .rst_n(rst_n)); | 
 |  | 
 |   otp_ctrl_if otp_ctrl_if(.clk_i(clk), .rst_ni(rst_n)); | 
 |  | 
 |   `DV_ALERT_IF_CONNECT() | 
 |  | 
 |   // edn_clk, edn_rst_n and edn_if are defined and driven in below macro | 
 |   `DV_EDN_IF_CONNECT | 
 |  | 
 |   assign otp_ctrl_if.lc_prog_req = lc_prog_if.req; | 
 |   assign otp_ctrl_if.lc_prog_err = lc_prog_if.d_data; | 
 |  | 
 |   // Assign to otp_ctrl_if for assertion checks. | 
 |   assign otp_ctrl_if.lc_prog_ack = lc_prog_if.ack; | 
 |   assign otp_ctrl_if.flash_acks = flash_data_if.ack; | 
 |   assign otp_ctrl_if.otbn_ack  = otbn_if.ack; | 
 |  | 
 |   // This signal probes design's alert request to avoid additional logic for triggering alert and | 
 |   // disable assertions. | 
 |   // Alert checkings are done independently in otp_ctrl's scb. | 
 |   // The correctness of this probed signal is checked in otp_ctrl's scb as well. | 
 |   assign otp_ctrl_if.alert_reqs = dut.alerts[0] | dut.alerts[1]; | 
 |  | 
 |   // connected to interface | 
 |   wire otp_ext_voltage_h = otp_ctrl_if.ext_voltage_h_io; | 
 |  | 
 |   // dut | 
 |   otp_ctrl dut ( | 
 |     .clk_i                      (clk        ), | 
 |     .rst_ni                     (rst_n      ), | 
 |     // edn | 
 |     .clk_edn_i                  (edn_clk    ), | 
 |     .rst_edn_ni                 (edn_rst_n  ), | 
 |     .edn_o                      (edn_if[0].req ), | 
 |     .edn_i                      ({edn_if[0].ack, edn_if[0].d_data}), | 
 |     // bus interfaces | 
 |     .core_tl_i                  (tl_if.h2d  ), | 
 |     .core_tl_o                  (tl_if.d2h  ), | 
 |     .prim_tl_i                  (prim_tl_if.h2d), | 
 |     .prim_tl_o                  (prim_tl_if.d2h), | 
 |     // interrupt | 
 |     .intr_otp_operation_done_o  (intr_otp_operation_done), | 
 |     .intr_otp_error_o           (intr_otp_error), | 
 |     // alert | 
 |     .alert_rx_i                 (alert_rx   ), | 
 |     .alert_tx_o                 (alert_tx   ), | 
 |     // ast | 
 |     .obs_ctrl_i                 (otp_ctrl_if.obs_ctrl_i), | 
 |     .otp_obs_o                  (otp_obs_o), | 
 |     .otp_ast_pwr_seq_o          (ast_req), | 
 |     .otp_ast_pwr_seq_h_i        (otp_ctrl_if.otp_ast_pwr_seq_h_i), | 
 |     // pwrmgr | 
 |     .pwr_otp_i                  (otp_ctrl_if.pwr_otp_init_i), | 
 |     .pwr_otp_o                  ({otp_ctrl_if.pwr_otp_done_o, otp_ctrl_if.pwr_otp_idle_o}), | 
 |     // lc | 
 |     .lc_otp_vendor_test_i       (otp_ctrl_if.otp_vendor_test_ctrl_i), | 
 |     .lc_otp_vendor_test_o       (otp_ctrl_if.otp_vendor_test_status_o), | 
 |     .lc_otp_program_i           ({lc_prog_if.req, lc_prog_if.h_data}), | 
 |     .lc_otp_program_o           ({lc_prog_if.d_data, lc_prog_if.ack}), | 
 |     .lc_creator_seed_sw_rw_en_i (otp_ctrl_if.lc_creator_seed_sw_rw_en_i), | 
 |     .lc_seed_hw_rd_en_i         (otp_ctrl_if.lc_seed_hw_rd_en_i), | 
 |     .lc_dft_en_i                (otp_ctrl_if.lc_dft_en_i), | 
 |     .lc_escalate_en_i           (otp_ctrl_if.lc_escalate_en_i), | 
 |     .lc_check_byp_en_i          (otp_ctrl_if.lc_check_byp_en_i), | 
 |     .otp_lc_data_o              (otp_ctrl_if.lc_data_o), | 
 |     // keymgr | 
 |     .otp_keymgr_key_o           (otp_ctrl_if.keymgr_key_o), | 
 |     // flash | 
 |     .flash_otp_key_i            (flash_req), | 
 |     .flash_otp_key_o            (flash_rsp), | 
 |     // sram | 
 |     .sram_otp_key_i             (sram_req), | 
 |     .sram_otp_key_o             (sram_rsp), | 
 |     // otbn | 
 |     .otbn_otp_key_i             (otbn_req), | 
 |     .otbn_otp_key_o             (otbn_rsp), | 
 |  | 
 |     .otp_hw_cfg_o               (otp_ctrl_if.otp_hw_cfg_o), | 
 |     .otp_ext_voltage_h_io       (otp_ext_voltage_h), | 
 |  | 
 |     //scan | 
 |     .scan_en_i                  (otp_ctrl_if.scan_en_i), | 
 |     .scan_rst_ni                (otp_ctrl_if.scan_rst_ni), | 
 |     .scanmode_i                 (otp_ctrl_if.scanmode_i), | 
 |  | 
 |     // Test-related GPIO output | 
 |     .cio_test_o                 (otp_ctrl_if.cio_test_o), | 
 |     .cio_test_en_o              (otp_ctrl_if.cio_test_en_o) | 
 |   ); | 
 |  | 
 |   for (genvar i = 0; i < NumSramKeyReqSlots; i++) begin : gen_sram_pull_if | 
 |     assign sram_req[i]              = sram_if[i].req; | 
 |     assign sram_if[i].ack           = sram_rsp[i].ack; | 
 |     assign sram_if[i].d_data        = {sram_rsp[i].key, sram_rsp[i].nonce, sram_rsp[i].seed_valid}; | 
 |     assign otp_ctrl_if.sram_acks[i] = sram_rsp[i].ack; | 
 |     initial begin | 
 |       uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(SRAM_DATA_SIZE)))::set(null, | 
 |                      $sformatf("*env.m_sram_pull_agent[%0d]*", i), "vif", sram_if[i]); | 
 |     end | 
 |   end | 
 |   assign otbn_req       = otbn_if.req; | 
 |   assign otbn_if.ack    = otbn_rsp.ack; | 
 |   assign otbn_if.d_data = {otbn_rsp.key, otbn_rsp.nonce, otbn_rsp.seed_valid}; | 
 |  | 
 |   assign flash_req            = {flash_data_if.req, flash_addr_if.req}; | 
 |   assign flash_data_if.ack    = flash_rsp.data_ack; | 
 |   assign flash_addr_if.ack    = flash_rsp.addr_ack; | 
 |   assign flash_data_if.d_data = {flash_rsp.key, flash_rsp.seed_valid}; | 
 |   assign flash_addr_if.d_data = {flash_rsp.key, flash_rsp.seed_valid}; | 
 |  | 
 |   assign interrupts[OtpOperationDone] = intr_otp_operation_done; | 
 |   assign interrupts[OtpErr]           = intr_otp_error; | 
 |  | 
 |   // Instantitate the memory backdoor util instance only for OS implementation | 
 |   // Proprietary IP will instantiate their own backdoor util | 
 |  | 
 |   if (`PRIM_DEFAULT_IMPL == prim_pkg::ImplGeneric) begin : gen_impl_generic | 
 |     `define MEM_MODULE_PATH \ | 
 |         tb.dut.u_otp.gen_generic.u_impl_generic.u_prim_ram_1p_adv | 
 |  | 
 |     `define MEM_ARRAY_PATH \ | 
 |         `MEM_MODULE_PATH.u_mem.gen_generic.u_impl_generic.mem | 
 |  | 
 |     initial begin : mem_bkdr_util_gen | 
 |       mem_bkdr_util m_mem_bkdr_util; | 
 |       m_mem_bkdr_util = new(.name("mem_bkdr_util"), | 
 |                             .path(`DV_STRINGIFY(`MEM_ARRAY_PATH)), | 
 |                             .depth($size(`MEM_ARRAY_PATH)), | 
 |                             .n_bits($bits(`MEM_ARRAY_PATH)), | 
 |                             .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_22_16)); | 
 |  | 
 |       uvm_config_db#(mem_bkdr_util)::set(null, "*.env", "mem_bkdr_util", m_mem_bkdr_util); | 
 |     end : mem_bkdr_util_gen | 
 |  | 
 |     `undef MEM_ARRAY_PATH | 
 |     `undef MEM_MODULE_PATH | 
 |   end : gen_impl_generic | 
 |  | 
 |   initial begin | 
 |     // DV forced otp_cmd_i to reach invalid state, thus violate the assertions | 
 |     $assertoff(0, tb.dut.gen_partitions[3].gen_buffered.u_part_buf.OtpErrorState_A); | 
 |     $assertoff(0, tb.dut.gen_partitions[4].gen_buffered.u_part_buf.OtpErrorState_A); | 
 |     $assertoff(0, tb.dut.gen_partitions[5].gen_buffered.u_part_buf.OtpErrorState_A); | 
 |     $assertoff(0, tb.dut.gen_partitions[6].gen_buffered.u_part_buf.OtpErrorState_A); | 
 |  | 
 |     // 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#(virtual clk_rst_if)::set(null, "*.env", | 
 |                                             "clk_rst_vif_otp_ctrl_prim_reg_block", clk_rst_if); | 
 |     uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent_otp_ctrl_core_reg_block*", | 
 |                                        "vif", tl_if); | 
 |     uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent_otp_ctrl_prim_reg_block", | 
 |                                        "vif", prim_tl_if); | 
 |     uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(OTBN_DATA_SIZE)))::set(null, | 
 |                    "*env.m_otbn_pull_agent*", "vif", otbn_if); | 
 |     uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(FLASH_DATA_SIZE)))::set(null, | 
 |                    "*env.m_flash_data_pull_agent*", "vif", flash_data_if); | 
 |     uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(FLASH_DATA_SIZE)))::set(null, | 
 |                    "*env.m_flash_addr_pull_agent*", "vif", flash_addr_if); | 
 |     uvm_config_db#(virtual push_pull_if#(.HostDataWidth(LC_PROG_DATA_SIZE), .DeviceDataWidth(1))):: | 
 |                    set(null, "*env.m_lc_prog_pull_agent*", "vif", lc_prog_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 otp_ctrl_if)::set(null, "*.env", "otp_ctrl_vif", otp_ctrl_if); | 
 |     $timeformat(-12, 0, " ps", 12); | 
 |     run_test(); | 
 |   end | 
 |  | 
 | endmodule |