Part of the  

Chip Design Magazine

  Network

About  |  Contact

Archive for April, 2015

Part II: The Ecstasy and the Agony of UVM Abstraction and Encapsulation Featuring the AMIQ APB VIP

Thursday, April 23rd, 2015

Part II of our tour through UVM reusability through TLM ports and the factory in the AMIQ APB VIP.

by Hamilton Carter – Senior Editor

Tuning the Receiver
Part I didn’t answer how, (or indeed if), the monitor’s messages make their way over to the write_item_from_mon method in the coverage collector.   Remember, the method is defined in the coverage collector, but apparently called from nowhere.  It gets worse.  Not only is the method not called from within the AMBA/APB package, but apparently it’s not called from the cagt package either!  Go ahead and look.  Take your time, grep through the files… I’ll be here when you get back.

You probably found the definition of the method up in the cagt package, but not a call to the method.  There’s a bit of UVM macro chicanery going on here.  You might have noticed a macro call at the top of the cagt version of the coverage file:

       `uvm_analysis_imp_decl(_item_from_mon)
       //coverage class
       class cagt_coverage#(type VIRTUAL_INTF_TYPE=int, type MONITOR_ITEM=uvm_sequence_item) extends 
             uvm_component;
              //pointer to the agent configuration class
              cagt_agent_config #(VIRTUAL_INTF_TYPE) agent_config;
               //port for receiving items collected by the monitor
               uvm_analysis_imp_item_from_mon#(MONITOR_ITEM,
                cagt_coverage#(VIRTUAL_INTF_TYPE, MONITOR_ITEM)) item_from_mon_port;

 

Interestingly, the argument to the `uvm_analysis_imp_decl macro contains the last few underscore terms of the method we’re looking for, ‘_item_from_mon’.  A little further down, notice that the partial phrase turns up again where the ‘port for receiving items…’ is declared.  The macro sets up a subclass of a TLM analysis port that’s specifically named uvm_analysis_imp* where the * is replaced by the macro’s argument.  Within that sub-class, unseen by mortal code-browsing eyes, the macro also sets up the call to the coverage collectors input method ‘write_item_from_mon’ which is defined as write* where the *, you guessed it, is once again replaced by the argument to the macro: ’_item_from_mon’.

Connecting the Components
OK, now we’ve located the pertinent communications methods, but where are the two ports attached to each other?  Is magical code automatically created that attaches the ports under the sheets?  Nope!  Look in the agent file within the cagt package.  There, you’ll find both the instantiation code for the monitor and the coverage collector, as well as the code that connects the two:

       if(coverage != null) begin
               coverage.agent_config = agent_config;
               monitor.output_port.connect(coverage.item_from_mon_port);

There, everything is well-explained… except for one last little detail.  Remember the cagt package doesn’t know a thing about the APB monitor or the APB coverage collector, nor should it.  It just sits back and happily and dumbly connects an abstracted monitor, (that doesn’t do anything), to an abstracted coverage collector, (that also doesn’t do anything).  Getting the environment to actually work requires the UVM factory to pull a switcheroo of object types using set_inst_override at the last minute in the APB agent file:

function new(string name = "amiq_apb_agent", uvm_component parent);
        super.new(name, parent);

        cagt_monitor#(.VIRTUAL_INTF_TYPE(amiq_apb_vif_t),
          .MONITOR_ITEM(amiq_apb_mon_item))::type_id::set_inst_override(amiq_apb_monitor::get_type(),
          "monitor", this);

        cagt_coverage#(.VIRTUAL_INTF_TYPE(amiq_apb_vif_t), 
          .MONITOR_ITEM(amiq_apb_mon_item))::type_id::set_inst_override(amiq_apb_coverage::get_type(),
          "coverage", this);

 endfunction

 

So, there you have it.  It took a bit of up-front planning—mostly defined by the UVM architecture—and a bit more work to dig through the code, (the first time anyway). Here’s what we got in return:

  1. Using the cagt package as a base, we never have to wire monitors to coverage collectors again.  We can build subclasses of cagt_monitor and cagt_coverage that add our specific code.  The banal connection code is executed automatically in the cagt_agent.
  2. Again with cagt: we never have to instantiate TLM analysis ports in either our monitors or coverage collectors ever again.
  3. Our monitor has no ties to the rest of the environment.  It needs its cagt base class, but it knows nothing of the specific objects it’s attached to, or for that matter, who’s doing the attaching.
  4. Ditto for the coverage collector.
  5. The base class can be used as the basic structure because it has no knowledge of what it’s specifically putting together.  Specifics are all handled by the factory’s switch at the last possible moment.  Here are more details about that little trick.

Consequently, we get a much better chance of write-once-and-walk-away-code—WOAWAC, as the natives say.   Oh!  And we get to look super-smart in the process!

 

The Ecstasy and the Agony of UVM Abstraction and Encapsulation Featuring the AMIQ APB VIP: Part I

Tuesday, April 21st, 2015

An interesting thing happened on the way to arriving at a completed article about the AMIQ APB VIP:  the code-base changed completely removing a layer of abstraction!  It’s a pretty cool little testament to the age of open source coding, and perhaps also to the agile manifesto which reads, in part, “…we have come to value…working software over comprehensive documentation.”  I’ll save the—maybe obvious—digression into inheritance vs. duplication of code for another post.  For now, I’ll go ahead and post the original article—a bit of a historical anachronism even if only by five days—because it provides perspectives into the design and construction of UVM objects that are hopefully still valuable examples.

by Hamilton Carter – Senior Editor

Why UVM and reuse?
Build it once, use it anywhere?  You can have that, but you’ll have to pay.  The good news is that if you do your job correctly, you only have to pay once.  The really good news is that the authors of UVM have already done most of the heavy lifting.

As you build each gleaming piece of your verification environment, there are a few reuse goals you should keep in mind:

  1. If at all possible, you don’t want to ever touch the code again… not ever.  You’ve got better things to do with your life, not the least of which is to create the next piece of gleaming verification goodness.
  2. You’ll want to be able to pass it around.  It’s good stuff!  Your buddies should totally get the benefit of knowing you—by having easier verification lives—through reuse of your stuff.
  3. Since you’re going to pass the code around, you’ll want it to seamlessly play with other pieces of verification IP.  This will make it easier for your buddies to use it and make you look like a genius!  It will also cut down on the number of support calls you get because—you know—you’re already working on the next great thing!

Amiq’s recent open source release of their AMBA-APB, UVM-compliant verification IP, (acronyms!  Everywhere acronyms!!!), gives us a nice platform to play around with and have discussions about UVM without the usual ‘invented here’ and NDA burdens to carry.  As an example of what UVM can buy for you, and what you have to pay to get it, let’s review an otherwise rather innocuous part of the APB UVC’s architecture: the connection between the monitor and coverage collector.

The above-mentioned reuse goals are accomplished for the APB bus monitor and its associated coverage collector.  Either of the two pieces can be used independently of the other.  It’s all done through the use of TLM ports and the factory.  Let’s walk through the code to get a good firm grounding of what’s there and how it’s done.  As we do, I’ll sprinkle in architectural and procedural details.

If you want to follow along in your code editor, you’ll need to pull the code repository for the AMBA APB project from https://github.com/amiq-consulting/amiq_apb as well as the supporting abstraction layer, (also from AMIQ), at https://github.com/amiq-consulting/cagt.  We’ll be rooting around in the sv subdirectory in each case.

NOTE:  With the recent code changes to the AMIQ APB VIP, to follow along clone the historical version of the APB code from https://github.com/hcarter333/amiq_apb.git.

Broadcast News
First, a few introductions:  The monitor’s job is to watch the APB bus and report, (broadcast actually), everything that’s happening.  The coverage collector’s job is to receive information from the monitor and format it into a cogent picture of the functional coverage generated by a given testcase.

A little bit of scrounging in the coverage collector code quickly reveals that it’s activated when the write_item_from_mon function is called.

       function void write_item_from_mon(amiq_apb_mon_item transfer);
             if(transfer.end_time != 0) begin
                   cover_item.sample(transfer);

This is also where the mysteries begin.  Who calls this function?   Since we’re collecting coverage based on what the monitor sees, the monitor would be the logical culprit.  A quick look at the monitor though reveals nothing.  The function is never mentioned.  The monitor does call a write function, but not write_item_from_mon.  Could the two be related?  Yup, they are.

Here’s what’s going on.  At the end of the day, you’d like to be able to use the monitor minus its associated coverage collector, (in an accelerated environment for example), without the monitor being any the wiser.  To pull this off, the authors used something called a TLM analysis port.


Monitor and coverage collector each with their associated TLM ports

The TLM port instantiated within the monitor provides a broadcast method named ‘write’.  The monitor calls this method without a clue as to whether anyone else is listening.  He proudly proclaims his latest APB news, and couldn’t care less if anyone hears.

The write method lives inside the monitor’s output_port and this brings up our next mystery.  Try to find where in the monitor the output_port was instantiated.  I dare you!  It’s just not there.  Careful attention to the figure above reveals answer.  The output port is declared in an abstract version of the monitor defined in the cagt package mentioned at the start of the article.

Amiq encapsulated the most basic, (and by basic I mean foundational, and by foundational, I mean the literal foundation of the environment), elements of the verification environment in the cagt package.  Almost all verification environments have monitors right?  Consequently, we’d like to have to write the foundational monitor code once and then leave it alone.  To accomplish this, the basics for the monitor are setup in the more abstract cagt package instead of the AMB/APB package.

A look at the cagt monitor reveals the declaration and instantiation of the monitor’s output port.  Now we know how the monitor is sending it’s messages out—using the output ports write method—as well as where the output port is declared—in cagt_monitor.sv.
Next: Tuning the Receiver