How to set_sequencer & adapter for the default maps present in the sub-blocks, which is instanced inside top level register blocks?

Hello Folks,

a. I have a top level register block with a default_map.
b. I have multiple sub-blocks added into top level block and added their default_map as sub_maps to top level sub_blocks.
c. I configured the respective sequencer and adapter for the sub-block map as given below.[Note: Using separate sequencer and adapter for each sub-block for parallel access]


    qr_reg_model.D0.default_map.set_sequencer(qr_reg_agt[i].qr_reg_sqr, qr_r2b_adapter[i]);
   

d. I tried doing register write/read as given below


    qr_reg_model.D0.R_D_CLR_ADDR.write(status, 15,     .parent(this));
    qr_reg_model.D0.R_D_CLR_ADDR.read(status,  data,   .parent(this));
    

e. When I tried accessing the registers I got the below error message

""neither the item’s sequencer nor dedicated sequencer has been supplied to start item in reg_acc_seq sequence “”

Do we need to set any default sequence for the top level register block as well ?? Kindly help me out on this.

Thanks & Regards
Desperado !!

In reply to desperadorocks:

Hello Folks,

I tried the below configuration to set separate sequencer & adapter for each sub-block inside the top level register block, so that I can launch register write/read tests parallely across multiple-sub blocks.


for (int i = 0; i < `NO_OF_AGT; i++) begin  
  if(top_reg_block.get_parent() == null) begin
   case(i)
     0: top_reg_block.sub_reg_block0.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);
     1: top_reg_block.sub_reg_block1.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);
     2: top_reg_block.sub_reg_block2.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);
     3: top_reg_block.sub_reg_block3.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);
   endcase
  end 
  
  if(each_reg_cfg.auto_predict[i] == UVM_ACTIVE) begin
   case(i) 
     0: top_reg_block.sub_reg_block0.default_map.set_auto_predict(1);
     1: top_reg_block.sub_reg_block1.default_map.set_auto_predict(1);
     2: top_reg_block.sub_reg_block2.default_map.set_auto_predict(1);
     3: top_reg_block.sub_reg_block3.default_map.set_auto_predict(1);
   endcase 
  end 
end

a. When I tried explicit register write/read to the explicit registers inside the blocks I received the below error:

""neither the item’s sequencer nor dedicated sequencer has been supplied to start item in reg_acc_seq sequence “”

b. And then when I launched the bit-bash sequence on a particular sequencer,

The transaction item that I received at the driver end is null-object pointer.

Can’t we not set the sequencer and adapter to the sub-blocks inside the top level block ? Or after setting the sub-blocks, do we need to set any top level sequencer & adapter for the top level register mode ? Kindly help me out on this issue.

Regards,
Desperado

In reply to desperadorocks:

Hello Folks,

Any comments on the above questions ?? how can we set separate sequencer & adapters for the sub-blocks which is present in the top-level blocks, so that we can parallely execute register write/read operations on each sub-blocks.

Kindly drop in your comments/share your views !!

Regards,
Desperado !!

In reply to desperadorocks:

Hello Folks,

a. I tried creating separate reg-map for each each sub-block inside the top level register block and added their default map as sub-maps to the separate reg-map as given below.


sub0_reg_map = create_map("sub0_reg_map", 'h20000000, 4, UVM_LITTLE_ENDIAN);
sub0_reg_map.add_submap(this.SUB0.default_map, 'h1200);

sub1_reg_map = create_map("sub1_reg_map", 'h20000000, 4, UVM_LITTLE_ENDIAN);
sub1_reg_map.add_submap(this.SUB1.default_map, 'h1400);

b. Then I made the sequencer & adapter configuration as given below.


0: top_reg_model.sub0_reg_map.set_sequencer(top_reg_agt[i].top_reg_sqr, top_r2b_adapter[i]);
1: top_reg_model.sub1_reg_map.set_sequencer(top_reg_agt[i].top_reg_sqr, top_r2b_adapter[i]);

0: top_reg_model.sub0_reg_map.set_auto_predict(1);
1: top_reg_model.sub1_reg_map.set_auto_predict(1);

c. And when I launched the bit-bash sequence as given below, it worked !!!


seq0.model = env.top_reg_model.SUB0;
seq0.start(top_reg_sqr[0]);
seq0.wait_for_sequence_state(FINISHED);

seq1.model = env.top_reg_model.SUB1;
seq1.start(top_reg_sqr[1]);
seq1.wait_for_sequence_state(FINISHED)

d. But is it not by any means I can set the respective sequencer & adapter as posted above & so does below for reference


0: top_reg_block.sub_reg_block0.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);
1: top_reg_block.sub_reg_block1.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);

Why was it throwing the above error’s when I made the above connections ? Can anyone share your comments/suggestions and help me out on this !!

Thanks in Adv !
Desperado

In reply to desperadorocks:

Don’t quote me on this, but I think the moment you instantiate your sub-blocks in your top level block and map the sub-maps in the big map, that will become the default map through which all register accesses are started, regardless of hierarchy. You probably don’t have a sequencer set for this map.

Since you want access through different maps (i.e. bus interfaces), I think you need to pass the corresponding map to ‘write(…)’ or ‘read(…)’ explicitly:


qr_reg_model.D0.R_D_CLR_ADDR.write(status, 15, .map(qr_reg_model.D0.default_map), .parent(this));

In reply to Tudor Timi:

Thanks Tudor, for your suggestions !

a. True, I didn’t set any sequencer/adapter for the default reg-map for the top level register block but I did for the default maps of the sub-level register block as given below.


0: top_reg_block.sub_reg_block0.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);
     1: top_reg_block.sub_reg_block1.default_map.set_sequencer(each_reg_agt[i].each_reg_sqr, each_r2b_adapter[i]);

But then to which sequencer/adapter will I map the top level default map too ?? because I had planned to use two separate interfaces to process registers present in the sub-block parallely and I cannot set two different sequencer/adapter to the same default top level register map right ?

Kindly share in your comments/thought process on this !!

Regards,
Desperado

In reply to desperadorocks:

I had a look in the code and it seems to me that the map you’ll get is implementation specific. There’s a ‘get_default_map()’ function in ‘uvm_reg’. If a register is mapped in multiple maps, it will do a loop over all maps:


foreach (m_maps[l]) begin
  // ...

‘m_maps’ is an associative array that contains all maps a register is mapped in. The IEEE 1800-2012 standard says in Section 7.8.5 Other user-defined types:

If the relational operator is defined for the index type, the ordering is as defined in the preceding
clauses. If not, the relative ordering of any two entries in such an associative array can vary, even
between successive runs of the same tool. However, the relative ordering shall remain the same
within the same simulation run while no indices have been added or deleted.

This means you can’t rely on which map gets selected. You have to always supply a map when a register is mapped multiple times.

N.B. I guess they implemented ‘m_maps’ as an associative array and not a normal array so they can use the ‘exists(…)’ method to check if a map exists or not. Since they only use SV 2009 code, they couldn’t use the new SV 2012 array locator methods.

In reply to Tudor Timi:

All I said above is valid, but I don’t think it actually pertains to your situation. Your registers are only mapped in one map. This means you’re always getting the same ‘default_map’, the one your register is mapped in. The access isn’t started on the sequencer associated with this map, but on the one associated with the system level map (i.e. the topmost level map). Since your top level ‘default_map’ doesn’t have any sequencer, you get the error message.

I guess you only need the top level map to set the offsets your sub-maps are at. What you could do is have 2 top level maps, one for each interface.


class top_reg_block extends uvm_reg_block;
  uvm_reg_map map0, map1;

  function void build();
    map0.add_submap(block0.default_map, 'h0);
    map1.add_submap(block1.default_map, 'h100);
  endfunction
endblock

You still need to set the sequencers for these two maps:


class top_reg_block extends uvm_reg_block;
  uvm_reg_map map0, map1;

  function void build();
    // ...
    map0.set_sequencer(block0.default_map.get_sequencer());
    map1.set_sequencer(block1.default_map.get_sequencer());
  endfunction
endblock

At the same time, instead of mapping your 2 sub-block maps inside other higher level maps, you could fiddle their offsets in the top reg block using ‘set_base_addr(…)’.


class top_reg_block extends uvm_reg_block;
  function void build();
    block0.default_map.set_base_addr('h0);
    block1.default_map.set_base_addr('h100);
  endfunction
endblock

In reply to Tudor Timi:

WoW ! Thanks Tudor ! Appreciate your timely comments/suggestions. I am going ahead with the separate maps for the sub-blocks as given above and its working fine.

But it would be great if they provide support in the UVM libraries for setting the sequencer/adapter for the sub-blocks from the top level block register map.

Anyways it was an awesome learning once again and appreciate your comments on timely manner. !!

Regards,
Desperado

In reply to desperadorocks:

Is this supported in UVM libraries now ?