ovm_sequence -> ovm_sequence_item -> ovm_transaction
ovm_sequence
The base class for combinations of transactions.
It can be nested, layered or virtual sequences.
It can be constrained random sequence of transactions.
It drive transactions into DUT.
ovm_sequence_item
The base class for user-defined sequence items and also the base class for the
ovm_sequence class. (
help)
ovm_transaction
The base class for all user-defined transactions.
Example
// To make transaction part of the sequence,
// we use ovm_sequence_item to extend transaction
class my_transaction extends ovm_sequence_item;
`ovm_object_utils(my_transaction)
rand bit cmd;
rand int addr;
rand int data;
constraint c_addr { addr >= 0; addr < 256; }
constraint c_data { data >= 0; data < 256; }
// transaction isn't part of the component family
// it doesn't have the "parent" parameter
function new (string name = "");
super.new(name);
endfunction: new
endclass : my_transaction
//--------------------------------------------------------------
// SV parameterized class, same as class template in C++
// use parameter to modify the properties later when used
// usually in sequencer, you can change the type or the way
// transactions are generated at specific time.
//--------------------------------------------------------------
class my_sequencer extends ovm_sequencer #(my_transaction);
`ovm_component_utils(my_sequencer)
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction: new
endclass : my_sequencer
//--------------------------------------------------------------
// Sequencer component will run multiple sequence which is
// composed of transactions and generated data
//--------------------------------------------------------------
class my_sequence extends ovm_sequence #(my_transaction);
`ovm_object_utils(my_sequence)
function new (string name = "");
super.new(name);
endfunction: new
// The standard method "body" used only in ovm_sequence
// to define the main behavior of the sequence,
// It generates a continuous stream of transactions and data
// It is a method but similar to a phase in ovm_component
task body;
forever
begin
my_transaction tx;
// Use factory method to instantiate the transaction
tx = my_transaction::type_id::create("tx");
// the start and finish items will evoke the machinary
// to communicate with the driver down stream
start_item(tx);
assert( tx.randomize() ); // randomize transactions
finish_item(tx);
end
endtask: body
endclass : my_sequence
// Driver is what drives the data into pins
class my_driver extends ovm_driver #(my_transaction);
`ovm_component_utils(my_driver)
virtual dut_if dut_vi;
function new(string name, ovm_component parent);
super.new(name, parent);
endfunction: new
function void build;
super.build();
...
task run;
repeat(4)
begin
my_transaction tx;
@(posedge dut_vi.clock);
// Driver consumes the transactions generated by
// my_transaction and wiggles the pins on the DUT
seq_item_port.get(tx);
// Pin Wiggling
dut_vi.cmd = tx.cmd;
dut_vi.addr = tx.addr;
dut_vi.data = tx.data;
end
@(posedge dut_vi.clock) ovm_top.stop_request();
endtask: run
endclass : my_driver
Example of ovm_sequence with constrained random sequence of transactions
class read_modify_write extends ovm_sequence #(my_transaction);
`ovm_object_utils(read_modify_write)
function new (string name = "");
super.new(name);
endfunction: new
task body;
my_transaction tx;
int a;
int d;
// create transaction using factory method
tx = my_transaction::type_id::create("tx");
start_item(tx);
// read
// inline constraint to read with random data
assert( tx.randomize() with { cmd == 0; } );
// modify
a = tx.addr;
d = tx.data;
++d;
// write
tx = my_transaction::type_id::create("tx");
start_item(tx);
assert( tx.randomize() with {
cmd == 1; addr == a; data == d; } );
finish_item(tx);
endclass : read_modify_write
class seq_of_commands extends ovm_sequence #(my_transaction);
`ovm_object_utils(seq_of_commands)
rand int n;
// a control knob that can be controlled from outside
constraint how_many { n inside {[2:4]}; }
...
task body;
repeat(n)
begin
read_modify_write seq;
seq = read_modify_write::type_id::create("seq");
start_item(seq);
finish_item(seq);
end
endtask: body
endclass : seq_of_commands
package my_seq_library;
import ovm_pkg::*;
class read_modify_write extends ovm_sequence #(my_transaction);
...
class seq_of_commands extends ovm_sequence #(my_transaction);
...
endpackage
class test1 extends ovm_test;
`ovm_component_utils(test1)
my_env my_env_h;
...
task run;
read_modify_write seq;
seq = read_modify_write::type_id::create("seq");
seq.start( my_env_h.my_agent_h.my_sequencer_h );
endtask : run
endclass : test1
class test2 extends ovm_test;
`ovm_component_utils(test2)
my_env my_env_h;
...
task run;
seq_of_commands seq;
seq = seq_of_commands::type_id::create("seq");
assert( seq.randomize() );
seq.start( my_env_h.my_agent_h.my_sequencer_h );
endtask : run
endclass : test2
class test3 extends ovm_test;
`ovm_component_utils(test3)
my_env my_env_h;
...
task run;
seq_of_commands seq;
seq = seq_of_commands::type_id::create("seq");
seq.how_many.constraint_mode(0);
assert( seq.randomize() with {
seq.n > 10 && seq.n < 20; } );
seq.start( my_env_h.my_agent_h.my_sequencer_h );
endtask : run
endclass : test3
module top;
...
initial
begin: blk
...
run_test("test3");
end
endmodule: top
Command line when leaving run_test(""); blank
% vsim +OVM_TESTNAME=test3