Hello again, i this blog we will verify 64KB RAM with UVM , Our TB Also Contain Scoreboard So That It Can Check Itself(self checking TB).I assume you know basic UVM.
Description of Design Signals is shown Below.
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Design of 64KB Ram
// Data input width = 8 -> data_in
// Data output width = 8 -> data_out
// Address width = 16 -> addr
// Address range 0 to 65535
// Synchronous with clk -> clk , rdn_wr, rst_p
// rdn_wr signal -> when rdn_wr=0 means read rdn_wr=1 means write
// synchronous reset -> rst_p means active high reset
////////////////////////////////////////////////////////////////////////////////////////////////////////
Major components of our TB is Coverage Collector and Scoreboard.
Sequence description :
-> write 0 (zero) in all address and read from all addresses.
-> write FF in all address and read from all addresses.
-> first write and read from same location consecutively
-> write in two locations and read from these two location
-> write randomly at any address
-> read randomly from any address
-> reset sequence
NOTE : you will find these in ram_sequence.sv file
Test Bench Architecture is shown below.
Design
////////////////////////////////////////////////////////////////////////////
// design of 64KB Ram
// data input width = 8
// data output width = 8
// address width = 16
// address range 0 to 65535
// synchronous with clk
// rdn_wr signal -> when rdn_wr=0 means read rdn_wr=1 means write
// synchronous reset -> rst_p means active high reset
////////////////////////////////////////////////////////////////////////////
module RAM(clk,
rst_p,
data_in,
data_out,
addr,
rdn_wr
);
parameter ADDR_WIDTH=16;
parameter DATA_WIDTH=8;
input clk;
input rst_p;
input rdn_wr;
input [DATA_WIDTH-1:0]data_in;
input [ADDR_WIDTH-1:0]addr;
output reg [DATA_WIDTH-1:0]data_out;
reg [DATA_WIDTH-1:0] mem[(2**ADDR_WIDTH-1):0];
always@(posedge clk )
begin
if(rst_p==1'b1)
begin
for(int unsigned i=0;i<2**ADDR_WIDTH;i++)
begin
mem[i]<=0;
data_out<=0;
end
end
end
always@(addr,data_in,rdn_wr)
begin
if(rdn_wr==1'b1) //write into RAM
begin
mem[addr]=data_in;
end
else if (rdn_wr==1'b0) // read from RAM
begin
data_out=mem[addr];
end
else
begin
data_out=data_out;
end
end
endmodule
Interface
interface intf(input bit clk);
// ------------------- port declaration-------------------------------------
parameter ADDR_WIDTH=16;
parameter DATA_WIDTH=8;
logic [DATA_WIDTH-1:0]data_in;
logic [DATA_WIDTH-1:0]data_out;
logic rdn_wr;
logic rst_p;
logic [ADDR_WIDTH-1:0]addr;
//--------------------------------------------------------------------------
//------------- clocking & modport declaration -----------------------------
/* clocking clocking_block_name @(posedge signal_name);
default input #1step output #1step;
output //input of DUT
input //output of DUT
endclocking
*/
//modport modport_name(clocking name_of_block);
//--------------------------------------------------------------------------
endinterface
ram_sequence_item
class ram_sequence_item extends uvm_sequence_item;
//------------ i/p || o/p field declaration-----------------
parameter ADDR_WIDTH=16;
parameter DATA_WIDTH=8;
rand logic [DATA_WIDTH-1:0]data_in;
rand logic rdn_wr;
rand logic [ADDR_WIDTH-1:0]addr;
logic rst_p;
logic [DATA_WIDTH-1:0]data_out;
//---------------- register ram_sequence_item class with factory --------
`uvm_object_utils_begin(ram_sequence_item)
`uvm_field_int( data_in ,UVM_ALL_ON)
`uvm_field_int( rdn_wr ,UVM_ALL_ON)
`uvm_field_int( rst_p ,UVM_ALL_ON)
`uvm_field_int( addr ,UVM_ALL_ON)
`uvm_field_int( data_out ,UVM_ALL_ON)
`uvm_object_utils_end
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="ram_sequence_item");
super.new(name);
endfunction
//----------------------------------------------------------------------------
function string convert2string();
return $sformatf("mux_sequence_item",$sformatf("data_in=%0f addr=%0f \
rdn_wr=%0b rst_p=%0b data_out=%0f",data_in,addr,rdn_wr,rst_p,data_out));
endfunction
endclass:ram_sequence_item
ram_sequencer
class ram_sequencer extends uvm_sequencer#(ram_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(ram_sequencer)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
endclass:ram_sequencer
ram_sequence
NOTE: Only Few Sequence is shown here other sequence you will find in link , which is at bottom.
class ram_sequence extends uvm_sequence#(ram_sequence_item);
//----------------------------------------------------------------------------
`uvm_object_utils(ram_sequence)
//----------------------------------------------------------------------------
ram_sequence_item txn;
//----------------------------------------------------------------------------
function new(string name="ram_sequence");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
virtual task body();
endtask:body
//----------------------------------------------------------------------------
endclass:ram_sequence
/********************************************************************
class name : reset_sequence
description : ->reset sequence for resetting RAM
*********************************************************************/
class reset_sequence extends ram_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(reset_sequence)
//----------------------------------------------------------------------------
ram_sequence_item txn;
//----------------------------------------------------------------------------
function new(string name="reset_sequence");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
txn=ram_sequence_item::type_id::create("txn");
start_item(txn);
txn.rst_p=1;
txn.data_in=0;
txn.rdn_wr=0;
txn.addr=0;
finish_item(txn);
endtask:body
//----------------------------------------------------------------------------
endclass:reset_sequence
/********************************************************************
class name : write_only
description : ->it will only write in RAM , in which data , address
are random
->you can change iteration to any value
*********************************************************************/
class write_only extends ram_sequence;
//----------------------------------------------------------------------------
`uvm_object_utils(write_only)
//----------------------------------------------------------------------------
ram_sequence_item txn;
int unsigned iteration=100;
//----------------------------------------------------------------------------
function new(string name="write_only");
super.new(name);
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
task body();
repeat(iteration)
begin
txn=ram_sequence_item::type_id::create("txn");
start_item(txn);
txn.randomize()with{txn.rdn_wr==1;};
txn.rst_p=0;
finish_item(txn);
end
endtask:body
//----------------------------------------------------------------------------
endclass:write_only
ram_driver
class ram_driver extends uvm_driver #(ram_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(ram_driver)
//----------------------------------------------------------------------------
uvm_analysis_port #(ram_sequence_item) drv2sb;
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
drv2sb=new("drv2sb",this);
endfunction
//----------------------------------------------------------------------------
//-------------------------- virtual interface handle -----------------------
virtual interface intf vif;
//----------------------------------------------------------------------------
//------------------------- get interface handle 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
endfunction
//----------------------------------------------------------------------------
//---------------------------- run task --------------------------------------
task run_phase(uvm_phase phase);
ram_sequence_item txn;
forever begin
seq_item_port.get_next_item(txn);
// write driver code here
@(posedge vif.clk);
vif.data_in <= txn.data_in;
vif.rdn_wr <= txn.rdn_wr;
vif.rst_p <= txn.rst_p;
vif.addr <= txn.addr;
#1;
drv2sb.write(txn); // send data to scoreboard
`uvm_info(get_type_name(),txn.convert2string(),UVM_MEDIUM)
// txn.printf();
seq_item_port.item_done();
end
endtask
//----------------------------------------------------------------------------
endclass:ram_driver
ram_monitor
class ram_monitor extends uvm_monitor;
//------------------------------------------------------------------------
`uvm_component_utils(ram_monitor)
//------------------------------------------------------------------------
//------------------- constructor ----------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//------------------------------------------------------------------------
//---------------- sequence_item class ---------------------------------------
ram_sequence_item txn;
//----------------------------------------------------------------------------
//------------------------ virtual interface handle---------------------------
virtual interface intf vif;
//----------------------------------------------------------------------------
//------------------------ analysis port -------------------------------------
uvm_analysis_port#(ram_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=ram_sequence_item::type_id::create("txn",this);
endfunction
//----------------------------------------------------------------------------
//-------------------- run phase ---------------------------------------------
task run_phase(uvm_phase phase);
forever
begin
// write monitor code here
@(negedge vif.clk);
txn.addr = vif.addr;
txn.data_in = vif.data_in;
txn.data_out = vif.data_out;
txn.rdn_wr = vif.rdn_wr;
txn.rst_p = vif.rst_p;
ap_mon.write(txn);
end
endtask
//-----------------------------------------------------------------------
endclass:ram_monitor
ram_agent
class ram_agent extends uvm_agent;
//----------------------------------------------------------------------------
`uvm_component_utils(ram_agent)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//----------------- class handles --------------------------------------------
ram_sequencer sequencer_h;
ram_driver driver_h;
ram_monitor monitor_h;
//----------------------------------------------------------------------------
//---------------------- build phase -----------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver_h = ram_driver::type_id::create("driver_h",this);
sequencer_h = ram_sequencer::type_id::create("sequencer_h",this);
monitor_h = ram_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:ram_agent
ram_coverage
class ram_coverage extends uvm_subscriber #(ram_sequence_item);
//----------------------------------------------------------------------------
`uvm_component_utils(ram_coverage)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
dut_cov=new();
endfunction
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
ram_sequence_item txn;
real cov;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
covergroup dut_cov;
option.per_instance=1;
ADDR:coverpoint txn.addr { option.auto_bin_max=65535;}
RDN_WR:coverpoint txn.rdn_wr;
ADDR_X_RDN_WR:cross ADDR,RDN_WR;
// ADDR_X_RDN_WR:cross ADDR,RDN_WR {option.cross_auto_bin_max=131072;}
// option.cross_auto_bin_max gives error in Aldec
DATA:coverpoint txn.data_in { option.auto_bin_max=255; }
endgroup:dut_cov
//----------------------------------------------------------------------------
//--------------------- write method ----------------------------------------
function void write(ram_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_LOW)
endfunction
//----------------------------------------------------------------------------
endclass:ram_coverage
ram_scoreboard
`uvm_analysis_imp_decl( _drv )
`uvm_analysis_imp_decl( _mon )
class ram_scoreboard extends uvm_scoreboard;
`uvm_component_utils(ram_scoreboard)
uvm_analysis_imp_drv #(ram_sequence_item, ram_scoreboard) aport_drv;
uvm_analysis_imp_mon #(ram_sequence_item, ram_scoreboard) aport_mon;
uvm_tlm_fifo #(ram_sequence_item) expfifo;
uvm_tlm_fifo #(ram_sequence_item) outfifo;
int VECT_CNT, PASS_CNT, ERROR_CNT;
parameter ADDR_WIDTH=16;
parameter DATA_WIDTH=8;
function new(string name="ram_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
reg [DATA_WIDTH-1:0] mem_test[(2**ADDR_WIDTH-1):0];
reg [ADDR_WIDTH-1:0] t_data_out;
function void write_drv(ram_sequence_item tr);
`uvm_info("write_drv STIM", tr.convert2string(), UVM_MEDIUM)
if(tr.rst_p==1)
begin
$display("------------------------------ RESET ------------------");
`uvm_info("RESET in scoreboard", "----- RESET ---------", UVM_MEDIUM)
for(int unsigned i=0;i<2**ADDR_WIDTH;i++)
begin
mem_test[i]=0;
tr.addr=0;
tr.data_in=0;
t_data_out=0;
tr.rdn_wr=0;
end
end
if(tr.rdn_wr==1)
begin
mem_test[tr.addr]=tr.data_in;
end
if(tr.rdn_wr==0)
begin
t_data_out=mem_test[tr.addr];
end
else
begin
t_data_out=t_data_out;
end
tr.data_out=t_data_out;
void'(expfifo.try_put(tr));
endfunction
function void write_mon(ram_sequence_item tr);
`uvm_info("write_mon OUT ", tr.convert2string(), UVM_MEDIUM)
void'(outfifo.try_put(tr));
endfunction
task run_phase(uvm_phase phase);
ram_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);
// `uvm_info("[exp]", exp_tr.convert2string(), UVM_MEDIUM)
// `uvm_info("[out]", out_tr.convert2string(), UVM_MEDIUM)
if(out_tr.rst_p==1) begin
$display("RESET Do not compare");
end
/*
else if (out_tr.compare(exp_tr)) begin
PASS();
`uvm_info ("PASS ",out_tr.convert2string() , UVM_LOW)
end
*/
else if(out_tr.data_out==exp_tr.data_out)
begin
PASS();
`uvm_info ("PASS ",out_tr.convert2string() , UVM_LOW)
end
else begin
ERROR();
`uvm_info ("ERROR [ACTUAL_OP]",out_tr.convert2string() , UVM_LOW)
`uvm_info ("ERROR [EXPECTED_OP]",exp_tr.convert2string() , UVM_LOW)
`uvm_warning("ERROR",out_tr.convert2string())
end
end
endtask
function void PASS();
VECT_CNT++;
PASS_CNT++;
endfunction
function void ERROR();
VECT_CNT++;
ERROR_CNT++;
endfunction
endclass
ram_env
class ram_env extends uvm_env;
//---------------------------------------------------------------------------
`uvm_component_utils(ram_env)
//---------------------------------------------------------------------------
//----------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//----------------------------------------------------------------------------
//-------------------- class handles -----------------------------------------
ram_agent agent_h;
ram_coverage coverage_h;
ram_scoreboard scoreboard_h;
//----------------------------------------------------------------------------
//---------------------- build phase -----------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent_h = ram_agent::type_id::create("agent_h",this);
coverage_h = ram_coverage::type_id::create("coverage_h",this);
scoreboard_h = ram_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:ram_env
ram_test
NOTE : Only one test is shown here other you will find in link provided.
class ram_test extends uvm_test;
//--------------------------------------------------------------------------
`uvm_component_utils(ram_test)
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function new(string name="",uvm_component parent);
super.new(name,parent);
endfunction
//--------------------------------------------------------------------------
ram_env env_h;
int file_h;
reset_sequence rst_seq;
write_only write_seq;
read_only read_seq;
read_only read_seq1;
//--------------------------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env_h = ram_env::type_id::create("env_h",this);
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
function void end_of_elobartion_phase(uvm_phase phase);
$display("End of eleboration phase in agent");
// print topology
// print();
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);
env_h.set_report_verbosity_level_hier(UVM_LOW);
print(); //prints topologi
endfunction
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
task run_phase(uvm_phase phase);
phase.raise_objection(this);
rst_seq = reset_sequence::type_id::create("rst_seq");
write_seq = write_only::type_id::create("write_seq");
read_seq = read_only::type_id::create("resd_seq");
read_seq1 = read_only::type_id::create("resd_seq1");
rst_seq.start(env_h.agent_h.sequencer_h);
read_seq.start(env_h.agent_h.sequencer_h);
write_seq.start(env_h.agent_h.sequencer_h);
read_seq.start(env_h.agent_h.sequencer_h);
#10;
phase.drop_objection(this);
endtask
//--------------------------------------------------------------------------
endclass:ram_test
tb_pkg
`ifndef TB_PKG
`define TB_PKG
`include "uvm_macros.svh"
package tb_pkg;
import uvm_pkg::*;
`include "ram_sequence_item.sv" // transaction class
`include "ram_sequence.sv" // sequence class
`include "ram_sequencer.sv" // sequencer class
`include "ram_driver.sv" // driver class
`include "ram_monitor.sv"
`include "ram_agent.sv" // agent class
`include "ram_coverage.sv" // coverage class
`include "ram_scoreboard.sv" // scoreboard class
`include "ram_env.sv" // environment class
`include "ram_test.sv" // test
endpackage
`endif
testbench_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);
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
RAM DUT (.clk(i_intf.clk),
.data_in(i_intf.data_in),
.data_out(i_intf.data_out),
.rst_p(i_intf.rst_p),
.addr(i_intf.addr),
.rdn_wr(i_intf.rdn_wr)
);
//----------------------------------------------------------------------------
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("test_write_read_all0");
// OR use +UVM_TESTNAME="test_name"
end
//----------------------------------------------------------------------------
endmodule
Link For Code : https://www.edaplayground
Thank You for Reading , have a nice day 😊😊.
KeyBoard Shortcut : Windows+v for clipboard history.
You Might Also Like