Hi there,
is it possible to have multiple frontdoor sequnces over the same register layer?
I would require this for a design having more (redundant) interfaces to access the same bus.
I could imagine something like:
ral.jtag_read()
ral.vme_read()
Hi there,
is it possible to have multiple frontdoor sequnces over the same register layer?
I would require this for a design having more (redundant) interfaces to access the same bus.
I could imagine something like:
ral.jtag_read()
ral.vme_read()
You could use different maps to go through different busses:
ral.read(..., .map(jtag_map);
ral.read(..., .map(vme_map);
In reply to dipling:
If you are using the same bus you need only one map.
I understood you have different adapters/bridges to access your bus, one from jtag and another one from vme. Is this correct?
In reply to chr_sue:
I understood you have different adapters/bridges to access your bus, one from jtag and another one from vme. Is this correct?
That is correct.
In reply to Tudor Timi:
Hi,
I started to do the coding for multiple maps with distinct frontdoor_seq (and physical interfaces), however I ran into the following error:
UVM_ERROR […] @ 0.0000us: reporter [RegModel] Map ‘ral.my_regs.reg_map’ is already a child of map ral.jtag_map
However the documentation of uvm_reg_map says:
An address map may be added to multiple address maps if it is accessible from multiple
physical interfaces
I obviously did something wrong, but I can’t figgure out what. Any hints?
class my_reg_block extends uvm_reg_block;
`uvm_object_utils(my_reg_block )
rand my_reg1_rc my_reg1;
rand my_reg2_rc my_reg2;
uvm_reg_map my_regs_map; // Block map
function new(string name = "my_reg_block ");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function void build();
my_reg1= my_reg1_rc ::type_id::create("my_reg1");
my_reg1.configure(this, null, "");
my_reg1.build();
...
my_regs_map= create_map("my_regs_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
my_regs_map.add_reg(my_reg1, 32'h8000 , "RW");
my_regs_map.add_reg(my_reg2, 32'h8001 , "RW");
endclass
class my_register_model extends uvm_reg_block;
`uvm_object_utils(my_register_model )
function new(string name = "my_register_model ");
super.new(name);
endfunction
rand my_reg_block my_regs;
uvm_reg_map jtag_map;
uvm_reg_map vme_map;
function void build();
// default map : jtag bus sequencer
jtag_map = new("jtag_map");
jtag_map = create_map("jtag_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
// same map again --> attach to VME sequencer
vme_map = new("vme_map");
vme_map = create_map("vme_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
// register blocks
my_regs= my_reg_block ::type_id::create("my_regs", , get_full_name());
my_regs.configure(this);
my_regs.build();
// add all register blocks (identical configuration) to the jtag and vme maps
jtag_map.add_submap(this.my_regs.default_map, 'h0);
vme_map.add_submap(this.my_regs.default_map, 'h0);
// define default submap == JTAG
default_map = jtag_map;
this.lock_model();
endfunction
endclass
class my_env extens uvm_env;
jtag_reg2cmd_adapter m_jtag_reg2cmd;
jtag_frontdoor_seq fdsq_jtag;
vme_reg2cmd_adapter m_vme_reg2cmd;
vme_frontdoor_seq fdsq_vme;
my_register_model ral;
//build phase
fdsq_jtag = jtag_frontdoor_seq::type_id::create("fdsq_jtag");
fdsq_vme = vme_frontdoor_seq::type_id::create("fdsq_vme");
//connect phase
uvm_reg regs[$];
uvm_reg_map vme_map, jtag_map;
vme_map = ral.get_map_by_name("vme_map");
jtag_map = ral.get_map_by_name("jtag_map");
ral.jtag_map.get_registers(regs);
foreach(regs[i]) begin
regs[i].set_frontdoor(.ftdr(fdsq_jtag), .map(jtag_map));
end
regs.delete();
ral.vme_map.get_registers(regs);
foreach(regs[i]) begin
regs[i].set_frontdoor(.ftdr(fdsq_vme), .map(vme_map));
end
regs.delete();
endclass
Hi,
at least for the “child-grandchild” error I have a solution.
However this is just as good as a complete duplication of the register model.
How can I make the predictor understand that the registers in the two maps refer to the same DUT registers?
class my_reg_block extends uvm_reg_block;
`uvm_object_utils(my_reg_block )
rand my_reg1_rc my_reg1;
rand my_reg2_rc my_reg2;
uvm_reg_map my_regs_map_for_vme; // Block map
uvm_reg_map my_regs_map_for_jtag; // Block map
function new(string name = "my_reg_block ");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function void build();
...
my_regs_map_for_vme= create_map("my_regs_map_for_vme", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
my_regs_map_for_vme.add_reg(my_reg1, 32'h8000 , "RW");
my_regs_map_for_vme.add_reg(my_reg2, 32'h8001 , "RW");
my_regs_map_for_jtag= create_map("my_regs_map_for_jtag", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
my_regs_map_for_jtag.add_reg(my_reg1, 32'h8000 , "RW");
my_regs_map_for_jtag.add_reg(my_reg2, 32'h8001 , "RW");
endclass
class my_register_model extends uvm_reg_block;
`uvm_object_utils(my_register_model )
function new(string name = "my_register_model ");
super.new(name);
endfunction
rand my_reg_block my_regs;
uvm_reg_map jtag_map;
uvm_reg_map vme_map;
function void build();
// default map : jtag bus sequencer
jtag_map = new("jtag_map");
jtag_map = create_map("jtag_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
// same map again --> attach to VME sequencer
vme_map = new("vme_map");
vme_map = create_map("vme_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
...
// add all register blocks (identical configuration) to the jtag and vme maps
jtag_map.add_submap(this.my_regs.my_regs_map_for_jtag, 'h0);
vme_map.add_submap(this.my_regs.my_regs_map_for_vme, 'h0);
// define default submap == JTAG
default_map = jtag_map;
this.lock_model();
endfunction
endclass
In reply to dipling:
The documentation and the implementation aren’t in sync. The error message you’re getting explicitly prohibits a map from being added to multiple address maps.
What you can do is create two different maps and add the registers to exactly the same offsets as in the default_map. This doesn’t mean that you have to duplicate the code. You can do this programmatically:
// get a list of all regs that are mapped in default_map
uvm_reg regs;
default_map.get_registers(regs);
// start adding all of those registers to the other map
foreach (regs*)
jtag_map.add_reg(regs[i], regs[i].get_offset(default_map);
// do the same for the 'vme_map'
// ...
This way you only specify the actual offsets of the registers once, when adding them to [i]default_map*.
DISCLAIMER: I didn’t test the code.