[dv/otp_ctrl] Fix lc sequence mismatch
This PR fixed nightly regression lc sequence mismatch to align with
design behavior in PR #5433
Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_if.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_if.sv
index 7c57570..b8778e0 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_if.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_if.sv
@@ -22,8 +22,9 @@
// connect with lc_prog push-pull interface
logic lc_prog_req, lc_prog_err;
- logic lc_prog_err_dly1, lc_prog_no_intr_check;
+ logic lc_prog_err_dly1, lc_prog_no_sta_check;
+ // Lc_err could trigger during LC program, so check intr and status after lc_req is finished.
// Lc_err takes one clock cycle to propogate to intr signal. So avoid intr check if it happens
// during the transition.
always_ff @(posedge clk_i or negedge rst_ni) begin
@@ -33,7 +34,7 @@
lc_prog_err_dly1 <= lc_prog_err;
end
end
- assign lc_prog_no_intr_check = lc_prog_err | lc_prog_err_dly1;
+ assign lc_prog_no_sta_check = lc_prog_err | lc_prog_err_dly1 | lc_prog_req;
// TODO: for lc_tx, except esc_en signal, all value different from On is treated as Off,
// technically we can randomize values here once scb supports
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
index 19eccf1..3be3eb1 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
@@ -13,7 +13,7 @@
bit [TL_DW-1:0] otp_a [OTP_ARRAY_SIZE];
// lc_state and lc_cnt that stored in OTP
- bit [LC_PROG_DATA_SIZE-1:0] otp_lc_data;
+ bit [7:0] otp_lc_data[LifeCycleSize];
bit key_size_80 = SCRAMBLE_KEY_SIZE == 80;
bit [EDN_BUS_WIDTH-1:0] edn_data_q[$];
@@ -28,7 +28,7 @@
// Status related variables
bit under_chk, under_dai_access;
- bit [TL_DW-1:0] exp_status;
+ bit [TL_DW-1:0] exp_status, status_mask;
bit macro_alert_triggered;
@@ -85,9 +85,9 @@
@(posedge cfg.otp_ctrl_vif.pwr_otp_init_i) begin
if (cfg.backdoor_clear_mem && cfg.en_scb) begin
bit [SCRAMBLE_DATA_SIZE-1:0] data = descramble_data(0, Secret0Idx);
- otp_a = '{default:0};
- digests = '{default:0};
- otp_lc_data = 0;
+ otp_a = '{default:0};
+ digests = '{default:0};
+ otp_lc_data = '{default:0};
sw_read_lock = 0;
// secret partitions have been scrambled before writing to OTP.
// here calculate the pre-srambled raw data when clearing internal OTP to all 0s.
@@ -143,27 +143,25 @@
virtual task process_lc_prog_req();
forever begin
push_pull_item#(.DeviceDataWidth(1), .HostDataWidth(LC_PROG_DATA_SIZE)) rcv_item;
- bit exp_err_bit;
- string err_msg;
+ bit exp_err_bit;
+ bit [7:0] lc_wr_data[LifeCycleSize];
lc_prog_fifo.get(rcv_item);
- err_msg = $sformatf("current lc_data %0h, request program lc_data %0h",
- otp_lc_data, rcv_item.h_data);
- // LC program request data is valid, no OTP macro error
- if ((otp_lc_data & rcv_item.h_data) == otp_lc_data) begin
- `DV_CHECK_EQ(rcv_item.d_data, 0, err_msg)
- otp_lc_data = rcv_item.h_data;
- exp_status[OtpLciErrIdx] = 0;
- end else begin
- `DV_CHECK_EQ(rcv_item.d_data, 1, err_msg)
- fork
- begin
- cfg.clk_rst_vif.wait_n_clks(1);
- predict_status_err(.dai_err(0), .lc_err(1));
- end
- join
+ // Even if lci_error happened, design will continue to program the rest of LC partitions.
+ lc_wr_data = {>>byte{rcv_item.h_data}};
+ foreach (otp_lc_data[i]) begin
+ if ((otp_lc_data[i] & lc_wr_data[i]) == otp_lc_data[i]) begin
+ otp_lc_data[i] = lc_wr_data[i];
+ end else begin
+ exp_err_bit = 1;
+ end
end
+
+ // LC program request data is valid means no OTP macro error.
+ `DV_CHECK_EQ(rcv_item.d_data, exp_err_bit)
+ if (exp_err_bit) predict_status_err(.dai_err(0), .lc_err(1));
+ else exp_status[OtpLciErrIdx] = 0;
end
endtask
@@ -545,10 +543,9 @@
"status": begin
if (addr_phase_read) begin
void'(ral.status.predict(.value(exp_status), .kind(UVM_PREDICT_READ)));
- end else if (data_phase_read) begin
- bit [TL_DW-1:0] status_mask;
- if (item.d_data[OtpDaiIdleIdx]) check_otp_idle(1);
+ // update status mask
+ status_mask = 0;
// Mask out check_pending field - we do not know how long it takes to process checks.
if (under_chk) status_mask[OtpCheckPendingIdx] = 1;
@@ -559,6 +556,12 @@
status_mask[OtpDaiErrIdx] = 1;
end
+ // Mask out LCI error bit if lc_req is set.
+ if (cfg.otp_ctrl_vif.lc_prog_no_sta_check) status_mask[OtpLciErrIdx] = 1;
+
+ end else if (data_phase_read) begin
+ if (item.d_data[OtpDaiIdleIdx]) check_otp_idle(1);
+
// STATUS register check with mask
`DV_CHECK_EQ((csr.get_mirrored_value() | status_mask), (item.d_data | status_mask),
$sformatf("reg name: status, compare_mask %0h", status_mask))
diff --git a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_base_vseq.sv b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_base_vseq.sv
index 615606fb..91d6bcd 100644
--- a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_base_vseq.sv
+++ b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_base_vseq.sv
@@ -238,9 +238,10 @@
virtual task rd_and_clear_intrs();
bit [TL_DW-1:0] val;
- wait(cfg.otp_ctrl_vif.lc_prog_no_intr_check == 0);
- csr_rd(ral.intr_state, val);
- csr_wr(ral.intr_state, val);
+ if (cfg.otp_ctrl_vif.lc_prog_no_sta_check == 0) begin
+ csr_rd(ral.intr_state, val);
+ csr_wr(ral.intr_state, val);
+ end
endtask
virtual task req_sram_key(int index);