Instructions
This FIFO design is synchronous, which means it uses common clocks
for Read and Write. When both the Read and Write clocks originate
from the same source, the FIFO operation and arbitration are simplified,
and the Empty and Full flags are easily generated.
Linear Feedback Shift Registers (LFSRs) are used for both the read
(read_addr) and write (write_addr) address counters. Because they
are addressing a RAM, a binary counting sequence is not necessary,
and the pseudo-random sequence of the LFSRs is acceptable. They
use very little logic, and are therefore much faster than a standard
binary implementation. The only drawback is that the FIFO size is
reduced by one, to 511x8. The fifo_gsr signal resets all counters.
The synchronous nature of the Block SelectRAM+ memory simplifies
the timing requirements to meeting setup times. To perform a read,
Read Enable (read_enable) is driven High prior to a rising clock
edge, and the Read Data (read_data) is presented on the outputs
during the next clock cycle. To do a Burst Read, simply leave Read
Enable High for as many clock cycles as desired. If Empty goes active
after reading, then the last word has been read, and the next Read
Data would be invalid.
To perform a write, the Write Data (write_data) must be present
on the inputs, and Write Enable (write_enable) is driven High prior
to a rising clock edge. As long as the Full flag is not set, the
Write will be executed. To do a Burst Write, the Write Enable is
left High, and new Write Data must be available every cycle.
The Empty flag is set when the Next Read Address (next_read_addr)
is equal to the current Write Address, and only a Read is being
performed. This early decoding allows Empty to be set immediately
after the last Read. It is cleared after a Write operation (with
no simultaneous Read). Similarly, the Full flag is set when the
Next Write Address (next_write_addr) is equal to the current Read
Address, and only a Write is being performed. It is cleared after
a Read operation (with no simultaneous Write). If both a Read and
Write are done in the same clock cycle, there is no change to the
status flags. During global reset (FIFO_gsr), both these signals
are driven High, to prevent any external logic from interfacing
with the FIFO during this time.
A FIFO count (fifocount) is added for convenience, to determine
when the FIFO is 1/2 full, 3/4 full, etc. It is a binary count of
the number of words currently stored in the FIFO. It is incremented
on Writes, decremented on Reads, and stays the same if both operations
are performed within the same clock cycle. In this application,
only the upper four bits are sent to I/O, but that can easily be
modified.
VHDL
--------------------------------------------------------------------
-- The following VHDL code implements a 511x8 FIFO in a Spartan-II
--
-- device. The inputs are a Clock, a Read Enable, a Write Enable,
--
-- Write Data, and a FIFO_gsr signal as an initial reset. The --
-- outputs are Read Data, Full, Empty, and the FIFOcount outputs,--
-- which indicate roughly how full the FIFO is. --
--------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity fifoctlr_cc is
port (clock_in: IN std_logic;
read_enable_in: IN std_logic;
write_enable_in: IN std_logic;
write_data_in: IN std_logic_vector(7 downto 0);
FIFO_gsr_in: IN std_logic;
read_data_out: OUT std_logic_vector(7 downto 0);
full_out: OUT std_logic;
empty_out: OUT std_logic;
fifocount_out: OUT std_logic_vector(3 downto 0));
END fifoctlr_cc;
architecture fifoctlr_cc_hdl of fifoctlr_cc is
signal clock: std_logic;
signal read_enable: std_logic;
signal write_enable: std_logic;
signal FIFO_gsr: std_logic;
signal read_data: std_logic_vector(7 downto 0) := "00000000";
signal write_data: std_logic_vector(7 downto 0);
signal full: std_logic;
signal empty: std_logic;
signal read_addr: std_logic_vector(8 downto 0) := "000000000";
signal write_addr: std_logic_vector(8 downto 0) := "000000000";
signal fcounter: std_logic_vector(8 downto 0) := "000000000";
signal read_allow: std_logic;
signal write_allow: std_logic;
signal gnd: std_logic;
signal gnd_bus: std_logic_vector(7 downto 0);
signal pwr: std_logic;
signal read_linearfeedback: std_logic;
signal write_linearfeedback: std_logic;
component BUFGP
port (
I: IN std_logic;
O: OUT std_logic);
END component;
component RAMB4_S8_S8
port (
ADDRA: IN std_logic_vector(8 downto 0);
ADDRB: IN std_logic_vector(8 downto 0);
DIA: IN std_logic_vector(7 downto 0);
DIB: IN std_logic_vector(7 downto 0);
WEA: IN std_logic;
WEB: IN std_logic;
CLKA: IN std_logic;
CLKB: IN std_logic;
RSTA: IN std_logic;
RSTB: IN std_logic;
ENA: IN std_logic;
ENB: IN std_logic;
DOA: OUT std_logic_vector(7 downto 0);
DOB: OUT std_logic_vector(7 downto 0));
END component;
BEGIN
read_enable <= read_enable_in;
write_enable <= write_enable_in;
FIFO_gsr <= FIFO_gsr_in;
write_data <= write_data_in;
read_data_out <= read_data;
full_out <= full;
empty_out <= empty;
read_allow <= (read_enable AND NOT empty);
write_allow <= (write_enable AND NOT full);
gnd_bus <= "00000000";
gnd <= '0';
pwr <= '1';
---------------------------------------------------------------------
-- A global buffer is instantianted to avoid skew problems. --
---------------------------------------------------------------------
gclk1: BUFGP port map (I => clock_in, O => clock);
---------------------------------------------------------------------
-- Block RAM instantiation for FIFO. Module is 512x8, of which one
--
-- address location is sacrificed for the overall speed of the design.---------------------------------------------------------------------
bram1: RAMB4_S8_S8 port map (ADDRA => read_addr, ADDRB => write_addr,
DIB => write_data, DIA => gnd_bus, WEA => gnd,
WEB => write_allow, CLKA => clock, CLKB => clock,
RSTA => gnd, RSTB => gnd, ENA => read_allow, ENB => pwr,
DOA => read_data);
---------------------------------------------------------------
-- Empty flag is set on FIFO_gsr (initial), or when on the --
-- next clock cycle, Write Enable is low, and either the --
-- FIFOcount is equal to 0, or it is equal to 1 and Read --
-- Enable is high (about to go Empty). --
---------------------------------------------------------------
proc1: PROCESS (clock, FIFO_gsr)
BEGIN
IF (FIFO_gsr = '1') THEN
empty <= '1';
ELSIF (clock'EVENT AND clock = '1') THEN
IF ((fcounter(8 downto 1) = "00000000") AND (write_enable = '0')
AND
((fcounter(0) = '0') OR (read_enable = '1'))) THEN
empty <= '1';
ELSE
empty <= '0';
END IF;
END IF;
END PROCESS proc1;
---------------------------------------------------------------
-- Full flag is set on FIFO_gsr (but it is cleared on the --
-- first valid clock edge after FIFO_gsr is removed), or --
-- when on the next clock cycle, Read Enable is low, and --
-- either the FIFOcount is equal to 1FF (hex), or it is --
-- equal to 1FE and the Write Enable is high (about to go --
-- Full). --
---------------------------------------------------------------
proc2: PROCESS (clock, FIFO_gsr)
BEGIN
IF (FIFO_gsr = '1') THEN
full <= '1';
ELSIF (clock'EVENT AND clock = '1') THEN
IF ((fcounter(8 downto 1) = "11111111") AND (read_enable = '0')
AND
((fcounter(0) = '1') OR (write_enable = '1'))) THEN
full <= '1';
ELSE
full <= '0';
END IF;
END IF;
END PROCESS proc2;
----------------------------------------------------------------
-- Generation of Read and Write address pointers. They use --
-- LFSR counters, which are very fast. Because of the --
-- nature of LFSRs, one address is sacrificed. --
----------------------------------------------------------------
read_linearfeedback <= NOT (read_addr(8) XOR read_addr(4));
write_linearfeedback <= NOT (write_addr(8) XOR write_addr(4));
proc3: PROCESS (clock, FIFO_gsr)
BEGIN
IF (FIFO_gsr = '1') THEN
read_addr <= "000000000";
ELSIF (clock'EVENT AND clock = '1') THEN
IF (read_allow = '1') THEN
read_addr(8) <= read_addr(7);
read_addr(7) <= read_addr(6);
read_addr(6) <= read_addr(5);
read_addr(5) <= read_addr(4);
read_addr(4) <= read_addr(3);
read_addr(3) <= read_addr(2);
read_addr(2) <= read_addr(1);
read_addr(1) <= read_addr(0);
read_addr(0) <= read_linearfeedback;
END IF;
END IF;
END PROCESS proc3;
proc4: PROCESS (clock, FIFO_gsr)
BEGIN
IF (FIFO_gsr = '1') THEN
write_addr <= "000000000";
ELSIF (clock'EVENT AND clock = '1') THEN
IF (write_allow = '1') THEN
write_addr(8) <= write_addr(7);
write_addr(7) <= write_addr(6);
write_addr(6) <= write_addr(5);
write_addr(5) <= write_addr(4);
write_addr(4) <= write_addr(3);
write_addr(3) <= write_addr(2);
write_addr(2) <= write_addr(1);
write_addr(1) <= write_addr(0);
write_addr(0) <= write_linearfeedback;
END IF;
END IF;
END PROCESS proc4;
----------------------------------------------------------------
-- Generation of FIFOcount outputs. Used to determine how --
-- full FIFO is, based on a counter that keeps track of how --
-- many words are in the FIFO. Also used to generate Full --
-- and Empty flags. Only the upper four bits of the counter --
-- are sent outside the module. --
----------------------------------------------------------------
proc5: PROCESS (clock, FIFO_gsr)
BEGIN
IF (FIFO_gsr = '1') THEN
fcounter <= "000000000";
ELSIF (clock'EVENT AND clock = '1') THEN
IF (((read_allow = '1') AND (write_allow = '0')) OR
((read_allow = '0') AND (write_allow = '1'))) THEN
IF (write_allow = '1') THEN
fcounter <= fcounter + '1';
ELSE
fcounter <= fcounter - '1';
END IF;
END IF;
END IF;
END PROCESS proc5;
fifocount_out <= fcounter(8 downto 5);
END fifoctlr_cc_hdl;
Verilog
/******************************************************************\
* Module : fifoctlr_cc.v Last Update: 12/13/99 *
* *
* Description : FIFO controller top level. *
* Implements a 511x8 FIFO with common read/write clocks. *
* *
* The following Verilog code implements a 511x8 FIFO in a Spartan-II*
* device. The inputs are a Clock, a Read Enable, a Write Enable,
*
* Write Data, and a FIFO_gsr signal as an initial reset. The outputs*
* are Read Data, Full, Empty, and the FIFOcount outputs, which *
* indicate roughly how full the FIFO is. *
\******************************************************************/
`timescale 1ns / 10ps
`define DATA_WIDTH 7:0
`define ADDR_WIDTH 8:0
module fifoctlr_cc (clock_in, read_enable_in, write_enable_in,
write_data_in, FIFO_gsr_in, read_data_out,
full_out, empty_out, fifocount_out );
input clock_in, read_enable_in, write_enable_in, FIFO_gsr_in;
input [`DATA_WIDTH] write_data_in;
output [`DATA_WIDTH] read_data_out;
output full_out, empty_out;
output [3:0] fifocount_out;
wire read_enable = read_enable_in;
wire write_enable = write_enable_in;
wire FIFO_gsr = FIFO_gsr_in;
wire [`DATA_WIDTH] write_data = write_data_in;
wire [`DATA_WIDTH] read_data;
assign read_data_out = read_data;
reg full, empty;
assign full_out = full;
assign empty_out = empty;
reg [`ADDR_WIDTH] read_addr, write_addr, fcounter;
wire read_allow, write_allow;
assign read_allow = (read_enable && ! empty);
assign write_allow = (write_enable && ! full);
wire gnd = 0;
wire pwr = 1;
/*******************************************************************\
* A global buffer is instantianted to avoid skew problems. *
\*******************************************************************/
BUFGP gclk1 (.I(clock_in), .O(clock));
/*******************************************************************\
* Block RAM instantiation for FIFO. Module is 512x8, of which one
*
* address location is sacrificed for the overall speed of the design.*
\*******************************************************************/
RAMB4_S8_S8 bram1 ( .ADDRA(read_addr), .ADDRB(write_addr), .DIB(write_data),
.DIA({gnd, gnd, gnd, gnd, gnd, gnd, gnd, gnd}),
.WEA(gnd), .WEB(write_allow), .CLKA(clock),
.CLKB(clock), .RSTA(gnd), .RSTB(gnd),
.ENA(read_allow), .ENB(pwr), .DOA(read_data) );
/***********************************************************\
* Empty flag is set on FIFO_gsr (initial), or when on the *
* next clock cycle, Write Enable is low, and either the *
* FIFOcount is equal to 0, or it is equal to 1 and Read *
* Enable is high (about to go Empty). *
\***********************************************************/
always @(posedge clock or posedge FIFO_gsr)
if (FIFO_gsr) empty <= 1;
else empty <= (! write_enable && (fcounter[8:1] == 8'h0) &&
((fcounter[0] == 0) || read_enable));
/***********************************************************\
* Full flag is set on FIFO_gsr (but it is cleared on the *
* first valid clock edge after FIFO_gsr is removed), or *
* when on the next clock cycle, Read Enable is low, and *
* either the FIFOcount is equal to 1FF (hex), or it is *
* equal to 1FE and the Write Enable is high (about to go *
* Full). *
\***********************************************************/
always @(posedge clock or posedge FIFO_gsr)
if (FIFO_gsr) full <= 1;
else full <= (! read_enable && (fcounter[8:1] == 8'hFF) &&
((fcounter[0] == 1) || write_enable));
/************************************************************\
* Generation of Read and Write address pointers. They use *
* LFSR counters, which are very fast. Because of the *
* nature of LFSRs, one address is sacrificed. *
\************************************************************/
wire read_linearfeedback, write_linearfeedback;
assign read_linearfeedback = ! (read_addr[8] ^ read_addr[4]);
assign write_linearfeedback = ! (write_addr[8] ^ write_addr[4]);
always @(posedge clock or posedge FIFO_gsr)
if (FIFO_gsr) read_addr <= 'h0;
else if (read_allow)
read_addr <= { read_addr[7], read_addr[6], read_addr[5],
read_addr[4], read_addr[3], read_addr[2],
read_addr[1], read_addr[0], read_linearfeedback };
always @(posedge clock or posedge FIFO_gsr)
if (FIFO_gsr) write_addr <= 'h0;
else if (write_allow)
write_addr <= { write_addr[7], write_addr[6], write_addr[5],
write_addr[4], write_addr[3], write_addr[2],
write_addr[1], write_addr[0], write_linearfeedback };
/************************************************************\
* Generation of FIFOcount outputs. Used to determine how *
* full FIFO is, based on a counter that keeps track of how *
* many words are in the FIFO. Also used to generate Full *
* and Empty flags. Only the upper four bits of the counter *
* are sent outside the module. *
\************************************************************/
always @(posedge clock or posedge FIFO_gsr)
if (FIFO_gsr) fcounter <= 'h0;
else if
((!
read_allow && write_allow) || (read_allow && ! write_allow))
begin
if (write_allow) fcounter <= fcounter + 1;
else fcounter <= fcounter - 1;
end
assign fifocount_out = fcounter[8:5];
endmodule
|