You are on page 1of 16

UVM

TESTBENCH
ARCHITECTURE
UVM TB ARCHITECTURE
Testbench Architecture

Verification Component includes:

Sequence_item - Data item based on the DUT protocol


Sequencer -Route sequence_items from a sequence to the driver
Driver - It converts sequence_item into the pin level for DUT
Monitor - It converts pin-level data to the transactions for use in the scoreboard,
coverage model, etc.,
Agent – Encapsulated with Sequencer, Driver, and Monitor
Agent Configuration ACTIVE — Sequencer, Driver
Agent Configuration PASSIVE—Monitor
Test - configuring the testbench. Initiate the testbench components construction
process by building the next level down in the hierarchy example:
environment(env). Initiate the stimulus by starting the sequence.
Environment - It is a container component for grouping higher-level
components like agents and scoreboards.
Scoreboard: - Receive data items from the monitor and compare them with the
expected value.
Configuration object -A container object, used to pass information to the agent
which affects what it does and how it is built and connected
Sequencers and Drivers are connected using TLM ports
Sequence: It defines the sequence in which the data items need to be generated
and sent/received to/from the driver.
Sequencer: It is responsible for routing the data packets(sequence_item)
generated in sequence to the driver or vice versa.
Interface: Contains design signals that can be driven or monitored.
Verification of Mod-13 Loadable UP Counter

Design Diagram

Testbench Architecture
============
//Interface
============
interface counter_inf (input bit clock);

logic [3:0] data_in ;


logic [3:0] data_out ;
logic load ;
logic rst;

//Driver Clocking Block


clocking driver_cb@(posedge clock);
default input #1 output #1;
output rst ;
output data_in;
output load;
endclocking

// output monitor clocking block


clocking output_mon_cb @(posedge clock);
default input #1 output #1 ;
input data_out ;
endclocking

//input monitor clocking block


clocking input mon cb@(posedge clock);
default input #1 output #1 ;
input load ;
input rst;
input data_in;
endclocking

//driver modport
modport DRIVER (clocking driver_cb);

//input Monitor modport


modport INPUT_MON (clocking input_mon_cb);

//Output monitor modport


modport OUTPUT_MON (clocking output_mon_cb );
endinterface
===================================
//Transaction Class (Sequence Ieam)
===================================
class counter_trans extends uvm_sequence_item ;
`uvm_object_utils (counter_trans)

rand logic rst ;


rand logic load;
randc logic [3:0] data_in;
logic [3 : 0] data_out ;
static int no_of_xtn ;

constraint VALID_RST {rst dist{ 1:=1,0:=15};}


constraint VALID_LOAD {load dist{ 1:= 1, 0:=15};}
constraint VALID_DATA {data_in inside {[0:15]};}

function new (string name = " counter_trans");


super.new(name);
endfunction:new

function bit do_compare (uvm_object rhs ,uvm_comparer comparer );


counter_trans rhs_;
if (!$cast (rhs_,rhs))
begin
`uvm_fatal (" do_compare","cast of the rhs object failed")
return 0;
end
return super.do_compare (rhs,comparer) &&
data_out== rhs_.data_out;
endfunction:do_compare

function void do_print (uvm_printer printer);


super.do_print (printer);
printer.print_field ("rst", this.rst, '1 , UVM DEC);
printer.print_field ("load ", this.load , '1 , UVM DEC);
printer.print_field (" data_in", this.data_in , 4, UVM_DEC);
printer.print_field ("data_out", this.data_out , 4 , UVM_DEC );
endfunction:do_print

function void post_randomize ();


no of xtn++;
`uvm_info("randomized data", $sformatf ("randomized transaction [%d] is \n%s"
no_of_xtn , this.sprint ()), UVM_MEDIUM)
endfunction :post_randomize
endclass

=====================
//Configuration Class
=====================
class counter_env_config extends uvm_object;
`uvm_object_utils(counter_env_config)
bit has_input_agent ;
bit has_output_agent ;
bit has_scoreboard ;
uvm_active_passive_enum input_agent_is_active ;
uvm_active_passive_enum output_agent_is_active;
virtual counter_inf vif ;

function new (string name = "counter_env_config");


super.new(name);
endfunction
endclass

=====================
//Input Driver
=====================
class counter_input_driver extends uvm_driver #(counter_trans);
`uvm_component_utils (counter_input_driver)
virtual counter_inf.DRIVER drv_inf;
counter_trans data2duv_pkt ;
counter_env_config m_cfg;

function new (string name="counter_input_driver", uvm_component parent);


super.new(name ,parent);
endfunction

function void build_phase (uvm_phase phase);


super.build_phase(phase);
if(!uvm_config_db
#(counter_env_config)::get(this,"","counter_env_config",m_cfg))
`uvm_fatal("CONFIG","cannot get() m_cfg from uvm_config_db. Have you set()
it?")
endfunction

function void connect_phase(uvm_phase phase );


drv_inf = m_cfg.vif ;
endfunction

task run_phase(uvm_phase phase);


forever
begin
seq_item_port.get_next_item =(req);
send_to_dut(req);
seq_item_port.item_done();
end
endtask

virtual task send_to_dut(counter_trans data2duv_pkt);


@(drv_inf.driver_cb);
drv_inf.driver_cb.data_in<=data2duv_pkt.data_in;
drv_inf.driver_cb.rst<=data2duv_pkt.rst;
drv_inf.driver_cb.load<=data2duv_pkt.load ;
endtask
endclass
=====================
//Input Sequencer
=====================
class counter_input_sequencer extends uvm_sequencer #(counter_trans);
`uvm_component_utils(counter_input_sequencer)

function new(string name="counter_input_sequencer", uvm_component parent);


super.new(name ,parent );
endfunction
endclass

=====================
//Input Monitor
=====================
class counter_input_monitor extends uvm_monitor ;
`uvm_component_utils (counter_input_monitor)

virtual counter_inf.INPUT_MON mon_if;


counter_trans drv2mon_pkt;
counter_env_config m_cfg ;
uvm_analysis_port#(counter_trans) monitor_port;

function new(string name="counter_input_monitor", uvm_component parent);


super.new(name ,parent);
endfunction

function void build_phase(uvm_phase phase);


super.build_phase (phase);
if (!uvm_config_db #(counter_env_config)::get
(this,"","counter_env_config",m_cfg ))
`uvm_fatal(get_type_name,"cannot get() m_cfg")
monitor_port = new("monitor_port", this);
endfunction

function void connect_phase(uvm_phase phase);


mon_if =m_cfg.vif ;
endfunction

task run_phase (uvm_phase phase);


@(mon_if.input_mon_cb);
forever
monitor();
endtask

task monitor();
begin
@(mon_if.input_mon_cb);
drv2mon_pkt = counter_trans::type_id::create("drv2mon_pkt") ;
drv2mon_pkt.load = mon_if.input_mon_cb.load ;
drv2mon_pkt.rst =mon_if.input_mon_cb.rst;
drv2mon_pkt.data_in= mon_if.input_mon_cb.data_in;
`uvm_info(get_type_name, $sformatf("input monitor has captured below
transaction \n%s", drv2mon_pkt.sprint ()), UVM_MEDIUM)
monitor_port.write(drv2mon_pkt);
end
endtask
endclass
=====================
//Input Agent
=====================
class counter_input_agent extends uvm_agent;
`uvm_component_utils(counter_input_agent)

counter_env_config m_cfg ;

counter_input_monitor monh;
counter_input_sequencer seqrh;
counter_input_driver drvh;

function new(string name = "counter_input_agent", uvm_component parent =


null);
super.new(name, parent);
endfunction

function void build_phase (uvm_phase phase);

super.build_phase(phase);

if(!uvm_config_db #(counter_env_config)::get
(this,"","counter_env_config",m_cfg))
`uvm_fatal("CONFIG","cANNOT GET() m_cfg from uvm_config_db. Have YOU set ()
it")
monh=counter_input_monitor::type_id::create("monh",this);

if(m_cfg input_agent_is_active==UVM_ACTIVE)
begin
drvh=counter_input_driver::type_id::create(" drvh",this);
seqrh=counter_input_sequencer ::type_id ::create("seqrh",this) ;
end
endfunction

function void connect_phase (uvm_phase phase);


if(m_cfg.input_agent_is_active==UVM_ACTIVE)
begin
drvh.seq_item_port.connect(seqrh.seq_item_export);
end
endfunction
endclass : counter_input_agent

=====================
//Output Monitor
=====================
class counter_output_monitor extends uvm_monitor ;
'uvm_component_utils(counter_output_monitor)

virtual counter_inf.OUTPUT MON rdmon_inf;


counter_trans output_mon_pkt ;
counter_env_config m cfg;
uvm_analysis_port#(counter_trans) monitor_port;

function new(strinq name"counter_input_monitor", uvm_component parent );


super.new(name ,parent);
endfunction
function void build_phase (uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(counter_env_config)::get(this,"",
"counter_env_config",m_cfg))
'uvm_fatal (get_type_name ,"cannot qet() m_cfg ")
monitor_port=new("monitor_port", this);
endfunction

function void connect_phase(uvm_phase phase);


rdmon_inf = m_cfg.vif ;
endfunction

task run_phase (uvm_phase phase);


repeat(2)
@(rdmon_inf.output_mon_cb);
forever
monitor();
endtask

task monitor ();


output_mon_pkt "' counter_trans ::type_id::create ("-.utput mon p :t");
@(rdmon inf .output mon cb);
output_mon_pkt.data_out = rdmon_inf.output_mon_cb .data_out ;
'uvm_info(get_type_name, $sformatf ("output monitor has captured below
transaction \n%s", output_mon_pkt .sprint() ) , UVM_MEDIUM)
monitor_port.write(output_mon_pkt );
endtask
endclass

=====================
//Output Agent
=====================
class counter_output_agent extends uvm_agent;
`uvm_cornponent_utils(counter_output_agent)

counter_env_config m_cfg ;
counter_output_monitor monh ;
function new (string name = "counter_output_agent",uvm_component parent
=null);
super.new (name , parent);
endfunction

function void build_phase (uvm_phase phase);


super.build_phase (phase);
if(!uvm_config_db #(counter_env_config)::get
(this,"","counter_env_config",m_cfg))
'uvm_fatal ("C0NIG"," cannot get() m_cfg from uvm_config_db.Have you set()
?")
if{m_cfg.output_agent_is_active==UVM_PASSIVE)
monh=counter_output_monitor ::type_id ::create ("monh", this);
endfunction
endclass : counter_output_agent
=======================================
//Scoreboard with Reference Model Logic
=======================================

class counter_scoreboard extends uvm_scoreboard;


`uvm_component_utils(counter_scoreboard)

uvm_tlm_analysis_fifo #(counter_trans) input_mon_fifo;


uvm=tlm_analysis=fifo #(counter_trans) output_mon_fifo ;

counter_trans input_mon_pkt;
counter_trans output_mon_pkt:
counter_trans expected_output_pkt ;
counter_trans cov_data_pkt;

int data_verified =0;


int input_mon_pkt_count =0;
int output_mon_pkt_count =0;

covergroup counter_coverage;
option.per_instance= 1;
LOAD_DATA : coverpoint cov_data_pkt.data_in {
bins ZERO ={0};
bins LOWl ={[1:2]};
bins LOW2 ={[3:4]};
bins MID_LOW ={[5:6]};
bins MID ={[7:8]};
bins MID HIGH ={[9:10]};
bins HIGHl ={[11:12]};
bins HIGH2 ={[13:14]};
bins MAX ={[15]};
}

RESET_CMD : coverpoint cov_data_pkt.rst{


bins cmd_rst ={1}I;
}
LOAD_CMD : coverpoint cov_data_pkt.load {
bins load_dut = {1};
}
READxWRITE : cross LOAD_CMD, LOAD_DATA;

function new(string name,uvm_component parent);


super.new(name.parent);
input_mon_fifo= new("input_mon_fifo",this) ;
output_mon_fifo= new(" output_mon_fifo", this) ;
expected_output_pkt=counter_trans::type_id::create (" expected_output_pkt");
;
counter_coverage=new:
endfunction

task run_phase (uvm_phase phase):


forever
begin
input_mon_fito.get(input_mon_pkt);
input_mon_pkt_count++:
'uvm_into(get_type_name, $sformatf ("sb has got below packet from input
monitor \n%s", input_mon_pkt .sprint ()), UVM_MEDIUM)
output_mon_fifo.get(output_mon_pkt );
output_mon_pkt_count++;
'uvm_into(get_type_name, $sformatf ("sb has got below packet from output
monitor \n%s", output_mon_pkt .sprint ()), UVM_MEDIUM)

ref_model_logic();
validate_output();
end
endtask

task ref_model_logic();
begin
if (input_mon_pkt.rst || (input_mon_pkt.load&input_mon_pkt.data_in >=13))
expected_output_pkt.data_out = 4'b0; ;
else if(input_mon_pkt.load)
expected_output_pkt.data_out = input_mon_pkt.data_in ;
else if (expected_output_pkt.data_out >=13)
expected_output_pkt.data_out = 4'b0;
else
expected_output_pkt.data_out=expected_output_pkt.data_out + 1'b1;
end
endtask

virtual task validate_output ();


if (!expected_output_pkt.compare(output_mon_pkt))
begin:failed compare
'uvm_info(get_type_name , $sformatf (" expected packet is below \n%s
",expected_output_pkt.sprint ()), UVM_MEDIUM)
'uvm_info(get_type_name , $sformatf (" dut's output packet is below \n%s
",expected_mon_pkt.sprint ()), UVM_MEDIUM)

//Sfinish ;
end:failed_compare

else
begin
'uvm info (get type name (), $sformatf ("Data Match successful ") ,
UVM_MEDIUM)
data_vrified++ ;
end
cov_data_pkt=input_mon_pkt;
counter_coverage.sample();
endtask

function void report_phase (uvm_phase phase);


$display (" \n----------- Scoreboard ---------- \n ");
$display (" input mon pkt count = %0d , output mon pkt count = %0d, no of
successful comparisions = %0d\n", input_mon_pkt_count,output_mon_pk t_count
,data_verified);
$display (" -------------------------------------- \n ");
endfunction
endclass
=====================
//Environment
=====================
class counter_env extends uvm_env ;

`uvm_component_utils(counter_env)
counter_input_agent input_agent_h ;
counter_output_agent output_agent_h;
counter_scoreboard scoreboard_h ;

counter_env_config m_cfg ;

function new (string name = "counter_input_agent" uvm_component parent =


null);
super.new(name , parent);
endfunction

function void build_phase (uvm_phase phase);


if(!uvm_config_db #(counter_env_config)::get (this,"","counter env config",m
cfg))
'uvm_fatal(get_type_name,"cannot get from contig db. Have you set() it?")
if (m_cfg.has_input_agent )
input_agent_h = counter_input_agent::type_id::create ("input_agent_h",this);
if(m_cfg.has_output_agent)
output_agent_h = counter_output_agent::type_id ::create ("output_agent_h"
this);
if(m_cfg .has_scoreboard)
scoreroard_h = counter_scoreboard ::type_id::create (" scoreboard_h" ,this);
super build_phase(phase);
endfunction

function void connect_phase(uvm_phase phase);


uvm_top.print_topology();
if(m_cfg.has_input_agent && m_cfg.has_scoreboard)
input_agent_h.monh.monitor_port.connect(scoreboard_h.input_mon_fifo.analysis_
export);
if(m_cfg.has_output_agent && m_cfg.has_scoreboard)
output_agent_h.monh.monitor_port.connect(scoreboard_h.output_mon_fifo.analysi
s_export);
endfunction
endclass
=====================
//Sequence
=====================
class counter_seq extends uvm_sequence # (counter_trans );
`object_utils(counter_seq)
int xtn_num =1;
function new (string name = "counter_seq");
super.new(name);
endfunction

task body ();


repeat(number_of_transactions)
begin
req=counter_trans::type_id::create("req");
start_item(req);
if (xtn_num ==1)
begin
assert(req.randomize() with {rst==1;});
xtn num++;
end
else
assert (req.randomize ());
finish_item(req);
end
endtask endclass

=====================
//Base testcase
=====================
import counter_pkg ::*;

class counter_base_test extends uvm_test;


`uvm_component_utils(counter_base_test)
counter_env_config m_cfg;
counter_env counter_env_h;

function new(string name = "counter_base_test",uvm_component parent=null);


super.new(name , parent);
endfunction

function void build_phase (uvm_phase phase);


m_cfg = counter_env_config ::type_id::create (" m_cfg");
if(!uvm_config_db #(virtual counter_inf )::get(this,"", "vif",m_cfg.vif))
`uvm_fatal(get_type_name," cannot get() interface vif from uvm_config_db");
m_cfg.has_input_agent =1;
m_cfg.has_outp1t_agent =1;
m_cfg.has_scoreboard =1;
m_cfg.output_agent_is_active = UVM_PASSIVE ;
m_cfg.input_agent_is_active = UVM_ACTIVE ;

uvm_config_db #(counter_env_config)::set(this,"*","counter_env_config",m
cfg);
counter_env_h = counter_env::type_id::create (" counter_env_h", this);
endfunction
endclass
=====================
//Derived testcase
=====================

class counte_test_1 extends counter base test;


`uvm_component_utils(counter_test_l)

counter_seq cnunter_seq_h ;

function new (string name = "counte_test_1" uvm_component parent = null);


super.new(name , parent);
endfunction

function void build_phase (uvm_phase phase);


super.build_phase(phase);
endfunction

task run_phase (uvm_phase phase );


phase.raise_objection (this);
counter_seq_h=counter_seq ::type_id ::create ("counter_seq_h");
counter_seq h.start (counter_env_h.input_agent_h.seqrh);
#30;
phase.drop_objection (this);
endtask
endclass

=====================
//Package
=====================
package counter_pkg;

int number_of_transactions=100 ;
import uvm_pkg ::*;

`include "uvm_macros.svh"

`include "counter_trans.sv"
`include "counter_env_config.sv"
`include "counter_input_driver.sv"
`include "counter_input_monitor.sv"
`include "counter_input_sequencer.sv "
`include "counter_input_agent.sv"
`include "counter_output_monitor.sv"
`include "counter_output_agent.sv"
`include "counter_scoreboard.sv"
`include "counter_env.sv "
`include "counter_sequence.sv"
`include "counter-test.sv"

endpackage
=====================
//Top Module
=====================
module counter_top ();

import counter_pkg ::*;


import uvm_pkg: :*;
parameter cycle =10;
reg clk ;
counter_inf DUT_INF (clk);

counter_load DUv(.clk(clk),
.rst (DUT_INF .rst),
.load (DUT_INF .loadl ,
.data out (DUT INF .data out),
.data=in (DUT_INF .data_ln));

initial
begin
uvm_config_db #(virtual counter_inf)::set (null,"*","vif",DUT_INF);
run_test ();
end

//Generate the clock


initial
begin
clk=1'b0;
forever
# (cycle/2) clk=clk;
end

endmodule

You might also like