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
No comments:
Post a Comment