blob: 29d3cceb95d5bbd6f96e7d26bf9a00856b1e6916 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Flash middle operation reset test. Send reset via power ready signal
// in the middle of operation program, read, erase and erase suspend.
class flash_ctrl_mid_op_rst_vseq extends flash_ctrl_base_vseq;
`uvm_object_utils(flash_ctrl_mid_op_rst_vseq)
`uvm_object_new
// Configure sequence knobs to tailor it to smoke seq.
virtual function void configure_vseq();
// enable high endurance
cfg.seq_cfg.mp_region_he_en_pc = 50;
cfg.seq_cfg.default_region_he_en_pc = 50;
// num of words to program
cfg.seq_cfg.op_max_words = 4;
endfunction
parameter uint NUM_TRANS = 20;
rand flash_op_t flash_op;
flash_op_t flash_op_q [NUM_TRANS];
flash_op_t flash_op_erase;
flash_op_t flash_op_rd;
rand data_q_t flash_op_data;
bit poll_fifo_status;
bit expect_alert;
// Constraint address to be in relevant range for the selected partition.
constraint addr_c {
if (flash_op.partition != FlashPartData) {
flash_op.addr inside
{[0:InfoTypeBytes[flash_op.partition>>1]-1],
[BytesPerBank:BytesPerBank+InfoTypeBytes[flash_op.partition>>1]-1]};
}
}
constraint flash_op_c {
flash_op.prog_sel == FlashProgSelNormal;
flash_op.erase_type == flash_ctrl_pkg::FlashErasePage;
flash_op.addr inside {[0 : FlashSizeBytes - 1]};
flash_op.num_words inside {[1 : FlashNumBusWords - flash_op.addr[TL_AW-1:TL_SZW]]};
flash_op.num_words <= cfg.seq_cfg.op_max_words;
flash_op.num_words < FlashPgmRes - flash_op.addr[TL_SZW+:FlashPgmResWidth];
}
constraint flash_op_data_c {
solve flash_op before flash_op_data;
flash_op_data.size() == flash_op.num_words;
}
// Memory protection regions settings.
flash_mp_region_cfg_t mp_regions[flash_ctrl_pkg::MpRegions];
// Information partitions memory protection pages settings.
rand flash_bank_mp_info_page_cfg_t
mp_info_pages[flash_ctrl_pkg::NumBanks][flash_ctrl_pkg::InfoTypes][$];
constraint mp_info_pages_c {
foreach (mp_info_pages[i, j]) {
mp_info_pages[i][j].size() == flash_ctrl_pkg::InfoTypeSize[j];
foreach (mp_info_pages[i][j][k]) {
mp_info_pages[i][j][k].en == MuBi4True;
mp_info_pages[i][j][k].read_en == MuBi4True;
mp_info_pages[i][j][k].program_en == MuBi4True;
mp_info_pages[i][j][k].erase_en == MuBi4True;
mp_info_pages[i][j][k].scramble_en == MuBi4False;
mp_info_pages[i][j][k].ecc_en == MuBi4False;
mp_info_pages[i][j][k].he_en dist {
MuBi4False :/ (100 - cfg.seq_cfg.mp_region_he_en_pc),
MuBi4True :/ cfg.seq_cfg.mp_region_he_en_pc
};
}
}
}
// Default flash ctrl region settings.
mubi4_t default_region_read_en;
mubi4_t default_region_program_en;
mubi4_t default_region_erase_en;
rand mubi4_t default_region_he_en;
mubi4_t default_region_scramble_en;
mubi4_t default_region_ecc_en;
// Bank erasability.
bit [flash_ctrl_pkg::NumBanks-1:0] bank_erase_en;
constraint default_region_he_en_c {
default_region_he_en dist {
MuBi4True :/ cfg.seq_cfg.default_region_he_en_pc,
MuBi4False :/ (100 - cfg.seq_cfg.default_region_he_en_pc)
};
}
task pre_start();
cfg.skip_init_buf_en = 1;
super.pre_start();
endtask // pre_start
virtual task body();
cfg.flash_ctrl_vif.lc_creator_seed_sw_rw_en = lc_ctrl_pkg::On;
cfg.flash_ctrl_vif.lc_owner_seed_sw_rw_en = lc_ctrl_pkg::On;
cfg.flash_ctrl_vif.lc_iso_part_sw_rd_en = lc_ctrl_pkg::On;
cfg.flash_ctrl_vif.lc_iso_part_sw_wr_en = lc_ctrl_pkg::On;
cfg.scb_check = 1;
cfg.check_full_scb_mem_model = 1;
poll_fifo_status = 1;
// program interrupt
for (int i = 0; i < NUM_TRANS; i++) begin
`DV_CHECK_RANDOMIZE_WITH_FATAL(this, flash_op.op == FlashOpProgram;
flash_op.partition == FlashPartData;)
flash_op_q[i] = flash_op;
do_cfg();
do_prog(flash_op);
fork
begin : isolation_fork_prog
fork
begin
cfg.clk_rst_vif.wait_clks(100);
end
begin
cfg.clk_rst_vif.wait_clks(30);
low_ready_h();
end
join_any;
disable fork;
end : isolation_fork_prog
join
wait_cfg_prog_rd();
end
// erase interrupt
for (int i = 0; i < NUM_TRANS; i++) begin
do_erase(flash_op_q[i]);
fork
begin : isolation_fork_erase
fork
begin
cfg.clk_rst_vif.wait_clks(100);
end
begin
cfg.clk_rst_vif.wait_clks(30);
low_ready_h();
end
join_any;
disable fork;
end : isolation_fork_erase
join
wait_cfg_prog_rd();
end
// erase suspend interrupt
fork
begin : isolation_fork_erase_suspend
fork
begin
do_erase(flash_op_q[0]);
cfg.clk_rst_vif.wait_clks(100);
end
begin
cfg.clk_rst_vif.wait_clks(30);
csr_wr(.ptr(ral.erase_suspend), .value(1));
low_ready_h();
end
join
end : isolation_fork_erase_suspend
join
wait_cfg_prog_rd();
// cleaning before full memory check
for (int i = 0; i < NUM_TRANS; i++) begin
do_erase(flash_op_q[i]);
wait_flash_op_done(.timeout_ns(cfg.seq_cfg.erase_timeout_ns));
end
// read interrupt
`DV_CHECK_RANDOMIZE_WITH_FATAL(this, flash_op.op == FlashOpRead;
flash_op.partition == FlashPartData;
flash_op.num_words == 1;)
do_cfg();
fork
begin : isolation_fork_read
fork
begin
do_read(flash_op);
cfg.clk_rst_vif.wait_clks(100);
end
begin
cfg.clk_rst_vif.wait_clks(19);
low_ready_h();
end
join
end : isolation_fork_read
join
wait_cfg_prog_rd();
endtask : body
// Task to wait and then do random program and read transactions and check that they complete
// successfully (and by this making sure the flash recovered from the power-loss)
task wait_cfg_prog_rd();
data_q_t exp_data;
// Wait some time to make sure flash is stable again.
cfg.clk_rst_vif.wait_clks(1_000);
// Make sure that flash initialization is complete.
csr_spinwait(.ptr(ral.status.init_wip), .exp_data(1'b0));
// Make sure to clear the op_status register's done.
clear_outstanding_done();
// Configure memry protection.
do_cfg();
// Do random program transaction, then check it completed successfully.
`DV_CHECK_RANDOMIZE_WITH_FATAL(this, flash_op.op == FlashOpProgram;
flash_op.partition == FlashPartData;)
do_prog(flash_op);
wait_flash_op_done(.timeout_ns(cfg.seq_cfg.prog_timeout_ns));
exp_data = cfg.calculate_expected_data(flash_op, flash_op_data);
cfg.flash_mem_bkdr_read_check(flash_op, exp_data);
cfg.clk_rst_vif.wait_clks(100);
// Do random read transaction, then check it completed successfully.
`DV_CHECK_RANDOMIZE_WITH_FATAL(this, flash_op.op == FlashOpRead;
flash_op.partition == FlashPartData;
flash_op.num_words == 1;)
do_read(flash_op);
wait_flash_op_done(.timeout_ns(cfg.seq_cfg.read_timeout_ns));
cfg.flash_mem_bkdr_read_check(flash_op, flash_op_data);
endtask : wait_cfg_prog_rd
// Task to clear the op_status register's done before starting the next transaction.
task clear_outstanding_done();
uvm_reg_data_t data;
bit done;
csr_rd(.ptr(ral.op_status), .value(data));
done = get_field_val(ral.op_status.done, data);
if (done) begin
data = get_csr_val_with_updated_field(ral.op_status.done, data, 0);
csr_wr(.ptr(ral.op_status), .value(data));
end
endtask : clear_outstanding_done
virtual task do_cfg();
// Default region settings
default_region_read_en = MuBi4True;
default_region_program_en = MuBi4True;
default_region_erase_en = MuBi4True;
default_region_ecc_en = MuBi4False;
default_region_scramble_en = MuBi4False;
flash_ctrl_default_region_cfg(
.read_en(default_region_read_en), .program_en(default_region_program_en),
.erase_en(default_region_erase_en), .scramble_en(default_region_scramble_en),
.ecc_en(default_region_ecc_en), .he_en(default_region_he_en));
// No Protection
foreach (mp_regions[i]) begin
mp_regions[i].en = MuBi4False;
end
foreach (mp_regions[k]) begin
flash_ctrl_mp_region_cfg(k, mp_regions[k]);
`uvm_info(`gfn, $sformatf("MP regions values %p", mp_regions[k]), UVM_HIGH)
end
foreach (mp_info_pages[i, j, k]) begin
flash_ctrl_mp_info_page_cfg(i, j, k, mp_info_pages[i][j][k]);
`uvm_info(`gfn, $sformatf("MP INFO regions values %p", mp_info_pages[i][j][k]), UVM_HIGH)
end
//Enable Bank erase
bank_erase_en = {NumBanks{1'b1}};
flash_ctrl_bank_erase_cfg(.bank_erase_en(bank_erase_en));
`uvm_info(`gfn, $sformatf("FLASH OP PROGRAM START OP: %0p", flash_op), UVM_HIGH)
endtask : do_cfg
virtual task do_erase(flash_op_t flash_op_erase);
flash_op_erase.op = FlashOpErase;
flash_ctrl_start_op(flash_op_erase);
endtask : do_erase
virtual task do_prog(flash_op_t flash_op);
cfg.flash_mem_bkdr_write(.flash_op(flash_op), .scheme(FlashMemInitSet));
flash_ctrl_start_op(flash_op);
flash_ctrl_write(flash_op_data, poll_fifo_status);
endtask : do_prog
virtual task do_read(flash_op_t flash_op_rd);
poll_fifo_status = 0;
cfg.flash_mem_bkdr_write(.flash_op(flash_op_rd), .scheme(FlashMemInitRandomize));
flash_ctrl_start_op(flash_op_rd);
flash_ctrl_read(flash_op_rd.num_words, flash_op_data, poll_fifo_status);
endtask : do_read
virtual task low_ready_h();
cfg.flash_ctrl_vif.power_ready_h = 1'b0;
cfg.clk_rst_vif.wait_clks(1);
cfg.flash_ctrl_vif.power_ready_h = 1'b1;
endtask : low_ready_h
endclass : flash_ctrl_mid_op_rst_vseq