I want to allow multiple interfaces to access the same memmap. Thus, I need multiple maps for multiple adaptors. I can’t seem to add the same registers to two maps.
I’ve:
- created another map and adding registers to it, but it won’t allow it.
- created a complete other block and and pulled in all maps and submaps and registers, but got stuck with similar errors: “reg… may not be added to address map since they’re not in the same block”
Seems like there should be examples on how to do this; I see this post: One register map for multiple agents? but it’s a little vague and seems complicated.
Can anyone offer a better solution?
Thanks for your help
That will depend on how you structure your testbench environment, but assuming your sequence has a handle to a top configuration object that has a handle to each agent configuration object.
Each agent configuration object has a handle for the agent sequencer and its adapter. Then you can use uvm_reg_map::set_sequencer
function to change the sequencer and the adapter of the map as you want and in that case, you only create one map in the register model
Here is how your sequence might look like :
class top_reg_seq extends some_base_seq;
`uvm_object_utils(...)
function new(string name = "");
....
endfunction
task body;
top_cfg.ob_rm.map_obj_name.set_sequencer(top_cfg.agent_0_cfg.ob_seqr, top_cfg.agent_0_cfg.ob_adapter);
// The following write should happen through agent_0
top_cfg.ob_rm.any_register_block.any_register.write(....);
top_cfg.ob_rm.map_obj_name.set_sequencer(top_cfg.agent_1_cfg.ob_seqr, top_cfg.agent_1_cfg.ob_adapter);
// The following write should happen through agent_1
top_cfg.ob_rm.any_register_block.any_register.write(....);
....
endtask: body
endclass: top_reg_seq
Hi Ahmed, Thanks for the reply and the psudo-code, I appreciate it. It sounds like your solution allows a way to simply change the sequencer associated with a map when you go to use it. This is helpful; I could set a variable in the sequence to choose which sequencer to associate the map to or call set_sequencer before starting the sequence. Thanks for the ideas.
I was hoping to allow multiple interfaces to have access to the same map at the same time and just create two maps pointing to the same registers. It doesn’t sound like this is really possible as there appears to be a link between the register and the map was added to. Would you agree? Anyway, I think I can use your suggestion as an alternative, so thank you.
That’s possible, but I wouldn’t recommend it as it defies the purpose of having multiple maps i.e. the same register will appear at different addresses depending on which bus is accessing it.
But if you want to do it, here is how the register model will look like and you will have two options for the sequence
class my_reg_model extends uvm_reg_block;
`uvm_object_utils(my_reg_model)
rand my_reg r0;
uvm_reg_map map_0;
uvm_reg_map map_1;
function new (string name = "");
....
endfunction
function void build;
r0 = my_reg::type_id::create("r0");
r0.build();
r0.configure(this);
r0.add_hdl_path_slice("r0", 0, 8);
map_0 = create_map("map_0", 0, 1, UVM_LITTLE_ENDIAN);
map_0.add_reg(r0, 0, "RW");
map_1 = create_map("map_1", 0, 1, UVM_LITTLE_ENDIAN);
map_1.add_reg(r0, 0, "RW");
lock_model();
endfunction
endclass
//--------------------------------------------//
// Option 1
//--------------------------------------------//
class top_reg_seq extends some_base_seq;
`uvm_object_utils(...)
function new(string name = "");
....
endfunction
task body;
top_cfg.ob_rm.set_default_map(top_cfg.ob_rm.map_0);
// The following write should happen through map_0
top_cfg.ob_rm.any_register_block.any_register.write(....);
top_cfg.ob_rm.set_default_map(top_cfg.ob_rm.map_1);
// The following write should happen through map_1
top_cfg.ob_rm.any_register_block.any_register.write(....);
....
endtask: body
endclass
//--------------------------------------------//
// Option 2
//--------------------------------------------//
class top_reg_seq extends some_base_seq;
`uvm_object_utils(...)
function new(string name = "");
....
endfunction
task body;
// The following write should happen through map_0
top_cfg.ob_rm.any_register_block.any_register.write(.status(...),
.value(..),
.map(top_cfg.ob_rm.map_0));
// The following write should happen through map_1
top_cfg.ob_rm.any_register_block.any_register.write(.status(...),
.value(..),
.map(top_cfg.ob_rm.map_1));
....
endtask: body
endclass
Thaks for the reply. Sorry for the delay in response.
In my case there is only one shared memory map in the DUT and each interface would access it using the same addresses. Consider having an ethernet interface and a different spi interface (or maybe multiple ethernet interfaces) that need to access the same registers. They’d all access them at the same address.
Your build method and the code you just posted is what I tried to do that led me to this post. It seems like i should have worked, but when I tried to create two memory maps and add the same registers to both of them, I got an error. It appears I cannot add a register to two different maps for some reason (some uvm ral limitation)? Have you seen this work?