blob: c1ede4ba107bf30c28a7978d764244ca6e0caeea [file] [log] [blame] [edit]
//----------------------------------------------------------------------
// 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