-
Notifications
You must be signed in to change notification settings - Fork 781
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
otp_ctrl/dv] Add templates for some sequences
This just copies the old implementation without modifications except for the header comment, and escapes for newline continuations escaped as ${"\\"}. Signed-off-by: Guillermo Maturana <[email protected]>
- Loading branch information
1 parent
9100be2
commit 394e21a
Showing
7 changed files
with
998 additions
and
9 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright lowRISC contributors. | ||
// Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
${gen_comment} | ||
// otp_ctrl_dai_lock_vseq is developed to read/write lock DAI interface by partitions, and request | ||
// read/write access to check if correct status and error code is triggered | ||
|
||
// Partitoin's legal range covers offset to digest addresses, dai_rd/dai_wr function will | ||
// randomize the address based on the granularity. | ||
`define PART_ADDR_RANGE(i) ${"\\"} | ||
{[PartInfo[``i``].offset : (PartInfo[``i``].offset + PartInfo[``i``].size - 8)]} | ||
|
||
class otp_ctrl_dai_lock_vseq extends otp_ctrl_smoke_vseq; | ||
`uvm_object_utils(otp_ctrl_dai_lock_vseq) | ||
|
||
`uvm_object_new | ||
|
||
// enable access_err for each cycle | ||
constraint no_access_err_c {access_locked_parts == 1;} | ||
|
||
constraint num_trans_c { | ||
num_trans inside {[1:10]}; | ||
num_dai_op inside {[1:50]}; | ||
} | ||
|
||
constraint partition_index_c {part_idx inside {[VendorTestIdx:LifeCycleIdx]};} | ||
|
||
constraint dai_wr_legal_addr_c { | ||
if (part_idx == VendorTestIdx) dai_addr inside `PART_ADDR_RANGE(VendorTestIdx); | ||
if (part_idx == CreatorSwCfgIdx) dai_addr inside `PART_ADDR_RANGE(CreatorSwCfgIdx); | ||
if (part_idx == OwnerSwCfgIdx) dai_addr inside `PART_ADDR_RANGE(OwnerSwCfgIdx); | ||
if (part_idx == HwCfg0Idx) dai_addr inside `PART_ADDR_RANGE(HwCfg0Idx); | ||
if (part_idx == HwCfg1Idx) dai_addr inside `PART_ADDR_RANGE(HwCfg1Idx); | ||
if (part_idx == Secret0Idx) dai_addr inside `PART_ADDR_RANGE(Secret0Idx); | ||
if (part_idx == Secret1Idx) dai_addr inside `PART_ADDR_RANGE(Secret1Idx); | ||
if (part_idx == Secret2Idx) dai_addr inside `PART_ADDR_RANGE(Secret2Idx); | ||
if (part_idx == Secret3Idx) dai_addr inside `PART_ADDR_RANGE(Secret3Idx); | ||
if (part_idx == LifeCycleIdx) { | ||
if (write_unused_addr) { | ||
dai_addr inside {[PartInfo[LifeCycleIdx].offset : {OTP_ADDR_WIDTH{1'b1}}]}; | ||
} else { | ||
dai_addr inside `PART_ADDR_RANGE(LifeCycleIdx); | ||
} | ||
} | ||
solve part_idx before dai_addr; | ||
} | ||
constraint dai_wr_digests_c { | ||
{dai_addr[TL_AW-1:2], 2'b0} dist { | ||
{VendorTestDigestOffset, CreatorSwCfgDigestOffset, OwnerSwCfgDigestOffset, HwCfg0DigestOffset, | ||
HwCfg1DigestOffset, Secret0DigestOffset, Secret1DigestOffset, Secret2DigestOffset, | ||
Secret3DigestOffset} :/ 1, | ||
[VendorTestOffset : '1] :/ 9 | ||
}; | ||
} | ||
|
||
virtual task pre_start(); | ||
super.pre_start(); | ||
is_valid_dai_op = 0; | ||
endtask | ||
|
||
virtual task dut_init(string reset_kind = "HARD"); | ||
super.dut_init(reset_kind); | ||
if ($urandom_range(0, 1)) begin | ||
cfg.otp_ctrl_vif.drive_lc_creator_seed_sw_rw_en(get_rand_lc_tx_val(.t_weight(0))); | ||
end | ||
endtask | ||
|
||
endclass | ||
|
||
`undef PART_ADDR_RANGE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
// Copyright lowRISC contributors. | ||
// Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
${gen_comment} | ||
// smoke test vseq to walk through DAI states and request keys | ||
`define PART_CONTENT_RANGE(i) ${"\\"} | ||
{[PartInfo[``i``].offset : (PartInfo[``i``].offset + PartInfo[``i``].size - DIGEST_SIZE - 1)]} | ||
|
||
class otp_ctrl_smoke_vseq extends otp_ctrl_base_vseq; | ||
`uvm_object_utils(otp_ctrl_smoke_vseq) | ||
|
||
`uvm_object_new | ||
|
||
rand bit do_req_keys, do_lc_trans; | ||
rand bit access_locked_parts; | ||
rand bit rand_wr, rand_rd, rd_sw_tlul_rd; | ||
rand bit [TL_DW-1:0] dai_addr; | ||
rand bit [TL_DW-1:0] wdata0, wdata1; | ||
rand int num_dai_op; | ||
rand otp_ctrl_part_pkg::part_idx_e part_idx; | ||
rand bit check_regwen_val, check_trigger_regwen_val; | ||
rand bit [TL_DW-1:0] check_timeout_val; | ||
rand bit [1:0] check_trigger_val; | ||
rand otp_ecc_err_e ecc_otp_err, ecc_chk_err; | ||
|
||
constraint no_access_err_c {access_locked_parts == 0;} | ||
|
||
// LC partition does not allow DAI access | ||
constraint partition_index_c {part_idx inside {[VendorTestIdx:Secret3Idx]};} | ||
|
||
constraint dai_wr_legal_addr_c { | ||
if (part_idx == VendorTestIdx) dai_addr inside `PART_CONTENT_RANGE(VendorTestIdx); | ||
if (part_idx == CreatorSwCfgIdx) dai_addr inside `PART_CONTENT_RANGE(CreatorSwCfgIdx); | ||
if (part_idx == OwnerSwCfgIdx) dai_addr inside `PART_CONTENT_RANGE(OwnerSwCfgIdx); | ||
if (part_idx == HwCfg0Idx) dai_addr inside `PART_CONTENT_RANGE(HwCfg0Idx); | ||
if (part_idx == HwCfg1Idx) dai_addr inside `PART_CONTENT_RANGE(HwCfg1Idx); | ||
if (part_idx == Secret0Idx) dai_addr inside `PART_CONTENT_RANGE(Secret0Idx); | ||
if (part_idx == Secret1Idx) dai_addr inside `PART_CONTENT_RANGE(Secret1Idx); | ||
if (part_idx == Secret2Idx) dai_addr inside `PART_CONTENT_RANGE(Secret2Idx); | ||
if (part_idx == Secret3Idx) dai_addr inside `PART_CONTENT_RANGE(Secret3Idx); | ||
if (part_idx == LifeCycleIdx) dai_addr inside `PART_CONTENT_RANGE(LifeCycleIdx); | ||
solve part_idx before dai_addr; | ||
} | ||
|
||
constraint dai_wr_blank_addr_c { | ||
dai_addr % 4 == 0; | ||
if (PartInfo[part_idx].secret) dai_addr % 8 == 0; | ||
} | ||
|
||
constraint num_trans_c { | ||
if (cfg.smoke_test) { | ||
num_trans == 1; | ||
num_dai_op inside {[1:2]}; | ||
} else { | ||
num_trans inside {[1:2]}; | ||
num_dai_op inside {[1:50]}; | ||
} | ||
} | ||
|
||
constraint regwens_c { | ||
check_regwen_val dist {0 :/ 1, 1 :/ 9}; | ||
check_trigger_regwen_val dist {0 :/ 1, 1 :/ 9}; | ||
} | ||
|
||
constraint check_timeout_val_c { | ||
check_timeout_val inside {0, [100_000:'1]}; | ||
} | ||
constraint ecc_otp_err_c {ecc_otp_err == OtpNoEccErr;} | ||
constraint ecc_chk_err_c {ecc_chk_err == OtpNoEccErr;} | ||
constraint apply_reset_during_pwr_init_cycles_c { | ||
apply_reset_during_pwr_init_cycles dist { | ||
[1:5] :/ 4, | ||
[6:2000] :/ 4, | ||
[2001:4000] :/ 2}; | ||
} | ||
virtual task dut_init(string reset_kind = "HARD"); | ||
if (do_apply_reset) begin | ||
lc_prog_blocking = 1; | ||
super.dut_init(reset_kind); | ||
csr_wr(ral.intr_enable, en_intr); | ||
end | ||
endtask | ||
virtual task pre_start(); | ||
super.pre_start(); | ||
num_dai_op.rand_mode(0); | ||
check_lc_err(); | ||
endtask | ||
virtual task check_lc_err(); | ||
fork | ||
forever begin | ||
wait(cfg.otp_ctrl_vif.lc_prog_err == 1); | ||
lc_prog_blocking = 0; | ||
wait(lc_prog_blocking == 1); | ||
end | ||
join_none; | ||
endtask | ||
task body(); | ||
for (int i = 1; i <= num_trans; i++) begin | ||
bit [TL_DW-1:0] tlul_val; | ||
`uvm_info(`gfn, $sformatf("starting seq %0d/%0d", i, num_trans), UVM_LOW) | ||
// to avoid access locked OTP partions, issue reset and clear the OTP memory to all 0. | ||
if (access_locked_parts == 0) begin | ||
do_otp_ctrl_init = 1; | ||
if (i > 1 && do_dut_init) dut_init(); | ||
// after otp-init done, check status | ||
cfg.clk_rst_vif.wait_clks(1); | ||
if (!cfg.otp_ctrl_vif.lc_esc_on) begin | ||
csr_rd_check(.ptr(ral.status.dai_idle), .compare_value(1)); | ||
end | ||
end | ||
do_otp_ctrl_init = 0; | ||
`DV_CHECK_RANDOMIZE_FATAL(this) | ||
// set consistency and integrity checks | ||
csr_wr(ral.check_regwen, check_regwen_val); | ||
csr_wr(ral.check_trigger_regwen, check_trigger_regwen_val); | ||
csr_wr(ral.check_timeout, check_timeout_val); | ||
trigger_checks(.val(check_trigger_val), .wait_done(1), .ecc_err(ecc_chk_err)); | ||
if (!$urandom_range(0, 9) && access_locked_parts) write_sw_rd_locks(); | ||
// Backdoor write mubi to values that are not true or false. | ||
force_mubi_part_access(); | ||
if (do_req_keys && !cfg.otp_ctrl_vif.alert_reqs) begin | ||
req_otbn_key(); | ||
req_flash_addr_key(); | ||
req_flash_data_key(); | ||
req_all_sram_keys(); | ||
end | ||
if (do_lc_trans && !cfg.otp_ctrl_vif.alert_reqs) begin | ||
req_lc_transition(do_lc_trans, lc_prog_blocking); | ||
if (cfg.otp_ctrl_vif.lc_prog_req == 0) begin | ||
for (int k = 0; k <= LciIdx; k++) begin | ||
csr_rd(.ptr(ral.err_code[k]), .value(tlul_val)); | ||
end | ||
end | ||
end | ||
for (int i = 0; i < num_dai_op; i++) begin | ||
bit [TL_DW-1:0] rdata0, rdata1, backdoor_rd_val; | ||
`DV_CHECK_RANDOMIZE_FATAL(this) | ||
// recalculate part_idx in case some test turn off constraint dai_wr_legal_addr_c | ||
part_idx = part_idx_e'(get_part_index(dai_addr)); | ||
`uvm_info(`gfn, $sformatf("starting dai access seq %0d/%0d with addr %0h in partition %0d", | ||
i, num_dai_op, dai_addr, part_idx), UVM_HIGH) | ||
// OTP write via DAI | ||
if (rand_wr && !digest_calculated[part_idx]) begin | ||
dai_wr(dai_addr, wdata0, wdata1); | ||
if (cfg.otp_ctrl_vif.lc_prog_req == 0) begin | ||
for (int k = 0; k <= LciIdx; k++) begin | ||
csr_rd(.ptr(ral.err_code[k]), .value(tlul_val)); | ||
end | ||
end | ||
end | ||
// Inject ECC error. | ||
if (ecc_otp_err != OtpNoEccErr && dai_addr < LifeCycleOffset) begin | ||
backdoor_rd_val = backdoor_inject_ecc_err(dai_addr, ecc_otp_err); | ||
end | ||
if (rand_rd) begin | ||
// OTP read via DAI, check data in scb | ||
dai_rd(dai_addr, rdata0, rdata1); | ||
end | ||
// if write sw partitions, check tlul window | ||
if (is_sw_part(dai_addr) && rd_sw_tlul_rd) begin | ||
uvm_reg_addr_t tlul_addr = cfg.ral.get_addr_from_offset(get_sw_window_offset(dai_addr)); | ||
// tlul error rsp is checked in scoreboard | ||
do_otp_rd = 1; | ||
tl_access(.addr(tlul_addr), .write(0), .data(tlul_val), .blocking(1), .check_rsp(0)); | ||
end | ||
// Backdoor restore injected ECC error, but should not affect fatal alerts. | ||
if (ecc_otp_err != OtpNoEccErr && dai_addr < LifeCycleOffset) begin | ||
cfg.mem_bkdr_util_h.write32({dai_addr[TL_DW-3:2], 2'b00}, backdoor_rd_val); | ||
// Wait for two lock cycles to make sure the local escalation error propogates to other | ||
// patitions and err_code reg. | ||
cfg.clk_rst_vif.wait_clks(2); | ||
end | ||
// Random lock sw partitions | ||
if (!$urandom_range(0, 9) && access_locked_parts) write_sw_rd_locks(); | ||
if (!$urandom_range(0, 9) && access_locked_parts) write_sw_digests(); | ||
if ($urandom_range(0, 1)) csr_rd(.ptr(ral.direct_access_regwen), .value(tlul_val)); | ||
if ($urandom_range(0, 1)) csr_rd(.ptr(ral.status), .value(tlul_val)); | ||
if (cfg.otp_ctrl_vif.lc_prog_req == 0) begin | ||
for (int k = 0; k <= LciIdx; k++) begin | ||
csr_rd(.ptr(ral.err_code[k]), .value(tlul_val)); | ||
end | ||
end | ||
end | ||
// Read/write test access memory | ||
otp_test_access(); | ||
// lock digests | ||
`uvm_info(`gfn, "Trigger HW digest calculation", UVM_HIGH) | ||
cal_hw_digests(); | ||
if ($urandom_range(0, 1)) csr_rd(.ptr(ral.status), .value(tlul_val)); | ||
if (cfg.otp_ctrl_vif.lc_prog_req == 0) begin | ||
for (int k = 0; k <= LciIdx; k++) begin | ||
csr_rd(.ptr(ral.err_code[k]), .value(tlul_val)); | ||
end | ||
end | ||
if ($urandom_range(0, 1)) rd_digests(); | ||
if (do_dut_init) dut_init(); | ||
// read and check digest in scb | ||
rd_digests(); | ||
// send request to the interfaces again after partitions are locked | ||
if (do_lc_trans && !cfg.otp_ctrl_vif.alert_reqs) begin | ||
req_lc_transition(do_lc_trans, lc_prog_blocking); | ||
if (cfg.otp_ctrl_vif.lc_prog_req == 0) begin | ||
for (int k = 0; k <= LciIdx; k++) begin | ||
csr_rd(.ptr(ral.err_code[k]), .value(tlul_val)); | ||
end | ||
end | ||
end | ||
if (do_req_keys && !cfg.otp_ctrl_vif.alert_reqs && !cfg.smoke_test) begin | ||
req_otbn_key(); | ||
req_flash_addr_key(); | ||
req_flash_data_key(); | ||
req_all_sram_keys(); | ||
end | ||
end | ||
endtask : body | ||
endclass : otp_ctrl_smoke_vseq | ||
`undef PART_CONTENT_RANGE |
Oops, something went wrong.