Sie sind auf Seite 1von 17

SystemVerilog for e Experts

Understanding the Migration Process


Janick Bergeron
Synopsys Scientist

May 2006
2006 Synopsys, Inc.
2006 Synopsys, Inc.
2

Abstract
This document identifes the major differences between the e language as defned by the IEEE P1647/
D6 draft standard and the SystemVerilog language as defned by the IEEE Std. 1800 2005 standard. It
explains the semantics of those differences and, where relevant, presents how similar functionality can be
obtained using SystemVerilog. The document concludes that any verifcation environment based on e could
easily and effciently be implemented in SystemVerilog.
Introduction
Like any modern programming language, e and SystemVerilog have much in common. Both provide
enumerated types, have a for-loop statement and support object-oriented programming. And being
verifcation languages, both support constrained randomization, functional coverage and interfacing to a
design under verifcation. Finally, both languages have recently become IEEE standards.
Despite having so much in common, these two languages differ signifcantly in certain critical areas. In terms
of industry support and momentum, SystemVerilog is without a doubt the choice for the vast majority of the
market with all major EDA vendors supporting, or pledging support for, the language. e is currently
supported by just one major EDA vendor. Various user surveys have also shown a clear preference for
SystemVerilog as the preferred language for future designs.
In technical terms, the two languages have major differences that may require users to take a slightly
different approach to testbench coding. The main focus of this document is to identify and explain these
differences, and to describe how functionality similar to e can be obtained using SystemVerilog.
HDL References
In e, a hardware description language (HDL) signal can be accessed without any prior reference or declara-
tion by simply specifying its hierarchical name between single quotes:
if (~/top.dut.blk_a.status_reg != 0) ...
SystemVerilog, being an extension of Verilog, has similar arbitrary access to any HDL signal through cross-
module references, either absolute or relative:
if (top.dut.blk_a.status_reg != 0) ...
However, SystemVerilog cross-module references cannot be runtime expressions: they must be literal
references, whereas an e HDL reference can contain a string expression that is evaluated at runtime. Similarly,
the root path of a relative HDL reference is specifed by the hdl_path() of the unit containing the reference.
This feature is used to defne the path and name of the interface signals a transactor is connected to.
module top;
reg tx_clk_0, tx_clk_1, tx_clk_2, tx_clk_3;
reg [3:0] txd_0, txd_1, txd_2, txd_3;
reg txe_0, txe_1, txe_2, txe_3;
...
endmodule

2006 Synopsys, Inc.
3
unit mii_bfm {
tx_clk: string;
txd : string;
tx_en : string;
...
event txc: rise((tx_clk)) @sim;
...
send(fr: eth_frame) @txc is {
...
(txd) <= nibble;
(tx_en) <= 1;
...
};
};

...
mii: mii_bfm[4] is instance;
keep for each in mii {
it.hdl_path() == ~/top;
it.tx_clk == append(tx_clk_, index);
it.txd == append(txd_, index);
it.tx_en == append(txe_, index);
};

This approach, although very congenial, has an important impact on runtime performance. First, because the
value of string variables used in the HDL reference expressions can change at runtimealthough in practice
they will rarely be modifedthe expression must be evaluated every time it is executed and appended to the
units root path. This results in unnecessary repeated evaluations of string expressions that reduce runtime
performance. Furthermore, because it is not possible to determine at compile time which HDL signals will be
accessed, it is not possible to optimize the signals and the PLI interface tables for the DUT, further incurring
a runtime penalty.
In SystemVerilog, a transactor is connected to the HDL signals it needs to drive or monitor through a virtual
interface. And because an interface can specify and group all of the signals required by a transactor, a
simple reference to the appropriate interface instance is required to connect a transactor to the appropriate
HDL signals, regardless of the number of signals.
interface mii_if;
reg tx_clk;
reg [3:0] txd;
reg txe;
...
endinterface: mii_if

module top;
mii_if[4];
...
endmodule
2006 Synopsys, Inc.
4
class mii_bfm;
local virtual mii_if sigs;
...
function new(virtual mii_if sigs);
this.sigs = sigs;
endfunction: new
...
task send(fr: eth_frame);
...
this.sigs.txd <= nibble;
this.sigs.txe <= 1;
...
endtask: send
endclass: mii_bfm

...
mii_bfm mii[4];
foreach (mii[i]) begin
mii[i] = new(top.mii_if[i]);
end
This approach enables a concise description of regular, iterated structures. It also allows the identifcation of
all signals in the simulation model that do not need to be accessed and can thus be optimized.
The example above is a simple usage of SystemVerilog interfaces. In that example, the mii_if interface can
only be used for transactors that drive the tx* signals. It cannot be used by transactors that would monitor
those same signals because the reg variables could not be connected to the corresponding output pins of
the design. Interface modports can be used to specify directionality perspectives on the same set of inter-
face signals. By using modports, the same interface can be used for all agents on a set of physical signals.
interface mii_if;
wire tx_clk;
wire [3:0] txd;
wire txe;
...
modport dte(input tx_clk,
output txd, txe,
input rx_clk,
input rxd, rxe, ...);
modport phy(input tx_clk,
input txd, txe,
input rx_clk,
output rxd, rxe, ...);
modport mon(input tx_clk,
input txd, txe,
input rx_clk,
input rxd, rxe, ...);
endinterface: mii_if

class mii_bfm;
local virtual mii_if.dte sigs;
...
function new(virtual mii_if.dte sigs);
this.sigs = sigs;
endfunction: new
...
task send(fr: eth_frame);
...
this.sigs.txd <= nibble;
this.sigs.txe <= 1;
...
endtask: send
endclass: mii_bfm
2006 Synopsys, Inc.
5
A SystemVerilog interface can also defne the sampling clock and setup and hold delays for synchronous
interface signals. In e, those synchronous signal relationships must be defned by the user using a verilog
variable statement. In SystemVerilog, these relationships are defned by the author of the interface descrip-
tion, thus ensuring that the interface signals and any transactor that uses them are functionally consistent.
interface mii_if;
wire tx_clk;
wire [3:0] txd;
wire txe;
...
clocking dte_tx @(posedge tx_clk);
input tx_clk,
output txd, txe,
endclocking: dte_tx
...
modport dte(dte_tx);
...
endinterface: mii_if

class mii_bfm;
local virtual mii_if.dte sigs;
...
function new(virtual mii_if.dte sigs);
this.sigs = sigs;
endfunction: new
...
task send(fr: eth_frame);
...
@this.sigs.dte_tx;
this.sigs.dte_tx.txd <= nibble;
this.sigs.dte_tx.txe <= 1;
...
endtask: send
endclass: mii_bfm
The Verifcation Methodology Manual (VMM) for SystemVerilog guidelines 4-4 through 4-12 provide
detailed rules and recommendations for properly implementing highly reusable interfaces.
Units
In e, units are static objects that are created at elaboration time and cannot be destroyed or allocated
during the simulation. They are used to model static structures in testbenches, such as transactors and
scoreboards. Structs are used for dynamic objects such as packets.
Units, being static, offer some additional capabilities over structs. For example, they can be associated with a
particular location in the design hierarchy.
SystemVerilog modules, interfaces and programs are similar to units because they, too, have static lifetimes
that are defned at model elaboration time. However, unlike units, they are not built on the object-oriented
framework. It is thus not possible to extend the implementation of a program, interface or module as a unit
can be extended. Furthermore, the simulation semantics are slightly different between modules and programs.
Units are better implemented using classes in SystemVerilog. Classes, being object-oriented, can be
extended to customize their behavior for a particular application. Although classes are dynamic, there is
nothing that restricts their usage as a static. Through proper methodology, such as the one described in the
VMM for SystemVerilog, classes implementing static testbench elements can be created at the beginning
of the simulation and maintained until the end.
This approach, although dependent on proper discipline from the user, offers additional benefts over using
modules, interfaces or programs.
2006 Synopsys, Inc.
6
The structure of module, interface and program instances can only be controlled using generate state-
ments. It is thus not possible to create randomly-specifed instances because the constraint solver can only
be invoked after elaboration of the modelwhen its structure has already been defnedunlike es pre-run
generation phase.
Another advantage is that some applications require reconfgurable testbenches to adapt to dynamic
reprovisioning of the design under verifcation. With a static testbench structure, such as one created using es
units, it is necessary to create a priori all possible structures a design might need. With a dynamic testbench
structure, it is possible to destroy a now-obsolete set of transactors and create a completely new structure
to conform to a new confguration of the design.
The VMM for SystemVerilog recommends that all transactors be implemented as classes. It also defnes
a simulation-sequencing base class that promotes the proper creation and management of testbench
structures and their separation from the creation of dynamic testbench stimulus.
Generation
Generation is the term used in e to describe the allocation of struct and unit instances and the setting of their
feld values according to user-specifed constraints. In e, the process of instance allocation and randomization
is an integrated concept. The same generation processcombined memory allocation and randomizationis
used for model elaborationcalled pre-run generationand the dynamic generation using the gen action.
while (1) do {
var fr: eth_frame;
gen fr keeping {
...
};
};
SystemVerilog separates instantiation from randomization. Instantiation of modules, interfaces and programs
is performed during model elaboration. It is somewhat equivalent to es pre-run-generation except that it
does not involve randomization of the content of module, interface or program instances. Class instances are
created only when they are constructed by calling the new() function. Creation of class instances does not
imply randomization. Randomization of a pre-allocated class instance is performed by calling the random-
ize() method on that class instance.
forever begin
eth_frame fr;
fr = new();
fr.randomize() with {
...
};
end
Because all testbench components should be implemented using classes, as described earlier in this
document, only the allocation and randomization of class instances will be considered here.
If automatic randomization of a class instance is required upon creation, it is a simple matter of adding a call
to the randomize() method in the class constructor:
function eth_frame::new();
...
this.randomize();
endfunction: new
The problem with this approach is that there is no way to specify additional or different constraints to the
randomization process upon the creation of a class instance. It will likely be necessary to re-randomize the
class with those additional constraints in a subsequent call to the randomize() method. For large classes
with complex constraint systems, performing needless randomization will reduce runtime performance.
2006 Synopsys, Inc.
?
Separating instantiation and randomization also reduces the fragmentation of dynamic memory and the cost
of constantly freeing and allocating objects. If new instances are not necessary, only new random values, the
SystemVerilog semantics will be more runtime effcient.
List Generation
e lists correspond to dynamic arrays or queues in SystemVerilog. As in e, both the content and length of
an array or queue can be randomized and constrained. However, the semantics of array-length randomiza-
tion are not very well defned in the SystemVerilog language reference manual (LRM). For example, in the
following example, assuming the current size of the data class property is 100, what are the consequences
of the data.size() == len constraint? Does it imply that the value of the len class property will be
constrained to be equal to 100? That may very be what a SystemVerilog constraint solver would choose to
do, but that would not produce a very wide range of solutions.
class eth_frame;
rand bit [47:0] dst;
rand bit [47:0] src;
rand bit [15:0] len;
rand bit [ 7:0] data[];

constraint valid_frame {
len inside {[46:1500]};
data.size() == len;
foreach (data[i]) {
data[i] != h00;
}
}
endclass: eth_frame
The LRM says that the size of a randomized array must be large enough to satisfy the constraints. Using
the example above, the size of the array will be randomized to a value between 46 and 1500. But if it is
randomized to a value less than 100the current size of the arraythe current version of the VCS


comprehensive RTL verifcation solution chooses not to truncate it. However, the foreach constraint will
iterate according to the size of the array during randomization, not the actual number of elements in the
array. After randomization, the actual size of the array will be 100 or more and will be different from the value
of lendespite the size() == len constraintif len is less than 100. It is thus a good idea to trim arrays
in the post_randomize() method to ensure consistency with other class properties.
class eth_frame;
rand bit [47:0] dst;
rand bit [47:0] src;
rand bit [15:0] len;
rand bit [ 7:0] data[];

constraint valid_frame {
len inside {46:1500};
data.size() == len;
foreach (data[i]) {
data[i] != h00;
}
}

function void post_randomize();
if (this.data.size() > this.len) begin
this.data = new [this.len] (this.data);
end
endfunction: post_randomize
endclass: eth_frame
2006 Synopsys, Inc.
8
Additionally, the LRM does not specify what happens should the size of a randomized array be left unconstrained.
One e-based tool has an implicit soft constraint on list sizes to keep them less than a confgurable valuewith
a default of 50. VCS solution chooses not to modify the size of randomized arrays if their size is unconstrained.
Randomizing arrays of scalars works very well in SystemVerilog. But randomizing arrays of objects creates a
challenge. Should the array be lengthened during randomization, what should the additional array elements
be flled with? Because randomization does not allocate new object instances, they are flled with null.
In most cases, what is desired is a random-length array populated with randomized object instances. To
achieve the desired functionality, it is necessary to pre-fll the array with the maximum number of object
instances. The array can then be truncatedand the extra object instances reclaimed by the garbage
collectorshould the array size be randomized to something shorter.
Soft Constraints
Soft constraints are usually used to specify default values or relationships that can be optionally modifed to
inject errors or corner cases. Soft constraints are required in e because constraints are strictly additive. Once
a constraint is specifed, it cannot be removed. But injecting errors requires that constraints limiting data
generation to valid solutions be relaxed to allow the generation of invalid data under controlled conditions.
Soft constraints, in cases, can provide this optional constraint specifcation.
struct eth_frame {
dst: uint (bits:48);
src: uint (bits: 48);
len: uint (bits: 16);
data: list of byte;

keep soft len in [46..1500];
keep data.size() == len;
};

extend eth_frame {
keep len < 46;
};
SystemVerilog does not have the concept of a soft constraints. All active constraints in SystemVerilog are
hard and always considered when randomizing a class instance. Any inconsistency will cause a runtime
error. But the key word here is active.
SystemVerilog constraints are built on the object-oriented framework. They have names and thus can be
referenced outside of the class that contains them, much like data properties or methods.This enables
SystemVerilog to allow constraint blocks to be turned off or on procedurally.
class eth_frame;
rand bit [47:0] dst;
rand bit [47:0] src;
rand bit [15:0] len;
rand bit [ 7:0] data[];

constraint valid_len {
len inside {46:1500};
}
constraint valid_frame {
data.size() == len;
}
endclass: eth_frame

eth_frame fr = new;
fr.valid_len.constraint_mode(0);
fr.randomize() with {
len < 46;
};
2006 Synopsys, Inc.
9
So, instead of relying on a contradiction to turn off a soft constraintif and only if a contradiction is created
and then turning off all previously defned soft constraints on that same feldSystemVerilog allows specifc
constraints to be reliably turned off to relax them, even if a solution would exist otherwise. For example, the
e code below will not have the intended effect because a solution exists that intersects the soft constraints
and the new constraint. Of course, the soft constraint on the len feld could be reset to turn it off, but this
would also turn off all other soft constraints on that same feld, potentially creating a different solution space
than the desired one.
extend eth_frame {
keep len in [0, 46, 1500, 65535];
};
Because SystemVerilog constraints are built on the object-oriented framework, like virtual methods, they can
be added to or overloaded based on the name of the constraint blocks in class extensions. So unlike the
strictly additive constraints in e, SystemVerilog constraints are additive, substitutive and negative.
class runt_eth_frame extends eth_frame;
constraint valid_len {
len <46;
}
endclass: runt_eth_frame
A short note on the use of curly braces in constraint blocks instead of begin/end keywords: The foreach
loop and if statements exist both for procedural code and constraints. When used in procedural contexts,
they use the begin/end keywords to group multiple statements in their bodies. When used in constraint
blocks, they use curly braceslike the constraint block itselfto group iterated or conditional constraints.
Why the difference?
begin/end keywords are used to defne procedural regions. These procedural regions can contain local vari-
able declarations. These regions are entered, executed and then exited. Procedural regions can be stepped
through in a debugger.
Curly braces are used to defned declarative regions. Constraints are declarative. Unlike procedural regions,
the sequence in which they are specifed is not functionally relevant. They are considered in parallel, not
sequentially. It is not possible to step through constraints, nor is it possible to declare local variables in a
declarative region.
Temporal Expressions
Temporal expressions in e are functionally equivalent to properties in SystemVerilog. As in e, these properties
can be used to trigger events, or they can be asserted to make sure they are never violated.
The major difference between e and SystemVerilog is the location where the properties are specifed. In e,
temporal expressions are specifed as events in structs or units. Both constructs should be implemented as
classes in SystemVerilog. However, properties cannot be specifed in classes. Properties can only be
specifed in interfaces or modules.
Although this appears to be a signifcant difference between e and SystemVerilog, in practice it does not
present a signifcant challenge when mapping the functionality of temporal expressions to SystemVerilog.
In almost all cases, temporal expressions are used to verify or detect specifc behavior in the design.
SystemVerilog properties can perform the same functionality by locating them in the same construct that
implements that behavior or in an interface that has visibility over all of the signals implementing a
protocol behavior. Using cross-module references, properties can also verify behavior across module
boundaries, when necessary.
2006 Synopsys, Inc.
10
property req_ack_p(req, r_data, ack, a_data, clk, reset);
logic [$bits(r_data)-1:0] data;
@(posedge clk) disable iff (reset)
(req, data = r_data) ##0 ack[->1]
|-> (r_data == a_data);
endproperty : req_ack_p
interface my_itf(
input logic my_req, my_ack,
input logic [15:0] my_data_in, my_data_out,
input logic clk, reset);
my_data_check: assert property (
req_ack_p(my_req, my_data_in,
my_ack, my_data_out, clk, reset));
endinterface : my_itf
As in e, local variables can be used to store values within a temporal property. The property can be reused
in different contexts. In the example above, it is instantiated in an interface that can then be instantiated
as a checker.
If it is desirable to specify properties outside of the module or interface implementing the functionality to
be observed, a program, interface or module encapsulating those properties can be bound, after the fact,
to a specifc instance or all instances of the interface or module implementing the observed functionality. In
the example below, an instance of the interface containing the temporal assertion is bound to all instances of
data_module.
bind data_module
my_itf check_data(
start_b, stop_b, id_in, id_out, ck, rst);
The ability to bind properties to all instances of a module or interface simplifes the equivalent process in e
where a unit containing the equivalent temporal expressions must be explicitly instantiated and its
hdl_path() appropriately set for each instance of the target interface or module.
There can be temporal expressions observing or checking behavior in the unit or struct itself. Those tend
to be relatively simple and often used solely to trigger an associated coverage group. Simple temporal
expressions can be easily implemented using equivalent behavioral code and coverage group can be easily
triggered procedurally using the implicit sample() coverage group method.
When Inheritance and Aspect-Oriented Programming (AOP)
When inheritance and aspect-oriented programming are two different mechanisms in e. But a proper e
methodology requires that both be used in tandem to achieve the desired results. Therefore, they must be
considered together when describing how they can be mapped to equivalent SystemVerilog.
When inheritance and AOP are used to implement many different functional aspects of verifcation. These
different aspects are implemented using different techniques in SystemVerilog, and thus must be considered
separately.
Data Modeling
When inheritance is used to model different variations of the same transaction or data descriptor. Under
different variances, some felds may or may not be available and the behavior of some methods may
be different.
struct operand {
mode: [SHORT, IMMEDIATE, REGISTER];
2006 Synopsys, Inc.
11
assemble(): list of bit is empty;
arg(): list of uint is empty;
};
extend SHORT operand {
value: uint (bits: 10);
assemble(): list of bit is only {
result = %{b110100, value};
};
};
extend IMMEDIATE operand {
value: uint (bits: 32);
assemble(): list of bit is only {
result = b110000;
};
arg(): list of uint is only {
result = {value};
};
};
extend DIRECT operand {
R: uint (bits: 4);
assemble(): list of bit is only {
result = %{b00, R};
};
};
It is tempting to implement the same data model using class inheritance in SystemVerilog. However,
because SystemVerilogs inheritance is similar to es like inheritance, it will be diffcult to randomly select
different variations or to constrain the data variation. Using class inheritance to model different variants will
cause the nature of the class instance to determine the variance. Since the nature of the class instance
cannot be modifed without allocating a different one, randomizing a specifc class instance will always
yield the same data variant.
Once stripped of its syntactic coating, all felds from different when extensions are located in the same
struct. The proper approach in SystemVerilog is thus to use the same implementation and explicitly declare
all properties in the same class.
class operand;
rand enum {SHORT, IMMEDIATE, REGISTER} mode;

rand bit [31:0] imm;
rand bit [ 3:0] R;
...
};
The when inheritance in e creates variant-centric model method descriptions: the unique attributes of each
variation in all methods are coded in separate extensions. Understanding the complete behavior of an par-
ticular method requires the understanding of the composition of each of the variations.
Data modeling in SystemVerilog is procedure-centric: the unique attributes of all variations for each method
are coded in the method itself. The composition of all variations is explicitly coded.
class operand;
rand enum {SHORT, IMMEDIATE, REGISTER} mode;

rand bit [31:0] imm;
rand bit [ 3:0] R;

2006 Synopsys, Inc.
12
function int assemble(output bit [31:0] image);
case (mode)
SHORT: begin
image = {b110100, imm[9:0]};
return 16;
end
IMMEDIATE: begin
image = b110000;
return 6;
end
SHORT: begin
image = {b00, R};
return 6;
end
endcase
endfunction: assemble

function void arg(output bit [31:0] image[]);
case (mode)
IMMEDIATE: begin
image = new [1];
image[0] = imm;
end
default: image = new [0];
endcase
endfunction arb
endclass: operand
The VMM for SystemVerilog guidelines 4-68 through 4-72 detail how to properly model data and transac-
tions with multiple variants.
Instance-Specifc Extensions
In e, aspect-oriented extensions extend all instances of the extended type. Their effect is global and per-
manent. If it is desirable to limit the effect of extensions to a specifc instance or for a specifc duration, it is
necessary to conditionalize the extension using when inheritance.
For example, the following code segment instantiates four instances of the same generator. Any extension
to the eth_frame struct type will affect all four instances.
unit eth_gen {
fr: eth_frame;

main(): @sys.any is {
while (1) {
gen me.fr;
send(fr);
};
};
...
};

extend sys {
gen: eth_gen[4] is instance;
};
To be able to specify instance-specifc extensions, it is necessary to introduce a when extension of the
generator and constrain the appropriate generator instance to be of the appropriate variation.
extend eth_gen {
IS_SPECIAL: bool;
keep soft not IS_SPECIAL;
};
2006 Synopsys, Inc.
13
extend IS_SPECIAL eth_gen {
keep fr.len == 46;
};

extend sys {
keep for each in gen {
(index == 2) => it.IS_SPECIAL;
};
};
The same functionality is implemented in SystemVerilog using a factory pattern. A factory pattern is a stan-
dard object-oriented technique that is used to implement classes that create other classesi.e., generators.
The example below shows a generator implemented using the factory pattern.
class eth_gen;
eth_frame fr;

task main();
forever begin
this.fr.randomize();
send(fr);
end
endtask: main
...
endclass: eth_gen

class sys;
eth_gen gen[4];
...
endclass: sys
Figure 1: Factory Pattern
Modifying a single instance of the generator is accomplished by replacing the instance of the randomized
class by an instance of an appropriately extended class. Because SystemVerilogs randomization does not
allocate a new instance, it will randomize the replacement, not the original one. And because the random-
ize() method is a virtual method, the randomization will be performed according to the rules defned in the
extended class, not the original class.
class short_eth_frame extends eth_frame;
constraint short_frames {
len == 46;
}
endclass: eth_frame

program test;
sys env = new;
Generated
Stream
Different
Stream
Extended
Factory
Test Test
Copy
Generator
Generator
Factory
2006 Synopsys, Inc.
14
initial
begin
short_eth_frame fr = new;
env.gen[2].fr = fr;
...
end
endprogram: test
The VMM for SystemVerilog guidelines 5-6 and 5-19 to 5-22 detail how to implement generators and how
to control them using the factory pattern.
Exception Injection
Exceptions are deviations from the standard and default behavior of a verifcation component. It is simple
to write a transactor that always does the correct thing, always acknowledges every transaction and
operates as fast as possible. But that is not very interesting from a verifcation standpoint. It must be
possible to introduce errors, refuse or drop transactions, or introduce delays.
In e, this is accomplished by extending the methods or redefning events that implement the default functionality.
Because methods can only be prepended or appended tonot extended in the middleit is necessaryand
just plain good coding practiceto provide empty methods that are initially empty for the express purpose of
extending them to modify the default behavior. The e language itself contains several such methods, such
as the pre_generate() and post_generate() methods. Failing to provide such method results in large-scale
code duplication with is only extensions to introduce minute differences in the method implementation.
unit usb_device {
reply_with(usb_packet req;
usb_packet *resp): @sys.any is empty;

main(): @sys.any {
while (1) {
var req, resp: usb_packet;
req = usb_port.rx();
resp = default_resp(req);
reply_with(req, resp);
usb_port.tx(resp);
};
};
...
};

extend usb_device {
reply_with(usb_packet req;
usb_packet *resp): @sys.any is also {
gen resp keeping {
kind == STALL;
...
};
};
};

extend usb_device {
reply_with(usb_packet req;
usb_packet *resp): @sys.any is also {
wait delay(20);
};
};
A similar approach is used with SystemVerilog. Virtual methods, designed specifcally to be overloaded to
introduce functional deviations, are provided in verifcation components.
2006 Synopsys, Inc.
15
Figure 2: Virtual Methods
class usb_device;
virtual task reply_with( usb_packet req,
ref usb_packet resp);
endtask: reply_with

task main();
forever begin
usb_packet req, resp;
req = usb_port.rx();
resp = default_resp(req);
reply_with(req, resp);
usb_port.tx(resp);
end
endtask: main
...
endclass: usb_device

class stalled_usb_device extends usb_device;
virtual task reply_with( usb_packet req,
ref usb_packet resp);
resp.randomize() with {
kind == STALL;
...
};
endtask: reply_with
endclass: stalled_usb_device

class slow_usb_device extends usb_device;
virtual task reply_with( usb_packet req,
ref usb_packet resp);
#20;
endtask: reply_with
endclass: slow_usb_device
The problem with the example above is that, unlike aspect-oriented extensions, object-oriented extensions
create new data types and follow a strict hierarchy and lineage. To combine orthogonal extensions, it is
necessary to put these extensions on the same class lineage. Then, the original instance of the verifcation
component in the verifcation environment must be replaced with an instance of the extended class, with
all of the potential connectivity issues that it entails. In contrast, all aspect-oriented extensions in e are
cumulative and are added to the original data type without creating a new one.
Fortunately, there is a simple mechanism in SystemVerilogin fact in all object-oriented languagesthat
allows the orthogonal extension of verifcation components, without creating new classes and without
having to replace existing instances. It is the faade pattern. All extension methods are defned in a separate
class called a faade. Extensions are then implemented by extending the faade, not the actual verifcation
component class. Instances of the faade extensions are then registered with the verifcation components.
To support multiple orthogonal extensions, a verifcation component should support multiple faade
registrations using a queue.
xactor
Virtual Method
Extension
2006 Synopsys, Inc.
16
Figure 3: Faade Pattern
class usb_device_callbacks;
virtual task reply_with( usb_packet req,
ref usb_packet resp);
endtask: reply_with
endclass: usb_device_callbacks

class usb_device;
usb_device_callbacks cbs[$];

task main();
forever begin
usb_packet req, resp;
req = usb_port.rx();
resp = default_resp(req);
foreach (this.cbs[i]) begin
this.cbs[i].reply_with(req, resp);
end
usb_port.tx(resp);
end
endtask: main
...
endclass: usb_device

class stalled_usb_device extends usb_device_callbacks;
virtual task reply_with( usb_packet req,
ref usb_packet resp);

resp.randomize() with {
kind == STALL;
...
};
endtask: reply_with
endclass: stalled_usb_device

class slow_usb_device extends usb_device_callbacks;
virtual task reply_with( usb_packet req,
ref usb_packet resp);
#20;
endtask: reply_with
endclass: slow_usb_device

program test;
usb_env sys = new;

initial begin
stalled_usb_device cb1 = new;
slow_usb_device cb2 = new;

xactor
sys.dev[3].cbs.push_back(cb1);
sys.dev[0].cbs.push_back(cb2);
sys.run();
end
endprogram: test
As shown in the example above, specifc instances of verifcation components can be extended by simply
registering the appropriate callback faade extension instances with the appropriate verifcation component
instance. There is no need to create conditional extensions as is needed in e.
The VMM for SystemVerilog guidelines 4-154 to 4-163 detail how to implement extensible verifcation
components and how to extend them using the faade pattern.
Other Differences
There are other differences between e and SystemVerilog that are not mentioned in this paper. For example,
struct felds in e are randomized by default unless they are prefxed with a !, whereas SystemVerilog class
properties must be prefxed with the rand attribute to be randomized. Some constructs do not have a direct
correspondence in the SystemVerilog language but can be mapped to utility classes providing similar
functionality. For example, e ports can be replaced with vmm_channels. This and other differences are
minor and do not present any challenges when migrating e code to SystemVerilog.
Other differences exist in the constructs and approaches defned in the eReuse Methodology (eRM). But
since the eRM and the additional language constructs it defnes are not part of the 1647 IEEE standard
and remain proprietary extensions to the IEEE e language, it is not possible for this paper to legally address
these differences. However, all Synopsys customers who have migrated their eRM-based verifcation
environment and tests found the publicly-available methodology and support classes specifed in the
Verifcation Methodology Manual for SystemVerilog to provide an effcient migration path.

Conclusions
SystemVerilog and e are different languages, so some changes to how verifcation environments are
developed is to be expected. However, any environment coded in e can easily and effciently be developed
in SystemVerilog. It is no different than Verilog and VHDL: these two languages have fewer features and are
even more similar to each other than SystemVerilog is to e, yet they have semantic differences that require
certain functionality to be implemented differently in each language. Verifcation teams can confdently move
from e to SystemVerilog, knowing they are not giving up language expressiveness or productivity and are
joining a broadly supported industry standard with a vibrant ecosystem of supporting tools, services,
IP and people.
Given nearly equivalent language capabilities, moving from e to SystemVerilog enables users to adopt
a widely-supported industry standard, reduce cost of ownership, increase verifcation performance, and
leverage a single unifed language to improve overall productivity across the entire verifcation and
design process.
More Information
More information on SystemVerilog, and Synopsys e to VCS Native Testbench Migration Services, can be
found at www.synopsys.com/SystemVerilog/etoVCS.
700 East Middlefeld Road, Mountain View, CA 94043 T 650 584 5000 www.synopsys.com
Synopsys, and the Synopsys logo are registered trademarks. All other trademarks or registered trademarks
mentioned in this release are the intellectual property of their respective owners and should
be treated as such. All rights reserved. Printed in the U.S.A.
2006 Synopsys, Inc. 5/06.CE.WO.06-14332

Das könnte Ihnen auch gefallen