Hello , this time we will verify simple 4bit Adder using UVM. In design of Adder threre are two inputs in1 and in2 both are of 4bits, a reset signal and a clock, output is of 5 bits.Thing is Adder should produce output at rising edge of clock. for example if in1=2 and in2=2 are changing value at rising edge of clk then output should be 4 at same time.
UVM Test Bench involve Scoreboard , Coverage Collector , Driver , Monitor and Similar Basic Components.
Test Becnh Architecture is shown below.
NOTE : For viewing coverage report download files from edaplayground and open coverage_data.html file. Link is given at bottom.
Design
module adder( clk,
in1,
in2,
out,
rst
);
parameter N=4;
input clk;
input rst;
input [N-1:0] in1;
input [N-1:0] in2;
output [N:0] out;
reg [N:0] temp;
assign out=(rst==1)?temp:(in1+in2);
always @(posedge clk or posedge rst)
if(rst==1)
begin
temp=0;
end
endmodule
adder_sequence_item
class adder_sequence_item extends uvm_sequence_item;
//------------ i/p || o/p field declaration----------------------------------
parameter N=4;
rand logic [N-1:0]in1; //i/p
rand logic [N-1:0]in2;
logic [N:0]out; //o/p
logic rst;
//---------------- register adder_sequence_item class with factory ----------
`uvm_object_utils_begin(adder_sequence_item)
`uvm_field_int( in1 ,UVM_ALL_ON)
`uvm_field_int( in2 ,UVM_ALL_ON)
`uvm_field_int( out ,UVM_ALL_ON)
`uvm_field_int( rst ,UVM_ALL_ON)
`uvm_object_utils_end
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="adder_sequence_item");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// write DUT inputs here for printing
function string input2string();
return($sformatf("in1=%4b in2=%4b rst=%0b", in1,in2,rst));
endfunction
// write DUT outputs here for printing
function string output2string();
return($sformatf("out=%5h ", out));
endfunction
function string convert2string();
return($sformatf({input2string(), " ", output2string()}));
endfunction
//----------------------------------------------------------------------------
endclass:adder_sequence_item
adder_sequences
/***************************************************
** class name : adder_sequence
** description : generate random inputs i.e, in1
and in2
***************************************************/
class adder_sequence extends uvm_sequence#(adder_sequence_item);
//----------------------------------------------------------------------------
`uvm_object_utils(adder_sequence)
//----------------------------------------------------------------------------
adder_sequence_item txn;
longint loop_count=20;
//----------------------------------------------------------------------------
function new(string name="adder_sequence");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
virtual task body();
repeat(loop_count)
begin
txn=adder_sequence_item::type_id::create("txn");
start_item(txn);
assert(txn.randomize());
txn.rst=0;
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass:adder_sequence
/***************************************************
** class name : adder_add_zero_in1
** description : add value 0 , in1 reamains 0
***************************************************/
class adder_add_zero_in1 extends adder_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(adder_add_zero_in1)
//----------------------------------------------------------------------------
adder_sequence_item txn;
longint loop_count=30;
//----------------------------------------------------------------------------
function new(string name="adder_add_zero_in1");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
repeat(loop_count)
begin
txn=adder_sequence_item::type_id::create("txn");
start_item(txn);
assert(txn.randomize()with{txn.in1==0;});
txn.rst=0;
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
/***************************************************
** class name : adder_add_zero_in2
** description : add 0 , in2 remains 0
***************************************************/
class adder_add_zero_in2 extends adder_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(adder_add_zero_in2)
//----------------------------------------------------------------------------
adder_sequence_item txn;
longint loop_count=30;
//----------------------------------------------------------------------------
function new(string name="adder_add_zero_in2");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
repeat(loop_count)
begin
txn=adder_sequence_item::type_id::create("txn");
start_item(txn);
assert(txn.randomize()with{txn.in2==0;});
txn.rst=0;
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
/***************************************************
** class name : add_F
** description : in1 and in2 are F(4'b1111)
***************************************************/
class add_F extends adder_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(add_F)
//----------------------------------------------------------------------------
adder_sequence_item txn;
longint loop_count=30;
//----------------------------------------------------------------------------
function new(string name="add_F");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
repeat(loop_count)
begin
txn=adder_sequence_item::type_id::create("txn");
start_item(txn);
assert(txn.randomize()with{txn.in1=='b1111; txn.in2=='b1111;});
txn.rst=0;
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
class reset extends adder_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(reset)
//----------------------------------------------------------------------------
adder_sequence_item txn;
//----------------------------------------------------------------------------
function new(string name="reset");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
begin
txn=adder_sequence_item::type_id::create("txn");
start_item(txn);
txn.rst=1;
txn.in1=0;
txn.in2=0;
#3;
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
adder_sequencer
class adder_sequencer extends uvm_sequencer#(adder_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(adder_sequencer)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
endclass:adder_sequencer
adder_driver
class adder_driver extends uvm_driver #(adder_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(adder_driver)
//----------------------------------------------------------------------------
uvm_analysis_port #(adder_sequence_item) drv2sb;
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
drv2sb=new("drv2sb",this);
endfunction
//----------------------------------------------------------------------------
//-------------------------- virtual interface handel -----------------------
virtual interface intf vif;
//----------------------------------------------------------------------------
//------------------------- get interface handel from top -------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!(uvm_config_db#(virtual intf)::get(this,"","vif",vif))) begin
`uvm_fatal(get_type_name(),"unable to get interface");
end
endfunction
//----------------------------------------------------------------------------
//---------------------------- run task --------------------------------------
task run_phase(uvm_phase phase);
adder_sequence_item txn;
forever begin
seq_item_port.get_next_item(txn);
@(posedge vif.clk); // or vif.Clk_Blk.clk
vif.in1 <= txn.in1;
vif.in2 <= txn.in2;
vif.rst <= txn.rst;
drv2sb.write(txn);
seq_item_port.item_done();
end
endtask
//----------------------------------------------------------------------------
endclass:adder_driver
interface
interface intf(input bit clk);
// ------------------- port declaration-------------------------------------
parameter N=4;
logic [N-1:0] in1;
logic [N-1:0] in2;
logic [N:0] out;
logic rst;
//--------------------------------------------------------------------------
property p1;
disable iff(rst==1)
@(posedge clk) (out==in1+in2);
endproperty
ASSERT:assert property(p1) $display("------------ PASS -------------");
else $display("------------ FAIL -------------");
endinterface
adder_monitor
class adder_monitor extends uvm_monitor;
//----------------------------------------------------------------------------
`uvm_component_utils(adder_monitor)
//----------------------------------------------------------------------------
//------------------- constructor --------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//---------------- sequence_item class ---------------------------------------
adder_sequence_item txn;
//----------------------------------------------------------------------------
//------------------------ virtual interface handle---------------------------
virtual interface intf vif;
//----------------------------------------------------------------------------
//------------------------ analysis port -------------------------------------
uvm_analysis_port#(adder_sequence_item) ap_mon;
//----------------------------------------------------------------------------
//------------------- build phase --------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!(uvm_config_db#(virtual intf)::get(this,"","vif",vif)))
begin
`uvm_fatal("monitor","unable to get interface")
end
ap_mon=new("ap_mon",this);
txn=adder_sequence_item::type_id::create("txn",this);
endfunction
//----------------------------------------------------------------------------
//-------------------- run phase ---------------------------------------------
task run_phase(uvm_phase phase);
forever
begin
@(negedge vif.clk);
txn.in1 = vif.in1;
txn.in2 = vif.in2;
txn.out = vif.out;
txn.rst = vif.rst;
ap_mon.write(txn);
end
endtask
//----------------------------------------------------------------------------
endclass:adder_monitor
adder_agent
class adder_agent extends uvm_agent;
//----------------------------------------------------------------------------
`uvm_component_utils(adder_agent)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//----------------- class handles --------------------------------------------
adder_sequencer sequencer_h;
adder_driver driver_h;
adder_monitor monitor_h;
//----------------------------------------------------------------------------
//---------------------- build phase -----------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver_h = adder_driver::type_id::create("driver_h",this);
sequencer_h = adder_sequencer::type_id::create("sequencer_h",this);
monitor_h = adder_monitor::type_id::create("monitor_h",this);
endfunction
//----------------------------------------------------------------------------
//----------------------- connect phase --------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver_h.seq_item_port.connect(sequencer_h.seq_item_export);
endfunction
//----------------------------------------------------------------------------
endclass:adder_agent
adder_coverage
class adder_coverage extends uvm_subscriber #(adder_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(adder_coverage)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
dut_cov=new();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
adder_sequence_item txn;
real cov;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
covergroup dut_cov;
option.per_instance=1;
// or coverpoint txn.in1;
// coverpoint txn.in2; it work as well.
IN1:coverpoint txn.in1 {
bins name1_1[]={[0:3]};
bins name2_1[]={[4:7]};
bins name3_1[]={[8:11]};
bins name4_1[]={[11:15]};
}
IN2:coverpoint txn.in2 {
bins name1_2[]={[0:3]};
bins name2_2[]={[4:7]};
bins name3_2[]={[8:11]};
bins name4_2[]={[11:15]};
}
endgroup:dut_cov
//----------------------------------------------------------------------------
//--------------------- write method ----------------------------------------
function void write(adder_sequence_item t);
txn=t;
dut_cov.sample();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function void extract_phase(uvm_phase phase);
super.extract_phase(phase);
cov=dut_cov.get_coverage();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info(get_type_name(),$sformatf("Coverage is %f",cov),UVM_MEDIUM)
endfunction
//----------------------------------------------------------------------------
endclass:adder_coverage
adder_scoreboard
/***************************************************
analysis_port from driver
analysis_port from monitor
***************************************************/
`uvm_analysis_imp_decl( _drv )
`uvm_analysis_imp_decl( _mon )
class adder_scoreboard extends uvm_scoreboard;
`uvm_component_utils(adder_scoreboard)
uvm_analysis_imp_drv #(adder_sequence_item, adder_scoreboard) aport_drv;
uvm_analysis_imp_mon #(adder_sequence_item, adder_scoreboard) aport_mon;
uvm_tlm_fifo #(adder_sequence_item) expfifo;
uvm_tlm_fifo #(adder_sequence_item) outfifo;
int VECT_CNT, PASS_CNT, ERROR_CNT;
reg [5:0]t_out,past_out;
reg [4:0]t_in1,t_in2;
function new(string name="adder_scoreboard",uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
aport_drv = new("aport_drv", this);
aport_mon = new("aport_mon", this);
expfifo= new("expfifo",this);
outfifo= new("outfifo",this);
endfunction
function void write_drv(adder_sequence_item tr);
`uvm_info("write_drv STIM", tr.input2string(), UVM_MEDIUM)
if(tr.rst==1)
begin
t_out=0;
end
else
begin
t_in1=tr.in1;
t_in2=tr.in2;
t_out=t_in1+t_in2;
end
tr.out = t_out;
void'(expfifo.try_put(tr));
endfunction
function void write_mon(adder_sequence_item tr);
`uvm_info("write_mon OUT ", tr.convert2string(), UVM_MEDIUM)
void'(outfifo.try_put(tr));
endfunction
task run_phase(uvm_phase phase);
adder_sequence_item exp_tr, out_tr;
forever begin
`uvm_info("scoreboard run task","WAITING for expected output", UVM_DEBUG)
expfifo.get(exp_tr);
`uvm_info("scoreboard run task","WAITING for actual output", UVM_DEBUG)
outfifo.get(out_tr);
if (out_tr.out == exp_tr.out) begin
PASS();
`uvm_info ("PASS ",out_tr.convert2string() , UVM_MEDIUM)
end
else begin
ERROR();
`uvm_info ("ERROR [ACTUAL_OP]",out_tr.convert2string() , UVM_MEDIUM)
`uvm_info ("ERROR [EXPECTED_OP]",exp_tr.convert2string() , UVM_MEDIUM)
`uvm_warning("ERROR",exp_tr.convert2string())
end
end
endtask
function void PASS();
VECT_CNT++;
PASS_CNT++;
endfunction
function void ERROR();
VECT_CNT++;
ERROR_CNT++;
endfunction
endclass
adder_env
class adder_env extends uvm_env;
//---------------------------------------------------------------------------
`uvm_component_utils(adder_env)
//---------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//-------------------- class handles -----------------------------------------
adder_agent agent_h;
adder_coverage coverage_h;
adder_scoreboard scoreboard_h;
//----------------------------------------------------------------------------
//---------------------- build phase -----------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent_h = adder_agent::type_id::create("agent_h",this);
coverage_h = adder_coverage::type_id::create("coverage_h",this);
scoreboard_h = adder_scoreboard::type_id::create("scoreboard_h",this);
endfunction
//----------------------------------------------------------------------------
//-------------------------- connect phase -----------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agent_h.monitor_h.ap_mon.connect(coverage_h.analysis_export);
agent_h.monitor_h.ap_mon.connect(scoreboard_h.aport_mon);
agent_h.driver_h.drv2sb.connect(scoreboard_h.aport_drv);
endfunction
//----------------------------------------------------------------------------
endclass:adder_env
adder_test
class adder_test extends uvm_test;
//--------------------------------------------------------------------------
`uvm_component_utils(adder_test)
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//--------------------------------------------------------------------------
adder_env env_h;
int file_h;
adder_sequence seq;
adder_add_zero_in1 seq1_1;
adder_add_zero_in1 seq1_2;
adder_add_zero_in2 seq2_1;
adder_add_zero_in2 seq2_2;
add_F seq3_1;
add_F seq3_2;
reset rst;
//--------------------------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env_h = adder_env::type_id::create("env_h",this);
seq=adder_sequence::type_id::create("seq");
seq1_1=adder_add_zero_in1::type_id::create("seq1_1");
seq1_2=adder_add_zero_in1::type_id::create("seq1_2");
seq2_1=adder_add_zero_in2::type_id::create("seq2_1");
seq2_2=adder_add_zero_in2::type_id::create("seq2_2");
seq3_1=add_F::type_id::create("seq3_1");
seq3_2=add_F::type_id::create("seq3_2");
rst=reset::type_id::create("rst");
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function void end_of_elobartion_phase(uvm_phase phase);
//super.end_of_elobartion_phase(phase);
//factory.print();
$display("End of eleboration phase in agent");
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function void start_of_simulation_phase(uvm_phase phase);
//super.start_of_simulation_phase(phase);
$display("start_of_simulation_phase");
file_h=$fopen("LOG_FILE.log","w");
set_report_default_file_hier(file_h);
set_report_severity_action_hier(UVM_INFO,UVM_DISPLAY+UVM_LOG);
env_h.set_report_verbosity_level_hier(UVM_MEDIUM);
seq.loop_count=100; // change value from here
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
task run_phase(uvm_phase phase);
phase.raise_objection(this);
// seq.start(env_h.agent_h.sequencer_h);
rst.start(env_h.agent_h.sequencer_h);
seq.start(env_h.agent_h.sequencer_h);
seq3_1.start(env_h.agent_h.sequencer_h);
seq1_1.start(env_h.agent_h.sequencer_h);
seq2_1.start(env_h.agent_h.sequencer_h);
#10;
phase.drop_objection(this);
endtask
//--------------------------------------------------------------------------
endclass:adder_test
tb_pkg
`ifndef TB_PKG
`define TB_PKG
`include "uvm_macros.svh"
package tb_pkg;
import uvm_pkg::*;
`include "adder_sequence_item.sv" // transaction class
`include "adder_sequence.sv" // sequence class
`include "adder_sequencer.sv" // sequencer class
`include "adder_driver.sv" // driver class
`include "adder_monitor.sv"
`include "adder_agent.sv" // agent class
`include "adder_coverage.sv" // coverage class
`include "adder_scoreboard.sv" // scoreboard class
`include "adder_env.sv" // environment class
`include "adder_test.sv" // test
endpackage
`endif
tb_top
`include "interface.sv"
`include "tb_pkg.sv"
module top;
import uvm_pkg::*;
import tb_pkg::*;
bit clk; // external signal declaration
//----------------------------------------------------------------------------
intf i_intf(clk);
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
adder DUT(.in1(i_intf.in1),
.in2(i_intf.in2),
.out(i_intf.out),
.clk(i_intf.clk),
.rst(i_intf.rst)
);
//----------------------------------------------------------------------------
always #5 clk=~clk;
initial begin
clk<=0;
end
//----------------------------------------------------------------------------
initial begin
$dumpfile("dumpfile.vcd");
$dumpvars;
end
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
initial begin
uvm_config_db#(virtual intf)::set(uvm_root::get(),"","vif",i_intf);
end
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
initial begin
run_test("adder_test");
end
//----------------------------------------------------------------------------
endmodule
Link for Code : https://www.edaplayground
Thank you for reading , have a nice day 😊😊👍.
You Might Also Like