Normal Adder UVM verification
Let’s take adder of the following specification :
it is a one-bit adder, one-bit result, one-bit carry
So system Verilog interface port definition will look like
interface dut_if1;
logic a_in, b_in, c_in;
logic sum_out;
logic carry_out;
logic clock,reset;
endinterface
So let’s go through the definition of each component
So lets design DUT first
module normal_adder(dut_if1 dut_if);
`include “uvm_macros.svh”
always_comb begin
if (dut_if.reset) begin
dut_if.sum_out =0;
dut_if.carry_out =0;
end
else
begin
dut_if.sum_out = (dut_if.a_in ^ dut_if.b_in ^ dut_if.c_in);
dut_if.carry_out = ((dut_if.a_in & dut_if.b_in) | (dut_if.b_in & dut_if.c_in) | (dut_if.c_in & dut_if.a_in));
end
$display(“The value of a_in= %0d, b_in=%0d,c_in=%0d , Sum=%0d,Carry=%0d” ,dut_if.a_in,dut_if.b_in,dut_if.c_in,dut_if.sum_out,dut_if.carry_out);
end
endmodule
So let’s define interface
interface dut_if1;
logic a_in, b_in, c_in;
logic sum_out;
logic carry_out;
logic clock,reset;
endinterface
So let’s Define basic transaction :
So in the adder, there could be any random bit in input operand, hence input a_in, b_in,c_in are randomized
So the file will look like below
class normal_adder_txn extends uvm_sequence_item;
`uvm_object_utils(normal_adder_txn)
function new(string name=”normal_adder_txn”) ;
super.new(name);
endfunction
rand bit a_in;
rand bit b_in;
rand bit c_in;
bit sum_out;
bit carry_out;
//Macros you may enable
/* `uvm_object_utils_begin(normal_adder_txn)
`uvm_field_int(a_in, UVM_ALL_ON)
`uvm_field_int(b_in, UVM_ALL_ON)
`uvm_field_int(c_in, UVM_ALL_ON)
`uvm_field_int(sum_out, UVM_ALL_ON)
`uvm_field_int(carry_out, UVM_ALL_ON)
`uvm_object_utils_end*/
endclass
Now let’s define sequence of adder
So in current scenario let the loop of randomization run for 8 times to get all input combination , hence it will look like below
class normal_add_sequence extends uvm_sequence#(normal_adder_txn);
`uvm_object_utils(normal_add_sequence)
function new(string name=”normal_add_sequence”) ;
super.new(name);
endfunction
virtual task body();
normal_adder_txn add_txn1;
repeat(8)
begin
add_txn1=normal_adder_txn::type_id::create(“add_txn1”);
start_item(add_txn1);
assert(add_txn1.randomize());
finish_item(add_txn1);
end
endtask
endclass
Now Lets Define Sequencer
`include “normal_adder_seq.sv” //include seq_file name
class normal_add_sequencer extends uvm_sequencer #(normal_adder_txn);
`uvm_component_utils(normal_add_sequencer)
function new(string name= “normal_add_sequencer”,uvm_component parent);
super.new(name,parent);
endfunction: new
endclass:normal_add_sequencer
Now Lets Define top of Test Bench
`include “uvm_macros.svh”//include uvm macros
`include “normal_add_test.sv”//include test file
module testbench;
import uvm_pkg::*;
dut_if1 intf1();
normal_adder dut_here(.dut_if(intf1));
initial begin
uvm_config_db #(virtual dut_if1)::set (null,”*”,”dut_vif”,intf1);
run_test(“normal_add_test”);
end
initial begin
intf1.clock=1;
intf1.reset = 1;
end
initial begin
forever #5 intf1.clock = ~intf1.clock;
end
initial begin
$dumpfile(“dump.vcd”);
$dumpvars(0, normal_adder);
end
endmodule:testbench
Now lets Define Driver
class normal_add_driver extends uvm_driver #(normal_adder_txn);
`uvm_component_utils(normal_add_driver)
virtual dut_if1 dut_vif;
function new (string name= “normal_add_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 dut_if1)::get( this,”” ,”dut_vif”,dut_vif))
`uvm_error(“”,”uvm_config_db::get failed”)
endfunction :build_phase
task run_phase(uvm_phase phase);
normal_adder_txn add_txn ;
dut_vif.reset=1;
#5 dut_vif.reset=0;
forever begin
seq_item_port.get_next_item(add_txn);
dut_vif.a_in=add_txn.a_in;
dut_vif.b_in=add_txn.b_in;
dut_vif.c_in=add_txn.c_in;
seq_item_port.item_done();
end
endtask
endclass:normal_add_driver
Now lets Define Monitor
class normal_add_monitor_before extends uvm_monitor;
`uvm_component_utils(normal_add_monitor_before)
uvm_analysis_port #(normal_adder_txn) mon_a_port_before;
normal_adder_txn add_tx_mon;
virtual dut_if1 dut_vif;
function new( string name=”normal_add_monitor_before”, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
mon_a_port_before =new(“mon_a_port_before”,this);
if(!uvm_config_db#(virtual dut_if1)::get(this, “” ,”dut_vif”, dut_vif)) begin
// $fatal_error(“interface file values should have been set”, get_full_hirrarchy());
`uvm_error(“”,”uvm_config_db::get failed”)
end
endfunction: build_phase
task run_phase(uvm_phase phase);
add_tx_mon= normal_adder_txn::type_id::create(“add_tx_mon”,this);
forever begin
//@(posedge dut_vif.clock)
@(dut_vif.a_in,dut_vif.b_in,dut_vif.c_in); begin
add_tx_mon.a_in=dut_vif.a_in;
add_tx_mon.b_in=dut_vif.b_in;
add_tx_mon.c_in=dut_vif.c_in;
add_tx_mon.sum_out=dut_vif.sum_out;
add_tx_mon.carry_out=dut_vif.carry_out;
mon_a_port_before.write(add_tx_mon);
end
end
endtask :run_phase
endclass : normal_add_monitor_before
// This Monitor Calculates the reference result
class normal_add_ref_monitor_after extends uvm_monitor;
`uvm_component_utils(normal_add_ref_monitor_after)
virtual dut_if1 dut_vif;
uvm_analysis_port#(normal_adder_txn) ref_mon_a_port_after;
normal_adder_txn add_mon_ref_txn;
function new(string name=”normal_add_ref_monitor_after”,uvm_component parent);
super.new(name,parent);
endfunction :new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual dut_if1)::get(this,””,”dut_vif”,dut_vif)) begin
`uvm_error(“”,”uvm_config_db::get failed”)
end
ref_mon_a_port_after=new(“ref_mon_a_port_after”,this);
endfunction:build_phase
task run_phase(uvm_phase phase);
add_mon_ref_txn=normal_adder_txn::type_id::create(“add_mon_ref_txn”);
forever begin
@(dut_vif.a_in,dut_vif.b_in,dut_vif.c_in); begin
add_mon_ref_txn.a_in=dut_vif.a_in;
add_mon_ref_txn.b_in=dut_vif.b_in;
add_mon_ref_txn.c_in=dut_vif.c_in;
add_mon_ref_add_result();
ref_mon_a_port_after.write(add_mon_ref_txn);
end
end
endtask:run_phase
virtual function void add_mon_ref_add_result();
bit [1:0] sum_res;
sum_res=add_mon_ref_txn.a_in +add_mon_ref_txn.b_in +add_mon_ref_txn.c_in;
add_mon_ref_txn.sum_out= sum_res[0];
add_mon_ref_txn.carry_out = sum_res[1];
endfunction:add_mon_ref_add_result
endclass:normal_add_ref_monitor_after
Now lets Define Agent
`include “normal_adder_seqr.sv”// include sequencer file name
`include “normal_add_monitor.sv”// add monitor file name
`include “normal_adder_driver.sv”// add driver file name
`include “normal_add_seqn.sv” //add sequence file name
class normal_add_agent extends uvm_agent;
`uvm_component_utils(normal_add_agent)
uvm_analysis_port #(normal_adder_txn) agent_a_port_before;
uvm_analysis_port #(normal_adder_txn) ref_agent_a_port_after;
normal_add_sequencer add_seq;
normal_add_monitor_before add_mon_before;
normal_add_ref_monitor_after add_mon_ref_after;
normal_add_driver add_driv;
function new(string name=”normal_add_agent“,uvm_component parent);
super.new(name, parent);
endfunction :new
function void build_phase(uvm_phase phase) ;
super.build_phase(phase);
add_seq =normal_add_sequencer::type_id::create(“add_seq”,this);
add_mon_before =normal_add_monitor_before::type_id::create(“add_mon_before”,this);
add_mon_ref_after=normal_add_ref_monitor_after::type_id::create(“add_mon_ref_after”,this);
add_driv = normal_add_driver::type_id::create(“add_driv”,this);
agent_a_port_before = new(“agent_a_port_before”,this);
ref_agent_a_port_after =new(“ref_agent_a_port_after”,this);
endfunction :build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
add_driv.seq_item_port.connect(add_seq.seq_item_export);
add_mon_before.mon_a_port_before.connect(agent_a_port_before);
add_mon_ref_after.ref_mon_a_port_after.connect(ref_agent_a_port_after);
endfunction:connect_phase
endclass:normal_add_agent
Now lets Define Environment
`include “normal_add_agent.sv” //include agent file name
`include “normal_adder_score.sv” //include score board file name
class normal_add_env extends uvm_env;
`uvm_component_utils(normal_add_env)
normal_add_agent agent;
normal_adder_score score_e;
function new(string name=”normal_add_env”, uvm_component parent) ;
super.new(name, parent);
endfunction :new
function void build_phase(uvm_phase phase) ;
super.build_phase(phase);
agent = normal_add_agent::type_id::create(“agent”,this);
score_e =normal_adder_score::type_id::create(“score_e”,this);
endfunction :build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agent.agent_a_port_before.connect(score_e.add_sc_before);
agent.ref_agent_a_port_after.connect(score_e.ref_add_sc_after);
endfunction:connect_phase
endclass:normal_add_env
Now lets Define Scoreboard
`uvm_analysis_imp_decl(_before)
`uvm_analysis_imp_decl(_after)
class normal_adder_score extends uvm_scoreboard;
`uvm_component_utils(normal_adder_score)
function new(string name=”normal_adder_score”,uvm_component parent);
super.new(name,parent);
endfunction
uvm_analysis_export #(normal_adder_txn) add_sc_before;
uvm_analysis_export #(normal_adder_txn) ref_add_sc_after;
uvm_tlm_analysis_fifo #(normal_adder_txn) add_f_sc;
uvm_tlm_analysis_fifo #(normal_adder_txn) ref_add_tlm_sc;
normal_adder_txn add_f_before;
normal_adder_txn ref_add_f_after;
function void build_phase(uvm_phase phase);
normal_adder_txn add_f;
normal_adder_txn ref_add_f;
add_f_before=normal_adder_txn::type_id::create(“add_f_before”);
ref_add_f_after=normal_adder_txn::type_id::create(“ref_add_f_after”);
add_sc_before=new(“add_sc_before”,this);
add_f_sc=new(“add_f_sc”,this);
ref_add_sc_after= new(“ref_add_sc_after”,this);
ref_add_tlm_sc=new(“ref_add_tlm_sc”,this);
endfunction
function void connect_phase(uvm_phase phase);
add_sc_before.connect(add_f_sc.analysis_export);
ref_add_sc_after.connect(ref_add_tlm_sc.analysis_export);
endfunction:connect_phase
task run_phase(uvm_phase phase);
forever begin
add_f_sc.get(add_f_before);
ref_add_tlm_sc.get(ref_add_f_after);
//$display(“show the contains of dut =%0d”,add_f_before.sum_out) ;
//$display(“show the contains of ref=%0d”,ref_add_f_after.sum_out) ;
if (add_f_before.sum_out == add_f_before.sum_out)
// $display(“Value Matched : Pass”);
`uvm_info(“compare”,{“Test :Pass”},UVM_LOW)
else
// $error
`uvm_info(“compare”,{“Test :Fail”},UVM_LOW)
end
endtask
endclass: normal_adder_score
Now lets Define Test Case
`include “normal_add_env.sv”//include environment file name
class normal_add_test extends uvm_test;
`uvm_component_utils(normal_add_test)
normal_add_env add_test_env;
normal_add_sequence seq_txn1;
function new(string name=”normal_add_test”,uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
add_test_env=normal_add_env::type_id::create(“add_test_env”,this);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
seq_txn1 = normal_add_sequence::type_id::create(“seq_txn1”,this);
seq_txn1.start(add_test_env.agent.add_seq);
phase.drop_objection(this);
phase.phase_done.set_drain_time(this, 50);
endtask
endclass