blob: 8125bc71d071ea73b59639a09f300a105ea9a712 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Pseudo Code:
// Randomize Flash Content (Backdoor)
// Power Up Initialisation (With Secret Seeds and Keys Enabled)
// Loop {
// Randomize OTP Keys, Grab During INIT
// Initialise Data and Info Partitions
// FLASH READ : Creator and Owner Partition and Compare Seeds Read with Key Manager.
// Additionally check Partitions with the previous data programmed
// after initial power (if programmed)
// FLASH ERASE : Creator and Owner Partitions (Backdoor Check)
// FLASH PROGRAM : Creator and Owner Partitions (Backdoor Check)
// FLASH READ : Creator/Owner Partition (Save Programmed Data)
// Check OTP Keys At Destination in Flash Ctrl Module
// Reset DUT - Enable Secret Key INIT
// Do Not Randomly Initialise Flash Content
// Repeat
// }
// flash_ctrl_hw_sec_otp Test
class flash_ctrl_hw_sec_otp_vseq extends flash_ctrl_base_vseq;
`uvm_object_utils(flash_ctrl_hw_sec_otp_vseq)
`uvm_object_new
// Overloaded Constraint from Base Class
constraint num_trans_c {num_trans inside {[32 : cfg.seq_cfg.max_num_trans]};}
// Configure sequence knobs to tailor it to this seq
virtual function void configure_vseq();
// Max Num Iterations
cfg.seq_cfg.max_num_trans = 256;
// Enable NO memory protection regions
cfg.seq_cfg.num_en_mp_regions = 0;
// Enable Checks Post Transaction
cfg.seq_cfg.check_mem_post_tran = 1;
// Enable Initial Secret Seed Readout
cfg.seq_cfg.en_init_keys_seeds = 1;
endfunction : configure_vseq
virtual task body();
// Local Variables
data_q_t flash_op_data;
data_q_t exp_creator_data;
data_q_t exp_owner_data;
data_q_t dummy_data; // Not Used (But Passed to Task)
uint case_sel;
bit creator_prog_flag;
bit owner_prog_flag; // Indicates When Secret Partition Has Been Written
`uvm_info(`gfn, "TEST : FLASH CTRL SECRET PARTITION & OTP KEY TESTS", UVM_LOW)
// Initialise Partion Flags to Indicate Unwritten (from Frontdoor)
creator_prog_flag = 1'b0;
owner_prog_flag = 1'b0;
// Test over a number of RESET Cycles
for (int iter = 0; iter < num_trans; iter++) begin
// Configure the FLASH Controller
// INITIALIZE FLASH REGIONS
init_data_part();
init_info_part();
// READ and COMPARE CREATOR AND OWNER SEEDS
`uvm_info(`gfn, "READ and COMPARE", UVM_LOW)
// Read back Creator and Owner seeds via Host, and compare with the data presented to the Key Manager Interface.
randcase
1: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpRead, flash_op_data);
if (creator_prog_flag) check_data_match(flash_op_data, exp_creator_data);
compare_secret_seed(FlashCreatorPart, flash_op_data);
end
1: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpRead, flash_op_data);
if (owner_prog_flag) check_data_match(flash_op_data, exp_owner_data);
compare_secret_seed(FlashOwnerPart, flash_op_data);
end
1: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpRead, flash_op_data);
if (creator_prog_flag) check_data_match(flash_op_data, exp_creator_data);
compare_secret_seed(FlashCreatorPart, flash_op_data);
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpRead, flash_op_data);
if (owner_prog_flag) check_data_match(flash_op_data, exp_owner_data);
compare_secret_seed(FlashOwnerPart, flash_op_data);
end
1: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpRead, flash_op_data);
if (owner_prog_flag) check_data_match(flash_op_data, exp_owner_data);
compare_secret_seed(FlashOwnerPart, flash_op_data);
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpRead, flash_op_data);
if (creator_prog_flag) check_data_match(flash_op_data, exp_creator_data);
compare_secret_seed(FlashCreatorPart, flash_op_data);
end
endcase
// ERASE CREATOR AND OWNER PARTITIONS
// Choose an Erase/Program Test Order
case_sel = $urandom_range(0, 3);
`uvm_info(`gfn, "ERASE", UVM_LOW)
// Choose Erase/Program Combination to perform this iteration
unique case (case_sel)
0: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpErase, dummy_data);
end
1: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpErase, dummy_data);
end
2: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpErase, dummy_data);
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpErase, dummy_data);
end
3: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpErase, dummy_data);
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpErase, dummy_data);
end
default: `uvm_error(`gfn, $sformatf("No case item match, FAIL"))
endcase
// PROGRAM CREATOR AND OWNER PARTITIONS
`uvm_info(`gfn, "PROGRAM", UVM_LOW)
// Note: Uses case_sel value from above
unique case (case_sel)
0: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpProgram, dummy_data);
end
1: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpProgram, dummy_data);
end
2: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpProgram, dummy_data);
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpProgram, dummy_data);
end
3: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpProgram, dummy_data);
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpProgram, dummy_data);
end
default: `uvm_error(`gfn, $sformatf("No case item match, FAIL"))
endcase
// READ CREATOR AND OWNER SEED PARTITIONS
`uvm_info(`gfn, "READ", UVM_LOW)
randcase
1: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpRead, exp_creator_data);
end
1: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpRead, exp_owner_data);
end
1: begin
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpRead, exp_creator_data);
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpRead, exp_owner_data);
end
1: begin
do_flash_op_secret_part(FlashOwnerPart, flash_ctrl_pkg::FlashOpRead, exp_owner_data);
do_flash_op_secret_part(FlashCreatorPart, flash_ctrl_pkg::FlashOpRead, exp_creator_data);
end
endcase
// OTP SCRAMBLE SEED TESTS - CONNECTIVITY TEST ONLY
otp_scramble_key_test_connect();
// RESET DUT
`uvm_info(`gfn, ">>> RESET DUT <<<", UVM_LOW)
lc_ctrl_if_rst(); // Restore lc_ctrl_if to Reset Values
cfg.seq_cfg.disable_flash_init = 1; // Disable Flash Random Initialisation
apply_reset();
// Delay
cfg.clk_rst_vif.wait_clks($urandom_range(10, 100));
end
endtask : body
virtual task init_data_part();
// DATA PARTITION
flash_mp_region_cfg_t mp_regions[flash_ctrl_pkg::MpRegions];
mubi4_t default_region_read_en;
mubi4_t default_region_program_en;
mubi4_t default_region_erase_en;
// MEMORY PROTECTION REGIONS
// No Protection Regions
foreach (mp_regions[i]) begin
mp_regions[i].en = MuBi4False;
end
// Configure the flash based on the given settings
foreach (mp_regions[i]) begin
flash_ctrl_mp_region_cfg(i, mp_regions[i]);
end
// DEFAULT REGIONS
default_region_read_en = MuBi4True;
default_region_program_en = MuBi4True;
default_region_erase_en = MuBi4True;
// Memory Default Regions
flash_ctrl_default_region_cfg(.read_en(default_region_read_en),
.program_en(default_region_program_en),
.erase_en(default_region_erase_en));
endtask : init_data_part
virtual task init_info_part();
// INFO REGION
flash_bank_mp_info_page_cfg_t info_regions[flash_ctrl_reg_pkg::NumInfos0];
foreach (info_regions[i]) begin
// Get secret partition cfg from flash_ctrl_pkg
if ( i inside {1, 2}) begin
// Copy protection from hw_cfg.
info_regions[i] = conv2env_mp_info(flash_ctrl_pkg::CfgAllowRead);
// Update program and erase control for the test purpose.
info_regions[i].program_en = MuBi4True;
info_regions[i].erase_en = MuBi4True;
end else begin
info_regions[i].en = MuBi4True;
info_regions[i].read_en = MuBi4True;
info_regions[i].program_en = MuBi4True;
info_regions[i].erase_en = MuBi4True;
end
flash_ctrl_mp_info_page_cfg(.bank(0), .info_part(0), .page(i), .page_cfg(info_regions[i]));
end
endtask : init_info_part
// Tests the connections between the Flash OTP and the Scramble Block in the Flash Ctrl
virtual task otp_scramble_key_test_connect();
logic [KeyWidth-1:0] prb_otp_addr_key [flash_ctrl_pkg::NumBanks];
logic [KeyWidth-1:0] prb_otp_data_key [flash_ctrl_pkg::NumBanks];
logic [KeyWidth-1:0] prb_otp_addr_rand_key[flash_ctrl_pkg::NumBanks];
logic [KeyWidth-1:0] prb_otp_data_rand_key[flash_ctrl_pkg::NumBanks];
// OTP SCRAMBLE KEY TESTS - CONNECTIVITY TEST ONLY
// OTP Acknowledge and Random Scramble Seeds are Provided by a model in the Base Seq
// (flash_ctrl_base_vseq), called otp_model()
`uvm_info(`gfn, "FLASH OTP KEY - Scramble Connectivity Check", UVM_LOW)
// Probe Internal Scramble Signals
for (int i = 0; i < flash_ctrl_pkg::NumBanks; i++) begin
prb_otp_addr_key[i] = read_key_probe(
$sformatf("tb.dut.u_eflash.gen_flash_cores[%0d].u_core.u_scramble.addr_key_i", i));
prb_otp_addr_rand_key[i] = read_key_probe(
$sformatf("tb.dut.u_eflash.gen_flash_cores[%0d].u_core.u_scramble.rand_addr_key_i", i));
prb_otp_data_key[i] = read_key_probe(
$sformatf("tb.dut.u_eflash.gen_flash_cores[%0d].u_core.u_scramble.data_key_i", i));
prb_otp_data_rand_key[i] = read_key_probe(
$sformatf("tb.dut.u_eflash.gen_flash_cores[%0d].u_core.u_scramble.rand_data_key_i", i));
end
// Compare OTP Keys - Probed vs Expected (For This Test Scenario)
for (int i = 0; i < flash_ctrl_pkg::NumBanks; i++) begin
compare_key_probe(i, "otp_addr_key", prb_otp_addr_key[i], otp_addr_key);
compare_key_probe(i, "otp_addr_rand_key", prb_otp_addr_rand_key[i], otp_addr_rand_key);
compare_key_probe(i, "otp_data_key", prb_otp_data_key[i], otp_data_key);
compare_key_probe(i, "otp_data_rand_key", prb_otp_data_rand_key[i], otp_data_rand_key);
end
endtask : otp_scramble_key_test_connect
// Function Reads the OTP Key values within the Flash Ctrl, at the Scrambing Module
virtual function logic [KeyWidth-1:0] read_key_probe(input string dut_prb);
if (!uvm_hdl_read(dut_prb, read_key_probe))
`uvm_error(`gfn, $sformatf("Unable to Read from DUT Probe : %s, FAIL", dut_prb))
endfunction : read_key_probe
// Task that compares an expected Key with a given key
virtual task compare_key_probe(input uint i, input string dut_prb,
input logic [KeyWidth-1:0] key,
input logic [KeyWidth-1:0] expected_key);
`uvm_info(`gfn, $sformatf("Compare OTP Key, Read : 0x%0x, Expected : 0x%0x", key, expected_key),
UVM_MEDIUM)
`DV_CHECK_EQ(key, expected_key, $sformatf(
"Flash OTP Scramble Key Mismatch, Key : %s[%0d], Read : 0x%0x, Expected : 0x%0x, FAIL",
dut_prb, i, key, expected_key))
endtask : compare_key_probe
endclass : flash_ctrl_hw_sec_otp_vseq