blob: 8b166057c2964a3f1bd07a1d889bbfb5e4b5944d [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Thoroughly test the pin mux and pad attribute controls.
class chip_padctrl_attributes_vseq extends chip_stub_cpu_base_vseq;
`uvm_object_utils(chip_padctrl_attributes_vseq)
`uvm_object_new
// Value to write for insel.
typedef enum {
InselZero,
InselOne,
InselPad
} insel_value_e;
// Value to write for outsel.
typedef enum {
OutselZero,
OutselOne,
OutselHighZ,
OutselPad
} outsel_value_e;
localparam prim_pad_wrapper_pkg::pad_type_e DioPadType[DioCount] = '{
prim_pad_wrapper_pkg::BidirStd, // DIO usbdev_usb_dp
prim_pad_wrapper_pkg::BidirStd, // DIO usbdev_usb_dn
prim_pad_wrapper_pkg::BidirStd, // DIO spi_host0_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_host0_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_host0_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_host0_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_device_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_device_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_device_sd
prim_pad_wrapper_pkg::BidirStd, // DIO spi_device_sd
prim_pad_wrapper_pkg::BidirOd, // DIO sysrst_ctrl_aon_ec_rst_l
prim_pad_wrapper_pkg::BidirOd, // DIO sysrst_ctrl_aon_flash_wp_l
prim_pad_wrapper_pkg::InputStd, // DIO spi_device_sck
prim_pad_wrapper_pkg::InputStd, // DIO spi_device_csb
prim_pad_wrapper_pkg::BidirStd, // DIO spi_host0_sck
prim_pad_wrapper_pkg::BidirStd // DIO spi_host0_csb
};
int dio_input_pads[$];
// For pad attributes testing.
//
// The following attributes are not supported:
// - od_en
// - slew_rate
// - schmitt_en
// - keep_en
// - drive_strength[3:1]
//
// The following attributes are supported for bi-directional pads:
// - invert
// - drive_strength[0] (0: pull, 1: strong)
// - virt_od_en
// - pull_en (0: hiz, 1: weak)
// - pull_select
//
// The following attributes are supported for input-only pads:
// - invert
rand prim_pad_wrapper_pkg::pad_attr_t mio_pad_attr[MioPadCount];
rand prim_pad_wrapper_pkg::pad_attr_t dio_pad_attr[DioCount];
// For MIO pinmux testing.
//
// Driving out of the chip:
// There are MioOutCount signals that can be driven to MioPadCount number of MIO pads. There are
// thus, MioPadCount number of outsel registers. Randomly pick MioPadCount number of signals and
// map them onto each pad in the outsel direction.
rand logic [MioOutCount-1:0] periph_to_mio;
rand logic [MioOutCount-1:0] periph_to_mio_oe;
rand mio_out_e periph_to_mio_map[MioPadCount];
rand outsel_value_e outsel_value_kind[MioPadCount];
constraint periph_to_mio_oe_c {
// Favor oe = 1 over 0 70% of the time.
foreach (periph_to_mio_oe[i]) {
periph_to_mio_oe[i] dist {1 :/ 7, 0 :/ 3};
}
}
constraint periph_to_mio_pad_map_c {
unique {periph_to_mio_map};
foreach (periph_to_mio_map[i]) {
periph_to_mio_map[i] != MioOutCount;
}
}
constraint outsel_value_kind_c {
solve mio_pad_attr before outsel_value_kind;
foreach (outsel_value_kind[i]) {
outsel_value_kind[i] dist {OutselZero :/ 1, OutselOne :/ 2, OutselHighZ :/ 2, OutselPad :/ 5};
// Pick Hi-Z only if pull_en is asserted. Otherwise, assertion errors may get thrown.
if (!mio_pad_attr[i].pull_en) outsel_value_kind[i] != OutselHighZ;
}
}
// Driving into the chip:
//
// There are MioPadCount pads that can be driven externally and forwarded to any of the
// MioInCount core/peripheral facing signals inside the chip. Randomly map the pads to each
// peripheral input. Pads may be duplicated to more than one peripheral input.
rand logic [MioPadCount-1:0] mio_to_periph;
rand logic [MioPadCount-1:0] mio_to_periph_oe;
rand mio_pad_e mio_to_periph_map[MioInCount];
rand insel_value_e insel_value_kind[MioInCount];
constraint mio_to_periph_oe_c {
solve mio_pad_attr before mio_to_periph_oe;
// Favor oe = 1 over 0 70% of the time, but only if pull is enabled (so that the peripherals do
// not see Xs).
foreach (mio_to_periph_oe[i]) {
if (mio_pad_attr[i].pull_en) {
mio_to_periph_oe[i] dist {1 :/ 7, 0 :/ 3};
} else {
mio_to_periph_oe[i] == 1;
}
}
}
constraint mio_to_periph_map_c {
foreach (mio_to_periph_map[i]) {
mio_to_periph_map[i] != MioPadCount;
}
}
constraint insel_value_kind_c {
foreach (insel_value_kind[i]) {
insel_value_kind[i] dist {InselZero :/ 2, InselOne :/ 2, InselPad :/ 6};
}
}
// For DIO pinmux testing.
//
// Pads are either analog, input only or bidirectional. For bdirectional, only drive either the
// pad or the periph input. If none are driven, then on the pull. For input only, drive the periph
// randomly - it should have no effect.
rand logic [DioCount-1:0] dio_to_periph;
rand logic [DioCount-1:0] dio_to_periph_oe;
rand logic [DioCount-1:0] periph_to_dio;
rand logic [DioCount-1:0] periph_to_dio_oe;
// Either only drive the pad or the periph input for bidirectional pads.
constraint periph_to_dio_oe_c {
solve dio_pad_attr before dio_to_periph_oe;
solve dio_pad_attr before periph_to_dio_oe;
solve dio_to_periph_oe before periph_to_dio_oe;
foreach (periph_to_dio_oe[i]) {
if (DioPadType[i] != prim_pad_wrapper_pkg::InputStd) {
if (dio_pad_attr[i].pull_en) {
!(dio_to_periph_oe[i] && periph_to_dio_oe[i]);
} else {
dio_to_periph_oe[i] ^ periph_to_dio_oe[i];
}
} else {
if (!dio_pad_attr[i].pull_en) {
dio_to_periph_oe[i] == 1;
}
}
}
}
virtual task body();
// The chip_padctrl_attributes test verifies the input / output connections of the pads to
// peripherals and fully verifies all pad attributes. In doing so, Xs may end up propagating
// into the peripheral. We hence, disable SVAs in these blocks while the test is running.
cfg.chip_vif.chip_padctrl_attributes_test_sva_disable = 1;
// TODO: remove later, once default pulls on straps are refactored.
cfg.chip_vif.tap_straps_if.disconnect();
// TODO: remove later, once default pulls on JTAG IOs are refactored.
cfg.chip_vif.mios_if.disconnect();
foreach (DioPadType[i]) begin
if (DioPadType[i] == prim_pad_wrapper_pkg::InputStd) dio_input_pads.push_back(i);
end
fork
begin : mio_test
pinmux_mio_outsel_test();
cfg.chip_vif.io_div4_clk_rst_if.wait_clks($urandom_range(1, 20));
pinmux_mio_outsel_reset();
pinmux_mio_insel_test();
cfg.chip_vif.io_div4_clk_rst_if.wait_clks($urandom_range(1, 20));
pinmux_mio_insel_reset();
end : mio_test
begin : dio_test
bit enable_spi_host_save = cfg.chip_vif.enable_spi_host;
cfg.chip_vif.cfg_default_weak_pulls_on_dios(0);
cfg.chip_vif.enable_spi_host = 0;
pinmux_dio_test();
cfg.chip_vif.enable_spi_host = enable_spi_host_save;
cfg.chip_vif.dios_if.disconnect();
cfg.chip_vif.cfg_default_weak_pulls_on_dios(1);
end : dio_test
// TODO: Test the "manual" DIO pads as well.
join
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_mio_oe_i(SignalProbeRelease));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_mio_i(SignalProbeRelease));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_dio_oe_i(SignalProbeRelease));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_dio_i_11_0(SignalProbeRelease));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_dio_i_15_14(SignalProbeRelease));
cfg.chip_vif.mios_if.disconnect();
// Reset the DUT before reenabling the assertions.
dut_init();
cfg.chip_vif.chip_padctrl_attributes_test_sva_disable = 0;
endtask : body
// Test the pinmux outsel functionality with pad attributes.
task pinmux_mio_outsel_test();
int iterations;
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(iterations, iterations inside {[5:20]};)
for (int i = 1; i <= iterations; i++) begin
`uvm_info(`gfn, $sformatf("pinmux_outsel_test %0d/%0d", i, iterations), UVM_LOW)
pinmux_mio_pad_attr_config();
pinmux_mio_outsel_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_mio_oe)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_mio)
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_mio_oe_i(SignalProbeForce,
periph_to_mio_oe));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_mio_i(SignalProbeForce, periph_to_mio));
repeat ($urandom_range(4, 20)) begin
cfg.chip_vif.io_div4_clk_rst_if.wait_clks($urandom_range(1, 20));
randcase
1: begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_mio_oe)
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_mio_oe_i(SignalProbeForce,
periph_to_mio_oe));
end
1: begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_mio)
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_mio_i(SignalProbeForce, periph_to_mio));
end
endcase
cfg.chip_vif.io_div4_clk_rst_if.wait_clks(1);
pinmux_mio_outsel_checks();
end
end
// Restore the MIO pad attributes to default.
pinmux_mio_pad_attr_reset();
endtask
// Program the MIO pad attr registers based on the values randomized.
task pinmux_mio_pad_attr_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(mio_pad_attr)
for (int i = 0; i < MioPadCount; i++) begin
uvm_reg_data_t value = '0;
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].invert, value,
mio_pad_attr[i].invert);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].virtual_od_en, value,
mio_pad_attr[i].virt_od_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].pull_en, value,
mio_pad_attr[i].pull_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].pull_select, value,
mio_pad_attr[i].pull_select);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].keeper_en, value,
mio_pad_attr[i].keep_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].schmitt_en, value,
mio_pad_attr[i].schmitt_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].od_en, value,
mio_pad_attr[i].od_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].slew_rate, value,
mio_pad_attr[i].slew_rate);
value = get_csr_val_with_updated_field(ral.pinmux_aon.mio_pad_attr[i].drive_strength, value,
mio_pad_attr[i].drive_strength);
`uvm_info(`gfn, $sformatf("%0d: mio_pad_attr = %0p / 0x%0h", i, mio_pad_attr[i], value),
UVM_LOW)
csr_wr(.ptr(ral.pinmux_aon.mio_pad_attr[i]), .value(value), .blocking(1), .predict(1));
end
endtask
// Reset the MIO pad attr registers.
task pinmux_mio_pad_attr_reset();
for (int i = 0; i < MioPadCount; i++) begin
uvm_reg_data_t value = ral.pinmux_aon.mio_pad_attr[i].get_reset();
csr_wr(.ptr(ral.pinmux_aon.mio_pad_attr[i]), .value(value), .blocking(1), .predict(1));
end
endtask
// Program the MIO outsel registers based on the values randomized.
task pinmux_mio_outsel_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_mio_map)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(outsel_value_kind)
for (int i = 0; i < MioPadCount; i++) begin
uvm_reg_data_t value = int'(outsel_value_kind[i]);
if (outsel_value_kind[i] == OutselPad) begin
value += periph_to_mio_map[i];
end
`uvm_info(`gfn, $sformatf("%0d: outsel_value_kind = %0s, periph_to_mio_map = %0s",
i, outsel_value_kind[i].name(), periph_to_mio_map[i].name()),
UVM_LOW)
csr_wr(.ptr(ral.pinmux_aon.mio_outsel[i].out), .value(value), .blocking(1), .predict(1));
end
endtask
// Reset the MIO outsel registers.
task pinmux_mio_outsel_reset();
for (int i = 0; i < MioPadCount; i++) begin
uvm_reg_data_t value = ral.pinmux_aon.mio_outsel[i].out.get_reset();
csr_wr(.ptr(ral.pinmux_aon.mio_outsel[i].out), .value(value), .blocking(1), .predict(1));
end
endtask
// Verifies the MIO pad value against the periph out value for the outsel test.
function void pinmux_mio_outsel_checks();
for (int i = 0; i < MioPadCount; i++) begin
string msg = $sformatf("on MIO[%0d]", i);
logic exp_oe, exp_out;
string exp_strength, obs_strength;
case (outsel_value_kind[i])
OutselZero: begin
exp_out = 0;
exp_oe = 1;
end
OutselOne: begin
exp_out = 1;
exp_oe = 1;
end
OutselHighZ: begin
exp_out = 0;
exp_oe = 0;
end
OutselPad: begin
exp_out = periph_to_mio[periph_to_mio_map[i]];
exp_oe = periph_to_mio_oe[periph_to_mio_map[i]];
end
default: ;
endcase
if (mio_pad_attr[i].invert && exp_out !== 1'bz && exp_oe) exp_out = ~exp_out;
// If virtual open drain is enabled, then the pad is driven to 0 if out is 0, else hi-z.
if (mio_pad_attr[i].virt_od_en && exp_out && exp_oe) exp_oe = 0;
obs_strength = $sformatf("%v", cfg.chip_vif.mios_if.pins[i]);
if (exp_oe && exp_out !== 1'bz) begin
exp_strength = {mio_pad_attr[i].drive_strength[0] ? "St" : "Pu", $sformatf("%0d", exp_out)};
`DV_CHECK_EQ(exp_out, cfg.chip_vif.mios_if.pins[i], msg)
// TODO: this check fails; address later: `DV_CHECK_STREQ(exp_strength, obs_strength, msg)
end else begin
if (mio_pad_attr[i].pull_en) begin
exp_strength = $sformatf("We%0d", mio_pad_attr[i].pull_select);
`DV_CHECK_EQ(mio_pad_attr[i].pull_select, cfg.chip_vif.mios_if.pins[i], msg)
// TODO: this check fails; address later: `DV_CHECK_STREQ(exp_strength, obs_strength, msg)
end else begin
`DV_CHECK_CASE_EQ(cfg.chip_vif.mios_if.pins[i], 1'bz, msg)
`DV_CHECK_STREQ(obs_strength, "HiZ", msg)
end
end
end
endfunction
// Test the pinmux insel functionality with pad attributes.
task pinmux_mio_insel_test();
int iterations;
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(iterations, iterations inside {[5:20]};)
for (int i = 1; i <= iterations; i++) begin
`uvm_info(`gfn, $sformatf("pinmux_insel_test %0d/%0d", i, iterations), UVM_LOW)
pinmux_mio_pad_attr_config();
pinmux_mio_insel_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(mio_to_periph_oe)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(mio_to_periph)
cfg.chip_vif.mios_if.pins_oe = mio_to_periph_oe;
cfg.chip_vif.mios_if.pins_o = mio_to_periph;
repeat ($urandom_range(4, 20)) begin
cfg.chip_vif.io_div4_clk_rst_if.wait_clks($urandom_range(1, 20));
randcase
1: begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(mio_to_periph)
cfg.chip_vif.mios_if.pins_o = mio_to_periph;
end
1: begin
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(mio_to_periph_oe)
cfg.chip_vif.mios_if.pins_oe = mio_to_periph_oe;
end
endcase
cfg.chip_vif.io_div4_clk_rst_if.wait_clks(1);
pinmux_mio_insel_checks();
end
end
// Restore the MIO pad attributes to default.
pinmux_mio_pad_attr_reset();
endtask
// Program the MIO insel registers based on the values randomized.
task pinmux_mio_insel_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(mio_to_periph_map)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(insel_value_kind)
for (int i = 0; i < MioInCount; i++) begin
uvm_reg_data_t value = int'(insel_value_kind[i]);
if (insel_value_kind[i] == InselPad) begin
value += mio_to_periph_map[i];
end
`uvm_info(`gfn, $sformatf("%0d: insel_value_kind = %0s, mio_to_periph_map = %0s",
i, insel_value_kind[i].name(), mio_to_periph_map[i].name()),
UVM_LOW)
csr_wr(.ptr(ral.pinmux_aon.mio_periph_insel[i].in), .value(value), .blocking(1), .predict(1));
end
endtask
// Reset the MIO insel registers.
task pinmux_mio_insel_reset();
for (int i = 0; i < MioInCount; i++) begin
uvm_reg_data_t value = ral.pinmux_aon.mio_periph_insel[i].in.get_reset();
csr_wr(.ptr(ral.pinmux_aon.mio_periph_insel[i].in), .value(value), .blocking(1), .predict(1));
end
endtask
// Verifies the MIO periph value against the pad input value for the insel test.
function void pinmux_mio_insel_checks();
for (int i = 0; i < MioInCount; i++) begin
string msg = $sformatf("on MIO_IN[%0d]", i);
mio_pad_e pad = mio_to_periph_map[i];
logic act_in, exp_in;
act_in = cfg.chip_vif.mio_to_periph[i];
case (insel_value_kind[i])
InselZero: exp_in = 0;
InselOne: exp_in = 1;
InselPad: begin
exp_in = cfg.chip_vif.mios_if.pins[pad];
if (mio_pad_attr[pad].invert && exp_in !== 1'bz) exp_in = ~exp_in;
if (exp_in === 1'bz && mio_pad_attr[i].pull_en) exp_in = mio_pad_attr[i].pull_select;
end
default: ;
endcase
`DV_CHECK_CASE_EQ(exp_in, act_in, msg)
end
endfunction
// Test the DIO pad attributes for both directions.
task pinmux_dio_test();
int iterations;
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(iterations, iterations inside {[5:20]};)
// Sanitize the inputs at the start of the test.
foreach (dio_to_periph_oe[i]) begin
if (DioPadType[i] == prim_pad_wrapper_pkg::InputStd) dio_to_periph_oe[i] = 1;
end
pinmux_dio_drive_inputs();
for (int i = 1; i <= iterations; i++) begin
`uvm_info(`gfn, $sformatf("pinmux_dio_test %0d/%0d", i, iterations), UVM_LOW)
pinmux_dio_pad_attr_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(dio_to_periph_oe)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_dio_oe)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(dio_to_periph)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_dio)
pinmux_dio_drive_inputs();
repeat ($urandom_range(4, 20)) begin
cfg.chip_vif.io_div4_clk_rst_if.wait_clks($urandom_range(1, 20));
randcase
1: `DV_CHECK_MEMBER_RANDOMIZE_FATAL(dio_to_periph)
1: `DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_dio)
1: `DV_CHECK_MEMBER_RANDOMIZE_FATAL(dio_to_periph_oe)
1: `DV_CHECK_MEMBER_RANDOMIZE_FATAL(periph_to_dio_oe)
endcase
pinmux_dio_drive_inputs();
cfg.chip_vif.io_div4_clk_rst_if.wait_clks(1);
pinmux_dio_insel_checks();
end
end
// Restore the DIO pad attributes to default.
pinmux_dio_pad_attr_reset();
endtask
// Program the DIO pad attr registers based on the values randomized.
task pinmux_dio_pad_attr_config();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(dio_pad_attr)
for (int i = 0; i < DioCount; i++) begin
uvm_reg_data_t value = '0;
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].invert, value,
dio_pad_attr[i].invert);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].virtual_od_en, value,
dio_pad_attr[i].virt_od_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].pull_en, value,
dio_pad_attr[i].pull_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].pull_select, value,
dio_pad_attr[i].pull_select);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].keeper_en, value,
dio_pad_attr[i].keep_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].schmitt_en, value,
dio_pad_attr[i].schmitt_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].od_en, value,
dio_pad_attr[i].od_en);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].slew_rate, value,
dio_pad_attr[i].slew_rate);
value = get_csr_val_with_updated_field(ral.pinmux_aon.dio_pad_attr[i].drive_strength, value,
dio_pad_attr[i].drive_strength);
`uvm_info(`gfn, $sformatf("%0d: dio_pad_attr = %0p / 0x%0h", i, dio_pad_attr[i], value),
UVM_LOW)
csr_wr(.ptr(ral.pinmux_aon.dio_pad_attr[i]), .value(value), .blocking(1), .predict(1));
end
endtask
function void pinmux_dio_drive_inputs();
cfg.chip_vif.dios_if.pins_oe = '0;
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_dio_i_11_0(SignalProbeForce,
periph_to_dio[11:0]));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_dio_i_15_14(SignalProbeForce,
periph_to_dio[15:14]));
void'(cfg.chip_vif.signal_probe_pinmux_periph_to_dio_oe_i(SignalProbeForce, periph_to_dio_oe));
for (int i = 0; i < DioCount; i++) begin
cfg.chip_vif.dios_if.pins_oe[DioToDioPadMap[i]] = dio_to_periph_oe[i];
cfg.chip_vif.dios_if.pins_o[DioToDioPadMap[i]] = dio_to_periph[i];
end
endfunction
// Reset the DIO pad attr registers.
task pinmux_dio_pad_attr_reset();
for (int i = 0; i < DioCount; i++) begin
uvm_reg_data_t value = ral.pinmux_aon.dio_pad_attr[i].get_reset();
csr_wr(.ptr(ral.pinmux_aon.dio_pad_attr[i]), .value(value), .blocking(1), .predict(1));
end
endtask
// Check both, the DIO pad and DIO periph value based on what is driven and the pad attributes.
function void pinmux_dio_insel_checks();
for (int i = 0; i < DioCount; i++) begin
string msg = $sformatf("on DIO[%0d]", i);
if (DioPadType[i] == prim_pad_wrapper_pkg::InputStd) begin
logic exp;
// periph_to_dio_oe / periph_to_dio_o have no effect.
if (dio_to_periph_oe[i]) exp = dio_to_periph[i];
else begin
`DV_CHECK(dio_pad_attr[i].pull_en)
exp = dio_pad_attr[i].pull_select;
end
if (dio_pad_attr[i].invert) exp = ~exp;
`DV_CHECK_CASE_EQ(exp, cfg.chip_vif.dio_to_periph[i], msg)
end else begin
logic exp, exp_in, exp_out;
case ({periph_to_dio_oe[i], dio_to_periph_oe[i]})
2'b00: begin
`DV_CHECK(dio_pad_attr[i].pull_en)
exp = dio_pad_attr[i].pull_select;
exp_in = exp;
exp_out = exp;
end
2'b01: begin
exp = dio_to_periph[i];
exp_in = exp;
exp_out = exp;
end
2'b10: begin
exp = periph_to_dio[i];
exp_out = exp;
if (dio_pad_attr[i].invert) exp_out = ~exp_out;
if (dio_pad_attr[i].virt_od_en && exp_out) exp_out = 1'bz;
if (exp_out === 1'bz && dio_pad_attr[i].pull_en) exp_out = dio_pad_attr[i].pull_select;
exp_in = exp_out;
if (exp_in === 1'bz) exp_in = 1'bx; // Undriven input treated as x.
end
2'b11: begin
`DV_CHECK_FATAL(0, "Tricky, unsupported stimulus")
continue;
end
default: ;
endcase
if (dio_pad_attr[i].invert) exp_in = ~exp_in;
`DV_CHECK_CASE_EQ(exp_in, cfg.chip_vif.dio_to_periph[i], msg)
`DV_CHECK_CASE_EQ(exp_out, cfg.chip_vif.dios_if.pins[DioToDioPadMap[i]], msg)
end
end
endfunction
task post_start();
// TODO: remove this hack that prevents base class' post_start from applying a reset.
cfg.use_jtag_dmi = 1;
super.post_start();
endtask
endclass