Fifo SV
Fifo SV
Functionality:
• Data Storage: A FIFO holds data in a sequential manner, storing it in the order it was received.
• Controlled Flow: The buffer maintains two pointers—one for the write (input) side and one for the read (output)
side. Data is written into the buffer at the write pointer and read out at the read pointer.
• Synchronization: In systems with clock domain crossing, FIFOs help by storing data temporarily until it can be
safely passed to a different clock domain.
• Overflow and Underflow Protection: FIFOs can manage situations where data input exceeds the available space
(overflow) or when data is being read from an empty buffer (underflow), usually by asserting status flags or error
signals.
Usage:
• Data Communication: FIFOs are essential in communication systems, especially for data buffering between
devices that produce and consume data at different rates, such as processors and peripheral devices.
• Pipelining: In pipeline architectures, FIFOs enable data buffering between processing stages.
• Clock Domain Crossing: FIFOs are used to safely transfer data between circuits operating under different clock
frequencies.
• Audio and Video Processing: In multimedia applications, FIFOs help in managing streams of audio or video
data, ensuring a smooth flow from one processing stage to another.
Design before correction :
////////////////////////////////////////////////////////////////////////////////
// Author: Kareem Waseem
// Course: Digital Verification using SV & UVM
//
// Description: FIFO Design
//
////////////////////////////////////////////////////////////////////////////////
module FIFO(inter.DUT intt);
parameter FIFO_WIDTH = 16;
parameter FIFO_DEPTH = 8;
localparam max_fifo_addr = $clog2(FIFO_DEPTH);
reg [FIFO_WIDTH-1:0] mem [FIFO_DEPTH-1:0];
reg [max_fifo_addr-1:0] wr_ptr, rd_ptr;
reg [max_fifo_addr:0] count;
endmodule
Verification plan :
Interface :
interface inter(clk);
parameter FIFO_WIDTH = 16;
input clk;
logic [FIFO_WIDTH-1:0] data_in;
logic rst_n, wr_en, rd_en;
logic [FIFO_WIDTH-1:0] data_out;
logic wr_ack, overflow;
logic full, empty, almostfull, almostempty, underflow;
modport DUT (
input clk,data_in,rst_n,wr_en,rd_en,
output data_out,wr_ack,overflow,full,empty,almostfull,almostempty,underflow
);
modport TB (
input clk,rd_en,data_out,wr_ack,overflow,full,empty,almostfull,almostempty,underflow,
output data_in,rst_n,wr_en
);
modport MONITOR (
input
clk,rd_en,data_out,wr_ack,overflow,full,empty,almostfull,almostempty,underflow,data_in,rst_n,
wr_en
);
endinterface //inter
classes that will be used :
Transaction class :
package trans;
class FIFO_transaction;
parameter FIFO_WIDTH = 16;
rand logic [FIFO_WIDTH-1:0] data_in;
rand logic rst_n, wr_en, rd_en;
logic clk;
logic [FIFO_WIDTH-1:0] data_out;
logic wr_ack, overflow;
logic full, empty, almostfull, almostempty, underflow;
integer RD_EN_ON_DIST , WR_EN_ON_DIST ;
function new(int rd_dst = 30 , wr_dst = 70 );
this.RD_EN_ON_DIST=rd_dst;
this.WR_EN_ON_DIST=wr_dst;
endfunction //new()
constraint rando{
rst_n dist {1:=90,0:=10};
wr_en dist {1:=(WR_EN_ON_DIST),0:=(100-WR_EN_ON_DIST)};
rd_en dist {1:=(RD_EN_ON_DIST),0:=(100-RD_EN_ON_DIST)};
}
endclass //
endpackage
Scoreboard class :
package score;
import trans::*;
class FIFO_scoreboard;
parameter FIFO_WIDTH = 16;
logic [FIFO_WIDTH-1:0] data_out_ref;
logic wr_ack_ref, overflow_ref;
logic full_ref, empty_ref, almostfull_ref, almostempty_ref, underflow_ref;
static integer error_count=0 , right_count=0 , size ;
logic [FIFO_WIDTH-1:0] data_mem [$] ;
static bit test_finished;
bit next_write,next_read;
task check_data (FIFO_transaction trans1);
reference_model(trans1);
if (!trans1.rst_n) begin
if (trans1.wr_ack!=wr_ack_ref || trans1.overflow!=overflow_ref || trans1.full
!= full_ref || trans1.empty != empty_ref || trans1.almostfull != almostfull_ref ||
trans1.almostempty != almostempty_ref) begin
error_count=error_count+1;
$display("error at reset");
if (trans1.wr_ack!=wr_ack_ref) begin
$display("wr_ack=%0b , wr_ack_ref=%0b at
%0t",trans1.wr_ack,wr_ack_ref,$time);
end
if (trans1.overflow!=overflow_ref) begin
$display("overflow=%0b , overflow_ref=%0b at
%0t",trans1.overflow,overflow_ref,$time);
end
if (trans1.full!=full_ref) begin
$display("full=%0b , full_ref=%0b at %0t",trans1.full,full_ref,$time);
end
if (trans1.empty!=empty_ref) begin
$display("empty=%0b , empty_ref=%0b at
%0t",trans1.empty,empty_ref,$time);
end
if (trans1.almostfull!=almostfull_ref) begin
$display("full=%0b , full=%0b at %0t",trans1.full,full_ref,$time);
end
if (trans1.almostempty!=almostempty_ref) begin
$display("almostempty=%0b , almostempty_ref=%0b at
%0t",trans1.almostempty,almostempty_ref,$time);
end
end
else begin
right_count = right_count+1;
end
end
else begin
if (trans1.wr_ack!=wr_ack_ref || trans1.overflow!=overflow_ref ||
trans1.data_out!=data_out_ref || trans1.full != full_ref || trans1.empty != empty_ref ||
trans1.almostfull != almostfull_ref || trans1.almostempty != almostempty_ref) begin
error_count=error_count+1;
$display("error at no reset");
if (trans1.wr_ack!=wr_ack_ref) begin
$display("wr_ack=%0b , wr_ack_ref=%0b , size=%0d at
%0t",trans1.wr_ack,wr_ack_ref,data_mem.size(),$time);
end
if (trans1.overflow!=overflow_ref) begin
$display("overflow=%0b , overflow_ref=%0b at
%0t",trans1.overflow,overflow_ref,$time);
end
if (trans1.data_out!=data_out_ref) begin
$display("dataout=%0d , dataout_ref=%0d, size=%0d at
%0t",trans1.data_out,data_out_ref,data_mem.size(),$time);
end
if (trans1.full!=full_ref) begin
$display("full=%0b , full_ref=%0b at %0t",trans1.full,full_ref,$time);
end
if (trans1.empty!=empty_ref) begin
$display("empty=%0b , empty_ref=%0b , size=%0d at
%0t",trans1.empty,empty_ref,data_mem.size(),$time);
end
if (trans1.almostfull!=almostfull_ref) begin
$display("almostfull=%0b , almostfull_ref=%0b at
%0t",trans1.almostfull,almostfull_ref,$time);
end
if (trans1.almostempty!=almostempty_ref) begin
$display("almostempty=%0b , almostempty_ref=%0b , size=%0d at
%0t",trans1.almostempty,almostempty_ref,data_mem.size(),$time);
end
end
else begin
right_count = right_count+1;
end
end
endtask
cover class:
package coverr;
import trans::*;
FIFO_transaction F_cvg_txn = new();
class FIFO_coverage;
covergroup p1 ;
rd_enable: coverpoint F_cvg_txn.rd_en iff(F_cvg_txn.rst_n);
wr_enable: coverpoint F_cvg_txn.wr_en iff(F_cvg_txn.rst_n);
wr_acknowledge: coverpoint F_cvg_txn.wr_ack iff(F_cvg_txn.rst_n);
overfloww: coverpoint F_cvg_txn.overflow iff(F_cvg_txn.rst_n);
underfloww: coverpoint F_cvg_txn.underflow iff(F_cvg_txn.rst_n);
fulll: coverpoint F_cvg_txn.full iff(F_cvg_txn.rst_n);
almostfulll: coverpoint F_cvg_txn.almostfull iff(F_cvg_txn.rst_n);
emptyy: coverpoint F_cvg_txn.empty iff(F_cvg_txn.rst_n);
almostemptyy: coverpoint F_cvg_txn.almostempty iff(F_cvg_txn.rst_n);
rd_enable_with_empty:cross rd_enable,emptyy;
rd_enable_with_almostempty:cross rd_enable,almostemptyy;
rd_enable_with_underflow : cross rd_enable,underfloww {
option.cross_auto_bin_max=0;
bins rd_on_under_off = binsof(rd_enable) intersect {1} && binsof(underfloww)
intersect {0};
bins rd_off_under_off = binsof(rd_enable) intersect {0} && binsof(underfloww)
intersect {0};
bins rd_on_under_on = binsof(rd_enable) intersect {1} && binsof(underfloww)
intersect {1};
}
wr_enable_with_full : cross wr_enable,fulll;
wr_enable_with_almostfull : cross wr_enable,almostfulll;
wr_enable_with_overflow : cross wr_enable,overfloww{
option.cross_auto_bin_max=0;
bins wr_on_over_off = binsof(wr_enable) intersect {1} && binsof(overfloww)
intersect {0};
bins wr_off_over_off = binsof(wr_enable) intersect {0} && binsof(overfloww)
intersect {0};
bins wr_on_over_on = binsof(wr_enable) intersect {1} && binsof(overfloww)
intersect {1};
}
wr_enable_with_wr_acknowledge : cross wr_enable,wr_acknowledge{
option.cross_auto_bin_max=0;
bins wr_on_wr_acknowledge_off = binsof(wr_enable) intersect {1} &&
binsof(wr_acknowledge) intersect {0};
bins wr_off_wr_acknowledge_off = binsof(wr_enable) intersect {0} &&
binsof(wr_acknowledge) intersect {0};
bins wr_on_wr_acknowledge_on = binsof(wr_enable) intersect {1} &&
binsof(wr_acknowledge) intersect {1};
}
endgroup
function new();
p1=new();
endfunction //new()
endclass //className
endpackage
Testbench module :
import score::*;
import trans::*;
module fifo_tb (inter.TB intt);
FIFO_transaction c=new();
FIFO_scoreboard cc=new();
initial begin
intt.rst_n=0;
intt.data_in=0;
intt.wr_en=0;
intt.rd_en=0;
repeat(2)
@(negedge intt.clk);
intt.rst_n=1;
c.rand_mode(0);
c.data_in.rand_mode(1);
c.constraint_mode(0);
repeat(5000) begin
intt.wr_en=1;
intt.rd_en=0;
repeat(9) begin
assert (c.randomize);
intt.data_in=c.data_in;
@(negedge intt.clk);
end
intt.wr_en=0;
intt.rd_en=1;
repeat(9) begin
@(negedge intt.clk);
end
end
c.rand_mode(0);
c.rand_mode(1);
c.constraint_mode(1);
repeat (5000) begin
assert (c.randomize);
intt.wr_en=c.wr_en;
intt.rd_en=c.rd_en;
intt.data_in=c.data_in;
intt.rst_n=c.rst_n;
@(negedge intt.clk);
end
cc.test_finished=1;
end
endmodule
Monitor module:
import score::*;
import coverr::*;
import trans::*;
module fifo_monitor (inter.MONITOR intt);
FIFO_transaction obj_trans;
FIFO_scoreboard obj2_score;
FIFO_coverage obj3_cover;
always @(*) begin
obj_trans.rst_n=intt.rst_n;
obj_trans.data_in=intt.data_in;
obj_trans.wr_en=intt.wr_en;
obj_trans.rd_en=intt.rd_en;
obj_trans.data_out=intt.data_out;
obj_trans.full=intt.full;
obj_trans.almostfull=intt.almostfull;
obj_trans.empty=intt.empty;
obj_trans.almostempty=intt.almostempty;
obj_trans.wr_ack=intt.wr_ack;
obj_trans.overflow=intt.overflow;
obj_trans.underflow=intt.underflow;
end
initial begin
obj_trans=new();
obj2_score=new();
obj3_cover=new();
forever begin
@(negedge intt.clk);
// obj_trans.rst_n=intt.rst_n;
// obj_trans.data_in=intt.data_in;
// obj_trans.wr_en=intt.wr_en;
// obj_trans.rd_en=intt.rd_en;
// obj_trans.data_out=intt.data_out;
// obj_trans.full=intt.full;
// obj_trans.almostfull=intt.almostfull;
// obj_trans.empty=intt.almostempty;
// obj_trans.almostempty=intt.almostempty;
// obj_trans.wr_ack=intt.wr_ack;
// obj_trans.overflow=intt.overflow;
// obj_trans.underflow=intt.underflow;
fork
//sample
begin
obj3_cover.sample_data(obj_trans);
end
begin
obj2_score.check_data(obj_trans);
end
join
if (obj2_score.test_finished) begin
$display("error_count=%0d
, right_count=%0d",obj2_score.error_count,obj2_score.right_count);
$stop;
end
end
end
endmodule
Top module :
module fifo_top ();
bit clk;
initial begin
forever begin
#10;
clk=!clk;
end
end
inter inter(clk);
FIFO_corrected DUT (inter);
fifo_tb TB(inter);
fifo_monitor MONITOR (inter);
endmodule
bugs found:
first bug :
Underflow should be sequential not compinational .
second bug :
Almostfull flag should be high at fifo_depth-2.
third bug :
reset isn’t applied on the following flags wr_ack,overflow,underflow.
fourth bug :
Underflow and overflow should be 0 when a successful read and write operation respectively occurs.
fifth bug :
at the case of both write and read occurs counter flag should behave differently.
Correct design :
////////////////////////////////////////////////////////////////////////////////
// Author: Kareem Waseem
// Course: Digital Verification using SV & UVM
//
// Description: FIFO Design
//
////////////////////////////////////////////////////////////////////////////////
module FIFO_corrected(inter.DUT intt);
parameter FIFO_WIDTH = 16;
parameter FIFO_DEPTH = 8;
localparam max_fifo_addr = $clog2(FIFO_DEPTH);
reg [FIFO_WIDTH-1:0] mem [FIFO_DEPTH-1:0];
reg [max_fifo_addr-1:0] wr_ptr, rd_ptr;
reg [max_fifo_addr:0] count;
else begin
intt.overflow <= 0;
end
end
end
else begin
intt.underflow <= 0;
end
end
end
Coverage :
THANKS