Una FIFO (First In First Out) es una estructura de memoria muy utilizada en los diseños digitales complejos. Consta de una memoria junto con una circuitería que le hace comportarse como una estructura de cola, donde los datos entran uno a uno y salen en el mismo orden en el que fueron escritos.

Las FIFO actúan como un buffer, recibiendo datos de un bloque y almacenándolos temporalmente hasta que el receptor esta listo para leerlos. Son por tanto muy útiles para comunicar periféricos con microprocesadores. Un ejemplo de esto puede ser un puerto serie que va recibiendo datos del exterior y los almacena en una FIFO. Cuando el procesador necesite leer los datos, los podrá extraer de dicha FIFO sin correr el riesgo de que el dato sea machacado por un nuevo dato proveniente del puerto serie.

Otra utilidad fundamental de las FIFO es transmitir datos entre dos partes del circuito que utilizan diferentes relojes. La FIFO que vamos a utilizar en este tutorial solo utiliza un reloj, pero se pueden utilizar relojes diferentes para lectura y escritura. De esta manera la FIFO actúa de frontera entre los dos dominios de reloj, aislándolos y sincronizándolos

Las FIFO en una FPGA pueden implementarse de diferentes maneras. Es posible “inferir” una FIFO a partir de un código VHDL. Es decir, que la descripción VHDL esté escrita de tal manera que la herramienta de síntesis sea capaz de entender que nos estamos refiriendo a una FIFO y sustituya el bloque por una. No obstante para generar memorias FIFO, tanto Altera (Intel) como Xilinx en sus herramientas proporcionan asistentes que nos permiten configurar y generar el bloque IP correspondiente a a FIFO.

En el siguiente video podéis ver los pasos que hay que seguir en la herramienta Vivado de Xilinx para generar una FIFO sencilla y simularla para entender su funcionamiento.

El resultado de la simulación de la FIFO es la siguiente:

simulacion fifo Vivado

En ella podemos comprobar como cada vez que hay un flanco de reloj y la señal de habilitación de escritura esta a ‘1’ se guarda un dato en su interior.

Tras escribir varios valores, activamos la señal de habilitar la lectura y leemos valores en la salida cada flanco de reloj, hasta que de nuevo la señal empty indica que no hay más valores que leer.

A continuación incluimos el código utilizado para simular la FIFO:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity fifo_tb is
--  Port ( );
end fifo_tb;

architecture Behavioral of fifo_tb is
   
  signal clk :  STD_LOGIC:='0';
  signal srst : STD_LOGIC;
  signal din :  STD_LOGIC_VECTOR(7 DOWNTO 0):="00000001";
  signal wr_en : STD_LOGIC;
  signal rd_en : STD_LOGIC;
  signal dout : STD_LOGIC_VECTOR(7 DOWNTO 0);
  signal full : STD_LOGIC;
  signal empty : STD_LOGIC;

begin

  fifo0: entity work.fifo_generator_0(fifo_generator_0_arch) port map(clk,srst,din,wr_en,rd_en,dout,full,empty);

  clk <= not(clk) after 10 ns; 
  srst <= '1', '0' after 10 ns;

  rd_en <='0', '1' after 160 ns, '0' after 240 ns;
  wr_en <= '0', '1' after 40 ns, '0' after 120 ns;
  din <= din+1 after 20ns;

end Behavioral;

Las FIFO son fundamentales en el diseño electrónico y las utilizaremos en posteriores tutoriales para conectar periféricos a Microblaze, Arduino o cualquier otro procesador. Es importante familiarizarse con ellas y manejarlas con soltura para poder crear diseños cada vez más complejos