blob: e9550c51e95d4b631aeb3f57f5be1b9ff1ebbd53 [file]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// One chip level interface to rule them all, and in the IOs, bind them...
//
// The top_earlgrey SoC provides a bunch of fixed-function and muxed IO pads. The interface serves
// as the gateway connection between the chip IOs and ALL functions mapped to the fixed and muxed
// IOs. It creates sub-interfaces for all functions and connects them all to the chip IOs together.
// The pin mapping to each function is provided in the following spreadsheet:
// https://docs.google.com/spreadsheets/d/1jp-paagh2_sJFMUFnewx0XAUmLdCCgXn8NnB2BNEk-Q
//
// All functional interfaces are internally (or externally, in this interface) gated off from
// driving the IOs at the same time. Since there are more functions than IOs, it is the test
// writer's responsibility to ensure that multiple functions that use the same IOs are not active at
// the same time. This interface provides an X-detection logic on all IOs to ensure there are no
// multiple drivers.
//
// This interface MUST be bound to the chip level DUT, since it references the DUT-internal signals
// via partial hierarchical paths.
interface chip_if;
import chip_common_pkg::*;
import dv_utils_pkg::*;
import uvm_pkg::*;
`include "dv_macros.svh"
`include "uvm_macros.svh"
// TODO: Move these to `include "./chip_hier_macros.svh". Deprecate ../tb/chip_hier_macros.svh.
// TODO: In Xcelium, the bind is not exposing the internal hierarchies to chip_if.
`ifdef XCELIUM
`define TOP_HIER tb.dut.top_earlgrey
`else
`define TOP_HIER top_earlgrey
`endif
`define ADC_CTRL_HIER `TOP_HIER.u_adc_ctrl_aon
`define AES_HIER `TOP_HIER.u_aes
`define ALERT_HANDLER_HIER `TOP_HIER.u_alert_handler
`define AON_TIMER_HIER `TOP_HIER.u_aon_timer_aon
`define AST_HIER u_ast
`define CLKMGR_HIER `TOP_HIER.u_clkmgr_aon
`define CPU_HIER `TOP_HIER.u_rv_core_ibex
`define CPU_CORE_HIER `CPU_HIER.u_core
`define CPU_TL_ADAPT_D_HIER `CPU_HIER.tl_adapter_host_d_ibex
`define CSRNG_HIER `TOP_HIER.u_csrng
`define ENTROPY_SRC_HIER `TOP_HIER.u_entropy_src
`define EDN_HIER(i) `TOP_HIER.u_edn``i
`define FLASH_CTRL_HIER `TOP_HIER.u_flash_ctrl
`define GPIO_HIER `TOP_HIER.u_gpio
`define HMAC_HIER `TOP_HIER.u_hmac
`define I2C_HIER(i) `TOP_HIER.u_i2c``i
`define KMAC_HIER `TOP_HIER.u_kmac
`define KEYMGR_HIER `TOP_HIER.u_keymgr
`define LC_CTRL_HIER `TOP_HIER.u_lc_ctrl
`define OTP_CTRL_HIER `TOP_HIER.u_otp_ctrl
`define OTBN_HIER `TOP_HIER.u_otbn
`define PATTGEN_HIER `TOP_HIER.u_pattgen
`define PINMUX_HIER `TOP_HIER.u_pinmux_aon
`define PWM_HIER `TOP_HIER.u_pwm_aon
`define PWRMGR_HIER `TOP_HIER.u_pwrmgr_aon
`define ROM_CTRL_HIER `TOP_HIER.u_rom_ctrl
`define RSTMGR_HIER `TOP_HIER.u_rstmgr_aon
`define RV_DM_HIER `TOP_HIER.u_rv_dm
`define RV_TIMER_HIER `TOP_HIER.u_rv_timer
`define SENSOR_CTRL_HIER `TOP_HIER.u_sensor_ctrl
`define SPI_DEVICE_HIER `TOP_HIER.u_spi_device
`define SPI_HOST_HIER(i) `TOP_HIER.u_spi_host``i
`define SRAM_CTRL_MAIN_HIER `TOP_HIER.u_sram_ctrl_main
`define SRAM_CTRL_RET_HIER `TOP_HIER,u_sram_ctrl_ret_aon
`define SYSRST_CTRL_HIER `TOP_HIER.u_sysrst_ctrl
`define UART_HIER(i) `TOP_HIER.u_uart``i
`define USBDEV_HIER `TOP_HIER.u_usbdev
// Identifier for logs.
string MsgId = $sformatf("%m");
// Identifier for the envorinment to which this interface is passed on via uvm_config_db.
string env_name = "env";
// Directly connected to chip IOs.
//
// DO NOT manipulate this signal in test sequences directly. Use the individual functional
// interfaces below instead.
wire [IoNumTotal-1:0] ios;
// Functional interface: for testing ALL chip IOs, such as pinmux and padctrl tests.
pins_if#(.Width(IoNumTotal), .PullStrength("Weak")) ios_if(.pins(ios));
// Weak pulls for each IO.
//
// All IOs are weak-pulled by default, using the ios_if interface. All IOs are pulled down, except
// for the 4 below.
initial begin
// Enable weak pulldown on most signals.
ios_if.pins_pd = '1;
// These are "inactive high".
ios_if.pins_pu[PorN] = 1;
ios_if.pins_pu[UsbP] = 1;
ios_if.pins_pu[IoR4] = 1; // JTAG t_rst_n.
ios_if.pins_pu[IoR8] = 1;
ios_if.pins_pu[IoR9] = 1;
// Leave dedicated chip outputs undriven.
ios_if.pins_pd[SpiHostCsL] = 0;
ios_if.pins_pd[SpiHostClk] = 0;
end
// X-check monitor on chip IOs.
//
// Chip IOs must always either be undriven or driven to a known value. Xs indicate multiple
// drivers, which is an issue likely caused by multiple functions simultaneously attempting to
// control the shared (muxed) pads.
for (genvar i = 0; i < IoNumTotal; i++) begin : gen_ios_x_check
wire glitch_free_io;
assign #1ps glitch_free_io = ios[i];
chip_io_e named_io = chip_io_e'(i);
always @(glitch_free_io) begin
if (glitch_free_io === 1'bx) begin
`uvm_error(MsgId, $sformatf("Detected an X on %0s", named_io.name()))
end
end
end : gen_ios_x_check
// Functional interfaces.
//
// The section below creates functional interfaces and connects the signals to the `ios` wires.
// Depending on the type of the IO, the following signaling choices are made:
//
// - For all dedicated and muxed IOs that are spare pins:
// - Create pins_if instance, since it internally has direction controls. If a dedicated IO has
// fixed direction, we still create a pins_if instance so that the default weak pulls
// implemented in ios_if work properly.
//
// - IO peripheral interfaces:
// - Create the corresponding IO interface, such as uart_if.
// - Ideally, the interface agent must internally provide direction control, especially for
// signals driven into the chip.
// - If that is infeasible, then create a control signal locally.
//
// - Internal probes and forces:
// - Create `logic` or equivalent data type signals, or create the UVM agent interfaces.
//
// DO NOT USE logic datatype to drive the ios signals directly.
//
// On the muxed IOs, multiple functional interfaces are connected to the same `ios` wires. A
// single `ios` wire cannot be driven by more than one function at the same time. This must be
// handled properly by the test sequence, which will enable the direction control for the required
// interfaces based on the test's needs at the right times. By default, all chip IOs are weak
// pulled via the chip_ios_if direction controls. If multiple drivers are found, The unknown
// monitor above will throw a fatal error and exit the simulation.
// Functional (dedicated) interface (input): power on reset input.
pins_if #(1) por_n_if(.pins(ios[PorN]));
// Functional (dedicated) interface (inout): USB.
// TODO!
// Functional (dedicated) interface (input): CC1, CC2.
pins_if #(2) cc_if(.pins(ios[CC2:CC1]));
// Functional (dedicated) interface (analog input): flash test volt.
pins_if #(1) flash_test_volt_if(.pins(ios[FlashTestVolt]));
// Functional (dedicated) interface (input): flash test mode0.
pins_if #(2) flash_test_mode_if(.pins(ios[FlashTestMode1:FlashTestMode0]));
// Functional (dedicated) interface (analog input): OTP ext volt.
pins_if #(1) otp_ext_volt_if(.pins(ios[OtpExtVolt]));
// Functional (dedicated) interface: SPI host interface (drives traffic into the chip).
// TODO: Update spi_if to emit all signals as inout ports.
// spi_if spi_host_if(.rst_n(`SPI_DEVICE_HIER.rst_ni),
// .sck(ios[SpiDevClk]),
// .csb(ios[SpiDevCsL]),
// .sio(ios[SpiDevD3:SpiDevD0]));
bit enable_spi_host = 1; // Since these are DIOs.
spi_if spi_host_if(.rst_n(`SPI_DEVICE_HIER.rst_ni));
assign ios[SpiDevClk] = enable_spi_host ? spi_host_if.sck : 1'bz;
assign ios[SpiDevCsL] = enable_spi_host ? spi_host_if.csb : 1'bz;
assign ios[SpiDevD0] = enable_spi_host ? spi_host_if.sio[0] : 1'bz;
assign spi_host_if.sio[1] = enable_spi_host ? ios[SpiDevD1] : 1'bz;
// Functional (dedicated) interface: SPI AP device interface (receives traffic from the chip).
// TODO: Update spi_if to emit all signals as inout ports.
// spi_if spi_device_ap_if(.rst_n(`SPI_HOST_HIER(0).rst_ni),
// .sck(ios[SpiHostClk]),
// .csb(ios[SpiHostCsL]),
// .sio(ios[SpiHostD3:SpiHostD0]));
bit enable_spi_device_ap = 1; // Since these are DIOs.
spi_if spi_device_ap_if(.rst_n(`SPI_HOST_HIER(0).rst_ni));
assign spi_device_ap_if.sck = enable_spi_device_ap ? ios[SpiHostClk] : 1'bz;
assign spi_device_ap_if.csb = enable_spi_device_ap ? ios[SpiHostCsL] : 1'bz;
// for (genvar i = 0; i < 4; i++) begin : gen_spi_device_ap_if_sio_conn
// // TODO: This logic needs to be firmed up.
// assign ios[SpiHostD0 + i] = spi_device_ap_if.sio_oe[i] ? spi_device_ap_if.sio[i] : 1'bz;
// assign spi_device_ap_if.sio[i] = ~spi_device_ap_if.sio_oe[i] ? ios[SpiHostD0 + i] : 1'bz;
// end
// Functional (dedicated) interface (inout): EC reset.
pins_if #(1) ec_rst_l_if(.pins(ios[IoR8]));
// Functional (dedicated) interface (inout): flash write protect.
pins_if #(1) flash_wp_l_if(.pins(ios[IoR9]));
// Functional (dedicated) interface (inout): power button.
pins_if #(1) pwrb_in_if(.pins(ios[IoR13])); // TODO: move to R0.
// Functional (muxed) interface: sysrst_ctrl.
// TODO: Replace with sysrst_ctrl IP level interface.
// TODO; combine all into 1 single sysrst_ctrl_if.
pins_if #(8) sysrst_ctrl_if(.pins({ios[IoR6], ios[IoR5], ios[IoC9], ios[IoC7],
ios[IoB9], ios[IoB8], ios[IoB6], ios[IoB3]}));
// Functional (dedicated) interface (input): AST misc.
pins_if #(1) ast_misc_if(.pins(ios[AstMisc]));
// Functional (muxed) interface: DFT straps.
pins_if #(2) dft_straps_if(.pins(ios[IoC4:IoC3]));
// Functional (muxed) interface: TAP straps.
pins_if #(2) tap_straps_if(.pins({ios[IoC5], ios[IoC8]}));
// Set JTAG TAP straps during the next powerup.
//
// The function waits for the pwrmgr fast FSM state to reach the strap sampling state and sets the
// JTAG TAP strap pins to the desired values. This function must be called after asserting POR
// or just before a new low power entry. The strap pins are set the moment pwrmgr FSM reaches the
// strap sampling state. The strap interface is disconnected from the chip IOs immediately once
// the pwrmgr advances to the next state, so that the chip IOs are freed up for other uses.
//
// In DFT-enabled LC state, the TAP straps are continuously sampled to allow switching back and
// forth between RV_DM and LC TAPs. For this usecase, the test sequence can set the TAP straps
// directly using the tap_straps_if interface.
//
// This method is non-blocking - it immediately returns back to the caller after spawning a
// thread. Care must be taken to ensure the calling thread is not killed unless desired.
wire pwrmgr_pkg::fast_pwr_state_e pwrmgr_fast_pwr_state = `PWRMGR_HIER.u_fsm.state_q;
function automatic void set_tap_straps_on_powerup(chip_jtag_tap_e tap_strap);
fork begin
wait (pwrmgr_fast_pwr_state == pwrmgr_pkg::FastPwrStateStrap);
tap_straps_if.drive(tap_strap);
wait (pwrmgr_fast_pwr_state != pwrmgr_pkg::FastPwrStateStrap);
tap_straps_if.drive_en('0);
end join_none
endfunction
// Set DFT straps during the next powerup.
//
// Similar in behavior to set_tap_straps_on_next_powerup(), but used for setting the DFT straps.
function automatic void set_dft_straps_on_powerup(bit [1:0] dft_strap);
fork begin
wait (pwrmgr_fast_pwr_state == pwrmgr_pkg::FastPwrStateStrap);
dft_straps_if.drive(dft_strap);
wait (pwrmgr_fast_pwr_state != pwrmgr_pkg::FastPwrStateStrap);
dft_straps_if.drive_en('0);
end join_none
endfunction
// Functional (muxed) interface: SW straps.
pins_if #(3) sw_straps_if(.pins(ios[IoC2:IoC0]));
// Functional (muxed) interface: GPIOs.
//
// Note: In an actual implementation, fewer GPIOs may be in use. For testing, we try to connect as
// many as the `gpio` peripheral supports. As of now, the other functions muxed with these IOs
// do not need to be enabled in GPIO tests.
pins_if #(31) gpio_pins_if(
.pins({ios[IoA0], ios[IoA1], ios[IoA2], ios[IoA3],
ios[IoA4], ios[IoA5], ios[IoA6], ios[IoB0],
ios[IoB1], ios[IoB2], ios[IoB3], ios[IoB4],
ios[IoB5], ios[IoB6], ios[IoB7], ios[IoB8],
ios[IoC5], ios[IoC6], ios[IoC7], ios[IoC9],
ios[IoC10], ios[IoC11], ios[IoC12], ios[IoR0],
ios[IoR1], ios[IoR2], ios[IoR3], ios[IoR4],
ios[IoR5], ios[IoR6], ios[IoR7]})
);
// Functional (muxed) interface: JTAG (valid during debug enabled LC state only).
// To connect the JTAG interface to chip IOs, just set the TAP strap to the desired value.
//
// Whether the desired JTAG TAP will actually selected or not depends on the LC state and the
// window of time when the TAP straps are set. It is upto the test sequence to orchestrate it
// correctly. Disconnect the TAP strap interface to free up the muxed IOs.
wire __enable_jtag = (tap_straps_if.pins != 0);
wire lc_hw_debug_en = (`LC_CTRL_HIER.lc_hw_debug_en_o == lc_ctrl_pkg::On);
jtag_if jtag_if();
assign ios[IoR0] = __enable_jtag ? jtag_if.tms : 1'bz;
assign jtag_if.tdo = __enable_jtag ? ios[IoR1] : 1'bz;
assign ios[IoR2] = __enable_jtag ? jtag_if.tdi : 1'bz;
assign ios[IoR3] = __enable_jtag ? jtag_if.tck : 1'bz;
assign ios[IoR4] = __enable_jtag ? jtag_if.trst_n : 1'bz;
// Functional (muxed) interface: Flash controller JTAG.
bit enable_flash_ctrl_jtag, flash_ctrl_jtag_enabled;
jtag_if flash_ctrl_jtag_if();
// TODO: Revisit this logic.
assign flash_ctrl_jtag_enabled = enable_flash_ctrl_jtag && lc_hw_debug_en;
assign ios[IoB0] = flash_ctrl_jtag_enabled ? flash_ctrl_jtag_if.tms : 1'bz;
assign flash_ctrl_jtag_if.tdo = flash_ctrl_jtag_enabled ? ios[IoB1] : 1'bz;
assign ios[IoB2] = flash_ctrl_jtag_enabled ? flash_ctrl_jtag_if.tdi : 1'bz;
assign ios[IoB3] = flash_ctrl_jtag_enabled ? flash_ctrl_jtag_if.tck : 1'bz;
// Functional (muxed) interface: AST2PAD.
pins_if #(9) ast2pad_if(.pins({ios[IoA0], ios[IoA1], ios[IoB3], ios[IoB4],
ios[IoB5], ios[IoC0], ios[IoC4], ios[IoC7],
ios[IoC9]}));
// Functional (muxed) interface: PAD2AST.
pins_if #(8) pad2ast_if(.pins({ios[IoA4], ios[IoA5], ios[IoB0], ios[IoB1],
ios[IoB2], ios[IoC1], ios[IoC2], ios[IoC3]}));
// Functional (muxed) interface: Pin wake up signal.
// TODO: For these tests, use chip_pins_if instead, so that any pin can be configured to wakeup.
pins_if #(1) pinmux_wkup_if(.pins(ios[IoB7]));
// Functional (muxed) interface: UARTs.
localparam chip_io_e AssignedUartTxIos[NUM_UARTS] = {IoC4, IoB5, IoA5, IoA1};
localparam chip_io_e AssignedUartRxIos[NUM_UARTS] = {IoC3, IoB4, IoA4, IoA0};
bit [NUM_UARTS-1:0] __enable_uart; // Internal signal.
for (genvar i = 0; i < NUM_UARTS; i++) begin : gen_uart_if_conn
uart_if uart_if();
assign ios[AssignedUartRxIos[i]] = __enable_uart[i] ? uart_if.uart_rx : 1'bz;
assign uart_if.uart_tx = __enable_uart[i] ? ios[AssignedUartTxIos[i]] : 1'b1;
initial begin
uvm_config_db#(virtual uart_if)::set(null, $sformatf("*.env.m_uart_agent%0d*", i),
"vif", uart_if);
end
end : gen_uart_if_conn
// Connects / disconnects the UART interfaces to / from the chip IOs.
//
// The pinmux must be programmed to connect the UART peripheral to the IO pins referenced above,
// in addition to UART interface being connected to the chip IOs. There may be a delay between
// these two events. When the test sequence enables UART on the chip IOs, we immediately flip
// the default pull on the assigned chip IOs to weak pullup to ensure protocol compliance.
function automatic void enable_uart(int inst_num, bit enable);
`DV_CHECK_FATAL(inst_num inside {[0:NUM_UARTS-1]}, , MsgId)
ios_if.pins_pu[AssignedUartTxIos[inst_num]] = enable;
ios_if.pins_pu[AssignedUartRxIos[inst_num]] = enable;
__enable_uart[inst_num] = enable;
endfunction
// Functional (muxed) interface: SPI EC device interface (receives traffic from the chip).
// TODO: Update spi_if to emit all signals as inout ports.
// spi_if spi_device_ec_if(.rst_n(`SPI_HOST_HIER(1).rst_ni),
// .sck(ios[IoB3]),
// .csb(ios[IoB0]),
// .sio(ios[IoB1:IoB2]));
// Functional (muxed) interface: I2Cs.
bit [NUM_I2CS-1:0] enable_i2c;
// TODO: Update i2c_if to emit all signals as inout ports.
// TODO: i2c_if i2c_if[NUM_I2CS-1:0]();
// Functional (muxed) interface: PWM.
localparam chip_io_e AssignedPwmIos[NUM_PWM_CHANNELS] = {IoB10, IoB11, IoB12,
IoC10, IoC11, IoC12};
for (genvar i = 0; i < NUM_PWM_CHANNELS; i++) begin : gen_pwm_if_conn
pwm_if pwm_if(.clk(`PWM_HIER.clk_i), .rst_n(`PWM_HIER.rst_ni));
assign pwm_if.pwm = ios[AssignedPwmIos[i]];
initial begin
uvm_config_db#(virtual pwm_if)::set(null, $sformatf("*.env.m_pwm_monitor%0d*", i),
$sformatf("m_pwm_monitor%0d_vif", i), pwm_if);
end
end : gen_pwm_if_conn
// Functional (muxed) interface: external clock source.
//
// The reset port is passive only.
clk_rst_if#("ExtClkDriver") ext_clk_if(.clk(ios[IoC6]), .rst_n(ios[PorN]));
// Internal probes / monitors.
// Legacy clk_rst_if mainly used passively for waiting for clock and reset events.
clk_rst_if clk_rst_if(.clk(ios[IoC6]), .rst_n(ios[PorN]));
wire cpu_clk = `CPU_HIER.clk_i;
wire cpu_rst_n = `CPU_HIER.rst_ni;
clk_rst_if cpu_clk_rst_if(.clk(cpu_clk), .rst_n(cpu_rst_n));
wire aon_clk = `CLKMGR_HIER.clocks_o.clk_aon_powerup;
wire aon_rst_n = `RSTMGR_HIER.resets_o.rst_por_aon_n[0];
clk_rst_if aon_clk_rst_if(.clk(aon_clk), .rst_n(aon_rst_n));
wire usb_clk = `USBDEV_HIER.clk_i;
wire usb_rst_n = `USBDEV_HIER.rst_ni;
clk_rst_if usb_clk_rst_if(.clk(usb_clk), .rst_n(usb_rst_n));
wire pwrmgr_low_power = `PWRMGR_HIER.low_power_o;
// alert_esc_if alert_if[NUM_ALERTS](.clk (`ALERT_HANDLER_HIER.clk_i),
// .rst_n(`ALERT_HANDLER_HIER.rst_ni));
// for (genvar i = 0; i < NUM_ALERTS; i++) begin : gen_alert_rx_conn
// assign alert_if[i].alert_rx = `ALERT_HANDLER_HIER.alert_rx_o[i];
// end
alerts_if alerts_if(.clk(`ALERT_HANDLER_HIER.clk_i), .rst_ni(`ALERT_HANDLER_HIER.rst_ni),
.alerts(`ALERT_HANDLER_HIER.alert_trig));
// TODO: use pwrmgr_low_power, internal aon clk / rst monitor instead.
pwrmgr_low_power_if pwrmgr_low_power_if(.clk (`CLKMGR_HIER.clocks_o.clk_aon_powerup),
.fast_clk(`CLKMGR_HIER.clocks_o.clk_io_div4_powerup),
.rst_n (`RSTMGR_HIER.resets_o.rst_por_io_div4_n[0]));
assign pwrmgr_low_power_if.low_power = `PWRMGR_HIER.low_power_o;
// Use this until we decide what to do with m_tl_agent_rv_dm_debug_mem_reg_block
// TODO reveiw m_tl_agent_rv_dm_debug_mem_reg_block.
tl_if dmi_tbd_if(.clk(cpu_clk), .rst_n(cpu_rst_n));
// Stub CPU envorinment.
//
// The initial value is sought from a plusarg. It can however, be set by the sequence on the fly
// as well. If enabled, the following things happen:
// 1. The clock to the CPU is forced off.
// 2. The address translation modules in rv_core_ibex are held in reset.
// 3. The TL agent interface takes over the tl_d interface on the adapter.
bit stub_cpu;
tl_if cpu_d_tl_if(.clk(cpu_clk), .rst_n(cpu_rst_n));
initial begin
void'($value$plusargs("stub_cpu=%0b", stub_cpu));
forever begin
if (stub_cpu) begin
// silence the main cpu clock to ensure there are no transactions.
// also silence the translation modules as they contain arbiters
// that are unhappy with X's, which can happen if csr_rw happens to
// hit the right register during testing.
// We cannot kill all clocks to CPU_CORE because the DV hijack point
// is in front of a FIFO, so potentially this can kill transactions
// being buffered.
force `CPU_CORE_HIER.clk_i = 1'b0;
force `CPU_HIER.u_ibus_trans.rst_ni = 1'b0;
force `CPU_HIER.u_dbus_trans.rst_ni = 1'b0;
force `CPU_TL_ADAPT_D_HIER.tl_out = cpu_d_tl_if.h2d;
force cpu_d_tl_if.d2h = `CPU_TL_ADAPT_D_HIER.tl_i;
// TL command integrity gen is in the design data path. TL driver provides correct cmd intg.
// Here forces it to random value to ensure that design generates the cmd intg
fork
forever begin : stub_cpu_cmd_intg_thread
@(cpu_d_tl_if.h2d.a_valid);
if (cpu_d_tl_if.h2d.a_valid) begin
force `CPU_TL_ADAPT_D_HIER.tl_out.a_user.cmd_intg = $urandom;
end else begin
release `CPU_TL_ADAPT_D_HIER.tl_out.a_user.cmd_intg;
end
end
join_none
// In stub_cpu mode, disable these assertions because writing rand value to clkmgr's CSR
// `extclk_sel` can violate these assertions.
$assertoff(0, u_ast.u_ast_clks_byp.u_all_clk_byp_req.PrimMubi4SyncCheckTransients_A);
$assertoff(0, u_ast.u_ast_clks_byp.u_all_clk_byp_req.PrimMubi4SyncCheckTransients0_A);
$assertoff(0, u_ast.u_ast_clks_byp.u_all_clk_byp_req.PrimMubi4SyncCheckTransients1_A);
end else begin
// when en_sim_sram == 1, need to make sure the access to sim_sram doesn't appear on
// cpu_d_tl_if, otherwise, we may have unmapped access as scb doesn't regnize addresses of
// sim_sram. `CPU_HIER.tl_d_* is the right place to avoid seeing sim_sram accesses
force cpu_d_tl_if.h2d = `CPU_HIER.cored_tl_h_o;
force cpu_d_tl_if.d2h = `CPU_HIER.cored_tl_h_i;
end
@stub_cpu;
disable stub_cpu_cmd_intg_thread;
end
end
// Pass interface handles to uvm_config_db.
//
// Since the chip_if handle itself will be passed to the chip env, there is no need to set
// sub-interface handles that are consumed by the chip env. Only pass the sub-interface handles
// for external interface agents.
initial begin
// TODO: Should we always drive external clock? This should move to the sequences.
ext_clk_if.set_active(.drive_clk_val(1), .drive_rst_n_val(0));
// Note that attempting to drive the external clock / power on reset using this interface will
// vacuously return instead of throwing an error. This is done to support the our base classes.
// The test sequences must use ext_clk_if and por_n_if respectively instead.
uvm_config_db#(virtual clk_rst_if)::set(null, "*.env*", "clk_rst_vif", clk_rst_if);
// TODO: Update once jtag_riscv_agent is replaced with jtag_dmi_agent / SBA accessor.
uvm_config_db#(virtual jtag_if)::set(null, "*.env.m_jtag_riscv_agent*", "vif", jtag_if);
uvm_config_db#(virtual tl_if)::set(
null, "*.env.m_tl_agent_chip_reg_block*", "vif", cpu_d_tl_if);
uvm_config_db#(virtual spi_if)::set(null, "*.env.m_spi_agent*", "vif", spi_host_if);
uvm_config_db#(virtual clk_rst_if)::set(
null, "*.env", "clk_rst_vif_rv_dm_debug_mem_reg_block", cpu_clk_rst_if);
uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent_rv_dm*", "vif", dmi_tbd_if);
// foreach (alert_if[i]) begin
// uvm_config_db#(virtual alert_esc_if)::set(null, $sformatf("*.env.m_alert_agent_%0s",
// LIST_OF_ALERTS[i]), "vif", alert_if[i]);
// end
end
// Helper methods.
// Verifies an LC control signal broadcast by the LC controller.
function automatic void check_lc_ctrl_enable_signal(lc_ctrl_signal_e signal, bit expected_value);
lc_ctrl_pkg::lc_tx_t value;
case (signal)
LcCtrlSignalDftEn: value = `LC_CTRL_HIER.lc_dft_en_o;
LcCtrlSignalNvmDebugEn: value = `LC_CTRL_HIER.lc_nvm_debug_en_o;
LcCtrlSignalHwDebugEn: value = `LC_CTRL_HIER.lc_hw_debug_en_o;
LcCtrlSignalCpuEn: value = `LC_CTRL_HIER.lc_cpu_en_o;
LcCtrlSignalCreatorSeedEn: value = `LC_CTRL_HIER.lc_creator_seed_sw_rw_en_o;
LcCtrlSignalOwnerSeedEn: value = `LC_CTRL_HIER.lc_owner_seed_sw_rw_en_o;
LcCtrlSignalIsoRdEn: value = `LC_CTRL_HIER.lc_iso_part_sw_rd_en_o;
LcCtrlSignalIsoWrEn: value = `LC_CTRL_HIER.lc_iso_part_sw_wr_en_o;
LcCtrlSignalSeedRdEn: value = `LC_CTRL_HIER.lc_seed_hw_rd_en_o;
LcCtrlSignalKeyMgrEn: value = `LC_CTRL_HIER.lc_keymgr_en_o;
LcCtrlSignalEscEn: value = `LC_CTRL_HIER.lc_escalate_en_o;
LcCtrlSignalCheckBypEn: value = `LC_CTRL_HIER.lc_check_byp_en_o;
default: `uvm_fatal(MsgId, $sformatf("Bad choice: %0s", signal.name()))
endcase
if (expected_value ~^ (value == lc_ctrl_pkg::On)) begin
`uvm_info(MsgId, $sformatf("LC control signal %0s: value = %0s matched",
signal.name(), value.name()), UVM_HIGH)
end else begin
`uvm_error(MsgId, $sformatf("LC control signal %0s: value = %0s mismatched",
signal.name(), value.name()))
end
endfunction
// Verifies all LC control signals broadcast by the LC controller.
function automatic void check_lc_ctrl_all_enable_signals(
bit [LcCtrlSignalNumTotal-1:0] expected_values);
foreach (expected_values[i]) begin
check_lc_ctrl_enable_signal(lc_ctrl_signal_e'(i), expected_values[i]);
end
endfunction
// Returns string path to an IP block instance.
function automatic string get_hier_path(chip_peripheral_e peripheral, int inst_num = 0);
string path = dv_utils_pkg::get_parent_hier($sformatf("%m"));
case (peripheral)
AdcCtrl: path = {path, ".", `DV_STRINGIFY(`ADC_CTRL_HIER)};
Aes: path = {path, ".", `DV_STRINGIFY(`AES_HIER)};
AlertHandler: path = {path, ".", `DV_STRINGIFY(`ALERT_HANDLER_HIER)};
AonTimer: path = {path, ".", `DV_STRINGIFY(`AON_TIMER_HIER)};
Ast: path = {path, ".", `DV_STRINGIFY(`AST_HIER)};
Clkmgr: path = {path, ".", `DV_STRINGIFY(`CLKMGR_HIER)};
Csrng: path = {path, ".", `DV_STRINGIFY(`CSRNG_HIER)};
Edn: path = {path, ".", `DV_STRINGIFY(`EDN_HIER()), $sformatf(inst_num)};
EntropySrc: path = {path, ".", `DV_STRINGIFY(`ENTROPY_SRC_HIER)};
FlashCtrl: path = {path, ".", `DV_STRINGIFY(`FLASH_CTRL_HIER)};
Gpio: path = {path, ".", `DV_STRINGIFY(`GPIO_HIER)};
Hmac: path = {path, ".", `DV_STRINGIFY(`HMAC_HIER)};
I2c: path = {path, ".", `DV_STRINGIFY(`I2C_HIER()), $sformatf(inst_num)};
Keymgr: path = {path, ".", `DV_STRINGIFY(`KEYMGR_HIER)};
Kmac: path = {path, ".", `DV_STRINGIFY(`KMAC_HIER)};
LcCtrl: path = {path, ".", `DV_STRINGIFY(`LC_CTRL_HIER)};
Otbn: path = {path, ".", `DV_STRINGIFY(`OTBN_HIER)};
OtpCtrl: path = {path, ".", `DV_STRINGIFY(`OTP_CTRL_HIER)};
SramCtrlMain: path = {path, ".", `DV_STRINGIFY(`SRAM_CTRL_MAIN_HIER)};
SramCtrlRet: path = {path, ".", `DV_STRINGIFY(`SRAM_CTRL_RET_HIER)};
Pattgen: path = {path, ".", `DV_STRINGIFY(`PATTGEN_HIER)};
Pinmux: path = {path, ".", `DV_STRINGIFY(`PINMUX_HIER)};
Pwrmgr: path = {path, ".", `DV_STRINGIFY(`PWRMGR_HIER)};
Pwm: path = {path, ".", `DV_STRINGIFY(`PWM_HIER)};
RomCrl: path = {path, ".", `DV_STRINGIFY(`ROM_CTRL_HIER)};
RstMgr: path = {path, ".", `DV_STRINGIFY(`RSTMGR_HIER)};
RvDm: path = {path, ".", `DV_STRINGIFY(`RV_DM_HIER)};
RvTimer: path = {path, ".", `DV_STRINGIFY(`RV_TIMER_HIER)};
SpiDevice: path = {path, ".", `DV_STRINGIFY(`SPI_DEVICE_HIER)};
SpiHost: path = {path, ".", `DV_STRINGIFY(`SPI_HOST_HIER()), $sformatf(inst_num)};
SysRstCtrl: path = {path, ".", `DV_STRINGIFY(`SYSRST_CTRL_HIER)};
Uart: path = {path, ".", `DV_STRINGIFY(`UART_HIER()), $sformatf(inst_num)};
UsbDev: path = {path, ".", `DV_STRINGIFY(`USBDEV_HIER)};
default: `uvm_fatal(MsgId, $sformatf("Bad peripheral: %0s", peripheral.name()))
endcase
return path;
endfunction
/*
* Helper methods for forcing internal signals.
*
* The macros invoked below create a static function to sample / force / release an internal
* signal. Please see definition in `hw/dv/sv/dv_utils/dv_macros.svh` for more details.
*/
// Signal probe function for LC program error signal in OTP ctrl.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_otp_ctrl_lc_err_o,
`OTP_CTRL_HIER.u_otp_ctrl_lci.lc_err_o)
// Signal probe function for wait cycle mask in alert handler.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_alert_handler_ping_timer_wait_cyc_mask_i,
`ALERT_HANDLER_HIER.u_ping_timer.wait_cyc_mask_i)
// Signal probe function for keymgr key state.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_keymgr_key_state,
`KEYMGR_HIER.u_ctrl.key_state_q)
// Signal probe function for RX idle detection in usbdev.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_usbdev_rx_idle_det_o,
`USBDEV_HIER.usbdev_impl.u_usb_fs_nb_pe.u_usb_fs_rx.rx_idle_det_o)
// Signal probe function for se0 signal in usbdev.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_usbdev_se0,
`USBDEV_HIER.usbdev_impl.u_usbdev_linkstate.line_se0_raw)
// Signal probe function for link reset signal in usbdev.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_usbdev_link_reset_o,
`USBDEV_HIER.usbdev_impl.u_usbdev_linkstate.link_reset_o)
// Signal probe function for SOF valid signal in usbdev.
`DV_CREATE_SIGNAL_PROBE_FUNCTION(signal_probe_usbdev_sof_valid_o,
`USBDEV_HIER.usbdev_impl.u_usb_fs_nb_pe.sof_valid_o)
`undef TOP_HIER
`undef ADC_CTRL_HIER
`undef AES_HIER
`undef ALERT_HANDLER_HIER
`undef AON_TIMER_HIER
`undef AST_HIER
`undef CLKMGR_HIER
`undef CPU_HIER
`undef CPU_CORE_HIER
`undef CPU_TL_ADAPT_D_HIER
`undef CSRNG_HIER
`undef ENTROPY_SRC_HIER
`undef EDN_HIER
`undef FLASH_CTRL_HIER
`undef GPIO_HIER
`undef HMAC_HIER
`undef I2C_HIER
`undef KMAC_HIER
`undef KEYMGR_HIER
`undef LC_CTRL_HIER
`undef OTP_CTRL_HIER
`undef OTBN_HIER
`undef PATTGEN_HIER
`undef PINMUX_HIER
`undef PWM_HIER
`undef PWRMGR_HIER
`undef ROM_CTRL_HIER
`undef RSTMGR_HIER
`undef RV_DM_HIER
`undef RV_TIMER_HIER
`undef SENSOR_CTRL_HIER
`undef SPI_DEVICE_HIER
`undef SPI_HOST_HIER
`undef SRAM_CTRL_MAIN_HIER
`undef SRAM_CTRL_RET_HIER
`undef SYSRST_CTRL_HIER
`undef UART_HIER
`undef USBDEV_HIER
endinterface