One register map for multiple agents? CONTINUED

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:

  1. created another map and adding registers to it, but it won’t allow it.
  2. 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