命令:
vcs -full64 -sverilog -timescale=1ns/1ps -R -ntb_opts uvm-1.1 uvm_seq_exam.sv
import uvm_pkg::*;
`include "uvm_macro.svh"
typedef seq0;
typedef seq1;
定义xaction
class xaction extends uvm_sequence_item;
rand int rng;
`uvm_object_utils_begin(xaction)
`uvm_field_int(rng, UVM_ALL_ON)
`uvm_object_utils_end
endclass
定义seqr
class seqr extends uvm_sequencer #(xaction);
`uvm_component_utils(seqr)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
定义drvr
class drvr extends uvm_driver #(xaction);
`uvm_component_utils(drvr)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual task run_phase(uvm_phase phase);
uvm_objection objection;
$display("drv begin to work......");
objection = phase.get_objection();
objection.set_drain_time(this, 1000);
forever begin
seq_item_port.get_next_item(req);
#10; // drive signals in xaction to bus
$display("@5 receive a xaction:\t%3d", $realtime, req.rng);
seq_item_port.item_done();
end
endtask
endclass
定义agent来封装seqr和drvr,启动seq
class agent extends uvm_agent;
seqr sqr;
drvr dvr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
`uvm_component_utils(agent)
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sqr = seqr::type_id::create("sqr", this);
dvr = drvr::type_id::create("dvr", this);
/*
uvm_config_db#(uvm_object_wrapper)::set(this, "sqr.run_phase", "default_sequence", seq0::type_id::get());
*/
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
dvr.seq_item_port.connect(sqr.seq_item_export);
endfunction
/*
task main_phase(uvm_phase phase);
seq0 seq0_inst;
seq1 seq1_inst;
seq0_inst = seq0::type_id::create("seq0_inst");
seq1_inst = seq0::type_id::create("seq1_inst");
seq0_inst.starting_phase = phase;
seq1_inst.starting_phase = phase;
fork
seq0_inst.start(this.sqr);
seq1_inst.start(this.sqr);
join
endtask
*/
endclass
定义seq0,seq1
seq0发偶数
seq1发奇数
class seq0 extends uvm_sequence #(xaction);
`uvm_object_utils(seq0)
function new(string name="seq0");
super.new(name);
endfunction
virtual task body();
starting_phase.raise_objection(this);
repeat(10) begin
`uvm_do_with(req, {rng inside {[0:100]}; rng[0]==0;})
end
starting_phase.drop_objection(this);
endtask
endclass
class seq1 extends uvm_sequence #(xaction);
`uvm_object_utils(seq1)
function new(string name="seq1");
super.new(name);
endfunction
virtual task body();
starting_phase.raise_objection(this);
repeat(10) begin
`uvm_do_with(req, {rng inside {[0:100]}; rng[0]==1;})
end
starting_phase.drop_objection(this);
endtask
endclass
定义program块
program uvm_run_test();
initial begin
agent agt_inst;
$timeformat(-9, 1, "ns", 10);
agt_inst = agent::type_id::create("agt_inst", null);
run_test();
end
endprogram
uvm_sequence, uvm_driver 的源码里声明了req,rsp变量,所以扩展的seq和drv里,
`uvm_do系列宏里和drv的seq_item_port的get_next_item
的参数可以用req。
例子中给出了两种启动seq的方式,见两段/* */注释之间的代码
第一种通过uvm_config_db
第二种是通过seq.start(sqr),通过第二种方式在一个seqr上启动了两个seq
仿真log如下:
可见,两个seq交替发出了xaction。
上面的代码中在drv里设置了set_drain_time来控制仿真时间。一般的环境中会放到tc里设置,不会放在drv组件中。