Verification Martial Arts: A Verification Methodology Blog

How you can figure how you configure (a VMM testbench): Part 1

Posted by JL Gray on December 7th, 2010

Jonathan Bromley, Verilab Inc, Austin, Tx

Part 1: Using configuration objects

Each VMM transactor class should have a companion config class, where you create data members for all critical “vital statistics” of the transactor.  Just before constructing the transactor object, an enclosing subenv would create one of these config objects and then pass it to the transactor as a constructor argument.  Every transactor should also provide a reconfigure method allowing other parts of the environment to set up a new configuration for it at any time.


Objects to control objects
Here’s an imaginary example of a transactor configuration class:

class MagicPacketXactor_cfg;
  rand shortint unsigned MaxLength;
  rand bit SupportsVoodooMode;
    constraint c_valid_packet {
      if (SupportsVoodooMode) { MaxLength inside {[64:16384]}; }
      else { MaxLength == 1024; }

Note how the class contains rand data members for all the transactor’s configurable attributes, and also has constraints so that it will yield a meaningful and interesting set of configuration values when randomized.  Of course, further constraints can easily be added to enforce specific configurations.

The corresponding transactor code might be something like this:

class MagicPacketXactor extends vmm_xactor;
  local MagicPacketXactor_cfg cfg;
  function new( … // usual VMM constructor arguments, and then…
                MagicPacketXactor_cfg cfg = null);
    if (cfg == null) begin
      cfg = new;
    this.cfg = cfg;
  function void reconfigure(MagicPacketXactor_cfg cfg);
    this.cfg = cfg;

In the transactor’s main() task, or elsewhere, we can now do things like

if (this.cfg.SupportsVoodooMode)

It’s really important to note that the transactor takes no responsibility for setting up its own configuration.  It merely assumes that a configuration object has been supplied from outside, and then makes use of the values within that configuration object.  If the enclosing environment fails to provide a configuration object, as a last resort the transactor constructs its own randomized configuration.

This is a good example of the notion of encapsulating configuration in a single object.  By gathering all important attributes of a component into a class:
•    we can pass the entire configuration around as a single object or reference;
•    it becomes easy to write randomization constraints that establish relationships among configuration attributes;
but most important of all:
•    it is straightforward to assemble several configuration objects into a single, larger configuration object suitable for use at the next level up the hierarchy– typically at the vmm_subenv level.

Environment configuration
A verification environment for a MagicPacket-to-Ethernet bridge will of course contain both MagicPacket and Ethernet transactors.  The environment or subenv gets its own configuration class, containing references to configuration objects for both its transactors:

class MagicToEthernet_subenv_cfg;
  rand MagicPacketXactor_cfg magic_cfg;
  rand Ethernet_cfg eth_cfg;

Configuration proceeds in much the same way as for the transactors.  The environment’s constructor takes one of these objects as an argument, and then passes on its inner configuration objects to the corresponding transactors as it constructs them.  Reconfiguring the environment is equally straightforward:

class MagicToEthernet_subenv extends vmm_subenv;
  MagicPacketXactor magic_xactor;
  EthernetXactor eth_xactor;
  function void reconfigure(MagicToEthernet_subenv_cfg cfg);

Finally, the code that launches your VMM test can create and populate all the necessary configuration objects, assemble them into environment-wide configuration objects, and pass them into constructors as needed.  It is also very easy to configure multiple transactors to match a common configuration simply by passing the same configuration object to all of them.

Testbench configuration vs. test configuration
The configuration mechanism we’ve explored is neat, powerful and straightforward.  However, it doesn’t offer very much help in separating the two rather different concerns of configuring the test environment and configuring the test.

Test environment configuration gets you the right structure – correct number of transactors, correct choice of active vs. passive transactors, choice of reference model or scoreboard – to match the chosen device-under-test.  Using that test environment, though, you probably wish to run a large and ever-growing battery of testcases as you develop new stimulus to hit elusive coverage objectives.  From a programming point of view, configuring the test is not very different from configuring the testbench –a matter of passing appropriate configuration objects to the constructors of various components.  From an organizational point of view, though, there are big differences.   Testbench configuration generally needs to be at least partly driven by parameters of the DUT and test harness, whereas testcase configuration is likely to be much more flexible and dynamic, and will vary from run to run.

When using configuration objects in this style, I’ve learnt the value of keeping a strict separation between these two kinds of configuration to simplify those organizational concerns.

In the second part of this article we’ll look at the impact of the extensive new configuration facilities in VMM 1.2, and explore a novel way to manage groups of inter-related configuration options.


One Response to “How you can figure how you configure (a VMM testbench): Part 1”

  1. CVCBLR (CVC Says:

    RT @am_its: How you can figure how you configure (a VMM testbench) – #VMM #SystemVerilog