Hi all, thanks in advance for suggestions/insights.
I have a DUT with an internal module that allows access to an external 4GB memory. For simulation, I swap it out with a system verilog model. The model uses an associative array: logic [7:0] memory [logic [32:0]];
This works fine when the DUT is reading/writing it. However, In my testbench I want to save time by pre-filling this memory array with data in my test (in the run_phase)
I have tried several things: Conceptual code is below:
top_tb.top_dut.ddr_inst.u_ddr_model.memory[addr] = data;
However, I get an error saying this is not found in the scope
I’ve also tried uvm_hdl_deposit/force(path, data) but the path is not found. adding a update_memory task to the model, but root access from within packages is not allowed so I don’t know how to call it. ($root.top_tb…u_ddr_axi_model.update_memory(addr, data) )
I’ve checked the path and believe it is correct.
Unable to force value to ‘top_tb.top_dut.ddr_inst.u_ddr_axi_model.memory[0]’ Either the path is incorrect, or you may not have PLI/ACC visibility to that object.
I’m using questa and specified the +acc option to vsim to allow access. ( I realized this is intended to be a vendor agnostic forum), just wanted to include details.
Here’s the interesting part: If I change the model to a fixed (smaller) sized array instead of an associative array, everything works fine, so my paths must be correct and simulation visibility seems right. (But is not a solution since I can’t make a 4GB fixed array due to memory issues in simulation)
Now the question: How can a test add elements to an associative array in this scenario?
I’m guessing this is because the UVM’s backdoor access was never designed to handle associative arrays.
You can create an abstract/concrete class interface to access the memory. Use the factory or uvm_config_db to get handle of the concrete class to your test.
package memory_interface;
interface class abstract_mem_intf;
typedef logic [31:0] addr_t;
typedef logic [7:0] data_t;
pure virtual function void mem_write(input addr_t addr, input data_t data);
pure virtual function data_t mem_read(input addr_t addr);
// other methods like readmem/writemem
pure virtual function void mem_dump();
endclass
endpackage
`include "uvm_macros.svh"
import uvm_pkg::*;
module behavioral_memory(/* ports */);
logic [7:0] memory [logic [32:0]];
class concrete_mem_intf extends uvm_object
implements memory_interface::abstract_mem_intf;
typedef logic [31:0] addr_t;
typedef logic [7:0] data_t;
`uvm_object_utils(concrete_mem_intf)
function new(string name="");
super.new(name);
endfunction
virtual function void mem_write(input addr_t addr, input data_t data);
memory[addr] = data;
endfunction
virtual function data_t mem_read(addr_t addr);
if (memory.exists(addr))
return memory[addr];
else
/* some error or return default pattern */;
endfunction
virtual function void mem_dump;
$display("Dumping memory");
foreach(memory[i]) $displayh(i,,memory[i]);
endfunction
endclass
endmodule
class test extends uvm_test;
`uvm_component_utils(test)
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction
memory_interface::abstract_mem_intf mem_intf;
function void build_phase(uvm_phase phase);
$cast(mem_intf, create_object("concrete_mem_intf"));
for(int i=0;i<10;i++) mem_intf.mem_write(i*4,$urandom);
mem_intf.mem_dump();
endfunction
endclass
module top;
behavioral_memory bm();
initial run_test("test");
endmodule
Hi Dave,
Sorry for the delay; I’ve been out sick.
I will definitely give this a try.
It’s challenging to know what’s available - e.g., abstract classes, etc… Are you aware of any training resources that cover some of these more advanced UVM and OOP topics. I’ve got enough experience to figure it out if I know about things, but otherwise it’s pretty difficult to figure these things out.
Thanks for any suggestions, I appreciate as always, your shared insights and expertise.
Brian