blob: 7e62783c36c8168c0d46283e53061ca22f1d8417 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This sequence accesses the rv_dm mem interface via JTAG and the TL-UL bus with randomly
// backdoor-loaded LC state. If the LC state gates the rv_dm mem interface (via lc_debug_en), we
// are expecting to see a d_error on the TL-UL bus and on JTAG we expect a read-write test to an RW
// reg to fail.
//
// Note that although this sequence runs in stub CPU mode, it still backdoor loads a valid ROM image
// so that the ROM check can complete successfully. This is needed since the TAP straps are
// currently sampled after the ROM check succeeds.
//
// TODO(#15624): the ROM dependency can be removed once the pwrmgr FSM has been simplified (due
// to the reset domain reorg). The strap sampling pulse will then be issued earlier, before the ROM
// check is performed.
class chip_rv_dm_lc_disabled_vseq extends chip_stub_cpu_base_vseq;
`uvm_object_utils(chip_rv_dm_lc_disabled_vseq)
`uvm_object_new
jtag_dmi_reg_block jtag_dmi_ral;
rand lc_state_e lc_state;
constraint num_trans_c {
num_trans inside {[5:10]};
}
// Add constraint to avoid lc_escalate_en being broadcasted and causes fatal alerts.
constraint lc_state_c {
lc_state != LcStScrap;
}
virtual function void set_handles();
super.set_handles();
jtag_dmi_ral = cfg.jtag_dmi_ral;
endfunction
virtual task pre_start();
// Select RV_DM TAP via the TAP straps.
cfg.chip_vif.tap_straps_if.drive(JtagTapRvDm);
super.pre_start();
max_outstanding_accesses = 1;
endtask
virtual task apply_reset(string kind = "HARD");
fork
if (kind inside {"HARD", "TRST"}) begin
jtag_dmi_ral.reset("HARD");
end
super.apply_reset(kind);
join
endtask
virtual task dut_init(string reset_kind = "HARD");
super.dut_init(reset_kind);
`uvm_info(`gfn, $sformatf("DUT Init with lc_state %0s", lc_state.name), UVM_LOW)
// TODO(#15624): remove this part later.
// We already wait for the ROM check to complete in the post_apply_reset sequence of
// chip_stub_cpu_base_vseq. However, we need to wait a few additional cycles here since
// the strap sampling pulse is released a few cycles after the ROM check completes.
cfg.clk_rst_vif.wait_clks(100);
`uvm_info(`gfn, "Attempt to activate RV_DM via JTAG.", UVM_MEDIUM)
// RV_DM needs to be activated for the registers to work properly.
// We always attempt to write this via the JTAG - even in states where the RV_DM is locked
// so that incorrect gating behavior is not masked by the RV_DM being disabled.
csr_wr(.ptr(jtag_dmi_ral.dmcontrol.dmactive), .value(1), .blocking(1), .predict(1));
cfg.clk_rst_vif.wait_clks(5);
endtask
virtual function void backdoor_override_otp();
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(lc_state)
cfg.mem_bkdr_util_h[Otp].otp_write_lc_partition_state(lc_state);
endfunction
virtual function void initialize_otp_sig_verify();
backdoor_override_otp();
super.initialize_otp_sig_verify();
endfunction
// Returns true if the RV_DM is accessible in a certain life cycle state.
virtual function bit allow_rv_dm_access();
if (lc_state inside {LcStTestUnlocked0, LcStTestUnlocked1, LcStTestUnlocked2,
LcStTestUnlocked3, LcStTestUnlocked4, LcStTestUnlocked5, LcStTestUnlocked6,
LcStTestUnlocked7, LcStRma, LcStDev}) begin
return 1;
end else begin
return 0;
end
endfunction
// Access check via JTAG.
virtual task rv_dm_jtag_access_check(bit gated);
uvm_reg_data_t wdata = $urandom();
uvm_reg_data_t exp_data, rdata;
// Write a random 32bit value to the sbaddress0 register.
csr_wr(.ptr(jtag_dmi_ral.sbaddress0), .value(wdata), .blocking(1), .predict(~gated));
cfg.clk_rst_vif.wait_clks(5);
// Expected readback data is all-zero if the JTAG interface is gated.
exp_data = gated ? '0 : wdata;
`uvm_info(`gfn, $sformatf("RV_DM sbaddress0 write data %0h, expected readback data %0h",
wdata, exp_data), UVM_HIGH)
// Read back and compare
csr_rd(.ptr(jtag_dmi_ral.sbaddress0), .value(rdata), .blocking(1));
`DV_CHECK_EQ(rdata, exp_data, $sformatf(
"RV_DM sbaddress0 read back check failed, got 0x%x, expected 0x%x",
rdata, exp_data))
cfg.clk_rst_vif.wait_clks(5);
endtask
// Access check via TL-UL bus.
virtual task rw_csr_addr_with_gating(uvm_reg csr, bit gated);
dv_base_reg dv_reg;
dv_base_reg_field flds[$];
bit [TL_AW-1:0] addr = csr.get_address();
bit [TL_DW-1:0] data = $urandom();
`downcast(dv_reg, csr)
dv_reg.get_dv_base_reg_fields(flds);
if (flds[0].get_access() inside {"RW", "WO"}) begin
`uvm_info(`gfn, $sformatf("Write addr %0h, write adata %0h, exp error %0d",
addr, data, gated), UVM_HIGH);
tl_access(.addr(addr), .write(1), .data(data), .exp_err_rsp(gated));
end
// Most RV_DM registers cannot be predicted correctly.
// We hence only check whether the accesses below error out or not.
// In case of an error, the data read back must be all ones.
if (flds[0].get_access() inside {"RW", "RO"}) begin
`uvm_info(`gfn, $sformatf("Read addr %0h, exp error %0d",
addr, gated), UVM_HIGH);
tl_access(.addr(addr), .write(0), .data(data), .exp_err_rsp(gated), .exp_data('1),
.check_exp_data(gated));
end
endtask
virtual task rand_rw_regs(uvm_reg regs[$], bit gated);
`DV_CHECK_NE(regs.size(), 0)
regs.shuffle();
foreach (regs[i]) rw_csr_addr_with_gating(regs[i], gated);
endtask
virtual task body();
for (int trans_i = 1; trans_i <= num_trans; trans_i++) begin
uvm_reg rv_dm_mem_regs[$];
// Re-randomize the life cycle state in most iterations.
if (trans_i > 1 && $urandom_range(0, 4)) dut_init();
`uvm_info(`gfn, $sformatf("Run iterations %0d/%0d with lc_state %0s", trans_i, num_trans,
lc_state.name), UVM_LOW)
// Check the RV_DM gating via JTAG. Since the serial JTAG interface wires are gated with the
// lc_dft_en signal, it is sufficient to check an RW'able register to verify whether the
// gating works or not.
if ($urandom_range(0, 1)) begin
rv_dm_jtag_access_check(~allow_rv_dm_access());
end
// Check RV_DM gating via the TL-UL bus.
if ($urandom_range(0, 1)) begin
ral.rv_dm_mem.get_registers(rv_dm_mem_regs);
rand_rw_regs(rv_dm_mem_regs, ~allow_rv_dm_access());
end
end
endtask : body
endclass