初学uvm验证方法学,试着验证了32位全加器,适合初学者做参考。
// adder32.sv 32位全加器
module adder32_sv(
input clk ,
input rst_n ,
input enable ,
input [31:0] a ,
input [31:0] b ,
input cin ,
output [31:0] s ,
output cout
);
reg [31:0] s = 32'h00000000 ;
reg cout = 1'h0 ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
s = 32'h00000000 ;
cout= 1'h0 ;
end
else if(enable) begin
{cout,s} <= a + b + cin;
end
else
begin
s <= s ;
cout <= cout ;
end
end
endmodul
//top.sv
`ifndef TB_SV
`define TB_SV
`timescale 1ns/1ns
`include "interface.sv"
`include "test.sv"
module top;
`include "uvm_macros.svh"
import uvm_pkg::*;
bit clk;
// Interface to connect the ALU agent with the DUT
slv_if my_if(clk);
// DUT connections
adder32_sv u_adder32 (
.clk(clk),
.rst_n(my_if.rst_n),
.enable(my_if.enable),
.a(my_if.a),
.b(my_if.b),
.cin(my_if.cin),
.cout(my_if.cout),
.s(my_if.s)
);
initial begin
my_if.cin = 1'b0 ;
my_if.a = 32'h00000000 ;
my_if.b = 32'h00000000 ;
my_if.enable = 1'b1 ;
my_if.rst_n = 1'b0 ;
#100 my_if.rst_n = 1'b1 ;
end
// Clock generator
initial begin
clk = 0;
forever begin
#50 clk = ~clk;
end
end
// Set the interface to the DUT to be used by UVM TB.
initial begin
uvm_config_db#(virtual slv_if)::set(null,"uvm_test_top.my_env.i_agt.drv","my_if",my_if);
uvm_config_db#(virtual slv_if)::set(null,"uvm_test_top.my_env.o_agt.mon","my_if",my_if);
run_test();
end
endmodule
`endif
`ifndef TEST_SV
`define TEST_SV
`include "env.sv"
class my_test extends uvm_test;
`uvm_component_utils(my_test)
env my_env;
extern function new(string name="my_test",uvm_component parent=null);
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void start_of_simulation_phase(uvm_phase phase);
endclass
function my_test::new (string name="my_test",uvm_component parent=null);
super.new(name,parent);
endfunction
function void my_test::build_phase(uvm_phase phase);
super.build_phase(phase);
my_env = env::type_id::create("my_env",this);
uvm_config_db#(uvm_object_wrapper)::set(this,"my_env.i_agt.seqr.main_phase","default_sequence",my_sequence::get_type());
endfunction
function void my_test::start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
uvm_top.print_topology(uvm_default_table_printer);
factory.print();
endfunction
`endif
`ifndef ENV_SV
`define ENV_SV
`include "agent.sv"
`include "scoreboard.sv"
`include "modle.sv"
class env extends uvm_env;
agent i_agt ; //my_driver functional
agent o_agt ; //my_monitor functional
model mdl ;
scoreboard scb ;
uvm_tlm_analysis_fifo #(transaction) agt_scb_fifo; //my_monitor
uvm_tlm_analysis_fifo #(transaction) agt_mdl_fifo; //my_driver
uvm_tlm_analysis_fifo #(transaction) mdl_scb_fifo; //my_model
extern function new (string name,uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void connect_phase(uvm_phase phase);
`uvm_component_utils(env)
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);
i_agt = agent::type_id::create("i_agt",this);
o_agt = agent::type_id::create("o_agt",this);
i_agt.is_active = UVM_ACTIVE;
o_agt.is_active = UVM_PASSIVE;
mdl = model::type_id::create("mdl",this);
scb = 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
function void 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
`ifndef AGENT_SV
`define AGENT_SV
`include "transaction.sv"
`include "driver.sv"
`include "monitor.sv"
`include "sequence.sv"
typedef uvm_sequencer #(transaction) sequencer ;
class agent extends uvm_agent;
`uvm_component_utils(agent)
sequencer seqr;
driver drv;
monitor mon;
uvm_analysis_port #(transaction) ap;
function new(string name = "agent",uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(is_active == UVM_ACTIVE) begin
seqr = sequencer::type_id::create("seqr", this);
drv = driver::type_id::create("drv", this);
end
else begin
mon = monitor::type_id::create("mon", this);
end
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if(is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
this.ap = drv.ap;
end
else begin
this.ap=mon.ap;
end
endfunction
endclass
`endif
`ifndef MODEL_SV
`define MODEL_SV
class model extends uvm_component;
uvm_blocking_get_port #(transaction) port; //from my_driver
uvm_analysis_port #(transaction) ap; //to scoreboard
extern function new (string name,uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
extern virtual task one_pkt(ref transaction pkt,ref transaction pkt2);
`uvm_component_utils(model)
endclass
function model::new (string name,uvm_component parent);
super.new(name,parent);
endfunction
function void model::build_phase(uvm_phase phase);
super.build_phase(phase);
port=new("port",this);
ap=new("ap",this);
endfunction
task model::main_phase(uvm_phase phase);
transaction tr,tr2;
super.main_phase(phase);
while(1) begin
tr2=new();
port.get(tr);
#100;
`uvm_info("MOL_MAIN_PHASE", tr.sprint(), UVM_MEDIUM)
one_pkt(tr2,tr);
ap.write(tr2);
`uvm_info("MOL_MAIN_PHASE", tr2.sprint(), UVM_MEDIUM)
end
endtask
task model::one_pkt(ref transaction pkt,ref transaction pkt2);
bit [32:0] sum_total;
begin
sum_total=pkt2.a+pkt2.b+pkt2.cin;
pkt.s=sum_total[31:0];
pkt.cout=sum_total[32];
end
endtask
`endif
`ifndef SCOREBOARD_SV
`define SCOREBOARD_SV
class scoreboard extends uvm_scoreboard;
int pre_number=0;
transaction expect_queue[$];
uvm_blocking_get_port #(transaction) exp_port;//from my_reference
uvm_blocking_get_port #(transaction) act_port;//from my_monitor
`uvm_component_utils(scoreboard)
extern function new (string name,uvm_component parent);
extern virtual function void build_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);
exp_port=new("exp_port",this);
act_port=new("act_port",this);
endfunction
task scoreboard::main_phase(uvm_phase phase);
transaction 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
pre_number=pre_number+1;
$display("compare SUCCESSFULLy:%0d",pre_number);
end
else begin
$display("compare FAILED");
$display("the expect pkt is");
tmp_tran.print();
$display("the actual pkt is");
get_actual.print();
end
end
else begin
//$display("ERROR::Received from DUT,while Expect Queue is empty");
get_actual.print();
end
end
join
endtask
`endif
`ifndef MONITOR__SV
`define MONITOR__SV
`include "interface.sv"
class monitor extends uvm_monitor;
virtual slv_if vif;
uvm_analysis_port #(transaction) ap; // to scoreboard
extern function new (string name,uvm_component parent);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
extern virtual task receive_one_pkt(ref transaction get_pkt);
`uvm_component_utils(monitor)
endclass
function monitor::new (string name,uvm_component parent);
super.new(name,parent);
endfunction
function void monitor::build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual slv_if)::get(this,"","my_if",vif))
`uvm_fatal("monitor","Error in Getting interface");
ap=new("ap",this);
endfunction
task monitor::main_phase(uvm_phase phase);
transaction tr;
super.main_phase(phase);
while(1) begin
tr=new();
receive_one_pkt(tr);
ap.write(tr);
end
endtask
task monitor::receive_one_pkt(ref transaction get_pkt);
@( negedge vif.mon_cb.enable);
get_pkt.cout=vif.mon_cb.cout;
get_pkt.s=vif.mon_cb.s;
endtask
`endif
`ifndef DRIVER_SV
`define DRIVER_SV
`include "transaction.sv"
`include "interface.sv"
`include "uvm_macros.svh"
class driver extends uvm_driver #(transaction);
virtual slv_if vif;
uvm_analysis_port #(transaction) ap; //to modle
`uvm_component_utils(driver)
function new(string name="driver",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual slv_if)::get(this,"","my_if",vif))
`uvm_fatal("driver","Error in Getting interface");
ap=new("ap",this);
endfunction
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
seq_item_port.get_next_item(req);
`uvm_info("DRV_RUN_PHASE", req.sprint(), UVM_MEDIUM)
drive_one_pkt(req);
ap.write(req);
#100;
seq_item_port.item_done();
end
endtask
task drive_one_pkt(transaction req);
@vif.drv_cb;
@vif.drv_cb;
begin
vif.drv_cb.enable<=1'b1;
vif.drv_cb.cin<=req.cin;
vif.drv_cb.a<=req.a;
vif.drv_cb.b<=req.b;
end
@vif.drv_cb;
@vif.drv_cb;
vif.drv_cb.enable<=1'b0;
endtask
endclass
`endif
`ifndef SEQUENCE_SV
`define SEQUENCE_SV
class my_sequence extends uvm_sequence #(transaction);
`uvm_object_utils(my_sequence)
function new(string name = "my_sequence");
super.new(name);
endfunction
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat(10) begin
`uvm_do(req);
`uvm_info("SEQUENCE", req.sprint(), UVM_MEDIUM)
end
#100
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
`endif
`ifndef TRANSACTION_SV
`define TRANSACTION_SV
class transaction extends uvm_sequence_item;
rand bit [31:0] a;
rand bit [31:0] b;
rand bit cin;
bit [31:0] s;
bit cout;
`uvm_object_utils_begin(transaction)
`uvm_field_int(a, UVM_ALL_ON)
`uvm_field_int(b, UVM_ALL_ON)
`uvm_field_int(cin, UVM_ALL_ON)
`uvm_field_int(cout, UVM_ALL_ON)
`uvm_field_int(s, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name= "transaction");
super.new();
endfunction
endclass
`endif
transaction是整个验证平台各个组件之间通信所传输的事物。
interface是验证平台和DUT之间进行通信的接口
`ifndef INTERFACE__SV
`define INTERFACE__SV
interface slv_if(input bit clk);
logic rst_n ;
logic cin ;
logic [31:0] a ;
logic [31:0] b ;
logic enable ;
wire cout;
wire [31:0] s;
clocking drv_cb @(posedge clk);
output enable,cin,a,b;
endclocking
clocking mon_cb @(posedge clk);
input cout,s,enable;
endclocking
endinterface
`endif
需要Makefile脚本文件的可以私信问哦