blob: d2e46cad315ea7922326bcdd63d07f1d8374b6e1 [file] [log] [blame]
// 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".
`define TOP_HIER top_earlgrey
`define ALERT_HANDLER_HIER `TOP_HIER.u_alert_handler
`define CPU_HIER `TOP_HIER.u_rv_core_ibex
`define LC_CTRL_HIER `TOP_HIER.u_lc_ctrl
`define PWM_HIER `TOP_HIER.u_pwm
`define RSTMGR_HIER `TOP_HIER.u_rstmgr_aon
`define USBDEV_HIER `TOP_HIER.u_usbdev
// Identifier for logs.
string MsgId = $sformatf("%m");
// 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 pad pin.
//
// All ios are weak-pulled by default. The test sequences disable the pull by "enabling" the IO
// functionality that is being tested.
initial begin
// Enable weak pulldown on most signals.
ios_if.pins_pd = '1;
ios_if.pins_pd[PorN] = 0;
ios_if.pins_pd[UsbP] = 0;
ios_if.pins_pd[IoR8] = 0;
ios_if.pins_pd[IoR9] = 0;
// Chip outputs.
ios_if.pins_pd[SpiHostCsL] = 0;
ios_if.pins_pd[SpiHostClk] = 0;
// These are weak pullups.
ios_if.pins_pu[PorN] = 1;
ios_if.pins_pu[UsbP] = 1;
ios_if.pins_pu[IoR8] = 1;
ios_if.pins_pu[IoR9] = 1;
ios_if.pins_pd[PorN] = 0;
end
// Unknown 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.
initial begin
foreach (ios[i]) begin
fork
forever @(ios[i]) begin
automatic int a_i = i;
automatic chip_io_e io = chip_io_e'(a_i);
`DV_CHECK_FATAL(ios[a_i] !== 1'bx,
$sformatf("Possible multiple drivers on chip IO %0s", io.name()), MsgId)
end
join_none
end
end
// 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:
//
// - Dedicated IOs with fixed direction (either input or output):
// - Create `logic` or equivalent data type signals to drive inputs / sample outputs.
//
// - Dedicated IOs that are bidirectional (inouts):
// - Create pins_if instance, since it internally has direction controls.
//
// - Muxed IOs:
// - Create pins_if instance, since it internally has direction controls.
//
// - 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.
//
// 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): POR_RST_N.
logic por_n;
assign ios[PorN] = por_n;
// Functional (dedicated) interface (inout): USB.
// TODO!
// Functional (dedicated) interface (input): CC1.
logic cc1;
assign ios[CC1] = cc1;
// Functional (dedicated) interface (input): CC2.
logic cc2;
assign ios[CC2] = cc2;
// Functional (dedicated) interface (analog input): flash test volt.
logic flash_test_volt;
assign ios[CC2] = flash_test_volt;
// Functional (dedicated) interface (input): flash test mode0.
logic flash_test_mode0;
assign ios[FlashTestMode0] = flash_test_mode0;
// Functional (dedicated) interface (input): flash test mode1.
logic flash_test_mode1;
assign ios[FlashTestMode1] = flash_test_mode1;
// Functional (dedicated) interface (analog input): OTP ext volt.
logic otp_ext_volt;
assign ios[OtpExtVolt] = otp_ext_volt;
// Functional (dedicated) interface: SPI host interface (drives traffic into the chip).
// spi_if spi_host_if(.rst_n(top_earlgrey.u_spi_device.rst_ni),
// .sck(ios[SpiDevClk]),
// .csb(ios[SpiDevCSL]),
// .sio(ios[SpiDevD3:SpiDevD0]));
// Functional (dedicated) interface: SPI AP device interface (receives traffic from the chip).
// spi_if spi_device_ap_if(.rst_n(top_earlgrey.u_spi_host0.rst_ni));
// assign spi_device_ap_if.csk = ios[SpiHostClk];
// assign spi_device_ap_if.csb = ios[SpiHostCsL];
// 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 (input): AST misc.
logic ast_misc;
assign ios[AstMisc] = ast_misc;
// Functional (muxed) interface: GPIOs.
//
// Note: The ChromeOS pinout uses fewer GPIO pins that what is assigned below.
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]})
);
// !!: Pins exclusively used by UART3 (AP) in ChromeOS, but treated as GPIOs for Enterprise.
// **: Pins exclusively used by UART2 in both, ChromeOS and Enterprise. However, UART2 is not
// active in all tests, so it is ok to connect them to GPIOs.
// Functional (muxed) interface: JTAG (valid during debug enabled LC state only).
logic enable_jtag, debug_enabled, jtag_enabled;
jtag_if jtag_if();
assign debug_enabled = (`LC_CTRL_HIER.lc_hw_debug_en_o == lc_ctrl_pkg::On);
assign jtag_enabled = enable_jtag && debug_enabled;
assign ios[IoR0] = jtag_enabled ? jtag_if.tms : 1'bz;
assign jtag_if.tdo = jtag_enabled ? ios[IoR1] : 1'bz;
assign ios[IoR2] = jtag_enabled ? jtag_if.tdi : 1'bz;
assign ios[IoR3] = jtag_enabled ? jtag_if.tck : 1'bz;
assign ios[IoR4] = jtag_enabled ? jtag_if.trst_n : 1'bz;
// Functional (muxed) interface: Flash controller JTAG.
logic enable_flash_ctrl_jtag, flash_ctrl_jtag_enabled;
jtag_if flash_ctrl_jtag_if();
assign flash_ctrl_jtag_enabled = enable_flash_ctrl_jtag && debug_enabled;
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: 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[IoC8], ios[IoC5]}));
// Functional (muxed) interface: SW straps.
pins_if #(3) sw_straps_if(.pins(ios[IoC2:IoC0]));
// 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) interfas2ace: 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: UARTs.
bit enable_uart[NUM_UARTS];
uart_if uart_if[NUM_UARTS-1:0]();
assign ios[IoC3] = enable_uart[0] ? uart_if[0].uart_rx : 1'bz;
assign uart_if[0].uart_tx = ios[IoC4];
assign ios[IoB4] = enable_uart[1] ? uart_if[1].uart_rx : 1'bz;
assign uart_if[1].uart_tx = ios[IoB5];
assign ios[IoA4] = enable_uart[2] ? uart_if[2].uart_rx : 1'bz;
assign uart_if[2].uart_tx = ios[IoA5];
assign ios[IoA0] = enable_uart[3] ? uart_if[3].uart_rx : 1'bz;
assign uart_if[3].uart_tx = ios[IoA1];
// Functional (muxed) interface: SPI EC device interface (receives traffic from the chip).
// spi_if spi_device_ec_if(.rst_n(top_earlgrey.u_spi_host1.rst_ni));
// assign spi_device_ec_if.csk = ios[IoB3];
// assign spi_device_ec_if.csb = ios[IoB0];
// assign spi_device_ec_if.sio[0] = ios[IoB1];
// assign ios[IoB2] = assign spi_device_ec_if.sio[1] : 1'bz;
// Functional (muxed) interface: I2Cs.
bit enable_i2c[NUM_I2CS];
// TODO: i2c_if i2c_if[NUM_I2CS-1:0]();
// Functional (muxed) interface: sysrst_ctrl.
// TODO: Replace with sysrst_ctrl IP level interface.
// pins_if #(8) sysrst_ctrl_if();
// Functional (muxed) interface: PWM.
// TODO: pwm_if pwm_if[NUM_PWM_CHANNELS-1:0](
// .clk(`PWM_HIER.clk_i),
// .rst_n(`PWM_HIER.rst_ni)
// );
// TODO: Use the GPIO ones instead.
// assign pwm_if[0].pwm = ios[IoB10];
// assign pwm_if[1].pwm = ios[IoB11];
// assign pwm_if[2].pwm = ios[IoB12];
// assign pwm_if[3].pwm = ios[IoC10];
// assign pwm_if[4].pwm = ios[IoB11];
// assign pwm_if[5].pwm = ios[IoB12];
// Functional (muxed) interface: external clock source.
wire unused;
clk_rst_if ext_clk_if(.clk(ios[IoC6]), .rst_n(unused));
// Internal monitors.
wire cpu_clk = `CPU_HIER.clk_i;
wire cpu_rst_n = `CPU_HIER.rst_ni;
wire alert_handler_clk = `ALERT_HANDLER_HIER.clk_i;
wire alert_handler_rst_n = `ALERT_HANDLER_HIER.rst_ni;
wire usb_clk = `USBDEV_HIER.clk_i;
wire usb_rst_n = `USBDEV_HIER.rst_ni;
// 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
// uvm_config_db#(virtual spi_if)::set(null, "*.env.m_spi_agent*", "vif", spi_host_if);
// uvm_config_db#(virtual jtag_if)::set(null, "*.env.m_jtag_riscv_agent*", "vif", jtag_if);
// foreach (uart_if[i]) begin
// uvm_config_db#(virtual uart_if)::set(null, $sformatf("*.env.m_uart_agent%0d*", i),
// "vif", uart_if[i]);
// end
// foreach (pwm_if[i]) 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[i]);
// end
// uvm_config_db#(virtual pins_if #(8))::set(null, "*.env", "sysrst_ctrl_vif", sysrst_ctrl_if);
end
`undef TOP_HIER
`undef ALERT_HANDLER_HIER
`undef CPU_HIER
`undef LC_CTRL_HIER
`undef PWM_HIER
`undef RSTMGR_HIER
`undef USBDEV_HIER
endinterface