Sunday, August 24, 2014

SystemVerilog 2012 Has Even More 'Class'

While scouring the Web for blogs on verification, I came upon this post on Ankit Gopani's blog. He tries to shed some light on the various types of classes that SystemVerilog has. What is missing, however, is the interface class, a new construct brought into the language by the IEEE 1800-2012 standard.

An interface class has nothing to do with the interface construct. It represents the same concept as an interface in Java (a lot of SystemVerilog's object oriented programming constructs are pretty similar similar to Java's). What does an interface class do? It's basically a collection of method declarations. Notice I've used the word 'declarations' and not 'definitions', as all methods of an interface class must be pure. Another class can implement an interface class, which requires it to implement all of the methods declared in that interface.

Why is this useful? I'll answer this question with the help of an example. Let's say I have my own library. In this library I expect to operate on a certain type of objects (by operating on objects I mean calling methods on them). Concretely, let's say I have the 'drivable' interface, which defines the capabilities of an object that can be driven (I don't want 'car' here and you'll see why in just a bit). What can a drivable object do? Well, it can accelerate, it can turn and it can brake, to name a few things. We model these as functions that a drivable object has:

interface class drivable_if;
  pure virtual function void accelerate();
  pure virtual function void turn_left();
  pure virtual function void turn_right();
  pure virtual function void brake();
endclass

A driver can use these methods to drive a drivable object:

class driver;
  protected drivable_if m_drivable;
  
  function new(drivable_if drivable);
    m_drivable = drivable;
  endfunction

  function void drive();
    m_drivable.accelerate();
    m_drivable.turn_right();
    m_drivable.accelerate();
    m_drivable.turn_left();
    m_drivable.brake();
  endfunction
endclass

Our driver class can operate on any object that provides the methods of the drivable_if interface, regardless of how these methods are implemented. (I'll use the term 'interface' instead of 'interface class' in this post, but just know that this is what I mean.)

In our code (outside of the library), we define the car class, that implements the drivable_if interface:

class car implements drivable_if;
  
  //----------------------------------------
  // methods of drivable_if  
  //----------------------------------------
  
  virtual function void accelerate();
    $display("I'm accelerating");
  endfunction

  virtual function void turn_left();
    $display("I'm turning left");
  endfunction

  virtual function void turn_right();
    $display("I'm turning right");
  endfunction

  virtual function void brake();
    $display("I'm braking");
  endfunction
endclass

We can now use an instance of this class, together with an instance of the driver class:

module top;
  initial begin
    static car the_car = new();
    static driver the_driver = new(the_car);
    the_driver.drive();
  end
endmodule

Remember, the driver class and the drivable_if interface are defined in an own package (that we downloaded, bought, etc.), which we'll assume we can't change. We could, however, let our own car object be driven by the driver object, even though the driver class did not know anything about the car class. This is because the car class provides the methods that the driver expects to be able to drive it. It doesn't matter how those methods were implemented, just that they were implemented.

What you're now probably going to ask is: "But Tudor, why didn't you just implement a virtual class? You can essentially get the same thing: you define the methods and you can't create any instances of that class.". And you would be right, but what if we want our car class to implement another interface at the same time? If I use a virtual class, I'm in trouble, because you can only extend one base class. You can, however, implement as many interfaces as you want.

What else do you want to do with a car besides drive it? You want to insure it. I don't know how it is in other places, but in most (if not all) European countries, the insurance premium depends on the size of the car's engine. What it may also depend on is the accident history of the car (not technically true in the real world, but please bear with me on this one). Insuring a car is a different aspect than driving it, so it makes sense to have a separate library the handles this topic. Following the example from above, this is how the interface for an insurable object (notice I didn't say car) might look like:

interface class insurable_if;
  pure virtual function int unsigned get_engine_size();
  pure virtual function int unsigned get_num_accidents();
  pure virtual function int unsigned get_damages(int unsigned accident_index);
endclass

Using these methods to query an object, an insurer could compute the premium for that object:

class insurer;
  virtual function int unsigned insure(insurable_if insurable);
    int engine_size = insurable.get_engine_size();
    int num_accidents = insurable.get_num_accidents();
    int damages;
    for (int i = 0; i < num_accidents; i++)
      damages += insurable.get_damages(i);

    // do some bogus calculation
    return engine_size * 10 + damages * 100;
  endfunction
endclass

Let's take our previous car class and expand it to be insurable. What we need to do is implement the insurable_if interface and define its methods:

class car implements drivable_if, insurable_if;
  protected int unsigned m_engine_size;
  protected int m_damages[];
  
  function new(int unsigned engine_size);
    m_engine_size = engine_size;
  endfunction

  function void crash(int damages);
    m_damages = new[m_damages.size() + 1] (m_damages);
    m_damages[m_damages.size() - 1] = damages;
  endfunction
  
  
  //----------------------------------------
  // methods of insurable_if  
  //----------------------------------------

  virtual function int unsigned get_engine_size();
    return m_engine_size;
  endfunction

  virtual function int unsigned get_num_accidents();
    return m_damages.size();
  endfunction

  virtual function int unsigned get_damages(int unsigned accident_index);
    assert (accident_index < get_num_accidents());
    return m_damages[accident_index];
  endfunction
  
  
  //----------------------------------------
  // methods of drivable_if  
  //----------------------------------------
  
  // ...
endclass

I've added a crash() method to simulate an accident. Let's insure our car:

module top;
  initial begin
    static car the_car = new(3);
    static driver the_driver = new(the_car);
    static insurer the_insurer = new();
    
    the_driver.drive();
    the_car.crash(500);
    $display("The insurance premium is ", the_insurer.insure(the_car));
  end
endmodule

What we can do now is drive the car, like before, but we can also insure it. We've managed to glue together two different behaviors into one single class (car) and then use them in objects that are each concerned with only one of these behaviors (driver and insurer). We also didn't mix in any information about insurability in the drivability package and vice-versa  This wouldn't have been possible without interface classes.

If we were to use only inheritance, this would mean that we would need to have a base class that contained both the drivable_if and the insurable_if methods. Then, both of these libraries could operate on subclasses of this class. The biggest (and I really mean big) problem with this is that this creates tight coupling between the two libraries. What if we want to use a third library? Our base class would need to contain the methods this library uses to operate on objects as well. Throw a forth library in the mix and it already becomes unmanageable. If we would want to implement just one of these behaviors in a subclass, we would still be cluttered with methods from the others. Using only inheritance results in big class hierarchies, with a lot of duplication and parallel branches.

Look at the UVM for example. It tries to do everything, simply because it has to do as much as possible. The reason is that once you're inheriting from a UVM class, you're kind of stuck in that class hierarchy. You have to use libraries that can operate with UVM classes. By using interface classes, you can happily extend from any UVM class, but at the same class implement any number of interfaces you want. This means you can now work with libraries that are completely agnostic of UVM. With interface classes using UVM stops being an "either/or" proposition.

The UVM BCL could also use a makeover. The current implementation of TLM is a mess in my opinion. It relies heavily on macros, with all TLM methods declared in all port types. The ones that are not supposed to be used in a certain port are blocked at run time by issuing an error. Ideally, calling a method not intended for a specific port should not make it past compile. Have a look at the implementation and tell me if that code is clear and maintainable to you (the files are uvm_tlm_ifs.svh, uvm_ports.svh and uvm_tlm_imps.svh).

TLM is implemented very cleanly in SystemC, using the interface concept. Dave Rich already touched on this subject in his DVCon Paper, "The Problems with Lack of Multiple Inheritance in SystemVerilog and a Solution". He already stated that interfaces would solve the problem of having to copy-paste a lot of code between classes. The paper was written in 2010, so there wasn't any interface class yet (though I suspect it was in the works). Here's a short example of how the TLM get interfaces could be implemented:

interface class uvm_blocking_get_if #(type T=int);
  pure virtual task get(output T t);
  pure virtual task peek(output T t);
endclass


interface class uvm_nonblocking_get_if #(type T=int);
  pure virtual function bit try_get(output T t);
  pure virtual function bit can_get();
  pure virtual function bit try_peek(output T t);
  pure virtual function bit can_peek();
endclass


interface class uvm_get_if #(type T) extends
  blocking_get_if #(T),
  nonblocking_get_if #(T);

Here we also see another cool fact: an interface class can extend as many interface classes as it wants. This means that the uvm_get_if will declare all of the methods of both the uvm_blocking_get_if and of the uvm_nonblocking_get_if. The family of get ports will implement these interfaces:

class uvm_blocking_get_port #(type T=int) implements
  uvm_blocking_get_if #(T);
  // ...
  
  virtual task get(output T t);
    // ...
  endtask
  
  // other uvm_blocking_get_if interface methods ...
endclass


class uvm_nonblocking_get_port #(type T=int) implements
  uvm_nonblocking_get_if #(T);
  // ...
  
  virtual function bit try_get(output T t);
    // ...
  endfunction
  
  // other uvm_nonblocking_get_if interface methods ...
endclass


class uvm_get_port #(type T=int) implements
  uvm_get_if #(T);
  // ...
  
  // uvm_blocking_get_if interface methods ...
  
  // uvm_nonblocking_get_if interface methods ...
endclass

Doing the following will now result in a compile error:

uvm_nonblocking_get_port some_port = new();
some_item item;

some_port.get(item);

The get(...) method is not defined in the uvm_nonblocking_get_port_if interface, so the compiler can immediately flag an error, something that isn't possible in the current release of the UVM library.

Now, dare I say that the whole TLM aspect could be spun out into a standalone library that could be used by others that want to use TLM, but not the whole UVM? Yes I do dare, but whether this will happen is doubtful. Many more such examples could be found in the UVM BCL; to name one, the whole sequence mechanism is also a pretty unwieldy beast.

I hope this post inspires you to incorporate interface classes into your coding to enable the creation of reusable libraries that are orthogonal to each other, but can be used together. A great example of this is the Java standard library. I also hope that this new feature will lead to the creation of more open source packages that can accomplish various tasks. Great initiatives are svlib and cluelib. I don't know if they use interface classes as I didn't look at the code, but if they don't, then they should consider it.

If you want to learn more about interface classes, you can find more info in the LRM. You can also read up more on interfaces in various Java articles as the concepts are pretty much the same. You can find the for the code for the drivable and insurable interfaces on the blog repository.

Stay tuned for more updates on other (not so) new SystemVerilog 2012 features!

Friday, August 8, 2014

Theory vs. Practice - Reserved Fields in UVM RAL

A seemingly simple question that comes up every now and then is "How do I properly handle reserved fields in UVM RAL?". The answer seems straightforward, right? You just don't model them. This is what the UVM guys tell you. While this does work in most cases, sometimes things aren't so simple. This may have been the intention of how it's supposed to work, but this is not what made it into the BCL implementation.

Let's take a step back and first look at what reserved fields are. They are usually empty bit locations in a register, where no "real" field is defined. Typically there are no storage elements behind them. These locations are reserved for future use, for example adding new fields in a register for a new version of the product.

But what if we have some register bits that are declared as reserved in the spec, but actually have some storage elements behind them? This is the opposite case from above. In this case some storage elements are implemented, but are not intended to be used anymore. This may be because the feature controlled by those bits is supposed to be phased out (but the RTL was not yet modified) or it is just plain hidden.

As luck would have it a colleague of mine had this situation about a month back. He was writing some random values to a register that included reserved bits, but when he was reading them back he didn't get 0s at those positions. When asked how he should handle this, I gave him the naïve answer from the beginning of the post: "Just don't model them and they won't be checked.". We tried this, but this isn't what happened.

I've distilled a little example for this case. Here is a simple register with two fields and a gap between them:

class example_reg_type extends uvm_reg;
  `uvm_object_utils(example_reg_type)
  
  rand uvm_reg_field field1;
  rand uvm_reg_field field2;
  
  function new(string name = "example_reg_type");
    super.new(name, 32, UVM_NO_COVERAGE);
  endfunction
  
  virtual function void build();
    field1 = uvm_reg_field::type_id::create("field1");
    field2 = uvm_reg_field::type_id::create("field2");
    
    field1.configure(this,  8, 24, "RW", 0, 0, 1, 1, 0);
    // there is a gap of 16 bits in between
    field2.configure(this,  8,  0, "RW", 0, 0, 1, 1, 0);
  endfunction
endclass

Using a test harness (the details of which I will spare you in this post), we can emulate bus accesses to this register. Let's do a little sanity check to see how errors are handled in the register model. We write all ones to the register, but when reading it back, let's say that the DUT has a bug in it and it didn't update the value of field1:

class example_reg_test extends uvm_test;
  // ...
  
  task run_phase(uvm_phase phase);
    example_reg_item item = new("item");
    
    // write all ones
    item.write = 1;
    item.data = '1;
    aport.write(item);
    $display("register value: %h", example_reg_block.example_reg.get());
    
    // read the register
    // - the DUT didn't update field1
    item.write = 0;
    item.data = 'hff;
    aport.write(item);
  endtask
  
endclass

In this case, the error message will look like this:

[RegModel] Register "example_reg_block.example_reg" value read from DUT (0x00000000000000ff) does not match mirrored value (0x00000000ff0000ff)
[RegModel] Field field1 (example_reg_block.example_reg[31:24]) mismatch read=8'h0 mirrored=8'hff

We can clearly see from the error message that our shadow register's field1 is out of sync with the one inside the DUT.

Now let's model the situation where our reserved bits are not so reserved. After writing all ones to the register, let's say that the DUT actually had some flip-flops for the bits between the two fields and that these were updated. Remember, we didn't model any field between bits 23 to 8 and because of this we aren't expecting the register model to care what happens at these locations. Here is the code for this:

class example_reg_test extends uvm_test;
  // ...
  
  task run_phase(uvm_phase phase);
    // ...
    
    // read the register
    // - the DUT delivers 1s for the reserved bits
    item.write = 0;
    item.data = 'hff_ffff;
    aport.write(item);
  endtask
  
endclass

I guess you already figured out that I did this little exercise to show you something goes wrong in this situation. The error message we get in this case is:

[RegModel] Register "example_reg_block.example_reg" value read from DUT (0x0000000000ffffff) does not match mirrored value (0x00000000000000ff)

There is no mention of what field has a different value. But how come? I thought that any "fields" left un-modeled won't get checked. We'll this isn't really true. If we look at the UVM source code (lines 2875 to 2885 of uvm_reg.svh in case you're interested) we see that any locations not containing fields do not get masked off. This means the value we receive from the DUT is compared with the 0s inside the shadow register. Coming back to the discussion at the start of the post, handling "don't care" locations like this (leaving them un-modeled) may have been the intention of the UVM developers, but this isn't what is implemented. There's even a Mantis entry for this issue (http://www.eda.org/mantis/view.php?id=4806), though I don't know what the status of this is since it's still marked as TBD. A thing like this could have been easily found by a unit test, but that's a different story...

It seems like what we need to do is disable the comparison for the specific locations. UVM RAL doesn't have a register compare mask per se as in vr_ad. Compare masks are set on a per field basis (and this is a good thing; if you want to have the same for e have a look at my post about disabling checks for fields in vr_ad). This means we need to define a dummy field at the problematic location. The access policy for it is irrelevant seeing as how we don't care about its value. What is key here is setting it as volatile.

class example_reg_type extends uvm_reg;
  `uvm_object_utils(example_reg_type)
  
  rand uvm_reg_field field1;
  rand uvm_reg_field rsvd;
  rand uvm_reg_field field2;
  
  function new(string name = "example_reg_type");
    super.new(name, 32, UVM_NO_COVERAGE);
  endfunction
  
  virtual function void build();
    field1 = uvm_reg_field::type_id::create("field1");
    rsvd   = uvm_reg_field::type_id::create("rsvd");
    field2 = uvm_reg_field::type_id::create("field2");
    
    field1.configure(this,  8, 24, "RW", 0, 0, 1, 1, 0);
    rsvd  .configure(this, 16, 8,  "RW", 1, 0, 1, 1, 0);
    field2.configure(this,  8,  0, "RW", 0, 0, 1, 1, 0);
  endfunction
endclass

When testing it we'll see that the error message goes away. Success!

Now we're fully equipped with how to handle problematic reserved fields in UVM RAL. Read-only locations without any flip-flops can be left un-modeled, but reserved fields with storage elements behind them must be modeled as volatile fields to disable checking. If you want to play around with this example you can find it on SourceForge.

Until next time! Also, don't forget to subscribe if you don't want to miss any future UVM posts.