Jump to content

RAL. Mirroring registers with the same addresses

Recommended Posts

I have DUT which contains 2 registers ( A and B ) with the same addres. DUT also has the third register ( C ) which control to what register write: to A or to B.

Using RAL we have problems with mirroring registers A and B, because they have the same physical addres.
How caw we solve it?

I found a way which works:
1) give registers A and B unique addresses
2) make register adapter to change address using register C

Link to post
Share on other sites

For your specific case, you might consider an alternative frontdoor path. With this method, you create a sequence that runs on--well, any sequencer really--and is assigned to the A & B registers using set_frontdoor. This sequence extends uvm_reg_frontdoor and contains an 'rw_info' variable. This rw_info variable holds the information of the transaction. Based on the value of C, the registers can then be manipulated like any other.



uvm_reg chosen_reg;
uvm_reg_status status;

chosen_reg = (p_sequencer.reg_block.C.SELECTOR.get() == <A_SELECTED>)? 
              p_sequencer.reg_block.A :

if(rw_info.kind == WRITE)
  chosen_reg.write(status, rw_info.value[0]);
else begin
  uvm_reg_data_t value;
  rw_info.value = new[1];
  chosen_reg.mirror(status, value);
  rw_info.value[0] = value;

It's something like that.


Not to be too self-aggrandizing, but my book demonstrates this method more clearly:


or the e-book: http://tinyurl.com/AdvancedUVM-ebook.

Link to post
Share on other sites

There's a section in the User Guide talking about indexed registers. Have a look at that.



For this comment, I think we can try to make it this way:

// -----------------------------------------
// Real DUT register
// way field controls which data register
// will be ascessed
// ------------------------------------------
class ctrl_reg extends uvm_reg;
  uvm_reg_field   some_field;
  uvm_reg_field  way; // if 0, access to data0 reg, if 1, access to data1 reg

// -----------------------------------------
// Virtual register, idx field is a handle
// to way field of ctrl_reg
// ------------------------------------------
class idx_reg extends uvm_reg;
  uvm_reg_field   idx;

// -----------------------------------------
// data0 and data1 share the same physical
// address
// ------------------------------------------
class data0_reg extends uvm_reg;
  uvm_reg_field field0;

class data1_reg extends uvm_reg;
  uvm_reg_field field0;
  uvm_reg_field field1;

// -----------------------------------------
// Indirect register for accesing data0 and
// data1 registers.
// The number of bits in each register in 
// the register array must be equal to n_bits 
// of this register.
// ------------------------------------------
class data_reg extends uvm_reg_indirect_data;
// No fields
class reg_model extends uvm_reg_block;
  ctrl_reg  ctrl;
  idx_reg   idx;
  data0_reg data0;
  data1_reg data1;
  data_reg  data;
  uvm_reg   reg_ar[];
  virtual function build();
    reg_ar = new[2];
    data0 = data0_reg::type_id::create();
    data1 = data1_reg::type_id::create();
    reg_ar[0] = data0;
    reg_ar[1] = data1;

    ctrl = ctrl_reg::type_id::create();

    idx = idx_reg::type_id::create();
    idx.idx = ctrl.way;
    data = data_reg::type_id::create();
    data.configure(idx, reg_ar, this, null);
    default_map = create_map(““, 0, 4, UVM_BIG_ENDIAN);
    default_map.add_reg(ctrl, 0);
    default_map.add_reg(data, 4);


P.S. this is just concept

Link to post
Share on other sites

What you can also do is define your own "indirect data register" class that is more tailored to your situation:

class some_indirect_data_reg extends uvm_reg_indirect_data;
  ctrl_reg ctrl;
  data0_reg data0;
  data1_reg data1;

  // override configure
  function void configure (ctrl_reg ctrl,
                           data0_reg data0,
                           data1_reg data1,
                           uvm_reg_block blk_parent,
                           uvm_reg_file regfile_parent = null);
    // ...
    m_tbl = new[2];
    m_tbl[0] = data0;
    m_tbl[1] = data1;

  virtual function uvm_reg get_indirect_reg(string  fname = "",
                                            int     lineno = 0);
    int unsigned idx = ctrl.way.get_mirrored_value();

  // do prediction and starting stuff using 'get_indirect_reg'

Encapsulating it like this means less code in your register block where you instantiate your regs, which will make it more readable. Everything else is just implementation detail which should be hidden. It's also more compile-time safe, because you force the reg block to connect regs of the appropriate types (ctrl_reg, data0_reg and data1_reg) instead of the generic uvm_reg type.


Unfortunately, the UVM class ("uvm_reg_indirect_data") is poorly written and it can't easily be extended. Ideally it would have relied on calls to "get_indirect_reg(...)" in its own code to figure out which register to use for updating or for checking. This would have made your life much easier, because you would have only needed to override this virtual function and everything else would have worked. You'll have to spend a bit of effort to get it to work like this, because you'll need to override other functions too.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...