[dv/otp_ctrl] OTP write_blank_error support [PART6] This PR cleans up the stress_all and stress_all_with_rand_reset sequences to support write_blank_error. To avoid previous sequence dai_wr affects next sequence, this PR wipes the OTP memory after one sequence finishes running. Signed-off-by: Cindy Chen <chencindy@opentitan.org>
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 522002d..a270508 100644 --- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv +++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
@@ -61,6 +61,7 @@ task run_phase(uvm_phase phase); super.run_phase(phase); fork + process_wipe_mem(); process_otp_power_up(); process_lc_esc(); process_lc_prog_req(); @@ -72,6 +73,36 @@ join_none endtask + // Once sequence uses backdoor method to clear memory, this task resets internal otp_a and + // resets `cfg.backdoor_clear_mem` to 0. + virtual task process_wipe_mem(); + forever begin + @(posedge cfg.backdoor_clear_mem) begin + bit [SCRAMBLE_DATA_SIZE-1:0] data = descramble_data(0, Secret0Idx); + otp_a = '{default:0}; + otp_lc_data = '{default:0}; + // secret partitions have been scrambled before writing to OTP. + // here calculate the pre-srambled raw data when clearing internal OTP to all 0s. + for (int i = SECRET0_START_ADDR; i <= SECRET0_END_ADDR; i++) begin + otp_a[i] = ((i - SECRET0_START_ADDR) % 2) ? data[SCRAMBLE_DATA_SIZE-1:TL_DW] : + data[TL_DW-1:0]; + end + data = descramble_data(0, Secret1Idx); + for (int i = SECRET1_START_ADDR; i <= SECRET1_END_ADDR; i++) begin + otp_a[i] = ((i - SECRET1_START_ADDR) % 2) ? data[SCRAMBLE_DATA_SIZE-1:TL_DW] : + data[TL_DW-1:0]; + end + data = descramble_data(0, Secret2Idx); + for (int i = SECRET2_START_ADDR; i <= SECRET2_END_ADDR; i++) begin + otp_a[i] = ((i - SECRET2_START_ADDR) % 2) ? data[SCRAMBLE_DATA_SIZE-1:TL_DW] : + data[TL_DW-1:0]; + end + `uvm_info(`gfn, "clear internal memory and digest", UVM_HIGH) + cfg.backdoor_clear_mem = 0; + end + end + endtask + // This task process the following logic in during otp_power_up: // 1. After reset deasserted, otp access is locked until pwr_otp_done_o is set // 2. After reset deasserted, if power otp_init request is on, and if testbench uses backdoor to @@ -79,31 +110,6 @@ virtual task process_otp_power_up(); if (cfg.en_scb) begin forever begin - @(posedge cfg.otp_ctrl_vif.pwr_otp_init_i) begin - if (cfg.backdoor_clear_mem) begin - bit [SCRAMBLE_DATA_SIZE-1:0] data = descramble_data(0, Secret0Idx); - otp_a = '{default:0}; - otp_lc_data = '{default:0}; - // secret partitions have been scrambled before writing to OTP. - // here calculate the pre-srambled raw data when clearing internal OTP to all 0s. - for (int i = SECRET0_START_ADDR; i <= SECRET0_END_ADDR; i++) begin - otp_a[i] = ((i - SECRET0_START_ADDR) % 2) ? data[SCRAMBLE_DATA_SIZE-1:TL_DW] : - data[TL_DW-1:0]; - end - data = descramble_data(0, Secret1Idx); - for (int i = SECRET1_START_ADDR; i <= SECRET1_END_ADDR; i++) begin - otp_a[i] = ((i - SECRET1_START_ADDR) % 2) ? data[SCRAMBLE_DATA_SIZE-1:TL_DW] : - data[TL_DW-1:0]; - end - data = descramble_data(0, Secret2Idx); - for (int i = SECRET2_START_ADDR; i <= SECRET2_END_ADDR; i++) begin - otp_a[i] = ((i - SECRET2_START_ADDR) % 2) ? data[SCRAMBLE_DATA_SIZE-1:TL_DW] : - data[TL_DW-1:0]; - end - predict_digest_csrs(); - `uvm_info(`gfn, "clear internal memory and digest", UVM_HIGH) - end - end @(posedge cfg.otp_ctrl_vif.pwr_otp_done_o || cfg.under_reset || cfg.otp_ctrl_vif.alert_reqs) begin if (!cfg.under_reset && !cfg.otp_ctrl_vif.alert_reqs) begin
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 c20923e..9bbe9ec 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
@@ -65,15 +65,24 @@ // setup basic otp_ctrl features virtual task otp_ctrl_init(); // reset memory to avoid readout X - cfg.mem_bkdr_util_h.clear_mem(); - cfg.backdoor_clear_mem = 1; - used_dai_addr_q.delete(); + clear_otp_memory(); lc_state = 0; lc_cnt = 0; endtask - // some registers won't set to default value until otp_init is done + virtual function void clear_otp_memory(); + cfg.mem_bkdr_util_h.clear_mem(); + cfg.backdoor_clear_mem = 1; + used_dai_addr_q.delete(); + endfunction + + // Overide this task for otp_ctrl_common_vseq and otp_ctrl_stress_all_with_rand_reset_vseq + // 1). Some registers won't set to default value until otp_init is done + // 2). Clear memory for next sequence to run. This can avoid ECC injection error and + // write_blank error virtual task read_and_check_all_csrs_after_reset(); + cfg.otp_ctrl_vif.drive_lc_escalate_en(lc_ctrl_pkg::Off); + clear_otp_memory(); otp_pwr_init(); super.read_and_check_all_csrs_after_reset(); endtask
diff --git a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv index ebc8d38..6701747 100644 --- a/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv +++ b/hw/ip/otp_ctrl/dv/env/seq_lib/otp_ctrl_smoke_vseq.sv
@@ -77,6 +77,13 @@ check_lc_err(); endtask + // Used for stress_all sequence to clear OTP internal memory before going to next test. + // This can avoid unexpected ECC injection errors or write_blank errors. + virtual task post_start(); + super.post_start(); + clear_otp_memory(); + endtask + virtual task check_lc_err(); fork forever begin