Hello , welcome back. so in this blog post we will verify 8-bit unsigned multiplier using UVM self check TestBench.
Our design has two 8-bit ports in1 and in2, 16-bit output port out.Multiplication tack place on every posedge of clock clk.
TestBench Architecture
design.sv
module mul(in1,
in2,
clk,
out
);
parameter N=8;
input [N-1:0] in1,in2;
input clk;
output [(2*N)-1:0] out;
reg[(2*N)-1:0] temp;
assign out=temp;
always@(posedge clk)
begin
temp=in1*in2;
end
endmodule
interface
interface intf(input bit clk);
// ------------------- port declaration-------------------------------------
logic [7:0]in1;
logic [7:0]in2;
logic [15:0]out;
endinterface
mul_sequence_item
class mul_sequence_item extends uvm_sequence_item;
//------------ i/p || o/p field declaration-----------------
rand logic [7:0]in1; //i/p
rand logic [7:0]in2;
logic [15:0]out; //o/p
//---------------- register mul_sequence_item class with factory --------
`uvm_object_utils_begin(mul_sequence_item)
`uvm_field_int( in1 ,UVM_ALL_ON)
`uvm_field_int( in2 ,UVM_ALL_ON)
`uvm_field_int( out ,UVM_ALL_ON)
`uvm_object_utils_end
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="mul_sequence_item");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// write DUT inputs here for printing
function string input2string();
return($sformatf("in1=%h in2=%h", in1,in2 ));
endfunction
// write DUT outputs here for printing
function string output2string();
return($sformatf("out=%h ",out));
endfunction
function string convert2string();
return($sformatf({input2string(), " ", output2string()}));
endfunction
//----------------------------------------------------------------------------
endclass:mul_sequence_item
mul_sequence
/***************************************************
** class name : mul_sequence
** description : send random data to DUT
***************************************************/
class mul_sequence extends uvm_sequence#(mul_sequence_item);
//----------------------------------------------------------------------------
`uvm_object_utils(mul_sequence)
//----------------------------------------------------------------------------
mul_sequence_item txn;
int loop_count=30;
//----------------------------------------------------------------------------
function new(string name="mul_sequence");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
virtual task body();
for(int i=0;i<loop_count;i++) begin
txn=mul_sequence_item::type_id::create("txn");
start_item(txn);
txn.randomize();
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass:mul_sequence
/***************************************************
** class name : mul_sequence_short
** description : vlaue of in1 and in2 is < 16
***************************************************/
class mul_sequence_short extends uvm_sequence#(mul_sequence_short);
//----------------------------------------------------------------------------
`uvm_object_utils(mul_sequence_short)
//----------------------------------------------------------------------------
mul_sequence_item txn;
int loop_count=30;
//----------------------------------------------------------------------------
function new(string name="mul_sequence_short");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
virtual task body();
for(int i=0;i<loop_count;i++) begin
txn=mul_sequence_item::type_id::create("txn");
start_item(txn);
txn.randomize()with{txn.in1<16;txn.in2<16;};
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
/***************************************************
** class name : mul_sequence_high
** description : vlaue of in1 and in2 is > 128
***************************************************/
class mul_sequence_high extends uvm_sequence#(mul_sequence_high);
//----------------------------------------------------------------------------
`uvm_object_utils(mul_sequence_high)
//----------------------------------------------------------------------------
mul_sequence_item txn;
int loop_count=30;
//----------------------------------------------------------------------------
function new(string name="mul_sequence_high");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
virtual task body();
for(int i=0;i<loop_count;i++) begin
txn=mul_sequence_item::type_id::create("txn");
start_item(txn);
txn.randomize()with{txn.in1>128;txn.in2>128;};
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
/***************************************************
** class name : in1_0_seq
** description : send data to DUT in which in1==0
***************************************************/
class in1_0_seq extends mul_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(in1_0_seq)
//----------------------------------------------------------------------------
mul_sequence_item txn;
int loop_count=30;
//----------------------------------------------------------------------------
function new(string name="in1_0_seq");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
for(int i=0;i<loop_count;i++) begin
txn=mul_sequence_item::type_id::create("txn");
start_item(txn);
txn.randomize()with{txn.in1==0;};
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass
mul_sequencer
class mul_sequencer extends uvm_sequencer#(mul_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(mul_sequencer)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="mul_sequencer",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
endclass:mul_sequencer
mul_driver
class mul_driver extends uvm_driver #(mul_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(mul_driver)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="mul_driver",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
uvm_analysis_port #(mul_sequence_item) drv2sb;
bit flag;
//-------------------------- 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("driver","unable to get interface");
end
drv2sb=new("drv2sb",this);
endfunction
//----------------------------------------------------------------------------
//---------------------------- run task --------------------------------------
task run_phase(uvm_phase phase);
mul_sequence_item txn;
forever begin
seq_item_port.get_next_item(txn);
@(posedge vif.clk);
vif.in1 <= txn.in1;
vif.in2 <= txn.in2;
flag=$isunknown(txn.in1);
if(flag==1) begin
$display(" UNKNOW VALUE DETECTED ");
seq_item_port.item_done();
end
else begin
drv2sb.write(txn);
`uvm_info(get_type_name(),txn.convert2string(),UVM_MEDIUM)
seq_item_port.item_done();
end
end
endtask
//----------------------------------------------------------------------------
endclass:mul_driver
mul_monitor
class mul_monitor extends uvm_monitor;
//----------------------------------------------------------------------------
`uvm_component_utils(mul_monitor)
//----------------------------------------------------------------------------
//------------------- constructor --------------------------------------------
function new(string name="mul_monitor",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//---------------- sequence_item class ---------------------------------------
mul_sequence_item txn;
//----------------------------------------------------------------------------
bit flag,flag1;
//------------------------ virtual interface handle---------------------------
virtual interface intf vif;
//----------------------------------------------------------------------------
//------------------------ analysis port -------------------------------------
uvm_analysis_port#(mul_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=mul_sequence_item::type_id::create("txn",this);
endfunction
//----------------------------------------------------------------------------
//-------------------- run phase ---------------------------------------------
task run_phase(uvm_phase phase);
forever
begin
@(posedge vif.clk);
txn.in1 = vif.in1;
txn.in2 = vif.in2;
txn.out = vif.out;
flag=$isunknown(txn.in1);
flag=$isunknown(txn.out);
`uvm_info(get_type_name(),txn.convert2string(),UVM_MEDIUM)
ap_mon.write(txn);
end
endtask
//----------------------------------------------------------------------------
endclass:mul_monitor
mul_agent
class mul_agent extends uvm_agent;
//----------------------------------------------------------------------------
`uvm_component_utils(mul_agent)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="mul_agent",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//----------------- class handles --------------------------------------------
mul_sequencer sequencer_h;
mul_driver driver_h;
mul_monitor monitor_h;
//----------------------------------------------------------------------------
//---------------------- build phase -----------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver_h = mul_driver::type_id::create("driver_h",this);
sequencer_h = mul_sequencer::type_id::create("sequencer_h",this);
monitor_h = mul_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:mul_agent
mul_coverage
class mul_coverage extends uvm_subscriber #(mul_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(mul_coverage)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="mul_coverage",uvm_component parent);
super.new(name,parent);
dut_cov=new();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
mul_sequence_item txn;
real cov;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
covergroup dut_cov;
option.per_instance= 1;
option.comment = "dut_cov";
option.name = "dut_cov";
option.auto_bin_max= 256;
IN1:coverpoint txn.in1;
IN2:coverpoint txn.in2;
endgroup:dut_cov;
//----------------------------------------------------------------------------
//--------------------- write method ----------------------------------------
function void write(mul_sequence_item t);
txn=t;
dut_cov.sample();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function void extract_phase(uvm_phase phase);
cov=dut_cov.get_coverage();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function void report_phase(uvm_phase phase);
`uvm_info(get_type_name(),$sformatf("Coverage is %f",cov),UVM_LOW)
endfunction
//----------------------------------------------------------------------------
endclass:mul_coverage
mul_scoreboard
/***************************************************
analysis_port from driver
analysis_port from monitor
***************************************************/
`uvm_analysis_imp_decl( _drv )
`uvm_analysis_imp_decl( _mon )
class mul_scoreboard extends uvm_scoreboard;
`uvm_component_utils(mul_scoreboard)
uvm_analysis_imp_drv #(mul_sequence_item, mul_scoreboard) aport_drv;
uvm_analysis_imp_mon #(mul_sequence_item, mul_scoreboard) aport_mon;
uvm_tlm_fifo #(mul_sequence_item) expfifo;
uvm_tlm_fifo #(mul_sequence_item) outfifo;
int q1[$];
int q2[$];
int i;
int VECT_CNT, PASS_CNT, ERROR_CNT;
logic [15:0]t_out;
function new(string name="mul_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(mul_sequence_item tr);
`uvm_info("write_drv STIM", tr.convert2string(), UVM_MEDIUM)
//write scoreboard code here
t_out = tr.in1*tr.in2;
tr.out = t_out;
q1.push_back(t_out);
void'(expfifo.try_put(tr));
endfunction
function void write_mon(mul_sequence_item tr);
`uvm_info("write_mon OUT ", tr.convert2string(), UVM_MEDIUM)
q2.push_back(tr.out);
void'(outfifo.try_put(tr));
endfunction
task run_phase(uvm_phase phase);
mul_sequence_item exp_tr, out_tr;
i=0;
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);
// $display("i = %0d",i);
// $display("q1 = %h",q1[i]);
// $display("q2 = %h",q2[i]);
i++;
/* 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 check_phase(uvm_phase phase);
super.check_phase(phase);
$display("INSIDE CHECK PHASE ");
foreach(q1[i])
begin
if(q1[i]==q2[i+2]) begin
//$display("q1=%h q2=%h : i=%d",q1[i],q2[i+2],i);
PASS();
`uvm_info ("PASS ",$sformatf("q1=%h q2=%h : PASS",q1[i],q2[i+2]) , UVM_LOW)
end
else begin
//$display("FAIL");
ERROR();
`uvm_warning("ERROR",$sformatf("q1=%h q2=%h : ERROR",q1[i],q2[i+2]))
end
if(i==(q1.size()-2)) begin
$display("BREAKING LOOP");
break;
end
end
endfunction
function void report_phase(uvm_phase phase);
super.report_phase(phase);
if (VECT_CNT && !ERROR_CNT)
`uvm_info("PASSED",$sformatf("*** TEST PASSED - %0d vectors ran, %0d vectors passed***",
VECT_CNT, PASS_CNT), UVM_LOW)
else
`uvm_info("FAILED",$sformatf("*** TEST FAILED - %0d vectors ran, %0d vectors passed, %0d vectors failed ***",
VECT_CNT, PASS_CNT, ERROR_CNT), UVM_LOW)
endfunction
function void PASS();
VECT_CNT++;
PASS_CNT++;
endfunction
function void ERROR();
VECT_CNT++;
ERROR_CNT++;
endfunction
endclass
mul_env
class mul_env extends uvm_env;
//---------------------------------------------------------------------------
`uvm_component_utils(mul_env)
//---------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="mul_env",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//-------------------- class handles -----------------------------------------
mul_agent agent_h;
mul_coverage coverage_h;
mul_scoreboard scoreboard_h;
//----------------------------------------------------------------------------
//---------------------- build phase -----------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent_h = mul_agent::type_id::create("agent_h",this);
coverage_h = mul_coverage::type_id::create("coverage_h",this);
scoreboard_h = mul_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:mul_env
mul_test
class mul_test extends uvm_test;
//--------------------------------------------------------------------------
`uvm_component_utils(mul_test)
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function new(string name="mul_test",uvm_component parent);
super.new(name,parent);
endfunction
//--------------------------------------------------------------------------
mul_env env_h;
int file_h;
//--------------------------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env_h = mul_env::type_id::create("env_h",this);
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function void end_of_elobartion_phase(uvm_phase phase);
//factory.print();
$display("End of eleboration phase in agent");
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function void start_of_simulation_phase(uvm_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);
set_report_verbosity_level_hier(UVM_LOW);
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
task run_phase(uvm_phase phase);
mul_sequence seq1,seq2;
in1_0_seq seq3;
mul_sequence_short seq4;
mul_sequence_high seq5;
phase.raise_objection(this);
seq1= mul_sequence::type_id::create("seq1");
seq2= mul_sequence::type_id::create("seq2");
seq3= in1_0_seq::type_id::create("seq3");
seq4=mul_sequence_short::type_id::create("seq4");
seq5=mul_sequence_high::type_id::create("seq5");
seq1.loop_count=100;
seq2.loop_count=100;
seq4.loop_count=200;
seq5.loop_count=200;
seq1.start(env_h.agent_h.sequencer_h);
seq2.start(env_h.agent_h.sequencer_h);
seq3.start(env_h.agent_h.sequencer_h);
seq4.start(env_h.agent_h.sequencer_h);
seq5.start(env_h.agent_h.sequencer_h);
#10;
phase.drop_objection(this);
endtask
//--------------------------------------------------------------------------
endclass:mul_test
tb_pkg
`ifndef TB_PKG
`define TB_PKG
`include "uvm_macros.svh"
package tb_pkg;
import uvm_pkg::*;
`include "mul_sequence_item.sv" // transaction class
`include "mul_sequence.sv" // sequence class
`include "mul_sequencer.sv" // sequencer class
`include "mul_driver.sv" // driver class
`include "mul_monitor.sv"
`include "mul_agent.sv" // agent class
`include "mul_coverage.sv" // coverage class
`include "mul_scoreboard.sv"
`include "mul_env.sv" // environment class
`include "mul_test.sv" // test1
endpackage
`endif
tb_top
`include "interface.sv"
`include "tb_pkg.sv"
module top;
import uvm_pkg::*;
import tb_pkg::*;
bit clk;
//----------------------------------------------------------------------------
intf i_intf(clk);
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
mul DUT(.in1(i_intf.in1),
.in2(i_intf.in2),
.clk(i_intf.clk),
.out(i_intf.out)
);
//----------------------------------------------------------------------------
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("mul_test");
end
//----------------------------------------------------------------------------
endmodule
Link For Code : https://www.edaplayground.com/x/s9tj
Output Result :
UVM_INFO /home/runner/mul_coverage.sv(50) @ 6305: uvm_test_top.env_h.
coverage_h [mul_coverage] Coverage is 85.937500
UVM_INFO /home/runner/mul_scoreboard.sv(109) @ 6305: uvm_test_top.env_h.
scoreboard_h [PASSED] *** TEST PASSED - 629 vectors ran,629 vectors passed***
For cross verify scoreboard you can change something in design and see whether it is working properly or not.
Thank You, for reading. have a nice Day 🙂🙂😇.