Jump to content
Sign in to follow this  
joniale

Maybe an error on UVM 1.1d for uvm_reg_map.svh class

Recommended Posts

Hi ,

To whom may correspond

I think there is some kind of error in the UVM 1.1d register model.

I have been experimenting with the UVM register model and i have seen the following code in uvm_reg_map.svh

 

task uvm_reg_map::do_bus_write (uvm_reg_item rw,
                                uvm_sequencer_base sequencer,
                                uvm_reg_adapter adapter);

  uvm_reg_addr_t     addrs[$];
  uvm_reg_map        system_map = get_root_map();
  int unsigned       bus_width  = get_n_bytes();
  uvm_reg_byte_en_t  byte_en    = -1;
  uvm_reg_map_info   map_info;
  int                n_bits;
  int                lsb;
  int                skip;
  int unsigned       curr_byte;
  int                n_access_extra, n_access;
  int               n_bits_init;

  Xget_bus_infoX(rw, map_info, n_bits_init, lsb, skip);
  addrs=map_info.addr;

  // if a memory, adjust addresses based on offset
  if (rw.element_kind == UVM_MEM)
    foreach (addrs[i])
      addrs[i] = addrs[i] + map_info.mem_range.stride * rw.offset;

  foreach (rw.value[val_idx]) begin: foreach_value

     uvm_reg_data_t value = rw.value[val_idx];

    /* calculate byte_enables */
    if (rw.element_kind == UVM_FIELD) begin
      int temp_be;
      int idx;
      n_access_extra = lsb%(bus_width*8);                
      n_access = n_access_extra + n_bits_init;
      temp_be = n_access_extra;
      value = value << n_access_extra;
      while(temp_be >= 8) begin
         byte_en[idx++] = 0;
         temp_be -= 8;
      end                        
      temp_be += n_bits_init;
      while(temp_be > 0) begin
         byte_en[idx++] = 1;
         temp_be -= 8;
      end
      byte_en &= (1<<idx)-1;
      for (int i=0; i<skip; i++)
        void'(addrs.pop_front());
      while (addrs.size() > (n_bits_init/(bus_width*8) + 1))
        void'(addrs.pop_back());
    end
    curr_byte=0;
    n_bits= n_bits_init;     

 

The code continues but the interesting part is already there.

Lets assume we have a register with 4 bytes and 1byte per address granularity (byte_addressing).

Now, we do a FIELD access of 8bits length (the first byte of a register). The field is configured "individual_accessible, so UVM should only access that FIELD. The reg2bus should generate that byte request to be written.

In other words, the vector "addrs" should have only one byte address.

Going to the code, i see that initially the addrs has the 4 address ( the whole register) and when it comes to the "if (rw.element_kind == UVM_FIELD) begin" and it will pop_back()/remove all the exceeding bytes that doesn't need to complete "n_bits_init" of the field access.

The problem is here:

UVM has
//while (addrs.size() > (n_bits_init/(bus_width*8) + 1))
and i think it should be
 while (addrs.size() > ((n_bits_init-1)/(bus_width*8) + 1))  //ejonalv possible error in UVM? check

That is because in case we want to write 8 bits, it will calculate 8/8+1=2 address in the UVM version, but in fact it should require only 1 address.

This is of course applicable for the READ variation.

Did i misunderstand something? It is very hard to go through the register model without proper documentation in the code.

I am looking forward your answer

Best Regards

Jonathan

Share this post


Link to post
Share on other sites

Hi again,

I want to report another minor issue.

the issue is applicable  in case you want a layering sequence for registers in AXI.

  I mean what is described here:

https://www.mentor.com/products/fv/resources/overview/a-new-class-of-registers-2e32ca83-d5ee-4e34-8880-c006be7e537f

As you can see a layering sequence allows you to create randomized register accesses that are not possible with the adapter and the default uvm_reg_map. This is needed to test that registers are written/read correctly with different AXI accessed than the fix accesses done by the uvm library. 

In that case you have to disable your adapter (being null) to avoid the bus_write and bus_read functions as described in the paper of the link.

Unfortunately,  the function "is_indv_accessible" needs an "adapter".

That means you cannot access is_individual_accessible field flag of your register model, in case you are using the sequence layering methodology. 

To workaround this problem and be able to use UVM_FIELD kind accesses,   we can redirect all uvm_reg_field write/read fuctions with a custom uvm_reg_field read/write functions(this can be done with settypeoverride by type all uvm_reg_field classes).  In those new custom_reg_field functions you can, 1. redirect the field call to a register type call with the same inputs and second use the extension to pass in the redirected REGISTER write/read the uvm_reg_item corresponding to the original FIELD access.

Afterwards, you can check in the sequence layer if the UVM_REG register request item has an extension containing a FIELD!=null. If that is the case, it means the register access is not a register access but in fact a redirected FIELD access. That field access can be processed in your layering sequence, that creates the stimuli needed for that field.

////////

However, the correct way would be that uvm retrieves the "supports_byte_enable" information not from the adapter but from uvm_reg_map.

In other words,

i think that the configuration flags "supports_byte_enable" and "provides_responses" should be declared inside the uvm_reg_map and not inside the adapter. Besides, there should be set and get functions for those signals so that these can be set from the environment or from the adapter itself.
 

I hope i have explained the issue.

Best regards,

Jonathan

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×