Estuve trabajando en eso durante los últimos cinco días y no sé qué pasó. Debo implementar un FIFO para enviar alguna información, adjunto el FIFO que utilizo. Como puede ver en el código, este FIFO utiliza tres procesos actualizar datos , proceso de puntero y enviar o recibir datos . La idea es enviar la información con una frecuencia un poco más baja que el reloj del FPGA, por eso el proceso utiliza la sensibilidad de wr_en y rd_en (las señales de habilitación) para realizar dos de los procesos. En primer lugar simulé todas las diferentes señales que el FIFO necesita para enviar o recibir la información y la simulación funciona bien sin problemas, todas las señales que esperaba estaban allí (también adjunto el banco de pruebas FIFO).
El problema es cuando intenté escribir en el FIFO, si hice eso con los interruptores, no hay problema, el FIFO funciona bien. Sin embargo, cuando intenté enviar la información con otro FPGA con una frecuencia más alta, el FIFO reconoce algunos datos falsos y, por este motivo, el FIFO está lleno incluso cuando la señal de wr_en era alta solo una (pero con una frecuencia más baja del principal). FPGA). Busqué mucho en la simulación y en el código, y no veo ningún problema, no sé por qué el FIFO no funciona como lo esperaba.
Cualquier consejo sobre lo que podría pasar realmente lo aprecio. Gracias
Código FIFO en VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
------------------------------------------------------
----------------------------------------------------------------------------
entity fifo is
Generic(
ADDR_W : integer := 7; -- address width in bits
DATA_W : integer := 24; -- data width in bits
BUFF_L : integer := 80; -- buffer length must be less than address space as in BUFF_L <or= 2^(ADDR_W)
ALMST_F : integer := 3; -- fifo flag for almost full regs away from empty fifo
ALMST_E : integer := 3 -- fifo regs away from empty fifo
);
Port (
clk : in std_logic;
n_reset : in std_logic;
rd_en : in std_logic; -- read enable
wr_en : in std_logic; -- write enable
data_in : in std_logic_vector(DATA_W- 1 downto 0);
data_out : out std_logic_vector(DATA_W- 1 downto 0);
data_count : out std_logic_vector(ADDR_W downto 0);
inputValid : out std_logic;
full : out std_logic;
rd_ptr_out : out std_logic_vector(ADDR_W-1 downto 0); -- current pointers
wr_ptr_out : out std_logic_vector(ADDR_W-1 downto 0); -- current pointers
err : out std_logic
);
end fifo;
----------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
architecture arch of fifo is
type reg_file_type is array (0 to ((2**ADDR_W) - 1)) of std_logic_vector(DATA_W - 1 downto 0);
-----------memory, pointers, and flip flops---------
signal mem_array : reg_file_type ;
signal rd_ptr, wr_ptr : std_logic_vector(ADDR_W-1 downto 0); -- current pointers
signal rd_ptr_nxt : std_logic_vector(ADDR_W-1 downto 0); -- next pointer
signal wr_ptr_nxt : std_logic_vector(ADDR_W-1 downto 0); -- next pointer
signal full_ff, empty_ff : std_logic; -- full and empty flag flip flops
signal full_ff_nxt : std_logic; -- full and empty flag flip flops for next state
signal empty_ff_nxt : std_logic;
signal q_reg, q_next : std_logic_vector(ADDR_W downto 0); -- data counter
signal q_add, q_sub : std_logic;
signal wr_en_prev,rd_en_prev : std_logic;
---------------------------------------------------
begin
---------- Process to update read, write, full, and empty on clock edges
reg_update :
process(clk)
begin
if falling_edge(clk) then
if (n_reset = '0') then
rd_ptr <= (others => '0');
wr_ptr <= (others => '0');
full_ff <= '0';
empty_ff <= '1';
q_reg <= (others => '0');
else
rd_ptr <= rd_ptr_nxt;
wr_ptr <= wr_ptr_nxt;
full_ff <= full_ff_nxt;
empty_ff <= empty_ff_nxt;
q_reg <= q_next;
wr_en_prev <= wr_en;
rd_en_prev <= rd_en;
end if; -- end of n_reset if
end if; -- end of falling_edge(clk) if
end process;
----------- Process to control read and write pointers and empty/full flip flops
Ptr_Cont_Original :
process(wr_en, rd_en, q_reg)
begin
wr_ptr_nxt <= wr_ptr; -- no change to pointers
rd_ptr_nxt <= rd_ptr;
full_ff_nxt <= full_ff;
empty_ff_nxt <= empty_ff;
q_add <= '0';
q_sub <= '0';
---------- check if fifo is full during a write attempt, after a write increment counter
----------------------------------------------------
if((wr_en /= wr_en_prev) or (rd_en /= rd_en_prev)) then
if(wr_en = '1' and rd_en = '0') then
if(full_ff = '0') then
q_add <= '1';
if(conv_integer(wr_ptr) < BUFF_L-1 ) then
wr_ptr_nxt <= wr_ptr + '1';
empty_ff_nxt <= '0';
else
wr_ptr_nxt <= (others => '0');
empty_ff_nxt <= '0';
end if;
-- check if fifo is full
if (conv_integer(wr_ptr + '1') = conv_integer(rd_ptr) or (conv_integer(wr_ptr) = (BUFF_L-1) and conv_integer(rd_ptr) = 0)) then
full_ff_nxt <= '1';
end if ;
end if;
end if;
---------- check to see if fifo is empty during a read attempt, after a read decrement counter
---------------------------------------------------------------
if(wr_en = '0' and rd_en = '1') then
if(empty_ff = '0') then
if(conv_integer(q_reg) > 0) then
q_sub <= '1';
else
q_sub <= '0';
end if;
if(conv_integer(rd_ptr) < BUFF_L-1 ) then
rd_ptr_nxt <= rd_ptr + '1';
full_ff_nxt <= '0';
else
rd_ptr_nxt <= (others => '0');
full_ff_nxt <= '0';
end if;
-- check if fifo is empty
if (conv_integer(rd_ptr + '1') = conv_integer(wr_ptr) or (conv_integer(rd_ptr) = (BUFF_L-1) and conv_integer(wr_ptr) = 0 )) then
empty_ff_nxt <= '1';
end if ;
end if;
end if;
-----------------------------------------------------------------
if(wr_en = '1' and rd_en = '1') then
if(conv_integer(wr_ptr) < BUFF_L-1 ) then
wr_ptr_nxt <= wr_ptr + '1';
else
wr_ptr_nxt <= (others => '0');
end if;
if(conv_integer(rd_ptr) < BUFF_L-1 ) then
rd_ptr_nxt <= rd_ptr + '1';
else
rd_ptr_nxt <= (others => '0');
end if;
end if;
end if;
end process;
-------- Process to control memory array writing and reading
mem_cont :
process(wr_en,rd_en,n_reset)
begin
if( n_reset = '0') then
mem_array <= (others => (others => '0')); -- reset memory array
data_out <= (others => '0'); -- reset data out
err <= '0';
else
-- if write enable and not full then latch in data and increment wright pointer
if( wr_en = '1') and (full_ff = '0') then
mem_array (conv_integer(wr_ptr)) <= data_in ;
err <= '0';
elsif(wr_en = '1') and (full_ff = '1') then -- check if full and trying to write
err <= '1';
end if ;
-- if read enable and fifo not empty then latch data out and increment read pointer
if( rd_en = '1') and (empty_ff = '0') then
data_out <= mem_array(conv_integer(rd_ptr));
err <= '0';
elsif(rd_en = '1') and (empty_ff = '1') then -- check if empty and trying to read
err <= '1';
end if ;
end if; -- end of n_reset if
end process;
------ counter to keep track of almost full and almost empty
q_next <= q_reg + 1 when q_add = '1' else
q_reg - 1 when q_sub = '1' else
q_reg;
-------- connect ff to output ports
full <= full_ff;
inputValid <= not empty_ff;
data_count <= q_reg;
wr_ptr_out <= wr_ptr;
rd_ptr_out <= rd_ptr;
end arch;
---------------------------------------------------------------------------------------
TestBench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY fifo_tb IS
END fifo_tb;
ARCHITECTURE behavior OF fifo_tb IS
COMPONENT fifo
Generic(
ADDR_W : integer := 4; -- address width in bits
DATA_W : integer := 24; -- data width in bits
BUFF_L : integer := 16; -- buffer length must be less than address space as in BUFF_L <= 2^(ADDR_W)
ALMST_F : integer := 3; -- fifo regs away from full fifo
ALMST_E : integer := 3 -- fifo regs away from empty fifo
);
Port (
clk : in std_logic;
n_reset : in std_logic;
rd_en : in std_logic; -- read enable
wr_en : in std_logic; -- write enable
data_in : in std_logic_vector(DATA_W- 1 downto 0);
data_out : out std_logic_vector(DATA_W- 1 downto 0);
data_count : out std_logic_vector(ADDR_W downto 0);
inputValid : out std_logic;
full : out std_logic;
err : out std_logic
);
END COMPONENT;
SIGNAL clk : std_logic;
SIGNAL n_reset : std_logic;
SIGNAL rd_en : std_logic;
SIGNAL wr_en : std_logic;
SIGNAL data_in : std_logic_vector(23 downto 0);
SIGNAL data_out : std_logic_vector(23 downto 0);
SIGNAL data_count : std_logic_vector(4 downto 0);
SIGNAL inputValid : std_logic;
SIGNAL err : std_logic;
SIGNAL full : std_logic;
constant PERIOD : time := 20 ns;
BEGIN
-- Please check and add your generic clause manually
uut: fifo PORT MAP(
clk => clk,
n_reset => n_reset,
rd_en => rd_en,
wr_en => wr_en,
data_in => data_in,
data_out => data_out,
data_count => data_count,
inputValid => inputValid,
err => err,
full => full
);
-- PROCESS TO CONTROL THE CLOCK
clock : PROCESS
BEGIN
clk <= '1';
WAIT FOR PERIOD/2;
clk <= '0';
WAIT FOR PERIOD/2;
END PROCESS;
-- *** Test Bench - User Defined Section ***
tb : PROCESS
BEGIN
n_reset <= '0';
rd_en <= '0';
WAIT FOR 40 NS;
n_reset <= '1';
wr_en <= '0';
WAIT FOR 20 NS;
wr_en <= '1';
data_in <= std_logic_vector(to_unsigned(10,24));
wait for 10*PERIOD;
wr_en <= '0';
wait for PERiOD;
wr_en <='1';
data_in <= std_logic_vector(to_unsigned(5,24));
WAIT FOR 40 NS;
n_reset <= '1';
wr_en <= '0';
WAIT FOR 20 NS;
-- write to fifo
for test_vec in 0 to 17 loop
WAIT FOR 20 NS;
wr_en <= '1';
data_in <= std_logic_vector(to_unsigned(test_vec,24));
WAIT FOR 20 NS;
wr_en <= '0';
end loop;
wait for 10 ns;
WAIT FOR 10 NS;
rd_en <= '1';
WAIT FOR 10 NS;
rd_en <= '0';
wait for 3*PERIOD;
-- read from fifo
for test_vec in 0 to 8 loop
WAIT FOR 10 NS;
rd_en <= '1';
WAIT FOR 10 NS;
rd_en <= '0';
end loop;
-- write to fifo
for test_vec in 0 to 15 loop
WAIT FOR 10 NS;
wr_en <= '1';
data_in <= std_logic_vector(to_unsigned(test_vec,24));
WAIT FOR 10 NS;
wr_en <= '0';
end loop;
-- read from fifo
for test_vec in 0 to 11 loop
WAIT FOR 10 NS;
rd_en <= '1';
WAIT FOR 10 NS;
rd_en <= '0';
end loop;
WAIT FOR 80 NS;
-- read and write to fifo
for test_vec in 0 to 11 loop
WAIT FOR 10 NS;
wr_en <= '1';
rd_en <= '1';
data_in <= std_logic_vector(to_unsigned(test_vec,24));
WAIT FOR 10 NS;
wr_en <= '0';
rd_en <= '0';
end loop;
-- read from fifo
for test_vec in 0 to 7 loop
WAIT FOR 10 NS;
rd_en <= '1';
WAIT FOR 10 NS;
rd_en <= '0';
end loop;
-- write to fifo
for test_vec in 0 to 13 loop
WAIT FOR 10 NS;
wr_en <= '1';
data_in <= std_logic_vector(to_unsigned(test_vec,24));
WAIT FOR 10 NS;
wr_en <= '0';
end loop;
wait; -- will wait forever
END PROCESS;
-- *** End Test Bench - User Defined Section ***
END;