RAL model implication for same UVM Register with different offset (with 2 interfaces)

Hi, I have an requirement where I need thoughts to handle a situation.
Requirement;

I have 1 register block called A. Under block A there are group of registers. Reg1, Reg2, …
In the design there are 2 interfaces. AHB and SPI.

Now to access register under block A (A.Reg1) from AHB and SPI has different offsets. Base addresses are different. Register can be accessed from both interfaces with different offsets. As there is only 1 physical address in RTL with different offsets would like to have UVM RAL model same way. In the DV we have 2 adapter, SPI, AHB with Reg block A instantiated. I do not want two different Reg block with offset hard-coded.

For an example in the RTL if from AHB adaptor we have a top_reg_blk.Reg1.write(status, 32’hbabacafe), same value can be read from SPI top_reg_blk.Reg1.read(). Mirror value from both of interface should be same.

This is an often situation when multiple interfaces have an access to dut regs with different offsets seen from them.

How we can implement this through RAL? Somewhere I read we need to create 2 different maps for such cases. Need example code with more details.
P.S. Ignore raise condition user will take care of accessing them together.

In reply to Geet:

In your register block, you can create two different maps for the two interfaces (e.g. AHB_MAP & SPI_MAP), and then specify the target interface in each read or write operation.

E.g.

class yourRegBlock extends uvm_reg_block;
  uvm_reg_map AHB_MAP;
  uvm_reg_map SPI_MAP;
  
  /* Instances of all registers in yourRegBlock: REG1_INST, REG2_INST, etc */
  
  virtual function void build();
    // TODO: Revisit create_map and pass the correct configuration
    AHB_MAP = create_map("AHB_MAP ", `UVM_REG_ADDR_WIDTH'(`AHB_MAP_ADDR_BASE), 4, UVM_LITTLE_ENDIAN, 0);
    SPI_MAP = create_map("SPI_MAP", `UVM_REG_ADDR_WIDTH'(`SPI_MAP_ADDR_BASE), 4, UVM_LITTLE_ENDIAN, 0);

   /* create, build, and config different registers */

   // TODO: Revisit add_reg and pass the correct configuration
   AHB_MAP.add_reg(REG1_INST, `UVM_REG_ADDR_WIDTH'(`REG1_AHB_OFFSET), "RW", 0);
   AHB_MAP.add_reg(REG2_INST, `UVM_REG_ADDR_WIDTH'(`REG2_AHB_OFFSET), "RW", 0);
   // ...
   SPI_MAP.add_reg(REG1_INST, `UVM_REG_ADDR_WIDTH'(`REG1_SPI_OFFSET), "RW", 0);
   SPI_MAP.add_reg(REG2_INST, `UVM_REG_ADDR_WIDTH'(`REG2_SPI_OFFSET), "RW", 0);
   // ...
  endfunction: build
endclass : yourRegBlock

And then you will need to set the sequencer of each map, e.g. in connect_phase() of your environment:

   hier_path_of_yourRegBlock_inst.AHB_MAP.set_sequencer( hier_path_of_ahb_seqr, hier_path_of_ahb_adapter )
   hier_path_of_yourRegBlock_inst.SPI_MAP.set_sequencer( hier_path_of_spi_seqr, hier_path_of_spi_adapter )

Last thing you will need to specify the target interface of any read or write operation, e.g.:

   path_to_REG1_INST.write( .status(status_var), .value(value_var), .map(hier_path_of_yourRegBlock_inst.SPI_MAP))

In reply to m_wafa:

Thank you so much m_wafa.
I have 1000 regs under reg block A.
Here can we add reg block under SPI/AHB MAP instead of regs?

I’m looking where I can add entire Reg blocks under AHB MAP/SPI Map.

In reply to Geet:

No function exists in uvm_reg_map for adding complete reg block (uvm_reg_map)

So I think you may need to get all the registers in your reg block (uvm_reg_block) and then loop on them to add each register to the different maps.

Hope you find more easer method!

1 Like

In reply to m_wafa:

As you have suggested, REG1 in AHB Map and SPI Map will be different as a memory location?
i.e. There will be two REG1, 1 mapped to SPI 1 mapped to AHB if we implement this way?

If yes, then 1 question:
If you think with respect to RTL, There will be always 1 register with 2 offset [As per my requirement]. In below implementation there will be 2 instances.

What is your thought on this?

// TODO: Revisit add_reg and pass the correct configuration
AHB_MAP.add_reg(REG1_INST, UVM_REG_ADDR_WIDTH'(REG1_AHB_OFFSET), “RW”, 0);
AHB_MAP.add_reg(REG2_INST, UVM_REG_ADDR_WIDTH'(REG2_AHB_OFFSET), “RW”, 0);
// …
SPI_MAP.add_reg(REG1_INST, UVM_REG_ADDR_WIDTH'(REG1_SPI_OFFSET), “RW”, 0);
SPI_MAP.add_reg(REG2_INST, UVM_REG_ADDR_WIDTH'(REG2_SPI_OFFSET), “RW”, 0);

In reply to Geet:

As you have suggested, REG1 in AHB Map and SPI Map will be different as a memory location?
i.e. There will be two REG1, 1 mapped to SPI 1 mapped to AHB if we implement this way?

No, only one REG1, the different maps is used just to specify through which interface/sequencer/adapter the frontdoor read/write transaction will be performed.

In below implementation there will be 2 instances.

For each register, one instance is instantiated, built, and configured in the reg_block, not two or multiple instances. Adding register to multiple maps doesn’t create different instances.

1 Like