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