前言
这里以UVM实战(张强)第二章为基础修改原有的DUT,将DUT修改为加法器,从而修改代码以使得更加深入的了解各个组件的类型和使用。
一. 组件的基本框架
和第二章的平台的主要区别点
(1)有两个transaction,一个为transaction_i,一个为transaction_o,由于DUT的输入输出值并不相同,输入为a,b,cin,输出为sum,cout。所以这里使用两个transaction,尤为注意my_model的输出需要使用transaction_o来运输。
(2)使用了两个monitor,一个为monitor_i,一个为monitor_o
(3)使用了两个agent,一个为agent_i,一个为agent_o,这样写is_active就不需要使用了
二.各个部分代码详解
2.1 DUT
module dut(
input clk,
input rst_n,
input [7:0] a,
input [7:0] b,
input cin,
input enable,
output reg [7:0] sum,
output reg cout
);
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)begin
sum <= 8'b0;
cout <= 1'b0;
end
else if (enable)
{cout,sum} <= a + b + cin;
else begin
sum <= sum;
cout <= cout;
end
end
2.2 my_driver
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SV
class my_driver extends uvm_driver;
virtual my_if vif;
`uvm_component_utils(my_driver)
function new(string name = "my_driver",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual my_if)::get(this,"","vif",vif))
`uvm_fatal("my_driver","virtual interface must be set for vif!!!")
endfunction
extern task mian_phase(uvm_phase phase);
extern task drive_one_pkt(my_transaction_i tr);
endclass
task my_driver::mian_phase(uvm_phase phase);
vif.a <= 8'b0;
vif.b <= 8,b0;
vif.cin <= 1'b0;
vif.enable <= 1'b0;
while(1)begin
seq_item_port.get_next_item(req);
drive_one_pkt(req);
seq_item_port.item_done();
end
endtask
//(1)如何理解
task my_driver::drive_one_pkt(my_transcation_i tr);
uvm_info("my_driver","begin to dirve one pkt",UVM_LOW);
@(posedge vif.clk);
vif.a <= tr.a;
vif.b <= tr.b;
vif.cin <= tr.cin;
vif.enable <= 1'b1;
`uvm_info("my_driver","end to drive one pkt",UVM_LOW);
endtask
`endif
(1)如何理解
这里只传递一个a,b,cin的值
2.3 my_transaction_i
`ifdenf MY_TRANSACTION_I__SV
`define MY_TRANSACTION_I__SV
class my_transaction_i extends uvm_sequence_item;
rand bit [7:0] a;
rand bit [7:0] b;
rand bit cin;
`uvm_object_utils_begin(my_transaction_i)
`uvm_field_int(a,UVM_ALL_ON)
`uvm_field_int(b,UVM_ALL_ON)
`uvm_field_int(cin,UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_transaction_i");
super.new();
endfunction
endclass
`endif
2.4 my_transaction_o
`idndef MY_TRANSACTION_O__SV
`define MY_TRANSACTION_O__SV
class my_transaction_o extends uvm_sequence_item;
bit [7:0] sum;
bit cout;
function new(string name = "my_transaction_o")
super.new();
endfunction
endclass
`endif
2.5 my_sequencer
`ifndef MY_SEQUENCER__SV
`define MY_SEQUENCER__SV
class my_sequencer extends uvm_sequencer #(my_transaction_i);
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
`uvm_component_utils(my_sequencer)
endclass
`endif
2.6 my_if
`ifndef MY_IF__SV
`define MY_IF__SV
interface my_if(input clk, input rst_n);
logic [7:0] a;
logic [7:0] b;
logic cin;
logic enable;
logic [7:0] sum;
logic cout;
endinterface
`endif
2.7 my_monitor_i
`ifndef MY_MONITOR_I__SV
`define MY_MONITOR_I__SV
class my_monitor_i extends uvm_monitor;
virtual my_if vif;
uvm_analysis_port #(my_transaction) ap;
`uvm_component_utils(my_monitor_i)
function new(string name = "monitor_i",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual my_if)::get(this,"","vif",vif))
`uvm_fatal("my_monitor","virtual interface must be set for vif!!!")
ap = new("ap",this);
endfunction
extern task main_phase(uvm_phase phase);
extern task drive_one_pkt(my_transaction_i tr);
endclass
task my_monitor::main_phase(uvm_phase phase);
my_transaction_i tr;
while(1) begin
tr.new("tr");
collect_one_pkt(tr);
ap.write(tr);
end
endtask
task my_monitor::collcet_one_pkt(my_transaction_i tr);
`uvm_info("my_monitor","begin to collcet one pkt",UVM_LOW);
@(posedge vif.clk);
tr.a <= vif.a;
tr.b <= vif.b;
tr.cin <= vif.cin;
tr.enable <= 1'b1;
`uvm_info("my_monitor","end to collcet one pkt",UVM_LOW);
endtask
`endif
2.8 my_monitor_o
`ifndef MY_MONITOR_O__SV
`define MY_MONITOR_O__SV
class my_monitor extends uvm_monitor_o
virtual my_if vif;
uvm_analysis_port #(my_transaction) ap;
`uvm_component_port #(my_transaction) ap;
function new(string name = "my_monitor_o",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual my_if)::get(this,"","vif",vif))
`uvm_fatal("my_monitor","virtual interface must be set for vif!!!")
ap = new("ap",this);
endfunction
extern task main_phase(uvm_phase phase);
extern task collcet_one_pkt(my_transaction_i tr);
endclass
task my_monitor::main_phase (uvm_phase phase);
my_transaction_o tr;
while(1) begin
tr = new("tr")
collcet_one_pkt(tr);
ap.write(tr);
end
endtask
task my_monitor::collcet_one_pkt(my_transction_o tr);
`uvm_info("my_monitor_o","begin to collcet one pkt",UVM_LOW);
@(posedge vif.clk)
tr.sum <= vif.sum;
tr.cout <= vif.cout;
`uvm_info("my_monitor_o","end to collcet one pkt",UVM_ALL);
endtask
`endif
2.9 my_agent_i
`ifndef MY_AGENT_I__SV
`define MY_AGENT_I__SV
class my_agent_i extends uvm_agent;
my_sequencer sqr;
my_driver drv;
my_monitor_i mon_i;
`uvm_analysis_port #(my_transaction_i) ap;
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void conncet_phase(uvm_phase phase);
`uvm_component_utils(my_agent_i)
endclass
function void my_agent_i::build_phase(uvm_phase phase);
super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr",this);
drv = my_driver::type_id::create("drv",this);
mon_i = my_monitor_i::type_id::create("mon_i",this);
endfunction
function void my_agent_i::conncet_phase(uvm_phase phase);
super.conncet_phase(phase);
drv_seq_item_port.conncet(sqr.seq_item_export);
ap = mon.ap;
endfunction
`endif
2.10 my_agent_o
`ifndef MY_AGENT_O__SV
`define MY_AGENT_O__SV
class my_agent_o extends uvm_agent;
my_sequencer sqr;
my_driver drv;
my_monitor_o mon_o;
`uvm_analysis_port #(my_transaction_o) ap;
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void conncet_phase(uvm_phase phase);
`uvm_component_utils(my_agent_o)
endclass
function void my_agent_o::build_phase(uvm_phase phase);
super.build_phase(phase);
mon_o = my_monitor_o::type_id::create("mon",this);
endfunction
function void my_agent_o::conncet_phase(uvm_phase phase);
super.conncet_phase(phase);
ap = mon.ap;
endfunction
`endif
2.11 my_model
`ifndef MY_MODEL__SV
`define MY_MODEL__SV
class my_model extends uvm_component;
uvm_blocking_get_port #(my_transaction) port;
uvm_analysis_port #(my_transaction) 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(my_model)
endclass
function my_model::new(string name,uvm_component parent);
super.new(name,parent);
endfunction
function void my_model::build_phase(uvm_phase phase);
super.build_phase(phase);
port = new("port",this);
ap = new("ap",this);
endfunction
task my_model::main_phase(uvm_phase phase);
my_transaction_i tr;
my_transaction_o tr2;
bit [8:0] sum_total;
super.main_phase(phase);
while(1)begin
port.get(tr);
tr2 = new("tr2");
sum_total = tr.a+tr.b+tr.cin;
tr2.sum = sum_total[7:0];
tr2.cout = sum_total[8];
`uvm_info("my_model", "get transactions, add and print it:", UVM_LOW)
new_tr.print();
ap.write(tr2);
end
endtask
`endif
2.12 my_scoreboard
`ifndef MY_SCOREBOARD__SV
`define MY_SCOREBOARD__SV
class my_scoreboard extends uvm_scoreboard;
my_transaction expect_queue[$];
uvm_blocking_get_port #(my_transaction_i) exp_port;
uvm_blocking_get_port #(my_transaction_o) act_port;
`uvm_component_utils(my_scoreboard)
extern function new(string name, uvm_component parent = null);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass
function my_scoreboard::new(string name, uvm_component parent = null);
super.new(name, parent);
endfunction
function void my_scoreboard::build_phase(uvm_phase phase);
super.build_phase(phase);
exp_port = new("exp_port", this);
act_port = new("act_port", this);
endfunction
task my_scoreboard::main_phase(uvm_phase phase);
my_transaction_i get_expect, get_actual, tmp_tran;
bit result;
super.main_phase(phase);
fork
while (1) begin
exp_port.get(get_expect);
expect_queue.push_back(get_expect);
end
while (1) begin
act_port.get(get_actual);
if(expect_queue.size() > 0) begin
tmp_tran = expect_queue.pop_front();
result = get_actual.compare(tmp_tran);
if(result) begin
`uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);
end
else begin
`uvm_error("my_scoreboard", "Compare FAILED");
$display("the expect pkt is");
tmp_tran.print();
$display("the actual pkt is");
get_actual.print();
end
end
else begin
`uvm_error("my_scoreboard", "Received from DUT, while Expect Queue is empty");
$display("the unexpected pkt is");
get_actual.print();
end
end
join
endtask
`endif
2.13 base_test
`ifndef BASE_TEST__SV
`define BASE_TEST__SV
class base_test extends uvm_test;
my_env env;
function new(string name = "base_test", uvm_component parent = null);
super.new(name,parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void report_phase(uvm_phase phase);
`uvm_component_utils(base_test)
endclass
function void base_test::build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
function void base_test::report_phase(uvm_phase phase);
uvm_report_server server;
int err_num;
super.report_phase(phase);
server = get_report_server();
err_num = server.get_severity_count(UVM_ERROR);
if (err_num != 0) begin
$display("TEST CASE FAILED");
end
else begin
$display("TEST CASE PASSED");
end
endfunction
`endif
2.14 my_env
`ifndef MY_ENV__SV
`define MY_ENV__SV
class my_env extends uvm_env;
my_agent_i i_agt;
my_agent_o o_agt;
my_model mdl;
my_scoreboard scb;
uvm_tlm_analysis_fifo #(my_transaction_o) agt_scb_fifo;
uvm_tlm_analysis_fifo #(my_transaction_i) agt_mdl_fifo;
uvm_tlm_analysis_fifo #(my_transaction_o) mdl_scb_fifo;
function new(string name = "my_env", uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
i_agt = my_agent_i::type_id::create("i_agt", this);
o_agt = my_agent_o::type_id::create("o_agt", this);
mdl = my_model::type_id::create("mdl", this);
scb = my_scoreboard::type_id::create("scb", this);
agt_scb_fifo = new("agt_scb_fifo", this);
agt_mdl_fifo = new("agt_mdl_fifo", this);
mdl_scb_fifo = new("mdl_scb_fifo", this);
endfunction
extern virtual function void connect_phase(uvm_phase phase);
`uvm_component_utils(my_env)
endclass
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
i_agt.ap.connect(agt_mdl_fifo.analysis_export);
mdl.port.connect(agt_mdl_fifo.blocking_get_export);
mdl.ap.connect(mdl_scb_fifo.analysis_export);
scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);
o_agt.ap.connect(agt_scb_fifo.analysis_export);
scb.act_port.connect(agt_scb_fifo.blocking_get_export);
endfunction
`endif
2.15 my_case0
`ifndef MY_CASE0__SV
`define MY_CASE0__SV
class case0_sequence extends uvm_sequence #(my_transaction_i);
my_transaction_i m_trans;
function new(string name= "case0_sequence");
super.new(name);
endfunction
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do(m_trans)
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
`uvm_object_utils(case0_sequence)
endclass
class my_case0 extends base_test;
function new(string name = "my_case0", uvm_component parent = null);
super.new(name,parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
`uvm_component_utils(my_case0)
endclass
function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(uvm_object_wrapper)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence",
case0_sequence::type_id::get());
endfunction
`endif
top_tb
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "my_if.sv"
`include "my_transaction_i.sv"
`include "my_transaction_o.sv"
`include "my_sequencer.sv"
`include "my_driver.sv"
`include "my_monitor_i.sv"
`include "my_monitor_o.sv"
`include "my_agent_i.sv"
`include "my_agent_o.sv"
`include "my_model.sv"
`include "my_scoreboard.sv"
`include "my_env.sv"
`include "base_test.sv"
`include "my_case0.sv"
module top_tb;
reg clk;
reg rst_n;
reg [7:0] a;
reg [7:0] b;
reg cin;
reg enable;
wire [7:0] sum;
wire cout;
my_if input_if(clk, rst_n);
my_if output_if(clk, rst_n);
dut my_dut(.clk(clk),
.rst_n(rst_n),
.a(input_if.a),
.b(input_if.b),
.cin(input_if.cin),
.enable(input_if.enable)
.sum(output_if.sum),
.cout(output_if.cout));
initial begin
clk = 0;
forever begin
#100 clk = ~clk;
end
end
initial begin
rst_n = 1'b0;
#1000;
rst_n = 1'b1;
end
initial begin
run_test();
end
initial begin
a = 8'b00000000;
b = 8'b00000000;
cin = 1'b0;
enable = 1'b1;
end
initial begin
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.drv", "vif", input_if);
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.mon_i", "vif", input_if);
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.o_agt.mon_o", "vif", output_if);
end
endmodule