Monday, March 31, 2014

Custom Field Access Policies in vr_ad

A big part of verifying a design is checking its registers. A register packages is usually used to accomplish this task. It provides an abstract way of describing registers, their fields and their specific access policies, reset values, etc. For Specman, the vr_ad package is the most widespread.

While register packages come with built-in support for standard access policies like read/write, read only, write only, read clear, and more, it's very common that a design employs some quirky access policies as well.

Let's take as an example an access policy defined as follows: writing to the field is allowed, except when trying to write the value 0; reading from the field is always allowed.

One way to do it in vr_ad is to use the side-effect hooks, in particular the post_access(...) method. Here's how this would look like:

<'
// define the register
reg_def EXAMPLE VGM 0x0 {
  reg_fld field1 : uint(bits : 16) : RW : 0;
  reg_fld field2 : uint(bits : 16) : RW : 0;
};

// setup quirkiness for field2
extend EXAMPLE vr_ad_reg {
  post_access(direction : vr_ad_rw_t) is also {
    if (direction == WRITE) {
      var prev_val := get_prev_value();
      var cur_val  := get_cur_value();
      
      // check value of field2
      if (cur_val[15:0] == 0) {
        write_reg_rawval(%{cur_val[31:16], prev_val[15:0]});
      };
    };
  };
};
'>

This code is pretty easy to understand. Whenever a write is performed, the value written to field2 is checked and in case it was 0 then the update is undone by writing the previous value back. This code has two main problems. Firstly, we make use of hard coded bit ranges to identify field2's bits inside the whole register. This is going to be a problem if the offset or width of field2 should change in the future. We could solve this by using some features that are buried a bit deeper inside the vr_ad implementation (but we're not going to do this here). Even after fixing the previous issue, the second problem still remains: when looking at the register definition, it isn't immediately apparent that field2 is quirky. Normally, the register definitions are generated from some sort of XML specification and the generated file is not edited by hand. Hook implementations are done in a separate file, which could lead to confusion.

Newer versions of vr_ad allow us to do the same thing in a more elegant manner. Users can now define their own custom access policies and specify what should happen on a write and on a read. Here is the new and improved version:

<'
// define a new access policy
extend vr_ad_field_attribute_t : [RWi0];

extend RWi0'fld_mask vr_ad_reg_field_info {

  // define what happens at write
  get_field_write_data_according_to_policy(read_data : vr_ad_data_t,
    ndata : vr_ad_data_t) : vr_ad_data_t is {
    if (ndata == 0) {
      result = read_data;
    }
    else {
      result = ndata;
    };
  };

  // define what happens at read
  get_field_read_data_according_to_policy(default_data : vr_ad_data_t,
    read_data : vr_ad_data_t) : vr_ad_data_t is {
    result = read_data;
  };
};


// define the register
reg_def EXAMPLE VGM 0x0 {
  reg_fld field1 : uint(bits : 16) : RW   : 0;
  reg_fld field2 : uint(bits : 16) : RWi0 : 0;
};
'>

What we first need to do is give our custom policy a name, RWi0. Then, we can extend vr_ad_reg_field_info and specify the behavior for operations on this field. The documentation for this feature is rather minimalistic, but browsing through the implementation one can discern the following:

  • the return value of get_field_write_data_according_to_policy will be used to update the field's value when performing a write operation
    • read_data contains the value that has been stored in the field prior to this write
    • ndata contains the value which is being tried to be written
  • the return value of get_field_read_data_according_to_policy will be compared with the value that was read from the DUT
    • default_data is the value that is returned for write-only fields; by default this is the reset value, but this can be changed using set_rmask_default_data(val: vr_ad_data_t)
    • read_data contains the value that is stored in the field

This code will behave in the same way as the previous one, but it has two main advantages. The first is that it it immediately visible from the register definition that field2 is quirky. The second is that if your company tends to use the same exotic policies in more designs, then the definitions of these policies could be stored in a central library somewhere and be reused. The old approach would have required a lot of duplicate code to implement the same type of quirkiness for fields in different registers.

You can find the code snippets, along with some test code, on the blog's SourceForge repository.

Stay tuned for the next post, where we'll do the same exercise in UVM RAL!

No comments:

Post a Comment