blob: 1e96fcf4343589d922eaa88812d95619f528c584 [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 Physical Controller Arbitration between host reads and controller operations
// 1.Scenario tests on the different banks arbitration
// 2.Scenario tests on the same bank arbitration
// 3.Scenario tests lost of priority of host read on the same bank
class flash_ctrl_phy_arb_vseq extends flash_ctrl_fetch_code_vseq;
`uvm_object_utils(flash_ctrl_phy_arb_vseq)
`uvm_object_new
// Randomized flash ctrl operation.
rand flash_op_t flash_op_host_rd;
data_q_t flash_rd_data;
rand uint bank_rd;
// knob for testing arbitration on same or different banks
logic bank_same = 0;
// Constraint for banks.
constraint bank_c {
solve bank before bank_rd;
if (bank_same == 1) {bank == bank_rd;} else {bank != bank_rd;}
bank inside {[0 : flash_ctrl_pkg::NumBanks - 1]};
bank_rd inside {[0 : flash_ctrl_pkg::NumBanks - 1]};
}
// Constraint host read address to be in relevant range for the selected partition.
constraint addr_rd_c {
solve bank_rd before flash_op_host_rd;
flash_op_host_rd.addr inside {[BytesPerBank * bank_rd :
BytesPerBank * (bank_rd + 1) - BytesPerBank / 2]};
}
constraint flash_op_host_rd_c {
flash_op_host_rd.partition == FlashPartData;
flash_op_host_rd.num_words inside {[10 : FlashNumBusWords -
flash_op_host_rd.addr[TL_AW-1:TL_SZW]]};
flash_op_host_rd.num_words <= cfg.seq_cfg.op_max_words;
flash_op_host_rd.num_words < FlashPgmRes - flash_op_host_rd.addr[TL_SZW+:FlashPgmResWidth];
}
addr_t read_addr;
// Single direct read data
data_t flash_rd_one_data;
localparam data_t ALL_ONES = {TL_DW{1'b1}};
// Configure sequence knobs to tailor it to smoke seq.
virtual function void configure_vseq();
// MAx number of transactions.
cfg.seq_cfg.max_num_trans = 10;
super.configure_vseq();
endfunction
virtual task body();
// enable sw rw access
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;
//disable polling of fifo status for frontdoor write and read
poll_fifo_status = 0;
// Scoreboard knob for blocking host reads
cfg.block_host_rd = 1;
// Scramble disable
default_region_scramble_en = MuBi4False;
//Enable Bank erase
flash_ctrl_bank_erase_cfg(.bank_erase_en(bank_erase_en));
// 1.Scenario tests on the different banks arbitration
`uvm_info(`gfn, $sformatf("1.Scenario tests on the different banks arbitration"), UVM_HIGH)
repeat (num_trans) begin
// Randomize self
bank_same = 0;
`DV_CHECK_RANDOMIZE_FATAL(this)
`uvm_info(`gfn, $sformatf(
"RAND FLASH OP bank:%0d bank_rd:%0d num_trans:%0d flash_op:%0p flash_op_data:%0p",
bank,
bank_rd,
num_trans,
flash_op,
flash_op_data
), UVM_HIGH)
cfg.flash_mem_bkdr_init(flash_op.partition, FlashMemInitInvalidate);
cfg.flash_mem_bkdr_init(flash_op_host_rd.partition, FlashMemInitInvalidate);
if (flash_op.op == flash_ctrl_pkg::FlashOpProgram) begin
cfg.flash_mem_bkdr_write(.flash_op(flash_op), .scheme(FlashMemInitSet));
end else if (flash_op.op == flash_ctrl_pkg::FlashOpRead) begin
cfg.flash_mem_bkdr_write(.flash_op(flash_op), .scheme(FlashMemInitRandomize));
end
cfg.flash_mem_bkdr_write(.flash_op(flash_op_host_rd), .scheme(FlashMemInitRandomize));
do_operations();
end
// 2.Scenario tests on the same bank arbitration
`uvm_info(`gfn, $sformatf("2.Scenario tests on the same bank arbitration"), UVM_HIGH)
repeat (num_trans) begin
// Randomize self
bank_same = 1;
`DV_CHECK_RANDOMIZE_FATAL(this)
`uvm_info(`gfn, $sformatf(
"RAND FLASH OP bank:%0d bank_rd:%0d num_trans:%0d flash_op:%0p flash_op_data:%0p",
bank,
bank_rd,
num_trans,
flash_op,
flash_op_data
), UVM_HIGH)
cfg.flash_mem_bkdr_init(flash_op.partition, FlashMemInitInvalidate);
cfg.flash_mem_bkdr_init(flash_op_host_rd.partition, FlashMemInitInvalidate);
if (flash_op.op == flash_ctrl_pkg::FlashOpProgram) begin
cfg.flash_mem_bkdr_write(.flash_op(flash_op), .scheme(FlashMemInitSet));
end else if (flash_op.op == flash_ctrl_pkg::FlashOpRead) begin
cfg.flash_mem_bkdr_write(.flash_op(flash_op), .scheme(FlashMemInitRandomize));
end
cfg.flash_mem_bkdr_write(.flash_op(flash_op_host_rd), .scheme(FlashMemInitRandomize));
do_operations();
end
// 3.Scenario tests lost of priority of host read on same bank
`uvm_info(`gfn, $sformatf("3.Scenario tests lost of priority of host read on same bank"),
UVM_HIGH)
// start host reads and controller program
`DV_CHECK_RANDOMIZE_FATAL(this)
flash_op.partition = FlashPartData;
flash_op_host_rd.addr = 0;
flash_op_host_rd.num_words = 30;
flash_op.op = flash_ctrl_pkg::FlashOpProgram;
flash_op.addr = 'h14;
flash_op.num_words = 10;
cfg.flash_mem_bkdr_init(flash_op_host_rd.partition, FlashMemInitInvalidate);
cfg.flash_mem_bkdr_write(.flash_op(flash_op_host_rd), .scheme(FlashMemInitSet));
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(flash_op_data, flash_op_data.size() == flash_op.num_words;)
`uvm_info(`gfn, $sformatf("FLASH OP PROGRAM:%0p DATA:%0p", flash_op, flash_op_data), UVM_HIGH)
do_arb();
endtask : body
virtual task do_operations();
// Configure the flash
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
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));
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
// Host direct read of random written value
`uvm_info(`gfn, $sformatf("Starting direct back-to-back reads and controller operations"),
UVM_HIGH)
fork
begin
// host read data and init of selected chunk of memory
host_read_data(flash_op_host_rd);
end
begin
// controller read, program or erase
if (flash_op.op == flash_ctrl_pkg::FlashOpRead) begin
controller_read_data(flash_op);
end else if (flash_op.op == flash_ctrl_pkg::FlashOpProgram) begin
controller_program_data(flash_op, flash_op_data);
end else begin //flash_op.op == flash_ctrl_pkg::FlashOpErase
controller_erase_data(flash_op);
end
end
join;
endtask : do_operations
// host read data.
virtual task host_read_data(flash_op_t flash_op);
data_4s_t rdata;
bit comp;
for (int j = 0; j < flash_op.num_words; j++) begin
read_addr = flash_op.addr + 4 * j;
do_direct_read(.addr(read_addr), .mask('1), .blocking(cfg.block_host_rd), .check_rdata(0),
.rdata(rdata), .completed(comp));
cfg.clk_rst_vif.wait_clks($urandom_range(0, 10));
end
endtask : host_read_data
// Controller read data.
virtual task controller_read_data(flash_op_t flash_op);
flash_rd_data.delete();
flash_ctrl_start_op(flash_op);
flash_ctrl_read(flash_op.num_words, flash_rd_data, poll_fifo_status);
wait_flash_op_done();
`uvm_info(`gfn, $sformatf("FLASH OP READ DATA: %0p", flash_rd_data), UVM_HIGH)
cfg.flash_mem_bkdr_read_check(flash_op, flash_rd_data);
cfg.clk_rst_vif.wait_clks($urandom_range(0, 10));
endtask : controller_read_data
// Controller program data.
virtual task controller_program_data(flash_op_t flash_op, data_q_t flash_op_data);
data_q_t exp_data;
exp_data = cfg.calculate_expected_data(flash_op, flash_op_data);
flash_ctrl_start_op(flash_op);
flash_ctrl_write(flash_op_data, poll_fifo_status);
wait_flash_op_done(.timeout_ns(cfg.seq_cfg.prog_timeout_ns));
`uvm_info(`gfn, $sformatf("FLASH OP PROGRAM DATA: %0p", flash_op_data), UVM_HIGH)
cfg.flash_mem_bkdr_read_check(flash_op, exp_data);
cfg.clk_rst_vif.wait_clks($urandom_range(0, 10));
endtask : controller_program_data
// Controller erase data.
virtual task controller_erase_data(flash_op_t flash_op);
data_q_t exp_data;
exp_data = cfg.calculate_expected_data(flash_op, flash_op_data);
flash_ctrl_start_op(flash_op);
wait_flash_op_done(.timeout_ns(cfg.seq_cfg.erase_timeout_ns));
`uvm_info(`gfn, $sformatf("FLASH OP ERASE DATA DONE"), UVM_HIGH)
cfg.flash_mem_bkdr_erase_check(flash_op, exp_data);
endtask : controller_erase_data
virtual task do_arb();
data_4s_t rdata;
data_q_t exp_data;
// setting non blocking host reads
cfg.block_host_rd = 0;
// Configure the flash
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
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));
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
`uvm_info(`gfn, $sformatf("Starting arbitration"), UVM_HIGH)
fork
begin // host read data
bit comp;
`uvm_info(`gfn, $sformatf("FLASH OP HOST RD ARB: %0p", flash_op_host_rd), UVM_HIGH)
cfg.clk_rst_vif.wait_clks(32);
for (int j = 0; j < flash_op_host_rd.num_words; j++) begin
read_addr = flash_op_host_rd.addr + 4 * j;
do_direct_read(.addr(read_addr), .mask('1), .blocking(cfg.block_host_rd),
.check_rdata(0), .rdata(rdata), .completed(comp));
`uvm_info(`gfn, $sformatf("FINISH SENDING HOST ADD: %0d", read_addr), UVM_HIGH)
end
csr_utils_pkg::wait_no_outstanding_access();
end
begin // controller program data
`uvm_info(`gfn, $sformatf("FLASH OP PROGRAM ARB: %0p DATA: %0p", flash_op, flash_op_data),
UVM_HIGH)
exp_data = cfg.calculate_expected_data(flash_op, flash_op_data);
flash_ctrl_start_op(flash_op);
flash_ctrl_write(flash_op_data, poll_fifo_status);
wait_flash_op_done(.timeout_ns(cfg.seq_cfg.prog_timeout_ns));
`uvm_info(`gfn, $sformatf("FINISH PROGRAM ADD: %0d expected:", flash_op.addr), UVM_HIGH)
cfg.flash_mem_bkdr_read_check(flash_op, exp_data);
end
join;
// check 6th host direct read data after losing priority
for (int j = 0; j < flash_op_host_rd.num_words; j++) begin
flash_rd_one_data = cfg.flash_rd_data.pop_front();
`uvm_info(`gfn, $sformatf("FLASH DIRECT READ DATA: 0x%0h", flash_rd_one_data), UVM_HIGH)
//first 5 data have init value while 6th value is overwritten by ctrl due to priority lost
if (j < 5) begin
`DV_CHECK_EQ(flash_rd_one_data, ALL_ONES)
end
if (j == 5) begin
`DV_CHECK_EQ(flash_rd_one_data, flash_op_data[0])
end
end
endtask : do_arb
endclass : flash_ctrl_phy_arb_vseq