Fifo Design
Fifo Design
VERIFICATION
AND
SYNTHESIS
OF
SYNCHRONOUS
FIFO
TABLE OF CONTENTS:
ACRONYMS ...3
ACKNOWLEDGEMENT ...4
HISTORY 5
ABSTRACT .6
INTRODUCTION ...7
BLACK-BOX VIEW OF SYNCHRONOUS FIFO ..10
PORT LIST ........10
FUNCTIONAL DESCRIPTION ...12
VERIFICATION OF THE MODULE ...22
SYNTHESIS OF THE MODULE .....27
CONCLUSION ..32
APPENDIX ....33
o A1: RTL DESCRIPTION OF SYNCHRONOUS FIFO USING
VERILOG HDL ......33
ACRONYMS:
EDA
CAD
CAE
ICs
: Integrated Circuits
RTL
TB
: Testbench
HDL
MSB
RAM
HOD
: Head Of Department
MIT
ABSTRACT
FIFO is a First-In-First-Out memory queue with control logic that manages
the read and write operations, generates status flags, and provides optional
handshake signals for interfacing with the user logic. It is often used to
control the flow of data between source and destination. FIFO can be
classified as synchronous or asynchronous depending on whether same clock
or different (asynchronous) clocks control the read and write operations. In
this project the objective is to design, verify and synthesize a synchronous
FIFO using binary coded read and write pointers to address the memory
array. FFIO full and empty flags are generated and passed on to source and
destination logics, respectively, to pre-empt any overflow or underflow of
data. In this way data integrity between source and destination is maintained.
The RTL description for the FIFO is written using Verilog HDL, and design
is simulated and synthesized using NC-SIM and RTL compiler provided by
Cadence Design Systems, Inc. respectively.
INTRODUCTION
WHAT IS A FIFO (first in first out)?
In computer programming, FIFO (first-in, first-out) is an approach to
handling program work requests from queues or stacks so that the oldest
request is handled first. In hardware it is either an array of flops or
Read/Write memory that store data given from one clock domain and on
request supplies with the same data to other clock domain following the first
in first out logic. The clock domain that supplies data to FIFO is often
referred as WRITE OR INPUT LOGIC and the clock domain that reads data
from the FIFO is often referred as READ OR OUTPUT LOGIC. FIFOs are
used in designs to safely pass multi-bit data words from one clock domain to
another or to control the flow of data between source and destination side
sitting in the same clock domain. If read and write clock domains are
governed by same clock signal the FIFO is said to be SYNCHRONOUS and
if read and write clock domains are governed by different (asynchronous)
clock signals FIFO is said to be ASYNCHRONOUS.
FIFO full and FIFO empty flags are of great concern as no data should be
written in full condition and no data should be read in empty condition, as it
can lead to loss of data or generation of non relevant data. The full and
empty conditions of FIFO are controlled using binary or gray pointers. In
this report we deal with binary pointers only since we are designing
SYNCHRONOUS FIFO. The gray pointers are used for generating full and
empty conditions for ASYNCHRONOUS FIFO. The reason why they are
used is beyond the scope of this document.
APPLICATIONS
FIFOs are used to safely pass data between two asynchronous clock
domains. In System-on-Chip designs there are components which
often run on different clocks. So, to pass data from
one such
requestor
capacities
to
supply
and
consume
data
SYNCHRONOUS
FIFO
PORT LIST
COMMON PORTS
Name
clk
I/O
I
reset_n
flush
Width
Description
1
Clock input to the FIFO. This is common
input to both read and write sides of FIFO
1
Active-low asynchronous reset input to
FIFO read and write logics
1
Active-high synchronous flush input to
FIFO. A clock-wide pulse resets the FIFO
read and write pointers
I/O
I
I
fifo_full
fifo_afull
write_ack
Width
Description
16
16-bit data input to FIFO
1
Qualifies the write data. Logic high
indicates the data on write_data bus is
valid and need to be sampled at next
rising edge of the clock.
1
Indicates to the source that FIFOs
internal memory has no space left to take
in new data
1
Indicates to the source that FIFOs
internal memory has only few spaces left
for new data. Upon seeing this source
may decide to slow down or stall the write
operation
1
Write acknowledgement to source.
I/O
I
read_data
rdata_valid
fifo_empty
fifo_aempty
Width
Description
1
Data read request to FIFO from the
requestor
16
Read data in response to a read request.
Data is valid in the next cycle of read_req
provided FIFO is not empty
1
Qualifies read data out. A logic high
indicates the data on read_data bus is
valid and need to be sampled at the next
rising edge of the clock
1
Indicates to the requestor that FIFOs
internal memory is empty and therefore
has no data to serve upon the read request
1
Indicates to the requestor that FIFOs
internal memory is almost empty and
therefore has only few data left to serve
upon the future read requests. Upon
seeing this requestor may decide to slow
down or stall the read operation.
9
FUNCTIONAL DESCRIPTION
Figure 2 depicts the basic building blocks of a synchronous FIFO which are:
memory array, write control logic and read control logic. The memory
array can be implemented either with array of flip-flops or with a dual-port
read/write memory. Both of these implementations allow simultaneous read
and write accesses. This simultaneous access gives the FIFO its inherent
synchronization property. There are no restrictions regarding timing between
accesses of the two ports. This means simply, that while one port is writing
to the memory at one rate, the other port can be reading at another rate
totally independent of one another. The only restriction placed is that the
simultaneous read and write access should not be from/to the same memory
location.
The Synchronous FIFO has a single clock port clk for both data-read and
data-write operations. Data presented at the module's data-input port
write_data is written into the next available empty memory location on a
rising clock edge when the write-enable input write_enable is high. The full
status output fifo_full indicates that no more empty locations remain in the
module's internal memory. Data can be read out of the FIFO via the
module's data-output port read_data in the order in which it was written by
asserting read-enable signal read_enable prior to a rising clock edge. The
memory-empty status output fifo_empty indicates that no more data resides
in the module's internal memory. There are almost empty and almost full
flags too viz. fifo_aempty and fifo_afull which can be used to control the
read and write speeds of the requestor and the source.
10
11
WRITE
CONTROL
LOGIC
I/O
I
I
I
wdata_valid
rd_ptr
write_enable
write_ptr
O
O
write_ack
fifo_full
fifo_afull
Width
Description
1
Clock input
1
Active-low reset input
1
Active-high synchronous flush input to
FIFO. A clock-wide pulse resets the FIFO
read and write pointers
1
Qualifies write data in. A logic high
indicates the data on write_data bus is
valid
5
Read pointer from Read Control Logic.
This along with write pointer is used to
find FIFO full and almost full condition
1
Write enable to FIFOs internal memory
5
Write pointer value. This serves as a write
address to FIFOs internal memory
1
Acknowledgement to source that write
operation is done.
1
Indicates to the source that FIFOs
internal memory has no space left to take
in new data
1
Indicates to the source that FIFOs
internal memory has only few spaces left
for new data. Upon seeing this source
may decide to slow down or stall the write
operation
12
READ
CONTROL
LOGIC
13
PORT LIST
Name
clk
reset_n
flush
I/O
I
I
I
read_req
write_ptr
I
I
read_enable
read_ptr
O
O
rdata_valid
fifo_empty
fifo_aempty
Width
Description
1
Clock input
1
Active-low reset input
1
Active-high synchronous flush input to
FIFO. A clock-wide pulse resets the FIFO
read and write pointers
1
Read request from the requestor.
5
Write pointer from Write Control Logic.
This along with read pointer is used to
find FIFO empty and almost empty
conditions
1
Read enable to FIFOs internal memory
5
Read pointer value. This serves as a read
address to FIFO internal memory
1
Acknowledgement to source that write
operation is done.
1
Indicates to the source that FIFOs
internal memory has no space left to take
in new data
1
Indicates to the source that FIFOs
internal memory has only few spaces left
for new data. Upon seeing this source
may decide to slow down or stall the write
operation
MEMORY ARRAY
Memory Array is an array of flip-flops which stores data. Number of data
words that the memory array can store is often referred as DEPTH of the
FIFO. Length of the data word is referred as WIDTH of the FIFO. Besides
flop-array it comprises read and write address decoding logic.
14
MEMORY
ARRAY
PORT LIST
Name
clk
write_addr
I/O
I
I
write_enable
write_data
read_addr
I
I
read_enable
read_data
I
O
Width
Description
1
Clock input
4
Write address to the memory. It is derived
from write pointer by knocking-off its
MSB
1
Active-high write enable input to the
memory
16
Data Input to the memory
4
Read address to the memory. It is derived
from read pointer by knocking-off its
MSB
1
Active-high read enable to memory
16
Data read out from the memory
will be of 9-bits. When their lower 8-bits point to same memory location
their MSBs are used to ascertain whether it is a full condition or empty
condition. In empty conditions the MSBs are equal whereas in full condition
MSBs are different. The verilog code shown below depicts the same:
assign fifo_full = ( (write_ptr[7 : 0] == read_addr[7 : 0]) &&
(write_ptr[8] ^ read_ptr[8]) );
assign fifo_empty = (read_ptr[8 : 0] == write_ptr[8 : 0]);
Following piece of verilog code shows logic almost full generation:
// Generating fifo almost full status
always @*
begin
if ( write_ptr[8] == read_ptr[8] )
fifo_afull = ((write_ptr[7:0] - read_ptr[7:0]) >= (DEPTH - AFULL));
else
fifo_afull = ((read_ptr[8:0] - write_ptr[8:0]) <= AFULL);
end
Here AFULL signifies the almost full-level. User can set it to 4, 8 or
whatever value depending on how soon it wants to intimate the source about
impending full condition. (AFULL=4) means almost full flag will get
asserted when at most 4 locations are left for new data.
17
18
In this way read keeps following write until the FIFO gets empty
again
If write operations are not matched by read soon FIFO will get full
and any further write will get stalled until fifo_full is pulled down by a
read
With the help of FIFO full and empty flags data integrity is
maintained between the source and the requestor
19
INPUT
STIMULUS
BLOCK
OUTPUT
CHECKER
BLOCK
20
21
SIMULATION
We used Cadence NC-SIM simulator to simulate our Synchronous FIFO
TB. The results are shown below:
FIFO FULL & ALMOST FULL FLAGS GENERATION
Yellow circle shows FIFO full and almost full flags getting asserted and deasserted depending on the values of write and read pointers. Note that when
FIFO full is asserted except for the MSBs the pointer values are same.
23
TB CHECKER
TB checker compares all the data which were sent to FIFO with all the data
received at the output of FIFO. They should match. The result of this
comparison is the match signal shown in the snapshot. If this signal is high
all the time it means the test has passed the checking.
24
25
EXAMPLE
RTL
assign z = a && b;
Netlist
AND2X1 u0 (.A(a), .B(b), .Z(z));
Where AND2X1 is a standard cell for AND gate in the library.
CONSTRAINTS
The constraints are the goals that the synthesis tool tries to meet. For
example, we may have a design that is targeted for several different
applications with different requirements:
Timing is most important; area is not a concern.
Power and area are more important; and timing is less so.
Timing, area, and power are all important, and we have specific
measures for each.
STANDARD CELL LIBRARY
Standard Cell Library is a collection of basic building blocks or standard
cells targeted to a specific semiconductor process technology.
26
27
28
RESULTS
It can be observed that there is a positive slack of 776ps (see the yellow
circle) for the worst case path. So the synthesis comfortably meets the timing
constraints set by us.
29
CONCLUSION
The objective of this training was to learn basics of digital logic design. And
during the course of this I learned the following aspects of digital design:
How to write RTL codes using Verilog HDL
How to write behavioral codes using Verilog HDL to develop
testbenches
Design of basic logic elements like half adders, full adders, counters,
Finite State Machines, sequence detectors etc.
Design and application of Synchronous FIFO
Basic difference between Synchronous & Asynchronous FIFO
How to develop testbench and run simulations to verify the
correctness of your design (using Cadence NC-SIM)
How to synthesize an RTL design to a gate-level design subject to
user defined constraints (using Cadence RTL Compiler)
Given the short duration of this training, I believe, my set objectives are
more than fulfilled.
30
APPENDIX
A1: RTL DESCRIPTION OF SYNCHRONOUS FIFO USING
VERILOG HDL
TOP LEVEL MODULE
//***********************************************************//
//
File Name:
sync_fifo.v
//
Module Name: sync_fifo
//
Description:
Synchronous FIFO
//
Place:
Cadence Design Systems, Inc.
//
Date:
July 10, 2008
//***********************************************************//
module sync_fifo #(
parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 16,
parameter DEPTH = 16,
parameter AEMPTY = 3,
parameter AFULL = 3
)
(
// Inputs
input
clk,
input
reset_n,
input
flush,
input
read_req,
input [DATA_WIDTH-1:0] write_data,
input
wdata_valid,
// Outputs
output [DATA_WIDTH-1:0]
output
output
output
output
output
output
);
read_data,
rdata_valid,
fifo_empty,
fifo_aempty,
fifo_full,
fifo_afull,
write_ack
31
.read_data(read_data)
);
endmodule
//***********************************************************//
READ CONTROL LOGIC
//***********************************************************//
//
File Name:
read_control_logic.v
//
Module Name: read_control_logic
//
Description:
Controls the read operation of sync_fifo. Generates
//
FIFO empty & almost empty flags.
//
Place:
Cadence Design Systems, Inc.
//
Date:
July 8, 2008
//***********************************************************//
module read_control_logic #(
parameter ADDR_WIDTH = 4,
parameter AEMPTY = 3,
parameter DEPTH = 16
)
(
// Inputs
input
[ADDR_WIDTH:0] write_ptr,
input
clk,
input
reset_n,
input
flush,
input
read_req,
// Outputs
output
output reg
output
output reg
output reg [ADDR_WIDTH:0]
read_enable,
rdata_valid,
fifo_empty,
fifo_aempty,
read_ptr
);
wire [ADDR_WIDTH-1:0] read_addr;
wire [ADDR_WIDTH-1:0] write_addr;
33
34
35
begin
write_ack <= 1'b0;
end
end
endmodule
//*********************************************************//
MEMORY ARRAY
//***********************************************************//
//
File Name:
mem_array.v
//
Module Name: mem_array
//
Description:
FIFO internal memory to store incoming data. It is
//
implemented as flop-array
//
Place:
Cadence Design Systems, Inc.
//
Date:
July 10, 2008
//***********************************************************//
module mem_array #(
parameter ADDR_WIDTH = 4,
parameter DEPTH = 16,
parameter DATA_WIDTH = 16
)
(
input
[ADDR_WIDTH-1:0] write_addr,
input
[ADDR_WIDTH-1:0] read_addr,
input
write_enable,
input
read_enable,
input
clk,
input
[DATA_WIDTH-1:0] write_data,
output reg [DATA_WIDTH-1:0] read_data
);
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
// Mem write
always @(posedge clk)
begin
if (write_enable)
37
38
initial
begin
reset_n=1'b0;
#550;
reset_n=1'b1;
end
// LFSR Counter
always @(posedge clk or negedge reset_n)
begin
if(~reset_n)
lfsr_count <= 16'h70f0;
else
lfsr_count <= {lfsr_count[14:0],
~(lfsr_count[15] ^ lfsr_count[14] ^
lfsr_count[12] ^ lfsr_count[3])};
end
// generating ready, count_enable and read request signal
assign ready
= lfsr_count[0] | lfsr_count[3];
assign read_req
= lfsr_count[7] | lfsr_count[13];
assign count_enable = (ready) && (~fifo_full);
//generating 16 bit input data
always @(posedge clk or negedge reset_n)
begin
if(~reset_n)
data_in<={{15{1'b0}},1'b1};
else if(count_enable)
data_in[15:0]<={data_in[14:0],data_in[15]^data_in[14]};
else
data_in<=data_in;
end
//destination logic.... clk,reset_n,flush are same as in source logic
wire [15:0] data_out;
wire rdata_valid;
wire fifo_empty;
wire fifo_aempty;
40
//instantiating DUT
sync_fifo #(
.ADDR_WIDTH(4),
.DATA_WIDTH(16),
.DEPTH(16),
.AEMPTY(3),
.AFULL(3)
)
DUT (
.clk(clk),
.reset_n(reset_n),
.flush(flush),
.read_req(read_req),
.write_data(data_in),
.wdata_valid(data_valid),
.read_data(data_out),
.fifo_empty(fifo_empty),
.fifo_aempty(fifo_aempty),
.fifo_full(fifo_full),
.fifo_afull(fifo_afull),
.write_ack(write_ack),
.rdata_valid(rdata_valid)
);
//source array
reg [15:0] source_array[0:2047];
reg [10:0] counter;
always @(posedge clk or negedge reset_n)
begin
if(~reset_n)
counter <= {11{1'b0}};
else if(data_valid && (~fifo_full))
begin
source_array[counter] <= data_in;
counter <= counter + {{10{1'b0}},1'b1};
end
end
//destination array
41
if(ready)
begin
ns = active;
data_valid = 1'b1 ;
end
end
active: begin
if((~fifo_full) && (~ready))
begin
ns = idle;
data_valid = 1'b0;
end
else
data_valid = 1'b1;
end
default: cs = idle;
endcase
end
always @(posedge clk or negedge reset_n)
begin
if (~reset_n)
cs <= idle;
else
cs <= ns;
end
endmodule
//***********************************************************//
43