e is a hardware verification language (HVL) which is tailored to implementing highly flexible and reusable verification testbenches.
History
e was first developed in 1992 in Israel by Yoav Hollander for his Specman software. In 1995 he founded a company, InSpec (later renamed Verisity), to commercialize the software. The product was introduced at the 1996 Design Automation Conference. Verisity has since been acquired by Cadence Design Systems.
Features
Main features of e are: Random and constrained random stimulus generation Functional coverage metric definition and collection Temporal language that can be used for writing assertions Aspect-oriented programming language with reflection capability Language is DUT-neutral in that you can use a single e testbench to verify a SystemC/C++ model, an RTL model, a gate level model, or even a DUT residing in a hardware acceleration box (using the UVM Acceleration for e Methodology) Can create highly reusable code, especially when the testbench is written following the Universal Verification Methodology (UVM) Formerly known as e Re-use Methodology (eRM) UVM e library and documentation can be downloaded here: UVM World
Language Features
The e language uses an aspect-oriented programming (AOP) approach, which is an extension of the object-oriented programming approach to specifically address the needs required in functional verification. AOP is a key feature in allowing for users to easily bolt on additional functionality to existing code in a non-invasive manner. This permits easy reuse and code maintenance which is a huge benefit in the hardware world, where designs are continually being tweaked to meet market demands throughout the project lifecycle. AOP also addresses cross cutting concerns (features that cut across various sections of the code) easily by allowing users to extend either specific or all instances of a particular struct to add functionality. Users can extend several structs to add functionality related to a particular feature and bundle the extensions into a single file if desired, providing for more organized file partitioning.
Comments
Executable e code is enclosed within code-segment markers <' and '>:
Example
Anything outside the markers is a comment
<'
extend sys {
// This is a comment Verilog style
-- This is a comment in VHDL style
post_generate() is also {
out("... and everything else within the markers is executable code."); }; }; '>
Classes
e also has two kinds of classes: Dynamic classes are labeled with the keyword 'struct'. Structs are used for creating data that only exists temporarily and may be cleaned by the garbage collector. Static classes are labeled with the keyword 'unit'. Units are used for creating the permanent testbench structure.
A class may contain fields, methods, ports and constraints. Fields can be of type integer, real, enum, string and even complex objects. The code segment shows a unit called 'environment_u' being instantiated within the e root 'sys'. This environment_u class contains a list of 5 packet_s objects and this packet_s class contains two fields and a method.
Example
<'
// This is a dynamic class with two fields
struct packet_s {
field0: uint (bits: 32); // This field is called 'field0' and is a
// 32 bit wide unsigned integer. field1: byte; // This field is called 'field1' and is a byte.
// This method is called once a packet_s object has been generated
post_generate() is also {
out(field0); // Printing the value of 'field0'
}; };
// This is a static class with a list of five packet struct
unit environment_u {
my_pkt[5]: list of packet_s; };
// sys is the root for every e environment and instantiates the 'test_env' object extend sys { test_env: environment_u is instance; }; '>
Randomization
In e each field is randomized by default. Field randomization can be controlled by hard constraints, soft constraints or even be turned off completely. Soft constraints are used as the default constraints, and may be automatically overridden by the test layer if a conflict occurs. Otherwise it behaves like a regular constraint.
Example
<'
struct my_pkt_s {
destination_address: uint (bits: 48); // this field is randomized and is not constrained. data_payload : list of byte; !parity_field : uint (bits: 32); // '!' prevents the parity_field from being randomized.