[dv, flash_ctrl] Fix the smoke test
- The smoke test writes and reads back a random chunk of memory within
the flash.
- The start address and the randomized number of words is bus-aligned
(i.e. 32 bits) and not flash word aligned (64-bits).
- Between each randomized configuration, the flash mem is invalidated.
This means if we write to a flash mem half word, while leaving the other
half word as Xs, that causes an X problem on reads, because flash ctrl
reads in the whole word, not just the half word.
This commit fixes that problem.
Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv
index 57eda60..c8ac3d7 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv
@@ -84,14 +84,23 @@
endfunction : flash_mem_bkdr_read
// Writes the flash mem contents via backdoor.
- // The addr arg need not be word aligned- its the same addr programmed into the `control` CSR.
+ //
+ // The addr need not be bus word aligned, Its the same addr programmed into the `control` CSR.
+ // The data queue is sized for the bus word.
// TODO: support for partition.
virtual function void flash_mem_bkdr_write(flash_op_t flash_op,
flash_mem_init_e scheme,
- logic [flash_ctrl_pkg::DataWidth-1:0] data[$] = {});
+ logic [TL_DW-1:0] data[$] = {});
flash_mem_addr_attrs addr_attrs = new(flash_op.addr);
- logic [flash_ctrl_pkg::DataWidth-1:0] wr_data;
- int num_words;
+ logic [TL_DW-1:0] wr_data;
+
+ // Randomize the lower half-word (if Xs) if the first half-word written in the below loop is
+ // corresponding upper half-word.
+ if (addr_attrs.bank_addr[flash_ctrl_pkg::DataByteWidth-1]) begin
+ _randomize_uninitialized_half_word(.partition(flash_op.partition), .bank(addr_attrs.bank),
+ .addr(addr_attrs.word_addr));
+ end
+
case (scheme)
FlashMemInitCustom: begin
flash_op.num_words = data.size();
@@ -106,24 +115,45 @@
wr_data = {flash_ctrl_pkg::DataWidth{1'bx}};
end
endcase
- // If start address is the 32 MSBs half word of some 64bits word and num_words is even, an
- // additional iteration is required to write all required words.
- num_words = (addr_attrs.is_start_addr_msb && (flash_op.num_words % 2 == 0)) ?
- flash_op.num_words + 1 : flash_op.num_words;
- for (int i = 0; i < num_words; i += 2) begin
- logic [flash_ctrl_pkg::DataWidth-1:0] loc_data = (scheme == FlashMemInitCustom) ? data[i] :
- (scheme == FlashMemInitRandomize) ? $urandom : wr_data;
- mem_bkdr_util_h[flash_op.partition][addr_attrs.bank].write64(addr_attrs.full64_bank_addr,
- loc_data);
+ for (int i = 0; i < flash_op.num_words; i++) begin
+ logic [TL_DW-1:0] loc_data = (scheme == FlashMemInitCustom) ? data[i] :
+ (scheme == FlashMemInitRandomize) ? $urandom() : wr_data;
+
+ mem_bkdr_util_h[flash_op.partition][addr_attrs.bank].write32(addr_attrs.bank_addr, loc_data);
`uvm_info(`gfn, $sformatf("flash_mem_bkdr_write: {%s} = 0x%0h", addr_attrs.sprint(),
loc_data), UVM_MEDIUM)
- addr_attrs.incr(flash_ctrl_env_pkg::FlashBankBytesPerWord);
+ addr_attrs.incr(TL_DBW);
+ end
+
+ // Randomize the upper half-word (if Xs) if the last word written in the above loop is
+ // corresponding lower half-word.
+ if (addr_attrs.bank_addr[flash_ctrl_pkg::DataByteWidth-1]) begin
+ _randomize_uninitialized_half_word(.partition(flash_op.partition), .bank(addr_attrs.bank),
+ .addr(addr_attrs.bank_addr));
end
endfunction : flash_mem_bkdr_write
+ // Helper function that randomizes the half-word at the given address if unknown.
+ //
+ // When the 'other' flash half-word is being written by the flash_mem_bkdr_write() method, the
+ // half-word at the given address needs to also be updated, of the data at that address is
+ // unknown. This is needed because the flash_ctrl RTL internally fetches full words. This method
+ // randomizes the data at the given address via backdoor.
+ function void _randomize_uninitialized_half_word(flash_dv_part_e partition, uint bank,
+ bit [TL_AW-1:0] addr);
+ logic [TL_DW-1:0] data = mem_bkdr_util_h[partition][bank].read32(addr);
+ if ($isunknown(data)) begin
+ `DV_CHECK_STD_RANDOMIZE_FATAL(data)
+ `uvm_info(`gfn, $sformatf("Data at 0x%0h is Xs, writing random 0x%0h", addr, data), UVM_HIGH)
+ mem_bkdr_util_h[partition][bank].write32(addr, data);
+ end
+ endfunction
+
// Checks flash mem contents via backdoor.
- // The addr arg need not be word aligned- its the same addr programmed into the `control` CSR.
+ //
+ // The addr need not be bus word aligned. Its the same addr programmed into the `control` CSR.
+ // The exp data queue is sized for the bus word.
// TODO: support for partition.
virtual function void flash_mem_bkdr_read_check(flash_op_t flash_op,
const ref bit [TL_DW-1:0] exp_data[$]);
@@ -134,7 +164,7 @@
end
endfunction : flash_mem_bkdr_read_check
- // Ensure that the flash page / bank has indeed been erased.
+ // Verifies that the flash page / bank has indeed been erased.
virtual function void flash_mem_bkdr_erase_check(flash_op_t flash_op);
flash_mem_addr_attrs addr_attrs = new(flash_op.addr);
bit [TL_AW-1:0] erase_check_addr;
diff --git a/hw/ip/flash_ctrl/dv/env/flash_mem_addr_attrs.sv b/hw/ip/flash_ctrl/dv/env/flash_mem_addr_attrs.sv
index d8fae9b..503b7cc 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_mem_addr_attrs.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_mem_addr_attrs.sv
@@ -5,34 +5,28 @@
// Provides abstraction for mapping a flash memory address in flash organization.
class flash_mem_addr_attrs;
- bit [TL_AW-1:0] addr; // Input addr (this is aligned to the bus word)
- bit [TL_AW-1:0] bank_addr; // Addr within the bank.
- bit [TL_AW-1:0] full64_addr; // Input full word addr (this is aligned to 64bits word)
- bit [TL_AW-1:0] full64_bank_addr; // Full word addr within the bank.
+ bit [TL_AW-1:0] addr; // Input addr, bus-word aligned.
+ bit [TL_AW-1:0] bank_addr; // Addr within the bank, bus-word aligned.
+ bit [TL_AW-1:0] word_addr; // Addr within the bank, flash word aligned.
+ int offset; // Byte offset within the flash word.
- bit [TL_AW-1:0] bank_start_addr; // Start addr of the bank.
+ bit [TL_AW-1:0] bank_start_addr; // Start addr of the bank (bus word aligned).
bit [TL_AW-1:0] page_start_addr; // Start addr of the page within the bank.
uint bank; // The bank the address belongs to.
uint page; // The page within the bank.
uint line; // The word line within the page.
-
- bit is_start_addr_msb; // Tells whether the start address of this addr_attr is
- // the 32 MSBs of some 64 bits word or the 32 LSBs.
+ uint byte_offset; // Byte offset within the flash word.
function new(bit [TL_AW-1:0] addr = 0);
- is_start_addr_msb = addr[flash_ctrl_pkg::BusByteWidth];
set_attrs(addr);
endfunction
// Set attributes from a sample input addr.
function void set_attrs(bit [TL_AW-1:0] addr);
-
this.addr = {addr[TL_AW-1:TL_SZW], {TL_SZW{1'b0}}};
bank_addr = this.addr[FlashMemAddrPageMsbBit : 0];
- full64_addr = {addr[TL_AW-1:flash_ctrl_env_pkg::FlashDataByteWidth],
- {flash_ctrl_env_pkg::FlashDataByteWidth{1'b0}}};
- full64_bank_addr = full64_addr[FlashMemAddrPageMsbBit : 0];
+ word_addr = {bank_addr[TL_AW-1:FlashDataByteWidth], {FlashDataByteWidth{1'b0}}};
bank_start_addr = {addr[TL_AW-1 : FlashMemAddrPageMsbBit+1], {FlashMemAddrPageMsbBit+1{1'b0}}};
page_start_addr = {addr[FlashMemAddrPageMsbBit : FlashMemAddrLineMsbBit+1],
@@ -41,6 +35,7 @@
bank = addr[FlashMemAddrBankMsbBit : FlashMemAddrPageMsbBit+1];
page = addr[FlashMemAddrPageMsbBit : FlashMemAddrLineMsbBit+1];
line = addr[FlashMemAddrLineMsbBit : FlashMemAddrWordMsbBit+1];
+ byte_offset = addr[FlashDataByteWidth-1 : 0];
endfunction
function void incr(bit [TL_AW-1:0] offset);
@@ -49,11 +44,11 @@
endfunction
function string sprint();
- return $sformatf({{"addr_attrs: addr = 0x%0h, bank_addr = 0x%0h "},
+ return $sformatf({{"addr_attrs: addr = 0x%0h, word_addr = 0x%0h, bank_addr = 0x%0h "},
{"bank_start_addr = 0x%0h, page_start_addr = 0x%0h "},
- {"bank = %0d, page = %0d, line = %0d"}},
- addr, bank_addr, bank_start_addr, page_start_addr,
- bank, page, line);
+ {"bank = %0d, page = %0d, line = %0d, byte_offset = %0d"}},
+ addr, word_addr, bank_addr, bank_start_addr, page_start_addr,
+ bank, page, line, byte_offset);
endfunction
endclass