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