blob: 56ebead9e6dd7828e9678f10ddd07a358513f8ed [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class chip_sw_sram_ctrl_scrambled_access_vseq extends chip_sw_base_vseq;
`uvm_object_utils(chip_sw_sram_ctrl_scrambled_access_vseq)
`uvm_object_new
// Number of words to write.
localparam uint BACKDOOR_DATA_WORDS = 16;
// Offsets in number of words for the locations in SRAM where we will write backdoor data.
// For retention RAM this can be anywhere except at the base address which is
// already used in the test for the scramble check.
// For main SRAM after scrambling the runtime environment will have been trashed so we only need
// to avoid the location of the scramble buffer. This will have been allocated by the
// compiler close to the start of the RAM.
// For both, an offset that is at the midpoint of the SRAM should suffice.
localparam uint BACKDOOR_RET_OFFSET = (top_earlgrey_pkg::TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_SIZE_BYTES / 8);
localparam uint BACKDOOR_MAIN_OFFSET = (top_earlgrey_pkg::TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_SIZE_BYTES / 8);
localparam string MAIN_INDEX = "0";
localparam string MAIN_REQ_INDEX = "3";
localparam string RET_INDEX = "1";
localparam string RET_REQ_INDEX = "4";
localparam string SRAM_CTRL_RET_HDL_PATH = "tb.dut.top_earlgrey.u_sram_ctrl_ret_aon";
localparam string SRAM_CTRL_MAIN_HDL_PATH = "tb.dut.top_earlgrey.u_sram_ctrl_main";
localparam string OTP_CTRL_KDI_HDL_PATH = "tb.dut.top_earlgrey.u_otp_ctrl.u_otp_ctrl_kdi";
localparam string KEY_VALID_PATH = ".u_reg_regs.u_status_scr_key_valid.qs[0]";
localparam string RET_NONCE_PATH = {
OTP_CTRL_KDI_HDL_PATH, ".sram_otp_key_o[", RET_INDEX, "].nonce"
};
localparam string RET_KEY_PATH = {OTP_CTRL_KDI_HDL_PATH, ".sram_otp_key_o[", RET_INDEX, "].key"};
localparam string RET_ACK_PATH = {OTP_CTRL_KDI_HDL_PATH, ".sram_otp_key_o[", RET_INDEX, "].ack"};
localparam string RET_REQ_PATH = {OTP_CTRL_KDI_HDL_PATH, ".req[", RET_REQ_INDEX, "]"};
localparam string MAIN_NONCE_PATH = {
OTP_CTRL_KDI_HDL_PATH, ".sram_otp_key_o[", MAIN_INDEX, "].nonce"
};
localparam string MAIN_KEY_PATH = {
OTP_CTRL_KDI_HDL_PATH, ".sram_otp_key_o[", MAIN_INDEX, "].key"
};
localparam string MAIN_ACK_PATH = {
OTP_CTRL_KDI_HDL_PATH, ".sram_otp_key_o[", MAIN_INDEX, "].ack"
};
localparam string MAIN_REQ_PATH = {OTP_CTRL_KDI_HDL_PATH, ".req[", MAIN_REQ_INDEX, "]"};
localparam string SRAM_CTRL_RET_SCR_KEY_VALID_PATH = {SRAM_CTRL_RET_HDL_PATH, KEY_VALID_PATH};
localparam string SRAM_CTRL_MAIN_SCR_KEY_VALID_PATH = {SRAM_CTRL_MAIN_HDL_PATH, KEY_VALID_PATH};
rand bit [7:0] backdoor_data[];
constraint backdoor_data_c {backdoor_data.size() == (BACKDOOR_DATA_WORDS * 4);}
bit [sram_scrambler_pkg::SRAM_BLOCK_WIDTH-1:0] sram_ret_nonce;
bit [ sram_scrambler_pkg::SRAM_KEY_WIDTH-1:0] sram_ret_key;
bit [sram_scrambler_pkg::SRAM_BLOCK_WIDTH-1:0] sram_main_nonce;
bit [ sram_scrambler_pkg::SRAM_KEY_WIDTH-1:0] sram_main_key;
virtual task check_hdl_paths();
int retval;
retval = uvm_hdl_check_path(RET_NONCE_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", RET_NONCE_PATH))
retval = uvm_hdl_check_path(RET_KEY_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", RET_KEY_PATH))
retval = uvm_hdl_check_path(RET_ACK_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", RET_ACK_PATH))
retval = uvm_hdl_check_path(RET_REQ_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", RET_REQ_PATH))
retval = uvm_hdl_check_path(MAIN_NONCE_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", MAIN_NONCE_PATH))
retval = uvm_hdl_check_path(MAIN_KEY_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", MAIN_KEY_PATH))
retval = uvm_hdl_check_path(MAIN_ACK_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", MAIN_ACK_PATH))
retval = uvm_hdl_check_path(MAIN_REQ_PATH);
`DV_CHECK_EQ_FATAL(retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", MAIN_REQ_PATH))
retval = uvm_hdl_check_path(SRAM_CTRL_RET_SCR_KEY_VALID_PATH);
`DV_CHECK_EQ_FATAL(
retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", SRAM_CTRL_RET_SCR_KEY_VALID_PATH))
retval = uvm_hdl_check_path(SRAM_CTRL_MAIN_SCR_KEY_VALID_PATH);
`DV_CHECK_EQ_FATAL(
retval, 1, $sformatf(
"Hierarchical path %0s appears to be invalid.", SRAM_CTRL_MAIN_SCR_KEY_VALID_PATH))
endtask
virtual task get_ret_keys();
int retval;
int req;
int ack;
forever begin
retval = uvm_hdl_read(RET_REQ_PATH, req);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", RET_REQ_PATH))
retval = uvm_hdl_read(RET_ACK_PATH, ack);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", RET_ACK_PATH))
if (req == 1 && ack == 1) begin
retval = uvm_hdl_read(RET_NONCE_PATH, sram_ret_nonce);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", RET_NONCE_PATH))
retval = uvm_hdl_read(RET_KEY_PATH, sram_ret_key);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", RET_KEY_PATH))
end
cfg.clk_rst_vif.wait_clks(1);
end
endtask
virtual task get_main_keys();
int retval;
int req;
int ack;
forever begin
retval = uvm_hdl_read(MAIN_REQ_PATH, req);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", MAIN_REQ_PATH))
retval = uvm_hdl_read(MAIN_ACK_PATH, ack);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", MAIN_ACK_PATH))
if (req == 1 && ack == 1) begin
retval = uvm_hdl_read(MAIN_NONCE_PATH, sram_main_nonce);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", MAIN_NONCE_PATH))
retval = uvm_hdl_read(MAIN_KEY_PATH, sram_main_key);
`DV_CHECK_EQ(retval, 1, $sformatf("uvm_hdl_read failed for %0s", MAIN_KEY_PATH))
end
cfg.clk_rst_vif.wait_clks(1);
end
endtask
virtual task ret_backdoor_write(int addr);
int retval;
bit scr_key_valid;
int offset = addr - top_earlgrey_pkg::TOP_EARLGREY_SRAM_CTRL_RET_AON_RAM_BASE_ADDR;
forever begin
retval = uvm_hdl_read(SRAM_CTRL_RET_SCR_KEY_VALID_PATH, scr_key_valid);
`DV_CHECK_EQ(retval, 1, $sformatf(
"uvm_hdl_read failed for %0s", SRAM_CTRL_RET_SCR_KEY_VALID_PATH))
// Wait for sram_ctrl.STATUS.SCR_KEY_VALID.
if (scr_key_valid == 1) begin
`uvm_info(`gfn, $sformatf("ret_backdoor_write start %x", offset), UVM_LOW)
// Write the data to a known offset in the SRAM. The random byte data
// is used little-endian.
for (int i = 0; i < BACKDOOR_DATA_WORDS; i++) begin
ret_sram_bkdr_write32(offset + (i * 4), {
backdoor_data[(i*4)+3],
backdoor_data[(i*4)+2],
backdoor_data[(i*4)+1],
backdoor_data[(i*4)+0]
}, sram_ret_key, sram_ret_nonce);
end
break;
end
cfg.clk_rst_vif.wait_clks(1);
end
endtask
virtual task main_backdoor_write(int addr);
int retval;
bit scr_key_valid;
int offset = addr - top_earlgrey_pkg::TOP_EARLGREY_SRAM_CTRL_MAIN_RAM_BASE_ADDR;
forever begin
retval = uvm_hdl_read(SRAM_CTRL_MAIN_SCR_KEY_VALID_PATH, scr_key_valid);
`DV_CHECK_EQ(retval, 1, $sformatf(
"uvm_hdl_read failed for %0s", SRAM_CTRL_MAIN_SCR_KEY_VALID_PATH))
// Wait for sram_ctrl.STATUS.SCR_KEY_VALID.
if (scr_key_valid == 1) begin
`uvm_info(`gfn, $sformatf("main_backdoor_write start %x", offset), UVM_LOW)
// Write the data to a known offset in the SRAM. The random byte data
// is used little-endian.
for (int i = 0; i < BACKDOOR_DATA_WORDS; i++) begin
main_sram_bkdr_write32(offset + (i * 4), {
backdoor_data[(i*4)+3],
backdoor_data[(i*4)+2],
backdoor_data[(i*4)+1],
backdoor_data[(i*4)+0]
}, sram_main_key, sram_main_nonce);
end
break;
end
cfg.clk_rst_vif.wait_clks(1);
end
endtask
virtual task cpu_init();
super.cpu_init();
// Init SRAM to avoid the software reading X after scrambling.
for (int ram_idx = 0; ram_idx < cfg.num_ram_ret_tiles; ram_idx++) begin
cfg.mem_bkdr_util_h[chip_mem_e'(RamRet0 + ram_idx)].set_mem();
end
for (int ram_idx = 0; ram_idx < cfg.num_ram_main_tiles; ram_idx++) begin
cfg.mem_bkdr_util_h[chip_mem_e'(RamMain0 + ram_idx)].set_mem();
end
endtask: cpu_init
virtual task sync_with_sw();
`DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInWfi)
`DV_WAIT(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInTest)
endtask:sync_with_sw
virtual task body();
string mem_sel;
int main_sram_offset;
int ret_sram_offset ;
super.body();
// Disable SRAM data integrity checks.
cfg.disable_d_user_data_intg_check_for_passthru_mem = 1;
cfg.en_scb_mem_chk = 0;
check_hdl_paths();
sw_symbol_backdoor_overwrite("kBackdoorExpectedBytes", backdoor_data);
sync_with_sw();
ret_sram_offset = int'(cfg.sw_logger_vif.printed_arg[0]);
main_sram_offset = int'(cfg.sw_logger_vif.printed_arg[1]);
`uvm_info(`gfn, $sformatf("Testing main sram addr: %x", main_sram_offset), UVM_LOW);
fork
get_main_keys();
main_backdoor_write(main_sram_offset);
join_none
sync_with_sw();
ret_sram_offset = int'(cfg.sw_logger_vif.printed_arg[0]);
main_sram_offset = int'(cfg.sw_logger_vif.printed_arg[1]);
`uvm_info(`gfn, $sformatf("Testing ret sram addr: %x", ret_sram_offset), UVM_LOW);
fork
get_ret_keys();
ret_backdoor_write(ret_sram_offset);
join_none
endtask
endclass : chip_sw_sram_ctrl_scrambled_access_vseq