| //---------------------------------------------------------------------- | |
| // Copyright (c) 2011-2012 by Doulos Ltd. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| //---------------------------------------------------------------------- | |
| // First Steps with UVM - Nested Sequences | |
| // Author: John Aynsley, Doulos | |
| // Date: 13-Sep-2012 | |
| `include "uvm_macros.svh" | |
| package my_pkg; | |
| import uvm_pkg::*; | |
| class my_transaction extends uvm_sequence_item; | |
| `uvm_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; } | |
| function new (string name = ""); | |
| super.new(name); | |
| endfunction | |
| function string convert2string; | |
| return $sformatf("cmd=%b, addr=%0d, data=%0d", cmd, addr, data); | |
| endfunction | |
| function void do_copy(uvm_object rhs); | |
| my_transaction tx; | |
| $cast(tx, rhs); | |
| cmd = tx.cmd; | |
| addr = tx.addr; | |
| data = tx.data; | |
| endfunction | |
| function bit do_compare(uvm_object rhs, uvm_comparer comparer); | |
| my_transaction tx; | |
| bit status = 1; | |
| $cast(tx, rhs); | |
| status &= (cmd == tx.cmd); | |
| status &= (addr == tx.addr); | |
| status &= (data == tx.data); | |
| return status; | |
| endfunction | |
| endclass: my_transaction | |
| class my_config extends uvm_object; | |
| rand int count; | |
| rand int max_addr; | |
| constraint c_count { count > 0; count < 128; } | |
| constraint c_max_addr { max_addr > 128; max_addr < 252; } | |
| endclass: my_config | |
| typedef uvm_sequencer #(my_transaction) my_sequencer; | |
| class child_sequence extends uvm_sequence #(my_transaction); | |
| `uvm_object_utils(child_sequence) | |
| rand int start_addr; | |
| constraint c_addr { start_addr >= 0; start_addr < 252; } | |
| function new (string name = ""); | |
| super.new(name); | |
| endfunction | |
| task body; | |
| if (starting_phase != null) | |
| starting_phase.raise_objection(this); | |
| for (int i = 0; i < 4; i++) | |
| begin | |
| req = my_transaction::type_id::create("req"); | |
| start_item(req); | |
| if( !req.randomize() with { addr == start_addr + i; } ) | |
| `uvm_error("", "Randomize failed") | |
| finish_item(req); | |
| end | |
| if (starting_phase != null) | |
| starting_phase.drop_objection(this); | |
| endtask: body | |
| endclass: child_sequence | |
| class alt_child_sequence extends child_sequence; | |
| `uvm_object_utils(alt_child_sequence) | |
| rand bit [2:0] fixed_data; | |
| function new (string name = ""); | |
| super.new(name); | |
| endfunction | |
| function void mid_do(uvm_sequence_item this_item); | |
| my_transaction tx; | |
| $cast(tx, this_item); | |
| tx.data = fixed_data; | |
| endfunction | |
| endclass: alt_child_sequence | |
| class top_sequence extends uvm_sequence #(my_transaction); | |
| `uvm_object_utils(top_sequence) | |
| `uvm_declare_p_sequencer(my_sequencer) | |
| function new (string name = ""); | |
| super.new(name); | |
| endfunction | |
| task body; | |
| my_config cfg; | |
| int count, max_addr; | |
| if ( uvm_config_db #(my_config)::get(p_sequencer, "", "config", cfg) ) | |
| begin | |
| count = cfg.count; | |
| max_addr = cfg.max_addr; | |
| end | |
| else | |
| begin | |
| count = 1; | |
| max_addr = 256; | |
| end | |
| if (starting_phase != null) | |
| starting_phase.raise_objection(this); | |
| repeat(count) | |
| begin | |
| child_sequence seq; | |
| seq = child_sequence::type_id::create("seq"); | |
| if( !seq.randomize() with { start_addr < max_addr; } ) | |
| `uvm_error("", "Randomize failed") | |
| seq.start(p_sequencer, this); | |
| end | |
| if (starting_phase != null) | |
| starting_phase.drop_objection(this); | |
| endtask: body | |
| endclass: top_sequence | |
| class my_driver extends uvm_driver #(my_transaction); | |
| `uvm_component_utils(my_driver) | |
| virtual dut_if dut_vi; | |
| function new(string name, uvm_component parent); | |
| super.new(name, parent); | |
| endfunction | |
| function void build_phase(uvm_phase phase); | |
| // Get interface reference from config database | |
| if( !uvm_config_db #(virtual dut_if)::get(this, "", "dut_if", dut_vi) ) | |
| `uvm_error("", "uvm_config_db::get failed") | |
| endfunction | |
| task run_phase(uvm_phase phase); | |
| forever | |
| begin | |
| seq_item_port.get_next_item(req); | |
| // Wiggle pins of DUT | |
| dut_vi.cmd = req.cmd; | |
| dut_vi.addr = req.addr; | |
| dut_vi.data = req.data; | |
| @(posedge dut_vi.clock); | |
| seq_item_port.item_done(); | |
| end | |
| endtask | |
| endclass: my_driver | |
| class my_env extends uvm_env; | |
| `uvm_component_utils(my_env) | |
| my_sequencer m_seqr; | |
| my_driver m_driv; | |
| function new(string name, uvm_component parent); | |
| super.new(name, parent); | |
| endfunction | |
| function void build_phase(uvm_phase phase); | |
| m_seqr = my_sequencer::type_id::create("m_seqr", this); | |
| m_driv = my_driver ::type_id::create("m_driv", this); | |
| endfunction | |
| function void connect_phase(uvm_phase phase); | |
| m_driv.seq_item_port.connect( m_seqr.seq_item_export ); | |
| endfunction | |
| endclass: my_env | |
| class my_test extends uvm_test; | |
| `uvm_component_utils(my_test) | |
| my_env m_env; | |
| function new(string name, uvm_component parent); | |
| super.new(name, parent); | |
| endfunction | |
| function void build_phase(uvm_phase phase); | |
| m_env = my_env::type_id::create("m_env", this); | |
| endfunction | |
| task run_phase(uvm_phase phase); | |
| my_config cfg; | |
| top_sequence seq; | |
| uvm_component component; | |
| my_sequencer sequencer; | |
| cfg = new; | |
| if ( !cfg.randomize() with { count == 3; } ) | |
| `uvm_error("", "Randomize failed") | |
| uvm_config_db #(my_config)::set(this, "*.m_seqr", "config", cfg); | |
| seq = top_sequence::type_id::create("seq"); | |
| if( !seq.randomize() ) | |
| `uvm_error("", "Randomize failed") | |
| seq.starting_phase = phase; | |
| component = uvm_top.find("*.m_seqr"); | |
| if ($cast(sequencer, component)) | |
| seq.start(sequencer); | |
| endtask | |
| endclass: my_test | |
| class my_test2 extends my_test; | |
| `uvm_component_utils(my_test2) | |
| function new (string name, uvm_component parent); | |
| super.new(name, parent); | |
| endfunction : new | |
| function void start_of_simulation_phase(uvm_phase phase); | |
| super.start_of_simulation_phase(phase); | |
| child_sequence::type_id::set_type_override( alt_child_sequence::get_type() ); | |
| endfunction : start_of_simulation_phase | |
| endclass: my_test2 | |
| endpackage: my_pkg | |
| module top; | |
| import uvm_pkg::*; | |
| import my_pkg::*; | |
| dut_if dut_if1 (); | |
| dut dut1 ( .dif(dut_if1) ); | |
| // Clock generator | |
| initial | |
| begin | |
| dut_if1.clock = 0; | |
| forever #5 dut_if1.clock = ~dut_if1.clock; | |
| end | |
| initial | |
| begin | |
| uvm_config_db #(virtual dut_if)::set(null, "*", "dut_if", dut_if1); | |
| uvm_top.finish_on_completion = 1; | |
| // run_test("my_test"); // Original test | |
| run_test("my_test2"); // Alternative test | |
| end | |
| endmodule: top |