Home > Community > Blogs > Functional Verification > when less is more part 1 is e really up to 3x more compact than systemverilog
 
Login with a Cadence account.
Not a member yet?
Create a permanent login account to make interactions with Cadence more conveniennt.

Register | Membership benefits
Get email delivery of the Functional Verification blog (individual posts).
 

Email

* Required Fields

Recipients email * (separate multiple addresses with commas)

Your name *

Your email *

Message *

Contact Us

* Required Fields
First Name *

Last Name *

Email *

Company / Institution *

Comments: *

When Less Is More, Part 1: Is e Really Up to 3x More Compact Than SystemVerilog?

Comments(12)Filed under: Functional Verification, OVM, SystemVerilog, e, IEEE 1647, OVM e, OOP, Aspect Oriented Programming, AOP, Object Oriented Programming, OVM SV, IES-XL, ClubTA famous expression in the software world is that “you can only expect 10 good lines of production code per day”.  Web search for this phrase and you will see there is ongoing debate whether this figure is still only 10 lines, or it’s improved to 20, or 100, or more.  One thing that’s not in dispute is that the more lines of code you need to support given task, the more difficult it is for others to comprehend, maintain, and reuse.

Hence, imagine the surprise of the attendees of the “ClubT” in Herzliya Israel last November where an IES-XL end user shared a case study where they had implemented a UVC in both OVM SystemVerilog and OVM e; and the OVM e version was literally half the number of lines of code.  Intrigued by this result, I’ve set out to demonstrate this code reduction for some common testbench tasks.  First, let’s consider stimulus generation.

Let's say we wanted to declare, and generate a simple list of packets to check their contents.  In e, we could do the following in a file called test1.e:


    <'
  type packet_type_t: [TYPE_A, TYPE_B];
  struct packet_s {
    size: uint;
    payload[size]: list of byte;
    keep size in [0..1500];
    type: packet_type_t;
  };
  extend sys {
    packets: list of packet_s;
  };
  '>


The above 12 lines of code would be all that is needed to declare, and generate a randomly sized list of packets.  Each packet in the list will contain random values for size, payload and type.  The construction, allocation and randomization is done during the generation phase automatically in e

Now, let's implement, as closely as possible, the same in OVM SystemVerilog in a file called test1.sv:

     import ovm_pkg::*;
   `include "ovm_macros.svh"

    typedef enum {TYPE_A, TYPE_B} my_type_t;

   class packet_c extends ovm_object;
      rand int unsigned size;
      rand byte unsigned payload[];
      rand my_type_t p_type;
      constraint c_size { payload.size() == size;
                                      size inside {[0:1500]};}

      `ovm_object_utils_begin(packet_c)
         `ovm_field_int(size, OVM_ALL_ON)
         `ovm_field_array_int(payload, OVM_ALL_ON)
         `ovm_field_enum(my_type_t, p_type, OVM_ALL_ON)
      `ovm_object_utils_end

      function new (string name="packet_c");
         super.new(name);
      endfunction: new
    endclass : packet_c

   class test1 extends ovm_test;
      packet_c pkt_array[$], cur_pkt;
      task run;
        for (int i=0; i<10; i++) begin
           cur_pkt = packet_c::type_id::create($psprintf("cur_pkt%0d",i));
           if (!cur_pkt.randomize())
              ovm_report_fatal("RANDFAIL", "Randomization Failure of Packet");
             pkt_array.push_front(cur_pkt);
        end
        global_stop_request();
      endtask
       `ovm_component_utils(test1)

       function new(string name, ovm_component parent);
           super.new(name, parent);
       endfunction
   endclass

   module top;
     initial run_test();
   endmodule

The above OVM SystemVerilog code is 37 lines long, which is more than 3 times the number of lines than in the e version.  What you may also notice in the above code is that it requires quite a bit of overhead (ovm base class inheritance, `ovm_* macros, new(), build(), run(), etc).  There are many operations verification users perform on objects such streaming them into bits, copying, randomizing and setting certain fields from testcases. While the SystemVerilog language does have some of these features built-in, it does not have all of them.  Class libraries such as OVM help to address this concern, making it much easier for the SystemVerilog user to perform common verification tasks, hence increasing productivity over SystemVerilog usage alone.  The extra overhead is merely the tradeoff. 

In contrast, the extra overhead is not needed in the e language since e natively supports the concept of "introspection".  This means that all e structs and units are inherently aware of what variables they contain.  Consequently, when performing common verification tasks, such as those mentioned above, all variables are automatically considered.

In the next post I’ll try out this exercise with a coverage description example.  In the mean time, I invite you to challenge your OVM SystemVerilog-using friends to see if they can write a more compact SystemVerilog example then the one I show above.

Happy coding!

Corey Goss
Staff Solutions Engineer
Team Specman

 

Comments(12)

By Paul on March 30, 2010
Your SV code also has the stimulus generation and testbench infrastructure; the e example does not include this so it's not quite an apples-to-apples comparison. Whilst the e result will still be more compact, it won't be the 3x that you claim. Your SV randomization code could be reduce to
assert(cur_pkt.randomize()); rather than printing out error messages which you have not included in the e code etc. etc.

By Dave Rich on March 30, 2010
Corey,
I used to do these comparisons between Verilog and VHDL, but gave it up 10 years ago. People complain about C being to cryptic.
I agree, when you try to impose a methodology from one language onto another, you are going to see lots of inefficiencies. You are really comparing e to OVM SystemVerilog, not the language SystemVerilog.
The core of the OVM was developed without taking advantage of a lot of SystemVerilog language features like bitstream casting, parametrized classes, and aggregate types.
I believe that both e and SystemVerilog are becoming too complex for their own good. The handful of 'experts' in each of their respective fields might be able to parse the code without consulting the LRM, but the vast majority of verification engineers will be struggling to understand what the code does without endless scanning of the LRMs
Dave

By Corey Goss on March 30, 2010
Hi Paul,
 

Thanks for the comment.  Stimulus generation is actually performed automatically in e so, in terms of generation, the above code is indeed all that is needed.  During the generation phase of the e simulator, the generator automatically fills in all fields with random constrained values.  The reverse situation is true in OVM SV, where the user needs to explicitly tell the simulator which fields to randomize.  This seemingly simple difference between the two languages is very important and a key differentiator so I will elaborate a bit.  To implement all possible scenarios in verification is, of course, quite challenging.  The e language was created specifically for verification, and enhances verification productivity through building in tons of automation features.  Users simply state what the legal/illegal scenarious are (through constraints) and the simulator will attempt to generate all possible combinations within your constraint set.  Every new seed produces a unique, yet replicatable (random stability has been a key feature of e for many years), set of stimulus for the design, exploring outside of the "known cases" automatically hence, catching more bugs as coverage of the DUT is increased.  I believe that the OVM SV performs automatic randomization as well for fields declared with rand and included in the `ovm_field_* macros. Again, the key difference is that this is built in to the e language, saving the user the need to think about what should and should not be randomized.
 

Regarding the testbench infrastructure, the sys struct shown in the extension above is a global structure that contains all e user code.  While it is not generally good methodology to place structures directly into sys for building a verification environment, it can be used for testing out small examples as shown above.  I am not sure, but I don't believe there is the equivalent in SV.  Please correct me if I am wrong.  If we did add an extra layer of hierarchy, we would add three new lines to the above example as follows:
 

unit testbench_u {

  packets: list of packet_s;

};

extend sys {

  testbench: testbench_u is instance;

};
 

Regarding the error messages if, for some reason, the generation fails in e, messages are printed to the screen automatically indicating whether certain constraints were not adhered to or whether a contradiction (overconstraint in SV) situation existed.  These messages provide hyperlinks to the associated source code lines and structures and, if commanded, will open the generation debugger to allow users to quickly debug the situation.  We could have definitely reduced the randomization to wrapping it with a generic assert() check (and I actually tried this in my code) to save us some code in the above SV example.
 

I hope this helps to clarify that the above examples are as close to apples to apples as I could get.  Again, if anyone can create a more compact solution, I would encourage you to post it!
 

Corey


By Corey Goss on March 30, 2010
Hi Dave,
 

Thanks for the comment!  
 

Indeed I am comparing OVM SV to e as, I have found, that without a methodology class library layered on top of the SV language, the user must implement a large amount of infrasture to allow for the language to be used productively in the verification space.  I have worked previously with the SV language for verification in the absence of a methodology library and, in a past life, I even helped develop an entire training course around it's usage.  With over 200 new constructs bolted on top of the previously existing Verilog constructs, I would agree that SystemVerilog has become a very complex language to use on it's own.  OVM SV simplifies the life of the verification engineer by implementing the infrastructure (overhead) needed to perform advanced verification that would otherwise have to be built by hand.  The extra overhead is minimal compared to developing the code for all of this functionality from scratch however, it does add complexity of it's own.

 

While the e language is continually being improved throughout the years, the core language and feature set has not changed dramatically for the past decade so I would have to disagree with your last comment when it comes to e.  In fact, what most people may not know is that e actually stands for english as e was originally created to be as readable as possible, allowing users to pass the code through their "visual parser" more easily than other languages.  Consider the following e code that prints out all the items in a list as an example of this readability:
 

if my_list is not empty then {

  for each in my_list do {

     print it;

  }

};
 

Now, the above example does not represent the entire language however, as you can see, the intention for english-like syntax is evident.
 

Corey


By Paul on March 30, 2010
Corey,
one almost never wants randomization to be done in advance - "just in time" is almost always better. Even in OVMe sequences only randomize their items when necessary. No-one builds pre-randomized lists - it's usually wasteful of CPU resources solving constraints in advance and at the wrong time. If randomization fails in either e or SV the tool will print out error messages - there's no compelling reason to issue an ovm_report. Both e and SV will perform whatever constrained randomization you want - but you should always think about what needs to be randomized as well as when. And both e and SV guarantee random stability.  As for randomization failures and other errors generating hyperlinks, that's not a language feature, that's a tool feature (and other simulators also do the same).
You're somewhat correct in your assertion that SV needs a methodology bolted on top to make it usable for verification, but, really, that's also true for e (hence the eRM and then OVMe). Those base class libraries are really the easiest part of verification - the hard part is figuring out what your DUT does and how to test it - not figuring out the plumbing between verification components. As both flavours of OVM attest, that's a pretty much solved problem.
Paul.

By Paul on March 31, 2010
This code is more closely equivalent to the e code - we don't need OVM to create a randomized list of packets:
module top;
typedef enum {TYPE_A, TYPE_B} my_type_t;
  class packet_c;
     rand bit[7:0] size;
     rand byte unsigned payload[];
     rand my_type_t p_type;
     constraint c_size { size inside {[0:1500]};
                         payload.size() == size; }
     function new();
       assert(this.randomize());
     endfunction
  endclass
  class packet_list_wrap;
     rand packet_c packet_list[];
     rand byte size;
     constraint list_size { packet_list.size() == size; }
  function void post_randomize();
       foreach (packet_list[i]) packet_list[i] = new();
  endfunction
  endclass
  initial begin
     packet_list_wrap list_of_packets = new();
     assert(list_of_packets.randomize());
  end
endmodule
Not that one would usually call randomize() in the constructor of a class, at least the code above gives essentially the same functionality as the e code.
Paul.

By Umer on March 31, 2010
Interesting thread.  
Paul your example is definitely smaller and simpler but it misses a few important verification concerns by not using OVM.  I find that small examples like this one are easy to understand but require more explanation to relate to verification automation and reuse that comes in very handy when dealing with large environments.
Specifically, your code is not equivalent to the OVM SV and e example for two reasons:
1) It requires user to implement print, copy, clone, pack/unpack that are built-in in "e" and are implemented using automation macros for convenience in the OVM example
2) Since you don't use a factory pattern, use of derived types for modeling variation in the packet class means changing your packet_list_wrap class and your test logic which is encapsulated in your initial block.  With this approach your test becomes hard coded and throw-away because it doesn't meet the requirement of overriding the testbench.  
Regards,
Umer

By Paul on March 31, 2010
Umer,
I agree with you - but for a trivial example it shows that pure line counts are only part of the picture. You're also correct that the OVM BCL implements a lot of the features that users would like in SV but, for various legacy and other reasons, are not present. A user should never have to implement boilerplate code (such as is provided implicitly in e and by the OVM automation macros) as it's a time consuming exercise that would be better served by tools - isn't that the purposed of design automation - to make life easier for the user? Sometimes I think we've forgotten what EDA stands for!
Factory patterns are useful, but they are not the be-all and end-all. If everything can be overriden by a factory replacement then the user API can become unwieldy - just as too much AOP applied without thought can be a bad thing. As always, careful thought and design is what is needed - and tools and languages should make life easier for the user, not harder. The worst thing about SystemVerilog is that it is verilog - one could also argue that the best thing about SV is that it is also verilog - but backwards compatibility has crippled many software efforts over the years.
Regards,
Paul

By Corey Goss on March 31, 2010
Hi Paul,
Again, thanks for the comments and the great SV code example. This is turning into a lively discussion!
Umer has already touched on some of the key differences between your code example and that of the e and OVM SV examples above so I will not comment further on that.
I would completely agree with you that pre-generating lists of packets that are to be streamed into a DUT are, most often, better done "just in time".  This allows for more reactive generation, where the generator could potentially sample the current state of the environment or the DUT while generating stimulus.  It is also more memory efficient. There are, however, situations where pre-run list generation is very useful. Consider a switching DUT that has a large number of input channels, some of which could be active, others disabled for any given simulation.  If you replace the list of packets in the above code with a list of BFMs/VIPs each driving/monitoring a random channel then each simulation would result in a new and unique environment topology.  Environment/DUT configurations, topologies, and many other items benefit from constrained pre-run generation of lists.
One of the key challenges in verification is attempting to create all possible legal, and sometimes illegal, scenarios to ensure that you have adequately covered your DUT.  Employing an "infinity minus" methodology of randomizing all possible values (according to constraints that define the rules) allows users to explore the largest amount of space within their DUT, with the least number of tests, greatly enhancing productivity.  Verification engineers focus on writing the rules of behaviour for their DUT through constraints, and not on generating all possible stimulus ... which is left to the power of automation through generation.
OVM and other SV verification methodologies do indeed include class libraries bolted on however, the native e language itself contains most, if not all of the features addressed in the SV class libraries.  This, in part, is what makes e code so compact and re-useable.  You did mention OVM e though, so let me comment on this point specifically.  The features of OVM e add additional verification functionality such as scoreboard structures, sequence enhancements and testflow features above and beyond what e has provided for many years.  The OVM e features are not required to perform typical verification actions such as printing, copying, comparing, bit streaming, generation and many other tasks performed on objects within the environment.  These features are built in to e.
The plumbing of the verification environment is indeed being addressed through class libraries in SV however, users do still need to spend significant time inspecting the parts, architecting/assembling, gluing it all together, adding new pieces throughout the project, patching repairs when they occur and generally maintaining their environment.  One of the points I am hoping to show in this series of posts is that if a user can spend less time plumbing, they can spend more time focusing on the challenging task of verifying their DUT.  Hopefully, I will illustrate this more in the next posts within this series.  
Keep the posts coming everyone!
Corey  

By Sandeep on March 31, 2010
When I attended the first OVM workshop 1 year back, my first impression of OVM was that it's a way to make SV based environemnt work like the e based env. Definately, this brought down the readability of OVM based env compated to e based env as one need to juggle with lengthy macros. Due to this, SV code is more complex to read. May be I feel that as I am e user for a long time and can feel e more closly than SV. In the industry, I have observed that new SV/OVM users who are non-e user feel OVM based env more readable and feel e is more complex to understand (mainly due to AOP). I think this is never ending INTERESTING debate

By Srinath Pai on April 28, 2010
I'm looking for the comparison between e and System Verilog for 'when' inheritance.

If somebody can point me on how to implement 'when' inheritance in System Verilog,

that is also fine.

'when' ineheritance is a common design pattern that I face in my Verification tasks  


By Corey Goss on May 3, 2010
Hi Srinath,
There simply is no direct equivalent to WHEN inheritance in SystemVerilog.  This level of built-in automation is one of the key things that make the e language so powerful and easy-to-use for verification.  The e language was created to allow for an environment to be easily extended to add new functionality in a non-intrusive manner and when inheritance is a key enabler for this very important feature that almost all verification environments must implement in one form or another.  
However, if you are working with a multi-language (e and SV) environment you can kinda-sorta try to replicate it with a free utility that’s included in IES-XL called “mltypemap”.  In a nutshell, mltypemap takes e code you want to wire up in a e-SystemVerilog multi-language environment and flattens the e WHEN subtypes on the SV side.  It employs some naming conventions to indicate which variables are part of a certain subtype, and also automatically generates the constructor and OVM automation macros.  Again, this is NOT equivalent to when subtyping but allows users to take an e when subtyped structure and map it into a OO class within SV.
Another way to implement some of the 'when' inheritance functionality would be to create separate child classes in SV for each subtype you would like to code and then use the factory to override specific/all instances of a class within the verification environment.  This too however, is not equivalent to when subtyping as it does not allow for mixing and matching of various classes within a single list and, since the user must manually call the factory to replace instances in the environment with the new class, it does not permit for easy randomization of the various combinations of all subtypes throughout the environment.  
In short, the ease of use that is enabled through when subtyping and other AOP features in e is unparallel in the industry.  No other industry standard was crafted from the ground up for verification hence, while it might be possible emulate some of e's features in SV and other languages, it is a very tedious, time consuming and manual process to do so.  This is on of the reasons that makes e users so productive and valuable to their respective companies.  
Keep the posts coming!  
Talk to everyone soon,
Corey

Leave a Comment


Name
E-mail (will not be published)
Comment
 I have read and agree to the Terms of use and Community Guidelines.
Community Guidelines
The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.