// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class [docs]mem_model #(int AddrWidth = bus_params_pkg::BUS_AW,
int DataWidth = bus_params_pkg::BUS_DW) extends uvm_object;
localparam int MaskWidth = DataWidth / 8;
typedef logic [AddrWidth-1:0] mem_addr_t;
typedef logic [DataWidth-1:0] mem_data_t;
typedef logic [MaskWidth-1:0] mem_mask_t;
logic [7:0] system_memory[mem_addr_t];
`uvm_object_param_utils(mem_model#(AddrWidth, DataWidth))
[docs]`uvm_object_new
function void [docs]init();
system_memory.delete();
endfunction
function int [docs]get_written_bytes();
return system_memory.size();
endfunction
function bit [7:0] [docs]read_byte(mem_addr_t addr);
bit [7:0] data;
if (addr_exists(addr)) begin
data = system_memory[addr];
`uvm_info(`gfn, $sformatf("Read Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
end else begin
`DV_CHECK_STD_RANDOMIZE_FATAL(data)
`uvm_error(`gfn, $sformatf("read from uninitialized addr 0x%0h", addr))
end
return data;
endfunction
function void [docs]write_byte(mem_addr_t addr, logic [7:0] data);
`uvm_info(`gfn, $sformatf("Write Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
system_memory[addr] = data;
endfunction
function void [docs]compare_byte(mem_addr_t addr, logic [7:0] act_data);
`uvm_info(`gfn, $sformatf("Compare Mem : Addr[0x%0h], Act Data[0x%0h], Exp Data[0x%0h]",
addr, act_data, system_memory[addr]), UVM_HIGH)
`DV_CHECK_CASE_EQ(act_data, system_memory[addr],
$sformatf("addr 0x%0h read out mismatch", addr))
endfunction
function void [docs]write(input mem_addr_t addr, mem_data_t data, mem_mask_t mask = '1);
bit [7:0] byte_data;
for (int i = 0; i < DataWidth / 8; i++) begin
if (mask[0]) begin
byte_data = data[7:0];
write_byte(addr + i, byte_data);
end
data = data >> 8;
mask = mask >> 1;
end
endfunction
function mem_data_t [docs]read(mem_addr_t addr, mem_mask_t mask = '1);
mem_data_t data;
for (int i = DataWidth / 8 - 1; i >= 0; i--) begin
data = data << 8;
if (mask[MaskWidth - 1]) data[7:0] = read_byte(addr + i);
else data[7:0] = 0;
mask = mask << 1;
end
return data;
endfunction
function void [docs]compare(mem_addr_t addr, mem_data_t act_data, mem_mask_t mask = '1,
bit compare_exist_addr_only = 1);
bit [7:0] byte_data;
for (int i = 0; i < DataWidth / 8; i++) begin
mem_addr_t byte_addr = addr + i;
byte_data = act_data[7:0];
if (mask[0]) begin
if (addr_exists(byte_addr)) begin
compare_byte(byte_addr, byte_data);
end else if (!compare_exist_addr_only) begin
`uvm_error(`gfn, $sformatf("address 0x%0x not exists", byte_addr))
end
end else begin
// Nothing to do here: since this byte wasn't selected by the mask, there are no
// requirements about what data came back.
end
act_data = act_data>> 8;
mask = mask >> 1;
end
endfunction
function bit [docs]addr_exists(mem_addr_t addr);
return system_memory.exists(addr);
endfunction
endclass