uvm_model
很早之前就说写一个简单的uvm环境
首先是一个简单的dut
`timescale lns/10fs
module mul(
clk,
rst_n,
num_a,
num_b,
num_c
);
input clk;
input rst__n;
input [7:0] num__a;
input [7:0] num__b;
output [7:0] num__c;
reg [7:0] a;
reg [7:0] b;
reg [7:0] c;
assign num_c = c;
always @(posedge clk or negedge rst_n)begin
if (!rst_n == l'bl)begin
c <= 8'h0;
end else begin
c <= num_a + num_b;
end
end
endmodule
`timescale lns/10fs
module top(
clk,
rst_n,
num_a,
num_b,
num_c
);
input clk;
input rst_n;
input [7:0] num_a;
input [7:0] num_b;
output [7:0] num_c;
mul U_MUL(
. clk(clk),
. rst_n(rst_n),
. num_a(num_a),
. num_b(num_b),
. num_c(num_c)
);
endmodule
之后是harness
module harness;
logic elk;
logic rst_n;
logic [7:0] num_a;
logic [7:0] num_b;
logic [7:0] num_c;
initial begin
clk = 0;
rst_n = 0;
#100ns rst_n = 1;
end
always begin
#5ns clk = ~clk;
end
my_interface tx_if(clk,rst_n);
my_interface rx_if(clk,rst_n);
top dut(
.clk(clk),
.rst_n(rst_n),
.num_a(num_a),
.num_b(num_b),
.num_c(num_c)
);
initial begin
uvm_config_db #(virtual my_interface) :: set(null, "uvm_test_top.env_.rx_agt*", "vif", rx_if);
uvm_config_db #(virtual my_interface) :: set(null, "uvm_test_top.env_.tx_agt*", "vif", tx_if);
end
initial begin
run_test();
end
assign num_a = tx_if.a;
assign num_b = tx_if.b;
assign rx_if.c = num_c;
initial begin
$vcdpluson;
$fsdbDumpon;
end
endmodule
之后是interface
interface my_interface(input bit clk,input bit rst_n);
logic [7:0] a;
logic [7:0] b;
logic [7:0] c;
clocking mon_cb@(posedge clk);
inout a;
inout b;
inout c;
endclocking
endinterface
之后是transaction
class my_transaction extends extends uvm_sequence_item;
rand bit [7:0] a;
rand bit [7:0] b;
rand bit [7:0] c;
rand byte kk[];
constraint k_cons{
kk.size >= 10;
kk.size <= 90;
}
`uvm_object_utils_begin(my_transaction)
//'uvm_field_int(a,UVM_ALL_0N)
//'uvm_field_int(b,UVM_ALL_0N)
`uvm_field_int(c,UVM_ALL_0N)
`uvm_field_array_int(kk,UVM_ALL_0N)
`uvm_object_utils_end
extern function new(string name = "my_transaction");
endclass
function my_transaction::new(string name = "my_transaction");
super.new(name);
endfunction
之后是sequencer
class my_sequencer extends uvm_sequencer #(my_transaction);
`uvm_component_utils(my_sequencer)
extern function new(string name, uvm_component parent);
endclass
function my_sequencer::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
之后是tx部分
class tx_driver extends uvm_driver #(my_transaction);
virtual my_interface vif;
`uvm_component_utils(tx_driver)
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern virtual task reset_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function tx_driver::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void tx_driver::build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual my_interface)::get(this,"","vif",vif))
`uvm_fatal("tx_driver","virtual interface get fail !");
endfunction
task tx_driver::reset_phase(uvm_phase phase);
vif.a <= $urandom_range(8'hff,8'h0);
vif.b <= $urandom_range(8'hff,8'h0);
endtask
task tx_driver::main_phase(uvm_phase phase);
my_transaction tx_tr;
super.main_phase(phase);
while(l)begin
seq_item_port.get_next_item(req);
tx_tr = req;
vif.a <= tx_tr.a;
vif.b <= tx_tr.b;
seq_item_port.item_done();
end
endtask
class tx_monitor extends uvm_monitor;
virtual my_interface vif;
uvm_analysis_port #(my_transaction) tx_mon_ap;
`uvm_component_utils(tx_monitor)
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function tx_monitor::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void tx_monitor::build_phase(uvm_phase phase);
super.build_phase(phase);
tx_mon_ap = new("tx_mon_ap", this);
if (!uvm_config_db#(virtual my_interface)::get(this,"","vif",vif))
`uvm_fatal("tx_monitor","virtual interface get fail !");
endfunction
task tx_monitor::main_phase(uvm_phase phase);
my_transaction tx_tr;
super.main_phase(phase);
while(l)begin
tx_tr = new();
tx_tr.a = vif.a;
tx_tr.b = vif.b;
tx_mon_ap.write(tx_tr);
@(posedge vif.clk);
end
endtask
class tx_agent extends uvm_agent;
tx_monitor mon;
tx_driver drv;
my_sequencer sqr;
uvm_analysis_port #(my_transaction) ap;
`uvm_component_utils(tx_agent)
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern function void connect_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function tx_agent::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void tx_agent::build_phase(uvm_phase phase);
super.build_phase(phase);
mon = tx_monitor ::type_id:: create ("mon", this);
drv = tx_driver ::type_id:: create ("drv", this);
sqr = my_sequencer ::type_id:: create ("sqr", this);
endfunction
function void tx_agent::connect_phase(uvm_phase phase);
super.connect_phase(phase);
ap = mon.tx_mon_ap;
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
task tx_agent::main_phase(uvm_phase phase);
super.main_phase(phase);
endtask
之后是rx部分
class rx_monitor extends uvm_monitor;
virtual my_interface vif;
uvm_analysis_port #(my_transaction) rx_mon_ap;
`uvm_component_utils(rx_monitor)
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function rx_monitor::new(string new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void rx_monitor::build_phase(uvm_phase phase);
super.build_phase(phase);
rx_mon_ap = new("rx_mon_ap", this);
if (!uvm_config_db#(virtual my_interface)::get(this,"","vif",vif))
'uvm_fatal("rx_monitor","virtual interface get fail !");
endfunction
task rx_monitor::main_phase(uvm_phase phase);
my_transaction rx_tr;
super.main_phase(phase);
while(l)begin
rx_tr=new();
@(posedge vif.clk);
rx_tr.c = vif.c;
rx_mon_ap.write (rx_tr);
end
endtask
class rx_agent extends uvm_agent;
rx_monitor mon;
uvm_analysis_port #(my_transaction) ap;
`uvm_component_utils(rx_agent)
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern function void connect_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function rx_agent::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void rx_agent::build_phase(uvm_phase phase);
super.build_phase(phase);
mon = rx_monitor::type_id::create("mon",this);
endfunction
function void rx_agent::connect_phase(uvm_phase phase);
super.connect_phase(phase);
ap = mon.rx_mon_ap;
endfunction
task rx_agent::main_phase(uvm_phase phase);
super.main_phase(phase);
endtask
之后是env
class env extends uvm_env;
rx_agent rx_agt;
tx_agent tx_agt;
rm rm_;
scoreboard sc;
`uvm_component_utils(env)
uvm_tlm_analysis_fifo #(my_transaction) mon_rm_fifo;
uvm_tlm_analysis_fifo #(my_transaction) rm_sc_fifo;
uvm_tlm_analysis_fifo #(my_transaction) sc_mon_fifo;
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern function void connect_phase(uvm_phase phase);
extern virtual task configure_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function env::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void env::build_phase(uvm_phase phase);
super.build_phase(phase);
rx_agt = rx_agent ::type_id:: create ("rx_agt", this);
tx_agt = tx_agent ::type_id:: create ("tx_agt", this);
rm_ = rm ::type_id:: create ("rm_ " , this);
sc = scoreboard ::type_id:: create ("sc " , this);
mon_rm_fifo = new("mon_rm_fifo", this);
rm_sc_fifo = new("rm_sc_fifo", this);
sc_mon_fifo = new("sc_mon_fifo", this);
endfunction
function void env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
tx_agt.ap. connect(mon_rm_fifo.analysis_export);
rm_.port. connect(mon_rm_fifo.blocking_get_export);
rm_.rm_ap. connect (rm_sc_fifo.analysis_export);
sc.rm_port. connect (rm_sc_fifo.blocking_get_export);
rx_agt.ap. connect(sc_mon_fifo.analysis_export);
sc.dut_port.connect(sc_mon_fifo.blocking_get_export);
endfunction
task env::configure_phase(uvm_phase phase);
super.configure_phase(phase);
endtask
task env::main_phase(uvm_phase phase);
super,main_phase(phase);
endtask
之后是rm
class rm extends uvm_component;
uvm_blocking_get_port #(my_transaction) port;
uvm_analysis_port #(my_transaction) rm_ap;
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
`uvm_component_utils(rm)
endclass
function rm::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void rm::build_phase(uvm_phase phase);
super.build_phase(phase);
port = new("port", this);
rm_ap = new("rm_ap",this);
endfunction
task rm::main_phase(uvm_phase phase);
my_transaction tr;
my_transaction send_tr;
super.main_phase(phase);
while(l)begin
port.get(tr);
send_tr = new("send_tr");
send_tr = tr;
send_tr.c = send_tr.a + send_tr.b;
rm_ap.write(send_tr);
end
endtask
class scoreboard extends extends uvm_scoreboard;
my_transaction rm_queue[$];
uvm_blocking_get_port #(my_transaction) rm_port;
uvm_blocking_get_port #(my_transaction) dut_port;
`uvm_component_utils(scoreboard)
extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern function void connect_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function scoreboard::new(string name, uvm_component parent);
super.new(name,parent);
endfunction
function void scoreboard::build_phase(uvm_phase phase);
super.build_phase(phase);
rm_port = new("rm_port ",this);
dut_port = new("dut_port", this);
endfunction
function void scoreboard::connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task scoreboard::main_phase(uvm_phase phase);
my_transaction rm_tr, dut_tr, chk_tr;
super.main_phase(phase);
fork
while(l)begin
rm_port.get(rm_tr);
rm_queue.push_back(rm_tr);
end
while(l)begin
dut_port.get(dut_tr);
if (rm_queue.size() > 0)begin
chk_tr = rm_queue.pop_front();
if(dut_tr.compare(chk_tr)) begin
`uvm_info("scoreboard", "ok", UVM_L0W);
dut_tr.print ();
chk_tr.print ();
end else begin
`uvm_error("scoreboard", "fail");
end
end
join
endtask
[...]很久之前写过一个非常简单的uvm_model文章地址但是没有提编译的一些细节:这里面一部分是封装在package中的,一部分则是直接在.f文件直接加载的。组件主要是通过package封装的,至于case以及sequence则采用,直接加载的方式。这样做的原因是,如果case以及sequence也采用package封装的话,会给调用rtl中的hierarchy造成很多的麻烦。../tc/vcs_pk[...]