Properly vendor in mem_model from OpenTitan

This removes the manually copied version at dv/uvm/core_ibex/common
and vendors things properly now that the vendor tool supports such
things (this picks up the same OpenTitan version as the previous
commit: lowRISC/opentitan@067272a2).
This commit is contained in:
Rupert Swarbrick 2020-07-23 11:17:26 +01:00 committed by Rupert Swarbrick
parent e37c81a1c1
commit 46ff63ad88
8 changed files with 117 additions and 62 deletions

View file

@ -46,8 +46,8 @@ execution.
Memory Model
""""""""""""
The code can be found in the
`dv/uvm/core_ibex/common/mem_model <https://github.com/lowRISC/ibex/tree/master/dv/uvm/core_ibex/common/mem_model>`_
The code is vendored from OpenTitan and can be found in the
`vendor/lowrisc_ip/mem_model <https://github.com/lowRISC/ibex/tree/master/vendor/lowrisc_ip/mem_model>`_
directory.
The testbench instantiates a single instance of this memory model that it loads the compiled
assembly test program into at the beginning of each test.

View file

@ -1,57 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class mem_model#(parameter int ADDR_WIDTH = 32,
parameter int DATA_WIDTH = 32) extends uvm_object;
typedef bit [ADDR_WIDTH-1:0] mem_addr_t;
typedef bit [DATA_WIDTH-1:0] mem_data_t;
bit [7:0] system_memory[mem_addr_t];
`uvm_object_param_utils(mem_model#(ADDR_WIDTH, DATA_WIDTH))
function new(string name="");
super.new(name);
endfunction
function bit [7:0] read_byte(mem_addr_t addr);
bit [7:0] data;
if(system_memory.exists(addr)) begin
data = system_memory[addr];
`uvm_info(get_full_name(),
$sformatf("Read Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
end
else begin
`DV_CHECK_STD_RANDOMIZE_FATAL(data)
`uvm_error(get_full_name(), $sformatf("read to uninitialzed addr 0x%0h", addr))
end
return data;
endfunction
function void write_byte(mem_addr_t addr, bit[7:0] data);
`uvm_info(get_full_name(),
$sformatf("Write Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
system_memory[addr] = data;
endfunction
function void write(input mem_addr_t addr, mem_data_t data);
bit [7:0] byte_data;
for(int i=0; i<DATA_WIDTH/8; i++) begin
byte_data = data[7:0];
write_byte(addr+i, byte_data);
data = data >> 8;
end
endfunction
function mem_data_t read(mem_addr_t addr);
mem_data_t data;
for(int i=DATA_WIDTH/8-1; i>=0; i--) begin
data = data << 8;
data[7:0] = read_byte(addr+i);
end
return data;
endfunction
endclass

View file

@ -61,13 +61,13 @@ ${PRJ_DIR}/ibex/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
+incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/tests
+incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent
+incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/irq_agent
+incdir+${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/mem_model
+incdir+${PRJ_DIR}/ibex/vendor/lowrisc_ip/mem_model
+incdir+${PRJ_DIR}/ibex/vendor/lowrisc_ip/dv_utils
${PRJ_DIR}/ibex/dv/uvm/top_pkg/top_pkg.sv
${PRJ_DIR}/ibex/vendor/lowrisc_ip/common_ifs/clk_rst_if.sv
${PRJ_DIR}/ibex/vendor/lowrisc_ip/common_ifs/pins_if.sv
${PRJ_DIR}/ibex/vendor/lowrisc_ip/dv_utils/dv_utils_pkg.sv
${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/mem_model/mem_model_pkg.sv
${PRJ_DIR}/ibex/vendor/lowrisc_ip/mem_model/mem_model_pkg.sv
${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf.sv
${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv
${PRJ_DIR}/ibex/dv/uvm/core_ibex/common/irq_agent/irq_if.sv

View file

@ -15,6 +15,7 @@
{from: "hw/dv/sv/csr_utils", to: "csr_utils"},
{from: "hw/dv/sv/dv_lib", to: "dv_lib"},
{from: "hw/dv/sv/dv_base_reg", to: "dv_base_reg"},
{from: "hw/dv/sv/mem_model", to: "mem_model"},
{from: "hw/dv/verilator", to: "dv_verilator"},
// We apply a patch to the top_pkg core file name when vendoring in

26
vendor/lowrisc_ip/mem_model/README.md vendored Normal file
View file

@ -0,0 +1,26 @@
## Memory Model
The memory model UVC models a memory device which any host interface can read
from or write to. It is implemented as a `uvm_object`, and instantiates an
associative array of bytes `system_memory`. This class is paramterized by both
the address width and the data width, and creates two `typedefs` to represent
both, `mem_addr_t` and `mem_data_t`.
The `mem_model` class has four main functions, which are detailed below.
### `read_byte(mem_addr_t addr)`
This function looks up the byte of data corresponding to the memory address
passed in, and returns it. If the address does not exist in `system_memory`, it
will randomize the returned data and throw a `UVM_ERROR`.
### `write_byte(mem_addr_t addr, bit [7:0] data)`
This function simply assigns the given data to the specified memory address
location in `system_memory`.
### `write(input mem_addr_t addr, mem_data_t data)`
This function writes a full memory word of width `mem_data_t` to the specified
address, breaking it down into a series of back-to-back calls to `write_byte()`
to correctly byte-address the memory.
### `read(mem_addr_t addr)`
This function reads a full memory word of width `mem_data_t` from the specified
address, breaking it down into a series of back-to-back calls to `read_byte()`
to correctly byte-address the memory.

View file

@ -8,7 +8,7 @@ description: "DV Memory Model"
filesets:
files_dv:
depend:
- lowrisc:dv:dv_utils
- lowrisc:constants:top_pkg
files:
- mem_model_pkg.sv
- mem_model.sv: {is_include_file: true}

View file

@ -0,0 +1,85 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class mem_model #(int AddrWidth = top_pkg::TL_AW,
int DataWidth = top_pkg::TL_DW,
int MaskWidth = top_pkg::TL_DBW) extends uvm_object;
typedef bit [AddrWidth-1:0] mem_addr_t;
typedef bit [DataWidth-1:0] mem_data_t;
typedef bit [MaskWidth-1:0] mem_mask_t;
bit [7:0] system_memory[mem_addr_t];
`uvm_object_param_utils(mem_model#(AddrWidth, DataWidth))
`uvm_object_new
function int get_written_bytes();
return system_memory.size();
endfunction
function bit [7:0] read_byte(mem_addr_t addr);
bit [7:0] data;
if (system_memory.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 to uninitialzed addr 0x%0h", addr))
end
return data;
endfunction
function void write_byte(mem_addr_t addr, bit [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 compare_byte(mem_addr_t addr, bit [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)
system_memory[addr] = act_data;
`DV_CHECK_EQ(act_data, system_memory[addr], $sformatf("addr 0x%0h read out mismatch", addr))
endfunction
function void 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 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 compare(mem_addr_t addr, mem_data_t act_data, mem_mask_t mask = '1);
bit [7:0] byte_data;
for (int i = 0; i < DataWidth / 8; i++) begin
byte_data = act_data[7:0];
if (mask[0]) begin
compare_byte(addr + i, byte_data);
end else begin
`DV_CHECK_EQ(byte_data, 0,
$sformatf("addr 0x%0h masked data aren't 0, mask 0x%0h", addr, mask))
end
act_data = act_data>> 8;
mask = mask >> 1;
end
endfunction
endclass