Professional Documents
Culture Documents
FIFO demo
FIFO demo
1.Overview of FIFO
FIFO buffer In computing and in systems theory, it is a method for organizing the manipulation of data
structures. Where the oldest (first) entry, or 'head' of the queue, is processed first. Such processing is
similar to serving people in the queue area on a first-come, first-served basis, in the same order in which
FIFO buffers are commonly used in electronic circuits to buffer and control flow between hardware
and software. In hardware form, FIFO mainly consists of a set of read and write pointers, storage and
control logic. The memory can be static random access memory (SRAM), flip-flops, latches, or any other
suitable form of storage. For FIFOs of non-small size, two-port SRAM is often used, where one port is
There are many ways to create a FIFO buffer, but the one used in this simulation exercise is a circular
FIFO (array-base buffer). As its name suggests (array base), this buffer is implemented based on an array.
Accompanied by two pointers Write and Read. Every time a write command is received, the prWrite
pointer will write data to the buffer, then increase by 1 unit. Every time a read command is received, the
prRead pointer will increase by one. Then read the value from the buffer. When a pointer reaches the end
- Full flag: is the state when the write pointer has written data one circle and meets the read pointer in
the second circle. In other words, the read pointer coincides with the write pointer when the write pointer
rotates 1 round larger than the read pointer. The data has not been read out but there has been a signal
written to that memory cell. Then we will not be allowed to write data anymore.
- Empty flag: is the state where the read pointer coincides with the write pointer when both pointers
are in the same cycle. Data that has not been written in has a signal read out, it is considered that the data
is also lost.
A FIFO can be thought of as a one-way tunnel that cars can pass through. At the end of the tunnel is a
toll booth. Once the gate opens, the car can leave the tunnel. If that gate doesn't open and more cars
continue to enter the tunnel, eventually the tunnel will fill up with cars. This is called a FIFO overflow.
The depth of the FIFO can be thought of as the length of the tunnel. The longer the FIFO, the more data
can go in before it overflows. FIFOs also have a width, which represents the width of the data (in terms of
- FIFO depth: corresponds to the maximum number of elements that the FIFO can store
- FIFO bandwidth: equivalent to the size of a data element read/written in one read/write cycle
Designers should never write data so that the FIFO overflows. Therefore, always check the FIFO full
flag to ensure there is room for another data frame, otherwise the old data will be lost.
The EMPTY state corresponds to when the read pointer Rptr points to the same location as the write
pointer Wptr. When the FIFO is reset, it is set to this state with pointers Rptr and Wptr both pointing to
memory location 0.
FULL state occurs when value Wptr + 1 = Rptr. Although in this case the memory array still has a
memory cell (whose address corresponds to the value of Wptr) that has not yet been written to, we cannot
save data to it. This is because after writing data to this memory cell, the value of Wptr is increased by 1
unit and points to the same memory cell as Rptr, and we cannot distinguish whether this is an EMPTY or
FULL state.
Basically, the transmitter FIFO and the receiver FIFO are the same, the only difference is that the
transmitter FIFO is a read FIFO so you pay more attention to the FULL flag, while the receiver FIFO is a
write FIFO so you pay more attention to the EMPTY flag more.
the RX and TX sets have not yet had time to read or send previously arrived data. To store data, the buffer
block must have a register file. In addition, to perform read and write, we need a read signal (rd), a write
signal (wr) and a pointer signal pointing to the address of the file you want to read or write. The block
outputs a full signal (full) = 1 when the queue is full and an empty signal (empty) = 1 when the queue is
empty and data is read (data_r). Because the block contains memory elements, we need to use clk pulses
Because UART transmit and receive data is 8 bits, each register row will have 8 bits. Suppose that the
We call the read and write pointers rd ptr and wr ptr respectively. Initially the queue is empty, signal
empty = 1. wr ptr and rd ptr will carry the address value at row 0 of the register file – Figure a. To
perform writing, signal wr = 1, we will write the value at each positive edge of the clk cycle. After each
write, the address of pointer wr ptr will be added by 1. Figures b and c depict the process of writing four
values to the register file. This takes place over 4 clock cycles. To perform a read, let the signal rd = 1.
The read will not depend on the clock cycle and the rd pointer will be added by 1 at each positive edge of
the clock cycle. Figure d depicts this process. For the full output signal, it signals full when we set wr = 1,
rd = 0 and wr ptr increases until it catches up with rd ptr as shown in figure f. For the empty output signal,
it will be reported as empty when we set wr = 0, rd = 1 and rd ptr will increase until it catches up with wr
ptr. In case we both read and write, the buffer will never be empty or full. The above process will be
described by the following summary table. We define signal_next as the value of that signal in the next
All signals used are listed in the table below. We call W the number of bits of input data written to the
To facilitate simulation, we let the buffer have 2 address bits (N = 2) equivalent to 4 register rows.
The number of bits we transmit into the queue is 8 (W = 8). So the register file here will be 4x8bit.
3. SOURCE CODE DESIGN FIFO-BUFFER BLOCK
module Fifo_buffer
#(
parameter W = 8, // number of bits per row
N = 2 // number of address bits
)
(
input wire wr, rd, clk, reset,
input wire [W-1:0] data_w,
output wire full, empty,
output wire [W-1:0] data_r
);
//signal declaration
reg [7:0] array [2**N - 1 : 0];
reg [N-1:0] r_ptr_reg, r_ptr_next, r_ptr_succ;
reg [N-1:0] w_ptr_reg, w_ptr_next, w_ptr_succ;
wire wr_en, r_en;
reg empty_next, full_next;
reg empty_reg, full_reg;
// body
// write operation
always@(posedge clk)
if(wr_en)
array[w_ptr_reg] <= data_w;
// read operation
/* if(r_en)
data_r <= array[r_ptr_reg]; */
assign data_r = array[r_ptr_reg];
// note
assign wr_en = ~full_reg & wr;
/*assign r_en = ~empty_reg & rd; */ // cannot be used in case 11
2'b10:
if(~empty_reg)
begin
r_ptr_next = r_ptr_succ;
full_next = 1'b0;
if(r_ptr_next == w_ptr_reg)
empty_next = 1'b1;
/* else
empty_next = 1'b1; */
end
2'b11: begin
r_ptr_next = r_ptr_succ;
w_ptr_next = w_ptr_succ;
end
endcase
end
//output
assign empty = empty_reg;
assign full = full_reg;
endmodule
endmodule
5. Test script
Checking the buffer block is carried out as follows:
• Step1: Pass the input value equal to 9. Because we are only interested in the read and write process, the
address movement of the read and write pointers in the block, the input value is not too important.
• Step 4: Perform full function test - set wr = 1, rd = 0 and write until the block is full
• Step 5: Check the empty function - set rd = 1, wr = 0 and read until the block is empty
At step 2, we see that the block has performed the write function: The array register file has stored the
value 9. In step 3, we also see that the read pointer (r_ptr_reg) has been added 1 at each positive edge
after when rd = 1. Reading out data is also always performed during buffer operations. Step 4 and step 5
also show that the system gave full and empty = 1 signals at the full and empty times in the register file,