La FIFO (First Input, First output) es básicamente un búfer de memoria usado para almacenar temporalmente datos hasta que otro proceso está listo para leer éstos. Como su nombre sugiere, el primer byte escrito dentro de la FIFO será el primero en aparecer en la salida. Típicamente los FIFO son usados cuando se tienen dos procesos que operan a diferente velocidad. Un ejemplo común es un canal de comunicaciones a alta velocidad que escribe una ráfaga de datos en la FIFO y entonces un canal de comunicaciones de menor velocidad lee los datos con la tasa que requiere.

En el sitio web http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/ puede un encontrarse código que es fácil de entender y muy funcional. Tal código se comenta a continuación.



contenido

  1. ...


El módulo FIFO, descrito a continuación, tiene dos propiedades que implican el ancho de palabra DATA_WIDTH y la profundidad FIFO_DEPTH. La variable DATA_WIDTH define el tamaño de la palabra que almacenará la FIFO así como el ancho del bus de entrada DataIn y el ancho del bus de salida DataOut. La variable FIFO_DEPTH determina la cantidad de palabras almacenables en la FIFO.

La variable índice Head es usada para indicar el frente de la fila (el primer elemento ingresado) y la variable índice Tail es usada para indicar la cola de la fila (el último elemento ingresado).

La señal empty se enciende cuando la cinta está vacía. Esto es, cuando la pila arranca y cuando se han leído todos los símbolos de la FIFO.

La señal Full se enciende cuando la cinta está llena. En este punto, ya no acepta más simbolos de entrada.



Formalmente, la FIFO circular se define como la 10-tupla

AFD = { QT , ΣIT , ΓT , δ , {q0} , Χ , Head , Tail }

donde:

QT = { q0 } Estados. La fila solamente tiene un estado.
ΣIT Alfabeto de símbolos contables.
ΓT Reglas de acceso.
q0 ∈ QT Estado único de la cinta.
Χ ∈ Σ*IT Contenido inicial de la cinta.
Tail ∈ ΣIT Cabezal de escritura.
Head ∈ ΣIT Cabezal de lectura.



Para escribir datos en la FIFO, primero se coloca un dato en el bus DataIn, luego se coloca un uno en el terminal WriteEn. Entonces, cuando llegue la transición positiva del pulso de reloj, se transferirá el dato a la FIFO. Para realizar una escritura en ráfaga, se deja este terminal en alto, de tal forma que en cada transición positiva del reloj se realiza una escritura de un dato puesto en DataIn, en la FIFO.

Una vez que un dato es escrito en la FIFO, la terminal Empty es puesta en cero

Cuando la terminal Full se levante significará que la FIFO se ha llenado y entonces no aceptará más datos entrantes. Esto puede implicar que incluso cuando lleguen más datos y la señal WriteEn esté en alto, si la FIFO está llena, estos datos entrantes se perderán.

Para una FIFO estándar, cuando se escribe el primer byte en la FIFO, éste no se ve en el bus de salida DataOut sino hasta que la señal ReadEn se habilita en alto y ocurre una transición positiva del reloj. Si se desea leer datos en ráfaga, la terminal ReadEn se deja en alto y entonces, se verá un dato nuevo en el bus DataOut con cada transición positiva del reloj.

Una vez que el último dato ha salida de la FIFO, la terminal Empty se pone en alto.

.

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
 
entity STD_FIFO is
	Generic (
		constant DATA_WIDTH  : positive := 8;
		constant FIFO_DEPTH  : positive := 256
	);
	Port ( 
		CLK	:  in STD_LOGIC;
		RST	:  in STD_LOGIC;
		WriteEn	:  in STD_LOGIC;
		DataIn	:  in STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
		ReadEn	:  in STD_LOGIC;
		DataOut	: out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
		Empty	: out STD_LOGIC;
		Full	: out STD_LOGIC
	);
end STD_FIFO;
 
architecture Behavioral of STD_FIFO is
 
begin
 
	-- Memory Pointer Process
	fifo_proc : process (CLK)
		type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
		variable Memory : FIFO_Memory;
		
		variable Head : natural range 0 to FIFO_DEPTH - 1;
		variable Tail : natural range 0 to FIFO_DEPTH - 1;
		
		variable Looped : boolean;
	begin
		if rising_edge(CLK) then
			if RST = '1' then
				Head := 0;
				Tail := 0;
				
				Looped := false;
				
				Full  <= '0';
				Empty <= '1';
			else

				if (WriteEn = '1') then
					if ((Looped = false) or (Head /= Tail)) then
						-- Write Data to Memory
						Memory(Head) := DataIn;
						
						-- Increment Head pointer as needed
						if (Head = FIFO_DEPTH - 1) then
							Head := 0;
							
							Looped := true;
						else
							Head := Head + 1;
						end if;
					end if;
				end if;


				if (ReadEn = '1') then
					if ((Looped = true) or (Head /= Tail)) then
						-- Update data output
						DataOut <= Memory(Tail);
						
						-- Update Tail pointer as needed
						if (Tail = FIFO_DEPTH - 1) then
							Tail := 0;
							
							Looped := false;
						else
							Tail := Tail + 1;
						end if;
						
						
					end if;
				end if;
						
				-- Update Empty and Full flags
				if (Head = Tail) then
					if Looped then
						Full <= '1';
					else
						Empty <= '1';
					end if;
				else
					Empty	<= '0';
					Full	<= '0';
				end if;
			end if;
		end if;
	end process;
		
end Behavioral;