Professional Documents
Culture Documents
2
VMM is available for free download at www.vmmcentral.org
VMM Golden Reference Guide
First Edition, January 2010
Copyright 2010 by Doulos Ltd. All rights reserved.
The information contained herein is the property of Doulos
Ltd and is supplied without liability for errors or omissions.
No part may be used, stored, transmitted or reproduced in
any form or medium without the written permission of
Doulos Ltd.
Doulos
Match
& remove
vmm_sb_ds
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 205
particularly useful when trying to locate, insert, or discard a packet within the
various queues. Packets can also be transformed using the transform()
method. For example, packets can be expanded, compressed, or translated
from one protocol to the next. Furthermore, scoreboard callbacks can be
registered to extend the scoreboards functionali ty (see
vmm_sb_ds_callbacks).
Scoreboards are typically integrated within an environment using callbacks or by
forking off a thread in the environment to sink channel packets into the
scoreboard. They may also be used to listen to analysis ports. Integration of
scoreboards wi th environments, channels, or notify objects is simplified by
defining the compile time macro, `VMM_SB_DS_IN_STDLIB. . This macro
enables the scoreboard registration functions.
For more examples, detai ls, and descriptions, please see the Synopsys VMM
Scoreboarding User Guide deli vered with the VMM Scoreboard Package
Declaration
class vmm_sb_ds_typed #(type INP = vmm_data , type EXP =
INP) extends vmm_sb_ds_base;
class vmm_sb_ds extends vmm_sb_ds_typed #(vmm_data);;
Methods
function new(
string name);
Constructor.
function void append_callback(
vmm_sb_ds_callbacks
#(INP,EXP) cb);
Adds the specified callback to
the scoreboard.
virtual function bit compare(
EXP actual,
EXP expected);
Compares two transaction
objects.
Returns TRUE if a match.
function void define_stream(
int stream_id,
string descr = "",
vmm_sb_ds::kind_e kind
= EITHER);
Pre-defines a data stream wi th
the specified stream ID.
kind can be INPUT, EXPECT,
or EITHER.
virtual function void
describe();
Displays any defined
scoreboard streams.
virtual function void display(
string prefix = "");
Displays the scoreboard's
contents.
vmm_sb_ds
206 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
virtual function vmm_data
expect_in_order(
EXP pkt,
int exp_stream_id = -1,
int inp_stream_id = -1,
bit silent = 0);
Compares expected packet
pkt with first input stream
packet.
Removes and returns packet if
matched.
Error message is not issued if
silent specified.
virtual function vmm_data
expect_out_of_order(
EXP pkt,
int exp_stream_id = -1,
int inp_stream_id = -1,
bit silent = 0);
Compares expected packet
pkt with all packets in a
stream.
Removes and returns packet if
matched.
Error message is not issued if
silent specified.
virtual function bit
expect_with_losses(
input EXP pkt,
output EXP matched,
output EXP lost[],
input int exp_stream_id = -1,
input int inp_stream_id = -1,
input bit silent = 0);
Compares expected packet
pkt with next packet in
stream, removi ng unmatched
packets as losses.
Returns packet if matched.
Error message is not issued if
silent specified.
Requires the
quick_compare() method.
virtual function void flush(); Resets and flushes all
contents of the scoreboard.
function int get_n_dropped(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of
dropped packets for the
specified stream(s).
function int get_n_inserted(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of
expected packets inserted into
the specified stream(s).
function int get_n_matched(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of
matched expected packets.
function int get_n_mismatched(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of lost
mismatched expected
packets.
function int get_n_not_found(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of
expected packets not found in
the scoreboard.
vmm_sb_ds
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 207
function int get_n_orphaned(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of leftover
packets in the scoreboard.
function int get_n_pending(
int exp_stream_id = -1,
int inp_stream_id = -1);
Returns the number of
expected packets sti ll in the
scoreboard.
virtual function bit insert(
vmm_data pkt,
vmm_sb_ds::kind_e kind
= INPUT,
int exp_stream_id = -1,
int inp_stream_id = -1);
Inserts packet into the
scoreboard in the specified
stream(s).
Returns TRUE if successful.
kind can be INPUT, EXPECT,
or EITHER.
virtual function bit match(
EXP actual,
EXP expected);
Performs a quick compare to
see if the data packets match.
Returns TRUE if matched.
function vmm_sb_ds_iter
new_sb_iter(
int exp_stream_id = -1,
int inp_stream_id = -1);
Creates and returns a
scoreboard iterator for
traversing across all the
scoreboard streams.
function vmm_sb_ds_stream_iter
new_stream_iter(
int exp_stream_id = -1,
int inp_stream_id = -1);
Creates and returns a stream
iterator for traversing a stream
for a particular packet.
function void prepend_callback(
vmm_sb_ds_callbacks
#(INP,EXP) cb);
Prepends the specified
callback to the registered
callbacks.
virtual function bit
quick_compare(
EXP actual,
EXP expected);
Performs a quick compare to
see if two packets match.
Returns TRUE if matched.
By default, returns TRUE.
virtual function bit remove(
vmm_data pkt,
vmm_sb_ds::kind_e kind
= INPUT,
int exp_stream_id = -1,
int inp_stream_id = -1);
Removes the specified packet
from the specified stream(s).
Returns TRUE if successful.
All packets created by
transform() are also
removed.
kind can be INPUT or
EXPECT.
virtual function void report(
int exp_stream_id = -1,
int inp_stream_id = -1);
Displays the scoreboard
statistics.
vmm_sb_ds
208 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
virtual function int stream_id(
vmm_data pkt,
vmm_sb_ds::kind_e kind
= EITHER);
User-definable function for
determining a packets stream
id.
Returns stream id.
virtual function bit transform(
input EXP in_pkt,
output EXP out_pkts[]);
Recei ves a data packet and
transforms it into one or more
packets.
Returns an array of packets.
function void
unregister_callback(
vmm_sb_ds_callbacks
#(INP,EXP) cb);
Unregisters a scoreboard
callback.
Members
vmm_tlm_analysis_export_exp#(vm
m_sb_ds_typed#(INP,EXP),EXP)
exp_ap;
Expect analysis export.
typedef enum {
EITHER,
INPUT,
EXPECT
} kind_e;
Stream kind enumeration.
vmm_tlm_analysis_export_inp#(vm
m_sb_ds_typed#(INP,EXP),INP)
inp_ap
Input analysis export.
vmm_log log; Message service instance.
typedef enum {
INSERTED = 999_000,
EMPTY,
MATCHED,
MISMATCHED,
DROPPED,
NOT_FOUND,
ORPHANED
} notifications_e;
Notification enumeration.
vmm_notify notify; Notification service instance.
typedef enum {
IN_ORDER,
WITH_LOSSES,
OUT_ORDER
} ordering_e;
Scoreboard ordering
enumeration.
vmm_sb_ds
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 209
Macros
`VMM_SB_DS_IN_STDLIB Enables scoreboard
integration methods.
Example
class usb_scoreboard extends vmm_sb_ds;
function new();
super.new( "USB Scoreboard" );
define_stream( 0, "CPU", INPUT );
define_stream( 1, "USB1", EXPECT );
define_stream( 2, "USB2", EXPECT );
endfunction
virtual function bit compare( vmm_data actual,
vmm_data expected );
usb_trans act, exp;
string text;
$cast( act, actual );
$cast( exp, expected );
return act.compare( exp, text );
endfunction
virtual function bit transform(
input vmm_data in_pkt,
output vmm_data out_pkts[]);
usb_trans tr;
$cast( tr, in_pkt.copy() );
tr.data = { << byte{ tr.data }}; // Reverse bytes
out_pkts = new[1]; // Add to the output
out_pkts[0] = tr;
return 0;
endfunction
endclass
vmm_sb_ds
210 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
class usb_to_sb extends usb_callbacks;
usb_scoreboard sb;
function new( usb_scoreboard sb );
this.sb = sb;
endfunction
virtual task post_tr( usb_master xactor, usb_trans tr );
vmm_data cpy = tr.copy();
sb.insert( cpy ); // Insert into scoreboard
endtask
endclass
class my_env extends vmm_env;
usb_scoreboard sb;
usb_xactor usb;
virtual function build();
super.build();
this.sb = new();
this.usb = new ( ... );
begin
usb_to_sb cb = new( this.sb );
this.usb.append_callback( cb );
end
endfunction
endclass
Tips
Transaction packets must be an ancestor of vmm_data in order to work
with the vmm_sb_ds base class.
Single stream scoreboards do not need to define stream identifiers. Multi -
stream scoreboards do.
Define VMM_SB_DS_IN_STDLIB when compiling to turn on the scoreboard
registration methods.
For faster performance, define a simple quick_compare() method for
finding those easy matches.
When using expect_with_losses(), be sure to define the match()
method, which is required.
vmm_sb_ds
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 211
Gotchas
Normally, streams are automatically created when packets are received
with different stream IDs. Defining a stream with define_stream()
means that streams will no longer be automatic and an error message will
be issued if an undefined stream ID is encountered.
If a stream is defined as EITHER kind by define_stream(), then all
streams must be of EITHER kind.
The insert() method does not accept packet kinds of EITHER (must be
either INPUT or EXPECTED).
Be aware that multiple indications may be issued by the scoreboard since it
operates without delays. Create an extended
vmm_notify_callbacks::indicated() method if indications need to
be caught.
Calling get_n_orphaned() causes the remaining packets in the
scoreboard to be orphaned. Therefore, only call this method at the end of
simulation or use get_n_pending() during simulation.
The report() function may report more packets not found than shown in
the indi vidual streams. This happens when packets do not include stream
IDs so they do not show up in any streams statistics.
See also
vmm_sb_ds_*iter, vmm_sb_ds_callbacks
You can also find further information on this topic at the VMM Golden Reference
Guide's companion page at http://www.doulos.com/vmm.
vmm_sb_ds_callbacks
212 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
The functionality of the data stream scoreboard can easily be extended by using
scoreboard callbacks, provided by extending the vmm_sb_ds_callbacks base
class. Callbacks are registered wi th the scoreboard using the scoreboard
methods append_callback() or prepend_callback(). The following table
summarizes the avai lable callbacks and when they are invoked by the
scoreboard:
Callback Invoking Scoreboard
Method
Description
dropped() expect_with_losses()
Invoked when a match is
not found at the beginning
of the stream; i.e., lost or
dropped packets preceded
the match.
matched() expect_in_order()
expect_with_losses()
expect_out_of_order()
Invoked when compare()
indicates a matched
packet.
mismatched() expect_with_losses()
Invoked when compare()
indicates a mismatched
packet.
not_found() expect_in_order()
expect_with_losses()
expect_out_of_order()
Invoked when a packet
cannot be found.
orphaned() get_n_orphaned()
Allows cleanup or
processing of orphaned
packets.
pre_insert() insert()
Invoked before the packet
is inserted into a stream.
post_insert() insert()
Invoked after the packet is
inserted into a stream.
Declaration
class vmm_sb_ds_callbacks #(type INP=vmm_data, EXP=INP);
vmm_sb_ds_callbacks
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 213
Methods
virtual function void dropped(
input vmm_sb_ds sb,
input vmm_data pkts[],
input int exp_stream_id,
input int inp_stream_id,
ref int count);
Called when packets are
considered lost and removed.
Lost packets are passed in
data_pkts[].
count used to increment the
scoreboards dropped counter.
virtual function void matched(
input vmm_sb_ds sb,
input vmm_data pkt,
input int exp_stream_id,
input int inp_stream_id,
ref int count);
Called when a packet is
matched and removed from
the scoreboard.
pkt contains matched packet.
count is used to increment
the scoreboards match
counter.
virtual function void
mismatched(
input vmm_sb_ds sb,
input vmm_data pkt,
input int exp_stream_id,
input int inp_stream_id,
ref int count);
Called when a packet
mismatches and is removed
from the scoreboard.
pkt contains matched packet.
count is used to increment
the scoreboards mismatched
counter.
virtual function void
not_found(
input vmm_sb_ds sb,
input vmm_data pkt,
input int exp_stream_id,
input int inp_stream_id,
ref int count);
Called after packet was not
found in the scoreboard.
pkt contains unmatched
packet.
count is used to increment
the scoreboards not found
counter.
virtual function void orphaned(
input vmm_sb_ds sb,
input vmm_data pkts[],
input int exp_stream_id,
input int inp_stream_id,
ref int count);
Called when packets are left
orphaned in the scoreboard.
Orphaned packets are passed
in data_pkts[].
count used to increment the
scoreboards orphaned
counter.
virtual function void
post_insert(
vmm_sb_ds sb,
vmm_data pkt,
int exp_stream_id,
int inp_stream_id);
Called after a packet is
inserted into the expected
queue.
pkt contains inserted packet.
vmm_sb_ds_callbacks
214 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
virtual function void
pre_insert(
input vmm_sb_ds sb,
input vmm_data pkt,
input vmm_sb_ds::kind_e kind,
ref int exp_stream_id,
ref int inp_stream_id,
ref bit drop);
Called before a packet is
inserted into the scoreboard.
pkt contains packet.
If kind is INPUT, then called
before the packet is
transformed and
exp_stream_id is invalid.
If kind is EXPECT, then called
before the packet is placed in
the expected queue.
If callback sets the drop field
to 1, then the packet is not
inserted.
Example
class my_cb extends vmm_sb_ds_callbacks;
virtual function void mismatched(
input vmm_sb_ds sb,
input vmm_data pkt,
input int exp_stream_id,
input int inp_stream_id,
ref int count );
`vmm_note( log,
$psprintf( "Packet mismatch! Count = %d", count );
endfunction
endclass
class my_env extends vmm_env;
usb_scoreboard sb;
...
function void build();
...
begin
my_cb cb = new();
sb.append_callback( cb ); // Add the callback
end
endfunction
endclass
vmm_sb_ds_callbacks
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 215
Tips
Any user-defined scoreboard expect function should invoke at least the
following callbacks: mismatched(), dropped(), matched(), and
not_found().
Gotchas
With the pre_insert() callback, modifying the stream identifiers wi ll
cause the packet to be inserted differently wi thin the scoreboard.
The pre/post_insert() callbacks are called only for the scoreboards
insert() method, not using the stream iterators prepend() and
append() methods.
See also
vmm_sb_ds
vmm_sb_ds_*iter
216 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Scoreboard iterators are used to traverse through the transaction packets and
streams within a scoreboard. The vmm_sb_ds_iter iterator provides access to
the scoreboards streams, and vmm_sb_ds_stream_iter enables traversal
within the stream itself to find specific packets. Neither are intended to be
created directly via the constructor; rather, they are created and initialized by the
vmm_sb_ds::new_sb_iter() and new_stream_iter() methods,
respecti vely. Iterators are created in the invalid state, which means that they
point to nothing particular until a call to first() or next() is made. .
Declaration
class vmm_sb_ds_iter #(type INP=vmm_data , type EXP=INP);
class vmm_sb_ds_stream_iter #(type INP=vmm_data,
type EXP=INP);
Methods
vmm_sb_ds_iter
function
vmm_sb_ds_iter #(INP,EXP)
copy();
Returns a copy of the stream
currently pointed to by the
iterator.
function int delete(); Flushes current stream and
removes it from the
scoreboard.
function string describe(); Returns a string description of
the stream.
function void display(
string prefix = "");
Displays the contents of the
iterator.
function int exp_stream_id(); Returns the expected stream
ID of the current stream.
function bit first(); Resets iterator to first stream.
function int get_n_dropped(); Returns the number of
dropped packets.
function int get_n_inserted(); Returns the number of
expected packets inserted.
function int get_n_matched(); Returns the number of
matched expected packets.
vmm_sb_ds_*iter
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 217
function int
get_n_mismatched();
Returns the number of
mismatched packets.
Determined by
expect_with_losses()
scoreboard method.
function int get_n_not_found(); Returns the number of packets
not found in the stream.
function int get_n_orphaned(); Returns the number of packets
orphaned in the stream.
function int get_n_pending(); Returns the number of packets
remaining in the stream.
function int incr_n_dropped(
int delta);
Modifies the number of
dropped packets.
function int incr_n_inserted(
int delta);
Modifies the number of
inserted packets.
function int incr_n_matched(
int delta);
Modifies the number of
matched packets.
function int incr_n_mismatched(
int delta);
Modifies the number of
mismatched packets.
function int incr_n_not_found(
int delta);
Modifies the number of not
found packets.
function int incr_n_orphaned(
int delta);
Modifies the number of
orphaned packets.
function int incr_n_pending(
int delta);
Modifies the number of
pending packets.
function int inp_stream_id(); Returns the input stream ID of
the current stream.
function bit is_ok(); Returns TRUE if the iterator is
pointing to a valid stream.
function bit last(); Resets iterator to last stream.
function int length(); Returns the number of
streams.
function
vmm_sb_ds_stream_iter#(INP,EXP)
new_stream_iter();
Creates and returns a new
stream iterator.
function bit next(); Sets iterator to the next
stream.
vmm_sb_ds_*iter
218 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
function int pos(); Returns current iterator
position.
Returns -1 if iterator does not
point to a valid stream.
function bit prev(); Changes iterator to previous
stream.
vmm_ds_sb_stream_iter
function void append(
EXP pkt);
Append specific packet after
current iterator position.
Iterator posi tion remains
unchanged.
function vmm_sb_ds_stream_iter
copy();
Copies iterator.
Returns an iterator at the
same current stream posi tion.
function vmm_data data(); Returns current stream
packet.
Returns null for invalid
packets.
function vmm_data delete(); Removes packet from stream
at current the iterator posi tion.
Returns removed packet, or
null if packet is invalid.
function string describe(); Returns a string description of
the stream.
function int exp_stream_id(); Returns the expected stream
ID.
function bit find(
EXP pkt);
Finds the specified packet in
the stream.
Returns TRUE and repositions
iterator if packet exists;
otherwise, iterator remains
unchanged.
function bit first(); Resets iterator position to the
beginning of the stream.
function int flush(); Flushes current stream.
Returns the number of flushed
packets.
function int inp_stream_id(); Returns the input stream ID.
vmm_sb_ds_*iter
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 219
function bit is_ok(); Returns TRUE if iterator points
to a valid expected packet.
function bit last(); Sets the iterator to the last
stream packet.
function int length(); Returns the number of packets
in the stream.
function bit next(); Changes iterator to the next
stream packet.
function int pos(); Returns the position of the
iterator in the stream.
Returns 0 for first position, and
-1 if last packet or empty
stream.
function int postflush(); Flushes packets in the stream
after current iterator position.
Returns number of flushed
packets or -1 if iterator points
to an invalid packet.
function int preflush(); Flushes packets in the stream
before current iterator position.
Returns number of flushed
packets or -1 if iterator points
to an invalid packet.
function void prepend(
EXP pkt);
Inserts the specific packet
before the iterator pointer in
the stream.
Iterator posi tion remains
unchanged.
function bit prev(); Changes iterator to previous
packet.
Example
Finding a packet throughout the scoreboard
class my_scoreboard extends vmm_sb_ds;
function vmm_data find( vmm_data pkt );
vmm_sb_ds_iter iter;
vmm_data current;
// Iterate through all the streams
iter = new_sb_iter();
while ( iter.next() ) begin
vmm_sb_ds_*iter
220 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
// Get a stream iterator
vmm_sb_ds_stream_iter s_iter;
s_iter = iter.new_stream_iter();
// Iterate through all the stream packets
while ( s_iter.next() ) begin
string text;
current = s_iter.data(); // Get a packet
// Does it match?
if ( current.compare( pkt, text ) )
return current; // Found it!
end
end
return null; // No match!
endfunction
...
endclass
Tips
When an iterator is first created, the next() method works just as well as
first().
The incr_n_*() methods can decrement the total number amounts by
specifying negati ve deltas (though the count will never go below 0).
Gotchas
Iterators are always created in the invalid state so be sure to call first()
or next() before using.
See also
vmm_sb_ds
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 221
Digital designs require more than just random transactions to test and configure.
A series of constrained random transactions are needed to properly test a
designs functionali ty. VMM provides this capabili ty through the use of
scenarios.
A simple scenario represents a constrained random stream of transactions. By
building one scenario upon another, a sense of order is superimposed on top of
the transaction stream. For example, a bus protocol can be described using two
basic scenariosread and write. A reset scenario builds upon these scenarios
by invoking both the read and write scenarios in a specific order. In such a way,
scenarios build and create sophisticated sti mulus for the design under test.
While scenarios define the way sti mulus wi ll be generated, a scenario generator
executes the scenarios and generates the actual transactions. These
transactions are then directed to one or more output channels, feeding other
scenarios or components (e.g., vmm_xactors) downstream. A scenario
generator is itself a vmm_xactor and multiple generators can be coordinated
together to create hierarchal sti mulus like what is required in a protocol stack.
Scenarios may be associated (registered) wi th one or more scenario generators.
Scenario generators repeatedly select an avai lable scenario, randomize it, and
then execute it. There are two types of scenario generators(1) single-stream
and (2) multi-stream. Single-stream generators have one output channel called
out_chan (similar to the vmm_atomic_gen). These are usually used to feed
the input of a single device interface.
In contrast, multi-stream scenario generators may drive transactions on any
number of channels. Channels are registered with the generator and scenarios
select the channel on which to drive. Thi s allows a multi-stream generator at a
high level to coordinate scenarios across many device interfaces.
Single-Stream Scenarios
Single-stream scenarios are executed on single-stream generators and their
transactions are funnelled through a single output channel. They are created
from vmm_ss_scenario automatically when using the
`vmm_scenario_gen() macro. There are three kinds of single-stream
scenarios: random, procedural, and hierarchical.
Single-Stream
Scenario
Generator
vmm_scenario_gen
Scenario
Scenario
Scenario
Scenario
Scenario
Scenario
out_chan
H
i
e
r
a
r
c
h
i
c
a
l
/
p
r
o
c
e
d
u
r
a
l
a
p
p
l
y
(
)
random
Scenario
items[]
vmm_ss_scenario #(T)
Scenarios
222 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Random
By default, a generator wi ll automatically generate a random stream of
transactions. Each single-stream scenario contains a rand array member called
items[] that holds the created random transactions. When a scenario is
selected, the generator randomizes it, determining the number of transactions to
create using the following constraint:
constraint T_scenario_valid {
items.size == length;
}
The method define_scenario()is used to register the scenario name
(scenario_kind) and set its length (i.e., the number of transactions to
generate). User-defined constraints may also be added to control randomization
of the transactions. For example, the following constraints could be used for a
read-modify-write scenario:
class APB_RMW_scenario extends APB_data_scenario;
...
constraint read_modify_write {
if ( scenario_kind == APB_RMW ) {
length == 2;
items[0].kind == apb_data::READ;
items[1].kind == apb_data::WRITE;
items[0].address == items[1].address;
}
}
endclass
Once the transactions are randomized, the scenarios apply() method is
automatically invoked to copy the generated transactions into the output
channel, out_chan.
Procedural
For greater control over transaction generation, the default apply() procedure
may be overwritten. Inside apply(), different transaction types may be
instantiated, randomized, and then applied to the output channel in any random
or directed order. The number of transactions inserted into the output channel
must be returned by incrementing the argument n_inst. For example, the
following illustrates a procedurally defined reset scenario:
// Create plcp_packet_scenario and channel with macro
`vmm_scenario_gen( plcp_packet, "PLCP Packets" )
class reset_scenario extends plcp_packet_scenario;
int cfg_reg[ string ] = '{ "CFG1" : 'h10, ... };
function new();
define_scenario( "Reset", 1 );
endfunction
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 223
// Overwrite the apply() method
virtual task apply( plcp_packet_channel channel,
ref int unsigned n_inst );
plcp_packet pk;
// Write to all config registers to reset
foreach ( cfg_reg[name] ) begin
pk.addr = cfg_reg[name];
...
channel.put( pk );
end
n_inst += cfg_reg.num;
endtask
endclass
Hierarchical
Hierarchical scenarios are built by instantiating and invoking other scenarios. By
their nature, they are procedural and the apply() method must be overridden.
For example, the above reset scenario could be written as follows:
class write_scenario extends plcp_packet_scenario;
rand int addr, data;
function new();
define_scenario( "WRITE Scenario", 0 );
endfunction
virtual task apply( plcp_packet_channel channel,
ref int unsigned n_inst );
plcp_packet pk = new();
// Random values used unless constrained
pk.addr = addr;
pk.data = data;
pk.kind = WRITE;
channel.put ( pk );
n_inst++;
endtask
endclass
class hier_reset_scenario extends plcp_packet_scenario;
write_scenario wr_scn;
function new();
wr_scn = new();
define_scenario( "Hier Reset Scenario", 0 );
endfunction
Scenarios
224 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
virtual task apply( plcp_packet_channel channel,
ref int unsigned n_inst );
wr_scn.randomize with { addr=h10; data=...; };
wr_scn.apply( channel, n_inst );
...
endtask
endclass
Multi-Stream Scenarios
Multi-stream scenarios offer the functionali ty of a single-stream scenario, but
with the capability of reading or writing to multiple channels. This typically allows
multi-stream scenarios to act as high-level scenarios, feeding controls or data to
lower-level single or multi-stream scenarios.
Multi-stream scenarios are defined as two types: contained and distributed. A
contained scenario is one that is associated wi th a particular scenario generator
and uses only channels or scenarios also associated with that generator. A
distributed scenario may use channels or scenarios across many generators.
Multi-stream scenarios are innately procedural and hierarchical, and may invoke
single-stream scenarios as well as other multi-stream ones.
Multi-stream scenarios are derived from the class vmm_ms_scenario. Since
multi-stream scenarios can use multiple channels across many generators, each
channel must be registered using register_channel(). References to
channels are obtained using get_channel(). Instead of using the apply()
contained scenarios
vmm_ms_scenario_gen
Multi-Stream
Scenario
Generator
channel 0
channel 1
channel n
MS
Scenario
Scenario
Scenario
Multi-Stream
Scenario
Generator
vmm_ms_scenario_gen
vmm_ms_scenario_gen
Multi-Stream
Scenario
Generator
channel 0
channel 1
channel n
Scenario
Scenario
MS
Scenario
Scenario MS
Scenario
MS
Scenario
d
i
s
t
r
i
b
u
t
e
d
s
c
e
n
a
r
i
o
s
execute()
execute()
vmm_ms_scenario
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 225
method, multi-stream scenarios use an execute() method, which must be
overloaded when a multi-stream scenario is defined. Like apply(), the
execute()method must increment the transaction count argument, similarly
named as n.
The following is an example of a multi-stream scenario:
class video_conferencing_scenario extends vmm_ms_scenario;
camera_input cam_scn; // Single-stream scenario
lcd_trans lcd_tr; // LCD transaction
rand int picture_size;
constraint pic_size { picture_size > 10; }
function new( vmm_ms_scenario parent = null );
super.new( parent );
cam_scn = new;
lcd_tr = new;
endfunction
virtual task execute( ref int n );
vmm_channel cam_chan = get_channel( "CAM" );
vmm_channel lcd_chan = get_channel( "LCD" );
fork
// Send the image through the camera
begin
cam_scn.randomize() with
{ length == picture_size; };
cam_scn.apply ( cam_chan, n );
end
// Wait for the image to appear on the LCD
begin
for (int i = 0; i < picture_size; i++)
begin
lcd_chan.get( lcd_tr );
// Check that the same thing went through
assert ( lcd_tr.data ==
cam_scn.items[i].data) else
`vmm_error( log, "Sent != Received");
end
end
join
endtask
endclass
Scenarios
226 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Hierarchical multi-stream scenarios
Multi-stream scenarios have the advantage that they can call scenarios from
other multi-stream scenario generators. This is accomplished by creating a
hierarchy through registering generators as sub-components of other generators
using register_ms_scenario_gen(). Once registered, multi-stream
scenarios can obtain a reference to other registered scenarios using
get_ms_scenario(). For example,
class high_level_scenario extends vmm_ms_scenario;
int scn_id = define_scenario( "high_level", 0 );
task execute( ref int n );
vmm_ms_scenario dma_scn
= get_ms_scenario("dma", "AHB_GEN");
vmm_ms_scenario rand_mem_scn
= get_ms_scenario("rand_mem", "DDR_GEN");
dma_scn.randomize();
rand_mem_scn.randomize();
fork
dma_scn.execute();
rand_mem_scn.execute();
join
endtask
endclass
program test1;
dma_cfg_scenario dma_scn = new;
rand_mem_scenario rmem_scn = new;
vmm_ms_scenario_gen ahb_gen = new( "AHB_GEN" );
vmm_ms_scenario_gen ddr_gen = new( "DDR_GEN" );
vmm_ms_scenario_gen top_gen = new( "TOP_GEN" );
initial
begin
ahb_gen.register_ms_scenario( "AHB_GEN", dma_scn );
ddr_gen.register_ms_scenario( "DDR_GEN", rmem_scn );
top_gen.register_ms_scenario_gen( "AHB_GEN", ahb_gen);
top_gen.register_ms_scenario_gen( "DDR_GEN", ddr_gen);
top_gen.start_xactor(); // Only on the top generator!
...
end
endprogram
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 227
Creating Scenarios
When creating single-stream scenarios, VMM defines two macros to si mplify
declaring the parameterized classes employed. These macros are:
`vmm_scenario_gen( class-name, text )
`vmm_scenario_gen_using( class_name, channel_type, text )
7
where class-name is the transaction type of the scenario, text is a class
description, and channel_type refers to the output channel type compatible
with class_name.
For example, the following macro statement:
`vmm_scenario_gen( APB, "APB" )
creates the following 5 user-defined class types:
Class Definition
APB_scenario_gen vmm_scenario_gen #( APB, "APB" )
APB_scenario vmm_ss_scenario #( APB, "APB" )
APB_atomic_scenario
8
vmm_atomic_scenario #(APB, "APB")
APB_scenario_gen_call
backs
vmm_scenario_gen_callbacks
#( APB, "APB" )
APB_scenario_election vmm_scenario_election
#( APB, "APB" )
These classes become the base classes for all derived scenario and generator
classes. With multi-stream scenarios, the multi-stream bases classes are
extended to create new scenarios and components. For example,
class ethernet_scenario extends vmm_ms_scenario;
class ocp_generator extends vmm_ms_scenario_gen;
Registering Scenarios
Both single and multi-stream scenarios require registering scenarios with their
respecti ve scenario generators. Registering a scenario is done by using
register_scenario() / register_ms_scenario(). Likewise, scenarios
7
In VMM 1.2, this macro is redundant and functionally equi valent to
`vmm_scenario_gen().
8
An atomic scenario is a single-stream scenario wi th a length of 1.
Scenarios
228 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
can be unregistered or replaced. An easy way to register scenarios is to use the
`foreach_vmm_xactor() macro. For example,
`foreach_vmm_xactor ( axi_scenario_gen, "/./", "/./" )
begin
axi_scenario scn = new;
xact.register_scenario( scn );
end
Scenario Selection
For both single and multi-stream scenario generators, scenarios are randomly
selected from all those registered in the scenario_set[$] array. The specific
scenario to pick is determined by randomizing a vmm_scenario_election /
vmm_ms_scenario_election instance (select_scenario) that contains a
field member select. By default, the election instance uses a round-robin
algorithm that can be disabled as follows:
env.gen.select_scenario.round_robin.constraint_mode( 0 );
Changing the selection algorithm involves nothing more than extending the
election class with user-defined constraints and assigning the instance to the
generators select_scenario variable.
Scenario Constraints
In addition to the length property, several other scenario properties can be
used to control the generation of scenario transactions. Scenarios contain a
repeated and repeat_thresh (threshold) field that specifies the number of
times to repeat the scenario. The actual number of transactions created by a
scenario will be (length * (repeated + 1)). The repeated field is hard
coded in a vmm_scenario to be equal to 0. In order to override this value, the
repetition constraint must be overwritten:
class my_apb_scenario extends apb_scenario;
constraint repetition {
repeated < 20;
}
endclass
By default, repeat_thresh is set to 100, which sets an upper maxi mum
number of repeats.
With single-stream scenarios, modifying constraints across all transactions is
easily accomplished by assigning a factory instance to a scenarios using
property. For example, the following uses a factory template to generate
scenario transactions:
trans_template tr = new;
foreach ( env.gen.scenario_set[i] ) begin
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 229
env.gen.scenario_set[i].using = tr;
end
The new factory replacement service also provides another easy alternati ve.
For example,
trans_template::override_with_new("@%*", tr, log);
Controlling indi vidual transaction randomization may be accomplished by either
specifying random constraints that constrain the items[] array or by manually
assigning values. For example, the fill_scenario() method will allocate
transactions in the items[] array without randomizing them (use
allocate_scenario() to generate using the factory pattern assigned to
using). Therefore, the following could replace the constraints on an indi vidual
transaction object:
ocp_trans tr = new;
ocp_scenario scn;
scn = env.gen.get_scenario( "Random" );
scn.fill_scenario();
scn.items[2] = tr;
Now when the generator randomizes the transactions, the new constraints for
items[2] will be used.
Scenario Callbacks
In addition to defining constraints in a scenario, callbacks may also be used to
configure or customize a scenario. Callbacks have the advantage that they can
configure a scenario at run-time, which allows testcases to customize scenario
behavior, or they can control timing relationships across multiple child scenarios.
VMM defines two callbacks as part of vmm_scenario_gen_callbacks:
pre_scenario_randomize() and post_scenario_gen(). As their names
imply, the first is invoked before randomization and the second afterwards;
however, both are called before a scenario injects a transaction into a channel.
The post_scenario_gen() callback includes a dropped bit so that a
transaction can be discarded instead of placed in the channel.
Configuring the Generator
A scenario generator continues to execute unti l either a certain number of
transactions have been generated or a specific number of scenarios have been
selected. These values are set by setting the generators
stop_after_n_insts to the maxi mum desired transactions or
stop_after_n_scenarios to the maxi mum number of scenarios.
Scenarios
230 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
VMM 1.2 uses a factory mechanism that can also configure scenarios and
generators. For example, a scenario can be defined using the class factory
macro:
class bus_scenario extends bus_trans_scenario;
function new(); ...
function vmm_data allocate(); ...
function vmm_data copy (vmm_data to = null ); ...
`vmm_class_factory( bus_scenario )
endclass
Then gi ven the following environment:
class env extends vmm_env;
`vmm_typename( env );
bus_scenario_gen gen;
bus_scenario scn;
...
virtual function void build ();
gen = new( "gen", 0 );
scn = new;
gen.register_scenario( "bus_scenario", scn );
endfunction
endclass
The following testcase can configure the generator using calls to the factory:
class test1 extends vmm_test;
...
// Swap bus_scenario wi th pci_scenario
virtual function void start_of_sim_ph();
bus_scenario::override_with_new(
"@env1:gen:bus_scenario",
pci_scenario::this_type,
log, `__FILE__, `__LINE__ );
endfunction
endclass
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 231
Controlling the Channel
On occasion, a scenario may need exclusi ve access to an output channel in
order to control the transaction stream. Exclusi ve access to a channel is granted
by using the grab()/ungrab() methods and specifying the grabber input to
the channel methods (put() or sneak()). For example,
virtual task apply( pci_channel channel,
ref int unsigned n_insts );
pci_trans tr;
tr = new;
tr.randomize with ( ... };
channel.grab( this );
channel.put ( tr.copy(), .grabber( this ));
channel.ungrab(this);
n_insts++;
endtask
In order to prevent deadlock in hierarchical scenarios, child scenarios have
access to channels grabbed by their parent. The parent-child relationship is
establi shed by using set_parent_scenario() as follows:
class soc_config_scenario extends ahb_scenario;
usb_cfg_scenario usb_scn = new();
dma_cfg_scenario dma_scn = new();
mmu_cfg_scenario mmu_scn = new();
function new();
define_scenario( "SOC Config", 0 );
usb_scn.set_parent_scenario( this );
dma_scn.set_parent_scenario( this );
mmu_scn.set_parent_scenario( this );
endfunction
virtual task apply( ahb_channel channel,
ref int unsigned n_insts );
channel.grab( this );
usb_scn.apply( channel, n_insts );
dma_scn.apply( channel, n_insts );
mmu_scn.apply( channel, n_insts );
channel.ungrab( this );
endtask
endclass
Scenarios
232 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Class Hierarchy
The scenario class hierarchy and how they interact are illustrated as follows:
Tips
Registered multi-stream scenarios can be obtained from anywhere inside
an environment by using get_ms_scenario(). This makes multi-stream
scenarios very flexible and reusable.
The `foreach_vmm_xactor() has many applications with scenarios. For
example, it is very convenient for registering scenarios or setting generator
values as follows:
`foreach_vmm_xactor( my_scenario_gen, "/./", "/./")
xact.stop_after_n_scenarios = 20;
A directed test can be created wi th one multi-stream scenario by pushing
the scenario to the front of the generators scenario_set[] array and
configuring the generator to run only 1 scenario.
In order to disable a generators round-robin algorithm, si mply turn off the
generators constraint (see Scenario Selection above).
A random multi-stream scenario can created by rand members or calling
randomize() inside the execute() method.
vmm_ms_scenario_gen
vmm_ms_scenario_election
stream_id
scenario_id
n_scenarios
scenario_set[$]
last_selected[$]
next_in_set
constraint round_robin
vmm_scenario_election
stream_id
scenario_id
n_scenarios
scenario_set[$]
last_selected[$]
next_in_set
constraint round_robin
vmm_ms_scenario_gen_callbacks
vmm_scenario_gen_callbacks
vmm_data
vmm_scenario
scenario_kind
length
repeated
repeat_thresh
vmm_ms_scenario
execute()
vmm_scenario_base
vmm_ss_scenario #(T)
items[]
T using
apply()
vmm_atomic_scenario #(T)
vmm_xactor_callbacks
vmm_xactor
vmm_scenario_gen
select_scenario
main()/ inject()
select_scenario
main()
Scenarios
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 233
Gotchas
Be sure to release (ungrab) a grabbed channel to prevent deadlock.
For hierarchical scenarios, be sure to use set_parent_scenario() so
that children can have access to channels grabbed by their parent.
A default-configuration single-stream scenario generator has significantly
less performance than an atomic generator due to the additional overhead
associated wi th scenarios.
9
See also
vmm_scenario, vmm_ms_scenario, vmm_scenario_gen,
vmm_ms_scenario_gen, vmm_ss_scenario, vmm_*_scenario_election,
vmm_*_scenario_gen_callbacks
You can also find further information on this topic at the VMM Golden Reference
Guide's companion page at http://www.doulos.com/vmm.
9
According to the VMM Standard Library User Guide, Version C-2009.06. Note,
a multi-stream generator used only wi th single-stream scenarios should have the
performance of a single-stream generator.
vmm_scenario
234 Copyri ght 2010 by Doul os Ltd. All ri ghts re served.
A scenario is a constrained random stream of transactions. The
vmm_scenario class is derived from vmm_data and it defines the members
and functionality needed for describing a basic scenario. For example,
vmm_scenario includes the number of transactions a scenario should create
(length), how many times it should be repeated (repeated), and essential
methods like define_scenario().
Both single and multi-stream scenarios are deri ved from this base class. In fact,
vmm_scenario is never used directly, but rather, all scenarios are extended
from either vmm_ss_scenario or vmm_ms_scenario. For single-stream
scenarios, the macro `vmm_scenario_gen( trans_type ) may be used
instead to automatically define a class called trans_type_scenario, which is
an descendent of vmm_scenario.
Declaration
class vmm_scenario extends vmm_data;
Methods
function new(
vmm_scenario parent = null);
Constructor.
virtual function vmm_data copy(
vmm_data to = null);
Copy method.
Returns a reference to a
vmm_scenario.
function int unsigned
define_scenario(
string name,
int unsigned max_len = 0);
Defines a new scenario name
and sets the maxi mum length
of the transaction stream (i.e.,
number of transactions to
generate).
Returns an integer scenario
kind identifier which can be
used for specifying scenario
kind related constraints.
protected function int unsigned
get_max_length();
Returns the maxi mum length
of the transaction stream.
function vmm_scenario
get_parent_scenario();
Returns the parent scenario.
Returns null for a top-level
scenario.
virtual function string
psdisplay(
string prefix = "");
Returns a string descripting
the scenario.
vmm_scenario
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 235
function void
redefine_scenario(
int unsigned scenario_kind,
string name,
int unsigned max_len = 0);
Redefines a scenarios name
or maxi mum length.
function string scenario_name(
int unsigned scenario_kind
= 0);
Returns the name of the
scenario specified by the
scenario_kind.
function void
set_parent_scenario(
vmm_scenario parent);
Sets the scenario hierarchy by
specifying the scenarios
parent.
Members
rand int unsigned length; Maxi mum number of
transactions to generate.
rand int unsigned repeated = 0; Number of times to repeat the
scenario.
static int unsigned
repeat_thresh = 100;
Maxi mum number of times to
repeat a scenario.
rand int unsigned
scenario_kind;
Numeric ID assigned to a
scenario when registered with
define_scenario().
int scenario_id; Generators scenario count
assigned before randomization
used to identify scenarios in a
stream or for random
constraints.
int stream_id; Generators stream ID
assigned before randomization
used by other components
(like a scoreboard) to
differentiate transactions.
constraint vmm_scenario_valid; Defines reasonable
constraints for the scenario
(like maxi mum length and
repetitions).
constraint repetition; Hard codes the repeated
value to 0.
Constraint must be overwritten
to change the repeated
value.
vmm_scenario
236 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Shorthand Macros
The vmm_scenario shorthand macros provide an easy way to automate the
creation of predefined functions such as copy(), print(), allocate(), or
psdisplay(). The member macros are placed between a
`vmm_scenario_member_begin / `vmm_scenario_member_end pair. The
default implementation for these methods can be extended or overwritten by
defining a do_copy(), do_print(), do_allocate(), etc.
The name field specifies the data member name. The do field specifies the
methods to automatically generate. The enumeration values can be OR-ed
together for specific methods or DO_ALL for all methods. Those macros wi th a
how field specify whether a vmm_data copy should be deep (DO_DEEPCOPY) or
shallow (DO_REFCOPY), or if a compare should be deep (DO_DEEPCOMPARE) or
shallow (DO_REFCOMPARE).
There is also an additional constructor macro called `vmm_scenario_new().
This macro provides an easy shorthand way of defining a default-configuration
constructor. It is not needed if `vmm_scenario_member_begin is used,
unless a user-defined constructor needs to be written.
Begin / end macros
`vmm_scenario_member_begin( class )
`vmm_scenario_member_end( class )
Scalar data members
`vmm_scenario_member_scalar( name, do )
`vmm_scenario_member_scalar_array( name, do )
`vmm_scenario_member_scalar_da( name, do )
`vmm_scenario_member_scalar_aa_scalar( name, do )
`vmm_scenario_member_scalar_aa_string( name, do )
Enumeration data members
`vmm_scenario_member_enum( name, do )
`vmm_scenario_member_enum_array( name, do )
`vmm_scenario_member_enum_da( name, do )
`vmm_scenario_member_enum_aa_scalar( name, do )
`vmm_scenario_member_enum_array( name, do )
`vmm_scenario_member_enum_aa_string( name, do )
vmm_scenario
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 237
String data members
`vmm_scenario_member_string( name, do )
`vmm_scenario_member_string_array( name, do )
`vmm_scenario_member_string_da( name, do )
`vmm_scenario_member_string_aa_scalar( name, do )
`vmm_scenario_member_string_aa_string( name, do )
Class handle data members
`vmm_scenario_member_handle( name, do )
`vmm_scenario_member_handle_array( name,do )
`vmm_scenario_member_handle_da( name,do )
`vmm_scenario_member_handle_aa_scalar( name,_do )
`vmm_scenario_member_handle_aa_string( name, do )
vmm_data members
`vmm_scenario_member_vmm_data( name, do, how )
`vmm_scenario_member_vmm_data_array( name, do, how )
`vmm_scenario_member_vmm_data_da( name, do, how )
`vmm_scenario_member_vmm_data_aa_scalar( name, do, how )
`vmm_scenario_member_vmm_data_aa_string( name, do, how )
Constructor macro
`vmm_scenario_new( class ) ..
vmm_scenario
238 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Example
`vmm_scenario_gen( instruction )
class branch_inst_scenario extends instruction_scenario;
constraint forward_long_branch {
foreach ( item[i] ) {
if ( items[i].opkind == BRANCH )
items[i].target > items[i].pc + 256;
}
}
endclass
`vmm_scenario_gen( ocp_trans )
class ocp_scenario extends ocp_trans_scenario;
constraint burst_mode {
if ( scenario_kind == burst ) {
length == 8;
repeated == 0;
foreach ( item[i] )
if ( i > 0 )
item[i].addr == item[i-1].addr + 1;
}
}
endclass
class my_scenario extends vmm_ms_scenario;
int my_scn = define_scenario("My Scenario", 0);
`vmm_scenario_member_begin( my_scenario )
`vmm_scenario_member_scalar( my_scn , DO_ALL )
`vmm_scenario_member_end( my_scenario )
virtual task execute(ref int n);
...
endtask
endclass
Tips
For single-stream scenarios, use the vmm_scenario data members to
constrain the transaction stream in items[].
Remember to overwrite the repetition constraint to set the repeated
value.
vmm_scenario
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 239
Remember to define scenarios with define_scenario() so that the
transaction stream length is set and scenario_kind can be used in
random constraints.
Gotchas
A vmm_scenario by itself does not have all the necessary elements
needed for scenario generation. Always create scenarios by extending
from either vmm_ms_scenario (for multi-stream) or vmm_ss_scenario
(for single-stream).
See also
Scenarios, vmm_ss_scenario, vmm_ms_scenario
vmm_*_scenario_election
240 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Both the single-stream (vmm_scenario_gen) and the multi-stream
(vmm_ms_scenario_gen) scenario generators use an election object to select
the next scenario to generate. This election object is provided as
vmm_scenario_election#(T,text) for single-stream generators, and
vmm_ms_scenario_election for multi-stream. The single-stream generator
macro, `vmm_scenario_gen(class), automatically creates the single-stream
election class named class_scenario_election. These classes are
essentially identical wi th the exception that the scenario_set[] arrays are
defined for the respecti ve type of scenarios.
When a generator goes to select a scenario, it copies its registered scenarios
into the election objects scenario_set[] array. By default, the election
object defines a round-robin selection constraint that assigns the next selected
scenario to the select property. The select property is then used by the
scenario generator to pick the next scenario.
In this way, a scenario generators selection algorithm can easily be changed by
extending the election class, overriding the round_robin constraint, adding
additional constraints, and assigning the new election object to the generators
select_scenario property. The several members of the election object are
updated by the generator before randomization so that constraints can be bui lt
using these property values. See the article on Scenarios more details.
Declaration
class vmm_scenario_election#(type T=vmm_data,
string text="" );
class vmm_ms_scenario_election;
Members
Shared between both classes
int unsigned last_selected[$]; History of the last
selected scenarios.
Maxi mum length of 10.
int unsigned n_scenarios; Total number of
registered scenarios.
int unsigned next_in_set; The next scenario in the
set.
Used by the
round_robin
constraint.
vmm_*_scenario_election
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 241
int scenario_id; Generators scenario
count assigned before
randomization.
rand int select; The selected scenario.
Used by the generator to
select the next scenario.
int stream_id; Generators stream ID
assigned before
randomization.
constraint
vmm_scenario_election_valid;
Constraint to ensure that
select has a valid
value.
constraint round_robin; Constraint to pick the
next scenario in the
scenario set in a round-
robin fashion.
vmm_scenario_election #(T, text)
vmm_ss_scenario#(T) scenario_set[$]; The set of registered
scenarios.
vmm_ms_scenario_election
vmm_ms_scenario scenario_set[$]; The set of registered
scenarios.
Example
Create a single-stream election definition
`vmm_scenario_gen( ahb_trans )
class random_election extends ahb_trans_scenario_election;
constraint round_robin {} // Removes constraint
endclass
program random_test;
random_election elect = new;
ahb_trans_scenario_gen gen = new( ... );
initial
begin
gen.select_scenario = elect; // New election algorithm
vmm_*_scenario_election
242 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
...
end
endprogram
Tips
Alternati vely to overriding the round_robin constraint, the constraint can
be disabled using SystemVerilogs constraint_mode() construct:
gen.select_scenario.round_robin.constraint_mode(0);
Use the `vmm_scenario_gen() macro to automatically define the
necessary election class.
See also
Scenarios, vmm_scenario_gen, vmm_ms_scenario_gen
vmm_scenario_gen
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 243
A scenario generator is defined by the vmm_scenario_gen class. A generator
is a vmm_xactor that automatically creates a transaction stream by invoking its
registered scenarios. By default, a vmm_scenario_gen scenario generator
has one output channel, out_chan, and is used only for single-stream
scenarios.
In order to generate transactions, a scenario must be registered with the
generator. This is accomplished by using the registration method
register_scenario(). Once registered, the generator randomly selects a
scenario using its vmm_scenario_election property, called
scenario_select. The selection algorithm can be changed by extending the
scenario election class and defining custom constraints. The default selection
algorithm selects scenarios in a round robin fashion, but this can be disabled by
turning off a generators round_robin constraint.
Scenario generators also invoke callbacks associated wi th the selected
scenario. Two callbacks are provideda pre-randomize method called
pre_scenario_randomize() and a post-randomize method called
post_scenario_gen(). Callbacks are created by extending the
vmm_scenario_gen_callbacks class.
The shorthand macro, `vmm_scenario_gen( class ), automatically
creates a scenario generator that generates transaction class objects.
Likewise, it automatically creates a basic scenario (class_scenario), atomic
scenario (class_atomic_scenario), callback
(class_scenario_gen_callbacks), and election class
(class_scenario_election).
The functionality of a scenario generator can be summari zed as follows:
1) Randomly selects a scenario.
2) Sets specific generator values like stream_id and scenario_id.
3) Calls any associated pre_scenario_randomize() callback.
4) Randomizes the scenario data members.
5) Calls any associated post_scenario_gen() callback.
6) Repeatedly call the scenarios apply() method to copy the randomly
generated transaction objects from the scenarios items[] array into the
output channel.
7) Stops if stop_after_n_insts or stop_after_n_scenarios is
reached.
See the article on Scenarios for more information.
Declaration
class vmm_scenario_gen_base extends vmm_xactor;
class vmm_scenario_gen #(type T = vmm_data,
string text = "")
extends vmm_scenario_gen_base;
vmm_scenario_gen
244 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Methods
vmm_scenario_gen_base
function new(
string name,
string inst,
int stream_id = -1);
Constructor.
virtual function void
register_scenario(
string name,
vmm_ss_scenario_base
scenario);
Registers scenario scenario
with the generator with the
name name.
virtual function void
replace_scenario(
string name,
vmm_ss_scenario_base
scenario);
Replaces the scenario
registered under name with the
alternati ve scenario
scenario.
virtual function bit
scenario_exists(
string name);
Returns true if the scenario
name is registered.
vmm_scenario_gen
function new(
string inst,
int stream_id = -1
vmm_channel_typed#(T)
out_chan = null);
Constructor.
If out_chan is null, then an
output channel is automatically
created.
virtual function void
get_all_scenario_names(
ref string name[$]);
Returns an array of all the
registered scenarios names.
function int unsigned
get_n_insts();
Returns the actual number of
transaction instances
generated.
function int unsigned
get_n_scenarios();
Returns the actual number of
scenarios applied.
function vmm_ss_scenario#(T)
get_scenario(
string name);
Returns the scenario
registered under name.
virtual function void
get_names_by_scenario(
vmm_ss_scenario_base
scenario,
ref string name[$]);
Returns an array of names
used to register the specified
scenario.
vmm_scenario_gen
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 245
virtual function int
get_scenario_index(
vmm_ss_scenario_base
scenario);
Returns the index of the
scenario in the
scenario_set[] array.
Returns -1 if not found.
virtual function string
get_scenario_name(
vmm_ss_scenario#(T)
scenario);
Returns the registered string
name of the specified
scenario.
virtual task inject(
vmm_ss_scenario#(T)
scenario);
Causes the generator to
execute the specific scenario.
May be used when the
generator is running or
stopped.
virtual task inject_obj(
T obj);
Injects a transaction object
into the output stream.
May be used when the
generator is running or
stopped.
virtual function string
psdisplay(
string prefix = "");
Returns a string description of
the generator.
virtual function void
register_scenario(
string name,
vmm_ss_scenario_base scen);
Registers the specified
scenario with the generator as
name.
virtual function void
replace_scenario(
string name,
vmm_ss_scenario_base scen);
Replaces the scenario
registered under name with
scenario scen.
virtual function void
reset_xactor(
vmm_xactor::reset_e rst_typ
= SOFT_RST);
Resets the generator.
Flushes the output channel
and clears the generators
data members.
virtual function bit
scenario_exists(
string name);
Returns true if scenario
specified by name is registered
in the scenario_set[]
array.
virtual function bit
unregister_scenario(
vmm_ss_scenario_base
scenario);
Unregisters the scenario
specified by scenario.
function vmm_ss_scenario#(T)
unregister_scenario_by_name(
string name);
Unregisters the scenario
specified by name.
vmm_scenario_gen
246 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Members
protected int inst_count; Number of transaction
instances generated.
vmm_channel_typed#(T) out_chan; Output channel.
protected int scenario_count; Number of scenarios
executed.
vmm_ss_scenario#(T)
scenario_set[$];
Array of registered scenarios.
vmm_scenario_election#(T, text)
select_scenario;
Election instance used for
selection scenarios.
int unsigned
stop_after_n_insts;
Maxi mum limi t of transaction
instances to generate.
int unsigned
stop_after_n_scenarios;
Maxi mum limi t of scenarios to
execute.
typedef enum int {
GENERATED,
DONE
} symbols_e;
Notification enumeration.
Macros
`vmm_scenario_gen( T, text ) Macro to automatically define the
following classes for transaction
type T:
T_scenario_gen
T_ss_scenario
T_atomic_scenario
T_scenario_gen_election
T_scenario_gen_callbacks
`vmm_scenario_gen_using(
T, channel_name, text )
Same as above, but specifies the
output channel type.
In VMM 1.2, equi valent to
`vmm_scenario_gen().
vmm_scenario_gen
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 247
Example
class pci_trans extends vmm_data;
...
endclass
`vmm_scenario_gen( pci_trans, "PCI transaction" )
class pci_scenario extends pci_trans_scenario;
int scn_id = define_scenario( "PCI, 5 );
...
endclass
class custom_elect extends pci_trans_scenario_gen_election;
constraint round_robin { } // Remove constraint so
// selection is random
endclass
program testcase;
pci_trans_scenario_gen pci_gen = new( "PCI Gen", 1 );
pci_scenario pci_scn = new;
custom_elect selection_algorithm = new;
initial
begin
pci_gen.register_scenario("PCI scenario", pci_scn);
pci_gen.stop_after_n_insts = 100;
pci_gen.select_scenario = selection_algorithm;
...
end
endprogram
Tips
When the maxi mum scenario or instance li mit is reached, the generator
must be reset before it can be restarted.
For a simple single transaction scenario, use the atomic scenario
automatically created by the `vmm_scenario_gen() macro.
The name that a scenario is registered wi th the generator does not need to
be the same as what was defined using define_scenario().
A scenario may be registered under different names to create aliases of the
scenario.
vmm_scenario_gen
248 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Gotchas
A scenario generator wi ll not stop in the middle of a scenario so the number
transaction instances created may actually exceed the
stop_after_n_insts limit, or the number of scenarios applied may be
less than the stop_after_n_scenarios. Use get_n_insts() for the
actual instance count and get_n_scenarios() for the scenario count.
By default, the stop_after_n_insts and stop_after_n_scenarios
properties are set to 0, which means that the generator will never stop.
Re-registering a registered scenario will generate an erroruse
replace_scenario() instead.
See also
Scenarios, vmm_scenario, vmm_ss_scenario, vmm_*_scenario_gen_callbacks,
vmm_*_scenario_election, vmm_ms_scenario_gen
You can also find further information on this topic at the VMM Golden Reference
Guide's companion page at http://www.doulos.com/vmm.
vmm_*_scenario_gen_callbacks
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 249
Both the single-stream (vmm_scenario_gen) and the multi-stream
(vmm_ms_scenario_gen) scenario generators use a scenario callback object,
vmm_scenario_gen_callbacks#(T,text) and
vmm_ms_scenario_gen_callbacks, respectively. Scenario callbacks are
extended from vmm_xactor_callbacks and are registered with the generator
in the usual way.
The callbacks class defines two virtual methods,
pre_scenario_randomize() and post_scenario_gen(). As their
names imply, the pre_scenario_randomize() is called by the generator
before the selected scenario is randomized, and the post_scenario_gen() is
called afterwards. These are useful functions for making test-specific
modifications at run-time instead of re-defining the scenario. While both the
single and multi-stream callbacks class define a post_scenario_gen()
method, only the single-stream scenario generator executes it. The
post_scenario_gen() method has a dropped argument which indicates to
the generator to drop the scenario. See the article on Scenarios more details.
Declaration
class vmm_scenario_gen_callbacks
#(type T=vmm_data, string text="" )
extends vmm_xactor_callbacks;
class vmm_ms_scenario_gen_callbacks
extends vmm_xactor_callbacks;
Methods
vmm_scenario_gen_callbacks #(T,text)
virtual task pre_scenario_randomize(
vmm_scenario_gen #(T, text) gen,
ref vmm_ss_scenario #(T) scenario);
Callback invoked by the
generator before
randomizing the
scenario.
gen refers to the
generator calling the
callback, and scenario
refers to the selected
executing scenario.
vmm_*_scenario_gen_callbacks
250 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
virtual task post_scenario_gen(
vmm_scenario_gen #(T, text) gen,
vmm_ss_scenario #(T) scenario,
ref bit dropped);
Callback invoked by
generator after
randomization and
before calling apply().
Similar arguments as
above. dropped
indicates to the
generator to drop the
scenario.
vmm_ms_scenario_gen_callbacks
virtual task pre_scenario_randomize(
vmm_ms_scenario_gen gen,
ref vmm_ms_scenario scenario);
Callback invoked by the
generator before
randomizing the
scenario.
gen refers to the
generator calling the
callback, and scenario
refers to the selected
executing scenario.
virtual task post_scenario_gen(
vmm_ms_scenario_gen gen,
vmm_ms_scenario scenario,
ref bit dropped);
Not used by the multi-
stream generator.
Example
`vmm_scenario_gen( ocp )
class ocp_scen_gen_callbacks extends
ocp_scenario_gen_callbacks;
virtual task post_scenario_gen( ocp_scenario_gen gen,
ocp_scenario scenario,
ref bit dropped );
// Print out the scenario
scenario.display();
`vmm_note( gen.log, "################### );
endtask
endclass
program interconnect_test;
ocp_scenario_gen gen = new( ... );
ocp_scen_gen_callbacks cb = new;
mem_transfer_scn mem_scn = new;
peripheral_scn periph_scn = new;
vmm_*_scenario_gen_callbacks
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 251
initial
begin
gen.register_scenario( "MEM_TRANSFER", mem_scn );
gen.register_scenario( "PERIPHALS", periph_scn );
gen.prepend_callback( cb );
...
end
endprogram
Tips
Use callbacks from testcases to enable/disable constraints, modify scenario
values, or cause the generator to drop scenarios.
Gotchas
The post_scenario_gen() callback is not used wi th multi-stream
scenarios.
See also
Scenarios, vmm_scenario_gen, vmm_ms_scenario_gen, vmm_xactor_callbacks
vmm_scheduler
252 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
A vmm_scheduler funnels transactions from multiple sources into one output
channel (the opposite effect of a vmm_broadcast). Unlike a simple channel
that indiscriminately interleaves transactions when fed from multiple sources, a
vmm_scheduler can identify source streams and use a user-configurable
scheduling algorithm to place the transactions in the output channel.
By default, the vmm_scheduler arbitrates in a round-robin method. The
vmm_scheduler::schedule() method can be overridden to define a custom
scheduling algorithm. An alternati ve approach is to define a custom
vmm_scheduler_election class, containing the appropriate random
constraints, and assign the election object to the
vmm_scheduler::randomized_sched variable instance (see
vmm_scheduler_election for details).
Declaration
class vmm_scheduler extends vmm_xactor;
Methods
function new(
string name,
string inst,
vmm_channel destination,
int instance_id = -1,
vmm_object parent = null);
destination refers to the
output channel.
instance_id is an
optional instance identifier.
virtual protected task
get_object(
output vmm_data obj,
input vmm_channel source,
input int unsigned input_id,
input int offset);
Overloadable method
invoked by schedule()
that returns transaction obj
from input channel source
at offset offset.
virtual function int new_source(
vmm_channel channel);
Adds the new input channel
source to the scheduler.
Returns identifier for input
channel or -1 on error.
channel
channel
channel
channel
v
m
m
_
s
c
h
e
d
u
l
e
r
vmm_scheduler
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 253
virtual function string
psdisplay(
string prefix = "");
Function to print out the
broadcast information.
virtual function void
reset_xactor(
vmm_xactor::reset_e rst_typ
= SOFT_RST);
Resets broadcaster and
flushes input/output
channels.
Reset type equals
SOFT_RST,
PROTOCOL_RST,
FIRM_RST, or HARD_RST
(see VMM reference manual
for details).
A HARD_RST replaces the
factory instance of
randomized_sched (see
vmm_scheduler_election).
virtual task sched_from_input(
int channel_id,
int on_off);
Schedules a transaction
from the specified channel if
turned on.
on_off specifies on if 1
and off if 0.
virtual protected task schedule(
output vmm_data obj,
input vmm_channel sources[$],
input int unsigned
input_ids[$]);
Overloadable method that
defines the scheduling rules
of the vmm_scheduler.
The transaction returned as
obj is added to the output
channel. A return of null
means that no transaction
will be added.
The input channels and
corresponding IDs are
provided as sources[$]
and input_ids[$].
virtual function void
start_xactor();
Starts the broadcaster
instance.
virtual function void
stop_xactor();
Stops the broadcaster
instance.
Members
vmm_log log; Message service instance.
protected vmm_channel out_chan; Reference to output channel
set by the constructor.
vmm_scheduler
254 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
vmm_scheduler_election
randomized_sched;
Factory instance of
vmm_scheduler_election
used by schedule() to pick
transactions.
Example
class my_scheduler extends vmm_scheduler;
randc bit [3:0] id; // randc so no repeated random IDs.
// (Note, the SystemVerilog standard
// only requires implementations of up to
// 8 bits for randc variables)
function new ( string name, string instance,
vmm_channel dst, int inst_id );
super.new ( name, instance, dst, inst_id );
endfunction
// User-defined custom scheduling algorithm
virtual protected task schedule ( output vmm_data obj,
input vmm_channel srcs[$],
input int unsigned input_ids[$] );
// A round-robin algorithm, but gi ving priority to the first input channel
if ( src[0].size() > 0 )
id = 0; // 1st channel is not empty so select it
else
// Randomize id to select the next channel to read from
void( this.randomize() with
{ id > 0 && id <= srcs.size(); } );
srcs[id].get( obj ); // Get object from selected channel
endtask
endclass
class my_env extends vmm_env;
my_scheduler sched;
trans_channel channels[4];
trans_channel dst;
...
function void build();
sched = new ( "scheduler", "sched", dst );
vmm_scheduler
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 255
foreach ( channels[i] ) begin
channels[i] = new ( ... );
sched.new_source( channels[i] );
end
...
endfunction
task start();
super.start();
sched.start_xactor();
...
endtask
task stop();
super.stop();
sched.stop_xactor();
...
endtask
endclass
Tips
Overloading the get_object() method enables user-configurable
changes to the transaction object like injecting errors, recording functional
coverage, or substituting alternati ve objects that are passed back to the
scheduling algorithm.
An easier approach to changing the scheduling algorithm than overloading
schedule() is to replace the vmm_scheduler_election instance in
the vmm_scheduler. See vmm_scheduler_election for details.
Gotchas
User extensions of start_xactor(), stop_xactor(), new_source(),
or sched_from_input() must call their respective base class methods
(e.g., super.start_xactor(), etc.).
If schedule() returns null, then no transaction will be scheduled and the
next scheduling cycle wi ll be delayed. When a scheduling cycle is delayed,
lock-up may occur unless (1) a new channel is added, (2) new data is put
into the channel, (3) a channel is turned on, or (4) the scheduler is
restarted.
vmm_scheduler
256 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
When overloading get_object(), make sure to remove objects from the
input channels using a method li ke vmm_channel::get() or else the
object may be used multiple ti mes.
See also
vmm_scheduler_election, vmm_broadcast, vmm_xactor
vmm_scheduler_election
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 257
A vmm_scheduler_election object defines the random constraints used by
the vmm_schedulers schedule() method to determine the input channel
and offset in the channel from which to extract the next transaction (i.e., the
elected transaction) every election cycle. There are 2 constraints defined: (1)
vmm_scheduler_election_valid, and (2) default_round_robin.
Constraint vmm_scheduler_election_valid determines if there are any
valid transactions to pick. Constraint default_round_robin picks the next
input channel and channel offset for the next transaction.
In order to create a custom scheduling algorithm for a vmm_scheduler, the
vmm_scheduler_election class can be extended wi th its own custom
constraints, or the constraints can be turned off in the vmm_schedulers
randomized_sched instance, resulting in a random transaction scheduling
instead of in round-robin fashion.
Declaration
class vmm_scheduler_election;
Members
constraint default_round_robin; Constraint used to select
transactions in a round-robin
fashion.
constraint
vmm_scheduler_election_valid;
Constraint used to determine if
any transactions are available.
int unsigned election_id; ID incremented by the
scheduler before every
election cycle.
int unsigned id_history[$]; A queue of the last 10 input
channel IDs that were selected
int unsigned ids[$]; Unique input channel IDs
corresponding to the channels
in the sources[$] queue.
int instance_id; Identifier of the
vmm_scheduler instance
randomizing this
vmm_scheduler_election
object.
int unsigned n_sources; Number of input sources.
int unsigned next_idx; Next input channel ID to
select. Used by round-robin
algorithm.
vmm_scheduler_election
258 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
vmm_data obj_history[$]; Queue of the last 10
transactions selected.
rand int unsigned obj_offset; Offset of selected transaction
within the source channel.
The default_round_robin
constraint constrains this to 0.
vmm_channel sources[$]; Queue of input channel
sources.
rand int unsigned source_idx; Index of input channel from
which to elect the next
transaction.
Example
//
// Example of replacing the vmm_scheduler_election constraints
//
class custom_algorithm extends vmm_scheduler_election;
// Disable the round robin constraint
constraint default_round_robin { /* empty */ };
// Custom function that picks the source channel which has the greatest
// number of transactions to relieve back-pressure
function void post_randomize();
int qsize;
foreach ( srcs[i] )
if ( srcs[i].size() > qsize ) begin
qsize = srcs[i].size();
source_idx = i;
end
endfunction
// obj_offset is still set by the base classs
// vmm_scheduler_election_valid constraint
endclass
vmm_scheduler_election
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 259
//
// Example of disabling constraints
//
class my_env extends vmm_env;
my_scheduler sched;
trans_channel channels[4];
trans_channel dst;
...
function void build();
sched = new ( "scheduler, "sched, dst );
foreach ( channels[i] ) begin
channels[i] = new ( ... );
sched.new_source( channels[i] );
end
// Disable the round-robin constraintmake election random
sched.randomized_sched.default_round_robin.constraint_mode(0);
// Could have also replaced the algorithm to disable the constraint:
// custom_algorithm cstm = new;
// sched.randomized_sched = cstm;
...
endfunction
endclass
Tips
While most of the members of the vmm_scheduler_election class are
used by the vmm_scheduler to perform the default round robin
scheduling, only source_idx and obj_offset are actually required to be
set for the vmm_scheduler.
Use the pre_randomize() and post_randomize() functions (example
shown above) to create custom scheduling election algorithms.
See also
vmm_scheduler
Shorthand Macros
260 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
The shorthand member macros automate the creation of various utili ty methods
for several VMM classes. Each member inside a class must be specified using
the macros so that they can be included in all the generated methods.
There are five components that use the shorthand member macrosvmm_data,
vmm_xactor, vmm_env, vmm_subenv, and vmm_scenario. The shorthand
macros provide the following methods:
vmm_data
vmm_scenario
vmm_xactor vmm_env vmm_subenv
allocate
byte_pack
byte_size
byte_unpack
copy
compare
is_valid
max_byte_size
new
psdisplay
psdisplay
kill_xactor
reset_xactor
start_xactor
stop_xactor
psdisplay
reset
start
stop
vote
psdisplay
reset
start
stop
vote
While the macros create different methods from component to component, the
same set of member macros are provided for the different components in the
following form:
`class_member_datatype ( name, do [, how] )
where class is one of vmm_data, vmm_scenario, vmm_xactor,
vmm_env or vmm_subenv and datatype is one of the following shorthand
macros:
Shorthand Macros
Macro Declares member
type:
`class_member_begin( class ) Starts the shorthand
section
`class_member_end( class ) Ends the shorthand
section
`class_member_enum( name, do ) Enumeration
Shorthand Macros
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 261
`class_member_enum_aa_scalar( name,
do )
Scalar-indexed
associati ve array of
enumerations
`class_member_enum_aa_string( name,
do )
String-indexed
associati ve array of
enumerations
`class_member_enum_array( name, do ) Fixed array of
enumerations
`class_member_enum_da( name, do )
(vmm_data and vmm_scenario only)
Dynamic array of
enumerations.
`class_member_scalar( name, do ) Integral type
(E.g., bit, bit vector,
packed data type etc.)
`class_member_scalar_aa_scalar( name,
do )
Scalar-indexed
associati ve array of
scalars
`class_member_scalar_aa_string( name,
do )
String-indexed
associati ve array of
scalars
`class_member_scalar_array( name, do ) Fixed array of scalars
`class_member_scalar_da( name, do )
(vmm_data and vmm_scenario only)
Dynamic array of
string
`class_member_string( name, do ) String
`class_member_string_aa_scalar( name,
do )
Scalar-indexed
associati ve array of
strings
`class_member_string_aa_string( name,
do )
String-indexed
associati ve array of
strings
`class_member_string_array( name,
do )
Fixed array of strings
`class_member_string_da( name, do )
(vmm_data and vmm_scenario only)
Dynamic array of
string
`class_member_user_defined( name ) User-defined
implementation
`class_member_vmm_data( name, do, how) vmm_data member
`class_member_vmm_data_aa_scalar(
name, do, how )
Scalar-indexed
associati ve array of
vmm_data members
Shorthand Macros
262 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
`class_member_vmm_data_aa_string(
name, do, how )
String-indexed
associati ve array of
vmm_data members
`class_member_vmm_data_array(
name, do, how )
Fixed array of
vmm_data members
`class_member_vmm_data_da(
name, do, how )
(vmm_data and vmm_scenario only)
Dynamic array of
vmm_data members
vmm_data / vmm_scenario specific
Macro Declares member
type:
`class_member_handle( name, do ) Class handle
`class_member_handle_aa_scalar( name,
do )
Scalar-indexed
associati ve array of
class handles
`class_member_handle_aa_string( name,
do )
String-indexed
associati ve array of
class handles
`class_member_handle_array( name,
do )
Fixed array of class
handles
`class_member_handle_da( name, do ) Dynamic array of
class handles
`class_new( class ) Turns off the
automatic constructor
definition
`class_member_vmm_scenario(
name, do, how )
(vmm_scenario only)
vmm_scenario
member
vmm_xactor / vmm_env / vmm_subenv specific
Macro Declares member
type:
`class_member_channel( name, do ) Channel member
`class_member_channel_aa_scalar(
name, do )
Scalar-indexed
associati ve array of
channels
`class_member_channel_aa_string(
name, do )
String-indexed
associati ve array of
channels
Shorthand Macros
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 263
`class_member_channel_array( name,
do )
Fixed array of
channels
`class_member_channel_aa_scalar(
name, do )
Scalar-indexed
associati ve array of
channels
`class_member_xactor( name, do ) vmm_xactor
member
`class_member_xactor_aa_scalar( name,
do )
Scalar-indexed
associati ve array of
xactors
`class_member_xactor_aa_string( name,
do )
String-indexed
associati ve array of
xactors
`class_member_xactor_array( name,
do )
Fixed array of xactors
vmm_env / vmm_subenv specific
Macro Declares member
type:
`class_member_subenv( name, do ) vmm_subenv
member
`class_member_subenv_aa_scalar( name,
do )
Scalar-indexed
associati ve array of
subenvs
`class_member_subenv_aa_string( name,
do )
String-indexed
associati ve array of
subevns
`class_member_subenv_array( name,
do )
Fixed array of
subenvs
Actions
With each member macro, there is a do action that must be specified. This
indicates what actions to automatically generated. These actions can be OR-ed
or added together to turn on certain actions as well as subtracted to turn off the
action. The vmm_data member macros also include a how field that specifies
how the copying and comparing should be done. These options are listed in the
following tables.
Macro do actions
DO_PRINT Print member
Shorthand Macros
264 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
DO_COPY Copy member
DO_COMPARE Compare member
DO_PACK Pack member
DO_UNPACK Unpack member
DO_ALL Do all automation
Macro how field
DO_NOCOPY Do not copy member
DO_REFCOPY Copy only member references
(shallow copy)
DO_DEEPCOPY Deep copy
HOW_TO_COPY Both REFCOPY and DEEPCOPY
DO_NOCOMPARE Do not compare members
DO_REFCOMPARE Compare using only references
DO_DEEPCOMPARE Deep compare (compare all sub-
members)
HOW_TO_COMPARE Both REFCOMPARE and
DEEPCOMPARE
DO_NONE Skip all copying and comparison
DO_REF All DO_REF*
DO_DEEP All DO_DEEP*
Overriding Methods
When the shorthand macros are used, they define the various functions like
copy() and compare(), which means that these methods can no longer be
user defined. However, these functions can be overridden by defining a do
version of the method. For example, to customize the psdisplay() method, a
do_psdisplay() function can be defined as follows:
virtual function string do_psdisplay( string prefix = "");
// Custom display with an ANSI color
$sformat( do_psdisplay,
"\034[34m %s: (%s.%s) data = %d, addr = %d \034[0m",
prefix, this.name, this.inst, this.data, this.addr );
endfunction
Now when the psdisplay() method is called, it will invoke the user-defined
do_psdisplay() method instead of providing the built-in functionality.
Shorthand Macros
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 265
Non-member macros
Both the vmm_data and vmm_scenario classes include some non-member
shorthand macros that are also useful. By default, the shorthand macros
automatically create a class new constructor. This can be disabled by using
either `vmm_data_new() or `vmm_scenario_new(), respecti vely. The
constructor macro must be called before the member macros begin in order to
disable the constructor generation. Another macro,
`vmm_data_byte_size( max, n )
defines the max_byte_size() and byte_size() methods automatically. The
_max field specifies the value returned by max_byte_size() and _n the value
returned from byte_size().
Example
class mac_frame extends vmm_data;
plcp_frame plcp_history[];
plcp_frame current_frame;
int crc;
`vmm_data_member_begin ( mac_frame )
`vmm_data_member_scalar( crc, DO_ALL )
`vmm_data_member_handle_da( plcp_history, DO_ALL )
`vmm_data_member_vmm_data( current_frame, DO_ALL,
DO_DEEP)
`vmm_data_member_end ( mac_frame )
endclass
class ahb_trans extends vmm_data;
rand int data;
rand int addr;
rand enum { READ, WRITE } kind;
// Automate everything but the compare() function
`vmm_data_member_begin ( ahb_trans )
`vmm_data_member_scalar( data, DO_ALL DO_COMPARE )
`vmm_data_member_scalar( addr, DO_ALL DO_COMPARE )
`vmm_data_member_enum( kind, DO_ALL DO_COMPARE )
`vmm_data_member_end ( ahb_trans )
function bit do_compare( vmm_data to,
output string diff,
input int kind = -1 );
if ( to == null ) begin
Shorthand Macros
266 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
diff = "to argument is null!";
return 0;
end
if ( to.addr == this.addr && to.data == this.data )
return 1;
else
begin
diff = "these two are not equal!";
return 0;
end
endfunction
endclass
Tips
Action values can be OR-ed or added together like this:
`vmm_data_member_scalar( addr, DO_PRINT + DO_COPY +
DO_COMPARE )
or subtracted:
`vmm_data_member_scalar( addr, DO_ALL DO_IS_VALID )
While a do_method() should not invoke its super class (i.e.,
super.do_method()), a do_method() does not need to totally override
the bui lt-in default functionality. In order to do an action first and then
perform the bui lt-in functionality, add the following assignment inside the
user-defined method:
function vmm_data copy( vmm_data to = null );
this.__vmm_done_user = 0;
...
Gotchas
When creating your own custom utility methods, do not call the parent base
class (i.e., using super()).
The constructor macro must precede the begin macro.
See also
vmm_data, vmm_scenario, vmm_xactor, vmm_env, vmm_subenv
vmm_simulation
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 267
The vmm_simulation class is a top-level singleton that controls the execution
of the pre-test, top-test, and post-test si mulation ti melines. It is used to start the
execution of tests, and can also be used to insert additional phases in the global
timelines.
Declaration
class vmm_simulation extends vmm_unit;
Methods
function new(); Constructor.
static function void
allow_new_phases(
bit allow = 1 );
Allows the addi tion of user-
defined phases in ti melines.
static function void
display_phases();
Displays how the phases will
be executed in each timeline.
static function vmm_timeline
get_post_timeline();
Returns a reference to the
post-test ti meline.
static function vmm_timeline
get_pre_timeline();
Returns a reference to the pre-
test ti meline.
static function vmm_simulation
get_sim();
Returns a reference to the top-
level singleton
vmm_simulation object.
static function vmm_timeline
get_top_timeline();
Returns a reference to the top
test ti meline.
static function void list(); Lists all avai lable tests.
static task run_tests(); Runs either the default
testcase or the test(s)
specified on the command
line.
Example
// Call run_tests() and display all the phases
program TB;
`include "vmm_sv"
class my_test extends vmm_test;
function void start_of_sim_ph();
vmm_simulation::display_phases();
endfunction
endclass
vmm_simulation
268 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
class my_env extends vmm_env;
my_xactor xactor;
...
endclass
initial begin
my_test t1 = new ( "t1" );
my_env env = new ( "env" );
...
vmm_simulation::run_tests();
end
endprogram
// Add a new phase
program P;
class my_test extends vmm_test;
// New phase
virtual task init_registers_ph();
...
endtask
endclass
// New phase definition
class init_registers_def extends vmm_forked_task_phase_def
#( my_test );
`vmm_typename ( init_registers_def )
task do_task_phase ( my_test t );
if (t.is_enabled())
t.init_registers_ph();
endtask
endclass
my_test t;
init_registers_def init_reg_def;
initial begin
init_reg_def = new;
t = new;
vmm_simulation
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 269
// Enable user phases
vmm_simulation::allow_new_phases();
// Add the new phase before "start"
vmm_simulation::insert_phase("init_registers_ph",
"start",
init_reg_def );
end
endprogram
Tips
The VMM specification recommends calling display_phases() after the
build phase.
The test(s) run by run_tests() is determined as follows:
o If the command line argument +vmm_test or
+vmm_test_file is specified, then use the specified tests:
+vmm_test_file=<filename> File list of test to run
+vmm_test=<test> Test case to run
+vmm_test=<test>+<test>+... List of test cases to run
+vmm_test=ALL_TESTS Run all declared tests
o If no +vmm_test/+vmm_test_file AND only one defined top-
level tests, then execute that test.
o If no +vmm_test/+vmm_test_file AND multiple top-level tests
defined, then a warning message is printed and no test is run.
Gotchas
By default, user defined phases are not allowed and wi ll issue an error
message unless allow_new_phases() is called.
A fatal error message will be issued if a user defined phase is added to a
non-existent phase.
See also
Phases, vmm_timeline, vmm_test
vmm_ss_scenario
270 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
The vmm_ss_scenario #(T) class defines a single-stream scenario where T
is the transaction type that is generated by the scenario. Each single-stream
scenario contains an items[] array for the transaction objects generated by the
scenario. The length of a scenario (set by define_scenario()) limits the
number of transactions generated. A scenarios default apply() method wi ll
copy the randomized transaction objects from items[] into a scenario
generators output stream. For greater control or creating hierarchal scenarios,
the apply() can be overwritten to create a custom algorithm such as calling
other scenarios or modifying transactions before being placed into the output
channel. See the article on Scenarios for more detai ls.
Declaration
class vmm_ss_scenario_base extends vmm_scenario;
class vmm_ss_scenario #( type T = vmm_data ) extends
vmm_ss_scenario_base;
Methods
function new(); Constructor.
function void
allocate_scenario(
T using = null);
Allocates new transaction
objects for the items[] array
using copies of using if
defined.
virtual task apply(
vmm_channel_typed#(T)
channel,
ref int unsigned n_insts);
Applies the transactions in the
items[] array into the output
channel.
n_insts should be
incremented wi th the number of
items copied into the output
channel.
virtual function vmm_data
copy(
vmm_data to = null);
Copy method.
Returns a reference to a single-
stream scenario of the specific
type.
vmm_ss_scenario
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 271
function int unsigned
define_scenario(
string name,
int unsigned max_len = 0);
Inherited from vmm_scenario.
Defines a new scenario name
and sets the maxi mum length of
the transaction stream (i.e.,
number of transactions to
generate).
Returns an integer scenario kind
identifier which can be used for
specifying scenario kind related
constraints.
function void fill_scenario(
T using = null);
Extends the items[] array to
the maxi mum length and fills all
empty locations by copying
using if defined.
function void pre_randomize(); Pre-randomization method that
calls fill_scenario().
Override method to allocate the
items[] array differently.
virtual function string
psdisplay(
string prefix = "");
Returns a string description of
the scenario.
function void
redefine_scenario(
int unsigned scenario_kind,
string name,
int unsigned max_len = 0);
Inherited from vmm_scenario.
Redefines a scenarios name or
maxi mum length.
function string scenario_name(
int unsigned scenario_kind
= 0);
Inherited from vmm_scenario.
Returns the name of the
scenario specified by the
scenario_kind.
Members
rand T items[]; Array of transaction T items
generated by the scenario.
static vmm_log log; Class-wide available message
service.
rand int unsigned
repeated = 0;
Inherited from vmm_scenario.
Number of times to repeat the
scenario.
static int unsigned
repeat_thresh = 100;
Inherited from vmm_scenario.
Maxi mum number of times to
repeat a scenario.
vmm_ss_scenario
272 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
rand int unsigned
scenario_kind;
Inherited from vmm_scenario.
Numeric ID assigned to a
scenario when registered with
define_scenario().
int scenario_id; Inherited from vmm_scenario.
Generators scenario count
assigned before randomization
used to identify scenarios in a
stream or for random
constraints.
int stream_id; Inherited from vmm_scenario.
Generators stream ID assigned
before randomization used by
other components (like a
scoreboard) to differentiate
transactions.
constraint T_scenario_valid; Constraint that limi ts items[]
size to length.
T using; Factory pattern template
variable used to fill the
items[] array.
Example
//
// Random register write sequence
//
`vmm_scenario_gen( ahb_trans )
class rand_reg_scenario extends ahb_trans_scenario;
int id = define_scenario( "Random Reg", 0 );
int reg_addrs[] = '{ CFG1_REG, CNTR_REG, ... };
function void pre_randomize();
reg_addrs.shuffle; // Randomize the array
endfunction
constraint write_regs {
length == reg_addrs.size();
foreach ( items[i] ) {
items[i].addr = reg_addrs[i];
items[i].mode = WRITE;
}
}
vmm_ss_scenario
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 273
virtual task apply( ahb_trans_channel channel,
ref int unsigned n_insts );
`vmm_note( log, "Generating register writes ..." );
super.apply( channel, n_insts );
endtask
endclass
Tips
Use the `vmm_scenario_gen macro to simplify creating single-stream
scenarios.
For a single item scenario, use the vmm_atomic_scenario #(T)
automatically generated by `vmm_scenario_gen().
Use stream_id for stream related constraints, and scenario_id to
constraint for specific scenarios.
Gotchas
Even if the repeated value is set to greater than 0, the generators
scenario count is only incremented once for a scenario regardless of the
number of times it is repeated.
See also
Scenarios, vmm_scenario, vmm_scenario_gen, vmm_ms_scenario
You can also find further information on this topic at the VMM Golden Reference
Guide's companion page at http://www.doulos.com/vmm.
vmm_subenv
274 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
VMM encourages the reuse of testbench components between block and
system-level environments through the use of sub-environments. A sub-
environment is a self-contained component that generally includes a moni tor,
driver, transactor, and some type of self-checking. In order to remain reusable,
VMM encourages constructing sub-environments according to the following
guidelines
A sub-environment should have transaction-level inputs and outputs.
For explicitly phased environments, a sub-environment should be derived
from `VMM_SUBENV so it can be re-targetable from the command line.
For implicitly phased environments, a sub-environment should be derived
from vmm_group.
Physical interfaces should be passed using a custom bind_vif()
function, or by wrapping the virtual interface in a custom class wrapper and
setting the custom class wrapper from the top level using the
vmm_opts::set_object() facility.
A sub-environment should include a configure() method for configuring
itself and its sub-components.
The configure() method should call super.configured() upon
completion so the environment can be started.
The configure() method should configure the design using the register
abstraction layer.
A sub-environment should include a configuration descriptor, which is set
using the vmm_opts::set/get object() facility.
A vmm_consensus instance should be passed as a constructor argument
to indicate that the sub-environment has reached its end-of-test condition.
Declaration
class vmm_subenv extends vmm_group;
Methods
function new(
string name,
string inst,
vmm_consensus end_test,
vmm_object parent = null);
end_test is used to signal
the sub-env has reached its
end-of-test condition.
virtual task cleanup();
Stops the sub-environment
and tests for end-of-test
conditions.
Requires super.cleanup().
vmm_subenv
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 275
protected function void
configured();
Sets the sub-environments
state as configured.
Required by the start()
method.
function void do_all(
do_what_e what,
vmm_env::restart_e
restart_kind = vmm_env::FIRM);
Method for configuring the
design.
protected virtual function
string do_psdisplay(
string prefix = "");
User-definable method for
overriding the default
psdisplay() method
created by the vmm_subenv
shorthand macros.
protected virtual task
do_reset(
vmm_env::restart_e kind);
User-definable method for
overriding the default
reset() method created by
the vmm_subenv shorthand
macros.
protected virtual task
do_start();
User-definable method for
overriding the default
start() method created by
the vmm_subenv shorthand
macros.
protected virtual task
do_stop();
User-definable method for
overriding the default stop()
method created by the
vmm_subenv shorthand
macros.
protected virtual task
do_vote();
User-definable method for
overriding the default
end_vote() method created
by the vmm_subenv
shorthand macros.
function vmm_consensus
get_consensus();
Returns the end-of-test
consensus.
virtual function string
psdisplay(
string prefix = "");
Function to print out sub-
environment information.
virtual function void report(); Method for reporting the
success or failure of a test.
virtual task reset(
vmm_env::restart_e
kind = vmm_env::FIRM);
Resets the sub-environment.
virtual task start() Starts the sub-environment.
vmm_subenv
276 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
virtual task stop(); Stops the sub-environment.
Members
typedef enum {
DO_PRINT,
DO_START,
DO_STOP,
DO_RESET,
DO_VOTE,
DO_ALL } do_what_e;
Macro actions enumeration.
vmm_log log; Message service interface for
this component.
protected vmm_consensus
end_test;
Notifies end-of-test condition
reached.
Macros
`VMM_SUBENV Extended user-defined sub-
environments should extend
using this macro.
Default is vmm_subenv.
Shorthand Macros
The vmm_subenv shorthand macros are a way of defining an environment wi th
automatically generated psdisplay(), start(), stop(), reset(), and
vote()
10
methods that have a default implementation. The macros are placed
between a `vmm_subenv_member_begin/`vmm_subenv_member_end pair.
Each macro has a do_what_e field, which specifies the methods to
automatically generate. The enumeration values can be OR-ed together for
specific methods or DO_ALL for all methods. The default i mplementation for
these methods can be extended or overwritten by defining a do_psdisplay(),
do_start(), do_stop(), do_reset(), or do_vote() method, respecti vely.
Begin / end macros
`vmm_subenv_member_begin( class )
`vmm_subenv_member_end ( class )
10
Automatically registers a member with the vmm_env::end_vote consensus
instance.
vmm_subenv
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 277
Scalar data members
`vmm_subenv_member_scalar( name, do )
`vmm_subenv_member_scalar_array( name, do )
`vmm_subenv_member_scalar_aa_scalar( name, do )
`vmm_subenv_member_scalar_aa_string( name, do )
Enumeration data members
`vmm_subenv_member_enum( name, do )
`vmm_subenv_member_enum_array( name, do )
`vmm_subenv_member_enum_aa_scalar( name, do )
`vmm_subenv_member_enum_aa_string( name, do )
String data members
`vmm_subenv_member_string( name, do )
`vmm_subenv_member_string_array( name, do )
`vmm_subenv_member_string_aa_scalar( name, do )
`vmm_subenv_member_string_aa_string( name, do )
VMM data members
`vmm_subenv_member_vmm_data( name, do )
`vmm_subenv_member_vmm_data_array( name, do )
`vmm_subenv_member_vmm_data_aa_scalar( name, do )
`vmm_subenv_member_vmm_data_aa_string( name, do )
Channel data members
`vmm_subenv_member_channel( name, do )
`vmm_subenv_member_channel_array( name, do )
`vmm_subenv_member_channel_aa_scalar( name, do )
`vmm_subenv_member_channel_aa_string( name, do )
Transactor data members
`vmm_subenv_member_xactor( name, do )
`vmm_subenv_member_xactor_array( name, do )
`vmm_subenv_member_xactor_aa_scalar( name, do )
vmm_subenv
278 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
`vmm_subenv_member_xactor_aa_string( name, do )
Sub-environment data members
`vmm_subenv_member_subenv( name, do )
`vmm_subenv_member_subenv_array( name, do )
`vmm_subenv_member_subenv_aa_scalar( name, do )
`vmm_subenv_member_subenv_aa_string( name, do)
User-defined data members
`vmm_subenv_member_user_defined( name )
Example
class my_subenv_cfg;
// Put config information here
endclass : my_subenv_cfg
class my_subenv extends vmm_subenv;
my_subenv_cfg cfg;
virtual dut_intf.tb dut_if;
tx_channel tx_chan;
my_scoreboard sb;
my_monitor mon;
my_driver drv;
my_atomic_gen gen;
my_ral_block ral;
function new ( string inst,
vmm_consensus end_test,
tx_channel chan,
virtual dut_intf.tb dut_if = null );
super.new ( "my_subenv", inst, end_test );
this.dut_if = dut_if;
if (tx_chan == null) begin
gen = new( "my_subenv gen", inst );
tx_chan = gen.out_chan;
end
this.tx_chan = chan;
vmm_subenv
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 279
sb = new ( inst, cfg );
mon = new ( inst, cfg, dut_if.mon );
drv = new ( inst, cfg, tx_chan, dut_if.drv );
endfunction : new
task configure();
ral.CONFIG.set(1); // Configure DUT using RAL
...
super.configured(); // Required for start()
endtask : configure
function void start();
super.start(); // Must call parent method!
// Start components
mon.start_xactor();
drv.start_xactor();
gen.start_xactor();
// Send received data to the scoreboard
fork
forever begin
trans tr;
mon.rx_chan.get( tr );
sb.put( tr );
end
join_none
// Setup for end-of-test
this.end_test.register_notification( gen.notify,
my_atomic_gen::DONE );
this.end_test.register_channel( tx_chan );
this.end_test.register_xactor( drv );
this.end_test.register_xactor( mon );
endfunction : start
task stop();
super.stop(); // Call parent method!
gen.stop_xactor();
drv.stop_xactor();
mon.stop_xactor();
endtask : stop
endclass : my_subenv
vmm_subenv
280 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Tips
When constructing a testbench, partition related components into a sub-
environment to maxi mize reuse between block and system-level
environments.
A sub-environment should define a configure() method that calls
super.configured().
Gotchas
Extended i mplementations of cleanup(), start(), and stop()
methods must call their base class methods via super.method_name().
The start() method wi ll throw an error unless the configured()
method has been called.
See also
vmm_env, vmm_group
You can also find further information on this topic at the VMM Golden Reference
Guide's companion page at http://www.doulos.com/vmm.
vmm_test
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 281
The vmm_test class is extended from the vmm_timeline and manages the
top-test timeline and its defined phases. It handles the registering of test cases,
and it provides a set_config() method that allows a single test case to
execute code before a testbench environment is constructed in the pre-test
timeline.
Declaration
class vmm_test extends vmm_timeline;
Methods
function new(
string name = "",
string doc = "",
vmm_object parent = null);
Constructor.
name is the name of the
instance and doc refers to a
user comment or
documentation like Reset
Test.
virtual function string
get_doc();
Returns a string description of
the test.
virtual function string
get_name();
Returns the name of the test
case.
function bit has_config_done(); Returns 1 upon complete of
set_config().
virtual task run(vmm_env env); Provided for backward
compatibility wi th VMM 1.1.
Calls the environments run
task to execute the legacy
VMM steps like gen_cfg,
reset_dut, build, start, stop,
etc.
See the `vmm_test_begin
macro below.
virtual function void
set_config();
Optionally user-defined
function that get executed
before the pre-test ti meline.
Useful for setting factory
configuration information
before the environment is
constructed.
vmm_test
282 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Macros
`vmm_test_begin( testclassname, envclassname, doc )
`vmm_test_end ( testclassname )
These macros are provided for backwards compatibility wi th VMM 1.1, which
executes steps gen_cfg, reset_dut, build, run, etc., but does not use the phasing
mechanism provided wi th VMM 1.2.
These macros create, instantiate, and register a test class. They also create the
run() task around the test case functionality. They provide a simple way to
define a test because only the run step functionali ty needs to be defined,
sandwiched between these two macros. Also, the macros create the test
constructor and register the test with the vmm_test_registry class.
It is important to note that tests created using these macros are statically
instantiated and are therefore visible to the environment. Likewise, the
environment is made visible to the test case, allowing it to register callbacks,
replace generators, traverse the testbench hierarchy, or anything else normally
done in a program block.
Since only the run() task is defined, vmm_simulation::run_tests() will
not execute the test case because the test has no defined phase callback (e.g.,
no run_test_ph()). Rather, vmm_test_registry::run(env) can be
used kick off the test and execute the traditional VMM steps.
`vmm_test_concatenate( starting-phase )
When multiple tests are to be executed, a test may specify itself as concatenable
with other tests by using the `vmm_test_concatenate macro. This macro is
placed inside the test class, and the phase to start the test is passed to the
macro. This automatically creates a concatenate_test_n_reset_phase()
function that will be invoked by the top-test ti meline to reset to the specified
phase when the test is executed.
Example
Example using set_config()
program P;
class test1 extends vmm_test;
`vmm_typename ( test1 )
function new ( string name = "" );
super.new ( name );
endfunction
// Swap out a testbench component created by the factory
function void set_config();
vmm_test
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 283
// Replace with error injecting generator
typical_gen::override_with_new (
"@%*",
error_gen::this_type(),
`__FILE__,
`__LINE__ );
endfunction
endclass
test1 t;
initial begin
t = new ( "test1" );
vmm_simulation::run_tests(); // Kick off tests
end
endprogram : P
Example using test macros
class odd_data extends data_trans;
contraint special { data[0] == 1 };
endclass
`vmm_test_begin ( test1, env, "Test case 1" )
`vmm_note(log, {"Starting test ", get_name() });
env.build(); // Build the environment
// Swi tch to the different transaction type
begin
odd_data t = new;
env.gen.randomized_obj = t;
end
env.run(); // Generate the transactions
`vmm_note(log, { get_name(), " test done." });
`vmm_test_end ( test1 )
program TB;
`include "vmm.sv"
initial begin
my_env env = new;
// Run the test cases
vmm_test_registry::run(env);
end
endprogram : TB
vmm_test
284 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Tips
Since vmm_test extends vmm_timeline, the method run_phase("$") can
be called on a test object to kick off the simulation phases.
Gotchas
The set_config() method can only be used when one test is executing
(i.e., it does not work for test concatenation). If multiple tests are specified
to execute, those that have a set_config() method will be removed from
the execution list.
The `vmm_test_begin/`vmm_test_end macros do not work wi th the
new VMM 1.2 phasing so vmm_test_registry::run(env) needs to be
called instead of the vmm_simulation::run_tests() (details above).
See also
vmm_ti meline, vmm_simulation, vmm_test_registry
vmm_test_registry
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 285
The vmm_test_registry class is used for globally registering testcases to run
for simulation. While an instance of vmm_test_registry can be used, all
methods are static and globally accessible, and the test registry exists as a
singleton entity.
The run() method starts the execution of the registered testcases. If none are
specified, then a special Default testcase is created and started that invokes
env::run(). When more than one testcase is register, it must be specified on
the command line using +vmm_test. The VMM guidelines require that
vmm_test_registry::run() be invoked from within a SystemVerilog
program.
Declaration
class vmm_test_registry;
Methods
static function void list(); Displays a list of all registered
test cases.
static task run(
vmm_env env);
Starts the execution of a
registered testcase and
invokes env.run().
If no testcase is registered,
then a default testcase is
created and run.
If more than one testcase is
registered, then a test name
must be specified using the
command line option
+vmm_test.
Example
program t;
`include "tests.sv" // Include all tests
my_env env = new();
initial
vmm_test_registry::run( env );
endprogram
vmm_test_registry
286 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Tips
The `vmm_test_begin/`vmm_test_end macros automatically create a
testcase and invoke vmm_test_registry::run(env).
Gotchas
The VMM 1.2 phasing runs testcases differently from
vmm_test_registry::run(env). Use
vmm_simulation::run_tests() to execute test(s) using the new VMM
1.2 simulation semantics.
See also
vmm_simulation
vmm_timeline
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 287
The control of the phasing in VMM occurs through the vmm_timeline class.
The root vmm_unit objects are implicitly controlled by the pre-test, top-test, and
post-test ti melines located in the vmm_simulation class, but timelines can be
inserted anywhere inside the testbench hierarchy to insert addition phases or re-
arrange the order of execution.
Timeline Execution
When a timeline is inserted within a testbench hierarchy, it becomes a sub-
timeline of the higher-level global ti melines. For example, vmm_test extends
vmm_timeline, so test cases are examples of sub-timelines that execute under
the global pre-test, top-test, and post-test ti melines. When a sub-timeline is
encountered, all the phases are executed up to the currently executing phase in
the immediate higher level timeline.
Ti melines and their phases refer to the progress of the overall si mulation, not the
state of the threads in the si mulation. Phase execution, including forked phases,
blocks until all components on a timeline complete a phase before movi ng on to
the next phase. Therefore, components should never define infinite loops within
their phase methods or timeline execution wi ll be blocked. Rather, components
should fork off blocking tasks such as main() so that timeline execution can
proceed. This means that the execution of tasks in a transactor, such as
main(), may continue across multiple timeline phases. A test finishes upon
completion of the run_test phase, when a vmm_unit (such as vmm_env)
consents to the end of a test and returns from the run_test_ph() task.
Controlling Phases
Ti melines can have additional phases added, removed, re-ordered, or even
renamed. The timeline class provides methods like insert_phase(),
add_phase(), rename_phase(), and others. A phase in a timeline can also
be overwritten using vmm_unit::override_phase().
Ti melines can step through phase execution phase-by-phase. Several methods
are provided to control phases like step_function_phase(), run_phase(),
reset_to_phase(), and abort_phase(). These methods provide a way to
control phase execution from within an environment, but an easier method is to
use the command line argument, +vmm_break_on_phase= X, where X is the
name of the phase to stop execution by a call to $stop. If a
vmm_timeline_callbacks object has been registered with the timeline, then
the break_on_phase() method will be invoked (if defined) instead of $stop.
Declaration
class vmm_timeline extends vmm_unit;
vmm_timeline
288 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Methods
function new(
string name = "",
string inst = "",
vmm_object parent = null);
Constructor.
function bit abort_phase(
string name,
string fname = "",
int lineno = 0);
Aborts the specified phase
name if currently executing,
prints a warning if phase name
has already completed, and
issues an error message if
phase name will be executed.
Returns 1 upon success.
function bit add_phase(
string name,
vmm_phase_def def);
Adds phase definition, def, to
phase name .
Returns 1 upon success, and
prints a fatal error if phase
name does not exist.
virtual function void
configure_test_ph();
Phase used by a testcase to
configure the environment.
Executed at the beginning of
the test root ti meline.
function bit delete_phase(
string phase_name,
string fname = "",
int lineno = 0);
Deletes the phase
phase_name from the
specified timeline.
Returns 1 upon success, and
0 if phase_name does not
exist.
function void display_phases(); Displays phases remaining to
be executed.
function string
get_current_phase_name();
Displays currently executing
phase.
function string
get_next_phase_name(
string name);
Returns the name of the
following phase.
Returns $ if name is the last
phase, and ? if name is
unknown.
function vmm_phase get_phase(
string name);
Returns the phase descriptor
for phase name.
Returns null if phase name is
unknown.
vmm_timeline
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 289
function string
get_previous_phase(
string name);
Returns the name of the
preceding phase.
Returns ^ if phase name is
the first one, and ? if
unknown.
function bit insert_phase(
string phase_name,
string before_name,
vmm_phase_def def,
string fname = "",
int lineno = 0);
Inserts phase phase_name
before phase before_name
in the current timeline, and
issues a warning that a new
user-defined phase has been
defined.
A before_name of ^ inserts
at the beginning of a timeline,
and $ inserts at the end.
function bit jump_to_phase(
string name,
string fname = "",
int lineno = 0);
Aborts execution of the current
phase in this and sub-
timelines, jumps to phase
name, and issues a warning
message.
Returns 1 upon success.
function void prepend_callback(
vmm_timeline_callbacks cb);
Prepends the specified
timeline callback.
function bit rename_phase(
string old_name,
string new_name,
string fname = "",
int lineno = 0);
Renames phase old_name
with the new phase name
new_name, and issues a
warning that the phase has
been renamed.
Returns 1 upon success, and
0 if phase old_name does not
exist new_name is a duplicate.
function void reset_to_phase(
string name,
string fname = "",
int lineno = 0);
Resets ti meline to phase
name.
If name is configure or
earlier, all vmm_units sub-
instances are re-enabled.
task run_phase(
string name = "$",
string fname = "",
int lineno = 0);
Executes phases in the
current timeline up to and
including the specified phase
name.
function void
run_function_phase(
string name);
Runs the specified phase.
vmm_timeline
290 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
function void
step_function_phase(
string name,
string fname = "",
int lineno = 0);
Executes function phase name
in the ti meline.
Phase name must be a
function phase and the next
executable phase or a warning
message is issued.
function bit
task_phase_timeout(
string name,
int unsigned delta
vmm_log::severities_e
error_severity
=vmm_log::ERROR_SEV,
string fname = "",
int lineno = 0);
Sets the ti meout value for the
completion of phase name,
and issues an error message if
the task phase does not
complete before the timeout.
A timeout value of 0 specifies
no timeout. Delta refers to the
number of time uni ts specified
by the `timescale or
timeunit.
Returns 1 upon success, and
0 if phase does not exist or is
not a task phase.
function void
unregister_callback(
vmm_timeline_callbacks cb);
Unregisters the ti meline
callback.
vmm_timeline_callbacks
Declaration
virtual class vmm_timeline_callbacks;
Methods
virtual function void
break_on_phase(
vmm_timeline tl,
string name);
Callback method called when
the +break_on_X_phase
command line argument is
specified.
tl is the timeline instance and
name is the phase to break on.
vmm_timeline
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 291
Example
class my_test extends vmm_test;
...
endclass
Example using run_phase
initial begin
my_test t = new ( "test1", "test1" );
// Cause the testcase to execute the bui ld phase
t.run_phase("build");
// Run all the phases
t.run_phase("$");
end
Example stepping through phases
initial begin
my_test t = new ("test1", "test1" );
t.run_phase("connect");
// Step to the next phase
t.step_function_phase("start_of_sim");
t.step_function_phase("reset");
...
end
Example setting a timeout
class test1 extends vmm_test;
...
function void start_of_sim_ph();
vmm_timeline tl = this.get_timeline();
// Set reset ti meout of 20 ti me units
if (task_phase_timeout("reset", 20 ) == 0)
`vmm_error(log, "Problem setting timeout!");
endfunction
endclass
vmm_timeline
292 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
Example of removing a phase from a timeline
class generic_env extends vmm_env;
...
function void build_ph();
vmm_timeline tl = this.get_timeline();
tl.delete_phase("training");
tl.delete_phase("start");
endfunction
endclass
Example inserting a new phase
class memory_init_phase_def extends
vmm_topdown_function_phase_def#(vmm_unit);
`vmm_typename( memory_init_phase_def )
function void do_function_phase(vmm_unit obj);
obj.memory_init_ph();
endfunction
endclass
class my_env extends vmm_env;
...
function void build();
vmm_timeline tl;
memory_init_phase_def mem_init_ph = new;
// Insert the new memory initialization phase before "config_dut"
tl = this.get_timeline();
tl.insert_phase( "memory_init",
"config_dut",
mem_init_ph );
endfunction
endclass
// Now define the memory_init_ph function for my_env
function void my_env::mem_init_ph();
// Read in memory values
...
endfunction
vmm_timeline
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 293
Tips
When inserting a phase with insert_phase(), a before_phase of ^
inserts the phase at the beginning of the timeline, and $ inserts at the end.
Using a task phase ti meout is a good way to avoid simulation hangs from
wai ting or looping in a task.
For greatest usability, adding phases to the top-level timeline should be
avoided. Instead, new phases should be added in a vmm_units build
phase by inserting into its enclosing ti meline (see examples above).
To skip the execution of a phase, the vmm_unit::override_phase()
method can also be used to replace a phase with the
vmm_null_phase_def class.
The +vmm_break_on_phase and +vmm_break_on_timeline command
line plusargs are useful for stepping through the si mulation phases.
The default phase name for run_phase() is $; therefore, run_phase()
can be called without arguments to execute all the phases.
Gotchas
Calling task_phase_timeout() while a phase is currently executing
causes the timer to be reset to the new value.
Calling reset_to_phase() wi ll re-enable any previous disabled sub-
modules.
Using jump_to_phase() to skip phases may skip necessary initialization
and configuration and seriously corrupt the state of a test environment.
This method should only be used to abort a testcase, si mulation, or jump to
the report phase.
See also
vmm_group, Phases, vmm_phase, vmm_si mulation, vmm_unit
TLM Interfaces
294 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
VMM implements a set of transport interfaces classes (not to be confused with
SystemVerilog interfaces) based on the OSCI TLM-2.0 standard which provide
standard transaction level modeling (TLM) communication. These methods exist
in blocking and non-blocking forms. Blocking methods may wait before
returning and are always tasks. Non-blocking methods are not allowed to wai t
and are implemented as functions. The interface methods are pure virtual tasks
and functions that must be implemented by a transactor.
Common to all TLM transport interface methods are the transaction object to be
transported, the phase, and the delay. While any data object can be passed, the
TLM-2.0 standard defines a basic transaction type called a generic payload,
defined in VMM as the vmm_tlm_generic_payload class, which extends
vmm_data. As a transaction is passed back and forth, its status (or the phase of
the object) may be updated and modified by the different components. The
various transaction phases are defined by the type vmm_tlm::phase_e as:
Type vmm_tlm::phase_e Meaning
BEGIN_REQ Beginning of the request phase.
END_REQ End of the request phase.
BEGIN_RESP Beginning of the response phase.
END_RESP End of the response phase.
The phases are not to be confused wi th the values returned from the non-
blocking transport method, which are defined by the type vmm_tlm::sync_e as
Type vmm_tlm::sync_e Meaning
TLM_ACCEPTED
Nei ther the transaction, the phase or
the delay argument were modified by
nb_transport.
TLM_UPDATED
nb_transport has modified the
transaction, phase and/or delay
argument.
TLM_COMPLETED
The transaction is complete. This is a
shortcut to the final phase.
TLM_REFUSED
Transaction refused by receiver. For
example, the recipients FIFO is too
full to receive the new transaction.
TLM Interfaces
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 295
The enum type vmm_tlm::inf_e gi ves the role played by the channel when
binding a TLM port to a vmm_channel:
Type vmm_tlm::intf_e
TLM_BLOCKING_PORT
TLM_BLOCKING_EXPORT
TLM_NONBLOCKING_FW_PORT
TLM_NONBLOCKING_FW_EXPORT
TLM_NONBLOCKING_PORT
TLM_NONBLOCKING_EXPORT
TLM_ANALYSIS_PORT
TLM_ANALYSIS_EXPORT
Blocking interfaces are used in one direction to transfer data from an initiator to a
target. The initiator blocks unti l the data transport completes so the initiator does
not manage the ti ming of the transaction. The transfer function has the name
b_transport().
The non-blocking interfaces provide unidirectional forward (initiator -> target) and
backward (target -> initiator) paths, appended with the suffi xes _fw and _bw,
respecti vely. Because the data transfer does not block and communication can
be made in both directions, the overall transaction may be broken down into
multiple phases, which allows for modelling a more approximately timed model.
These transfer functions are referred to as nb_transport_fw() and
nb_transport_bw().
TLM-2.0 also specifies a bidirectional interface known as a socket to simplify
connections and provide a more generic usage model. A socket combines the
blocking and non-blocking unidirectional interfaces into one easy-to-use
connection, providing a combination of the three functions (b_transport(),
nb_transport_fw(), and nb_transport_bw()).
The actual TLM connections are made using ports and exports. TLM ports and
exports are each associated wi th one of the TLM interfaces. They are used as
members of transactors and channels. TLM ports and exports provide a
mechanism to decouple the initiator and target of a transaction, providing
encapsulation and i mproving reusabili ty. An export provides the functional
implementation of the interface methods. It is used to terminate a chain of
connected ports and exports.
A unidirectional TLM port can be connected to any unidirectional TLM export
provided the transaction type is the same. Likewi se, a socket port can connect
to any socket export. The type of transaction carried by an interface, port or
TLM Interfaces
296 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
export is set by a type parameter. There are two socket classes
vmm_tlm_initiator_socket and vmm_tlm_target_socket. Both contain
a port and an export.
TLM-2.0 also specifies another special type of port called an analysis port. An
analysis port allows for more than one connection and broadcasts transactions
to all bound connections through its write() method.
Declarations
Blocking Unidirectional Ports and Exports
class vmm_tlm_b_transport_port
#(type INITIATOR = vmm_tlm_xactor,
type DATA = vmm_data)
extends ...;
class vmm_tlm_b_transport_export
#(type TARGET = vmm_tlm_xactor,
type DATA = vmm_data)
extends ...;
Non-blocking Unidirectional Ports and Exports
class vmm_tlm_nb_transport_fw_port
#(type INITIATOR = vmm_tlm_xactor,
type DATA = vmm_data,
type PHASE = vmm_tlm::phase_e)
extends ...;
class vmm_tlm_nb_transport_fw_export
#(type TARGET = vmm_tlm_xactor,
type DATA = vmm_data,
type PHASE = vmm_tlm::phase_e )
extends ...;
class vmm_tlm_nb_transport_bw_port
#(type INITIATOR = vmm_tlm_xactor,
type DATA = vmm_data,
type PHASE = vmm_tlm::phase_e)
extends ...;
class vmm_tlm_nb_transport_bw_export
#(type TARGET = vmm_tlm_xactor,
type DATA = vmm_data,
type PHASE = vmm_tlm::phase_e)
extends ...;
Analysis Port and Export
class vmm_tlm_analysis_port
#(type INITIATOR = vmm_tlm_xactor,
TLM Interfaces
Copyri ght 2010 by Doul os Ltd. All ri ghts reserved. 297
type DATA = vmm_data)
extends ...;
class vmm_tlm_analysis_export
#(type TARGET = vmm_tlm_xactor,
type DATA = vmm_data)
extends ...;
Bidirectional Socket Ports and Exports
class vmm_tlm_nb_transport_port
#(type INITIATOR = vmm_tlm_xactor,
type DATA = vmm_data,
type FW_PHASE = vmm_tlm::phase_e,
type BW_PHASE = FW_PHASE)
extends ...;
class vmm_tlm_nb_transport_export
#(type TARGET = vmm_tlm_xactor,
type DATA = vmm_data,
type FW_PHASE = vmm_tlm::phase_e,
type BW_PHASE = FW_PHASE)
extends ...;
class vmm_tlm_initiator_socket
#(type INITIATOR = vmm_tlm_xactor,
type DATA = vmm_data,
type PHASE = vmm_tlm::phase_e)
extends ...;
class vmm_tlm_target_socket
#(type TARGET = vmm_tlm_xactor,
type DATA = vmm_data,
type PHASE = vmm_tlm::phase_e)
extends ...;
Methods
Common to all base classes
vmm_tlm_port_base
vmm_tlm_export_base
vmm_tlm_socket_base
vmm_tlm_analysis_port_base
vmm_tlm_analysis_export_base
function check_bindings(); Checks bindings of ports and
exports and issues warnings if
anything is unbound.
function print_bindings(); Prints all ports and exports.
TLM Interfaces
298 Copyri ght 2010 by Doul os Ltd. All ri ghts reserved.
function report_unbound(); Reports all unbound ports and
exports.
function vmm_tlm_TYPE
_base
#(DATA,PHASE) get_peer();
Returns the export bound to
this port, or null if unbound.
function void tlm_bind(
vmm_tlm_TYPE
_base
#(DATA,PHASE) peer,
int id = -1,
string fname = "",
int lineno = 0);
Binds TLM export peer to the
TLM port.
id used to distinguish between
multiple exports connected to
the port. An error is generated
if id is duplicated.
function void tlm_import(
vmm_tlm_TYPE
_base
#(DATA,PHASE) peer,
string fname = "",
int lineno = 0);
Imports a port from an inner
level of hierarchy to an outer
level.
function void tlm_unbind(
string fname = "",
int lineno = 0);
Unbinds a port, and issues a
warning if already unbound.