Synchronous FIFOs

Sparty's Favorite Recipes 008 Kiss Your ASIC Good-bye!

Ingredients:

  • Any Spartan-II Device
  • 2.1i Development System
  • VHDL or Verilog
  • Nutritional Analysis:

  • Block RAM: 1
  • 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

     

    Related Information


     
      Trademarks and Patents
    Legal Information

    Privacy Policy
    | Home | Products | Support | Education | Purchase | Contact | Search |