2017-02-14 7 views
0

Я пытаюсь реализовать FIFO из прототипирования Fpga по примерам Vhdl (Wiley), и у меня возникают некоторые проблемы. Первые введенные данные фактически являются вторыми данными. Кажется, он пропускает один слот FIFO.Проблема с синхронным FIFO [VHDL]

Вот код:

library IEEE; 
USE ieee.std_logic_1164.ALL; 
USE ieee.numeric_std.ALL; 
use WORK.my_pkg.ALL; 

entity Fifo is  
    Port(
     clk    : in STD_LOGIC; 
     rst_n    : in STD_LOGIC; 
     -- DATA 
     push_data_i : in STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0);  -- Data IN. 
     pop_data_o  : out STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0);  -- Data out. 
     -- CONTROL 
     push_valid_i : in STD_LOGIC;            -- 1 to write push_data_i into the FIFO. 
     pop_grant_i : in STD_LOGIC;            -- 1 to read from the FIFO. 
     -- STATUS 
     push_grant_o : out STD_LOGIC;            -- 0 when full. To write push_grant_o=1 and push_valid_i=1. 
     pop_valid_o  : out STD_LOGIC            -- 1 where there is data available in the FIFO. 
     ); 
end Fifo; 

architecture Behavioral of Fifo is 
    type reg_type is array (2**FIFO_DEPTH-1 downto 0) of STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0);    -- FIFO_WIDTH x FIFO_DEPTH 2D-array. 
    signal array_reg : reg_type;                         -- FIFO itself. Data is stored here. 
    signal write_ptr_reg, write_ptr_next, write_ptr_succ : STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);  -- Write control registers. 
    signal read_ptr_reg, read_ptr_next, read_ptr_succ : STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);   -- Read control registers. 
    signal full_reg, full_next : STD_LOGIC := '0';                   -- Status registers 
    signal empty_reg, empty_next : STD_LOGIC := '1';                  -- Status registers 
    signal operation : STD_LOGIC_VECTOR (1 downto 0) := "00";               -- Operation 2 bit array 
    signal wr_en: STD_LOGIC;                          -- Write possible register. 

    begin 
     -- ** PUSH & POP PORTS (data) ** -- 
     process(clk, rst_n) 
     begin 
      if(rst_n='0') then 
       array_reg <= (others=>(others=>'0'));          -- Sets the entire array_reg (2D-array) to 0. 
       write_ptr_reg <= (others=>'0'); -- Resets all write registers (to 0). 
       read_ptr_reg <= (others=>'0'); -- Resets all read registers (to 0). 
       full_reg <= '0';      -- Full register is set to 0 as FIFO is not FULL. 
       empty_reg <= '1';      -- Empty register is set to 1 as FIFO is empty. 
      elsif (clk'event and clk='1') then            -- Rising edge of the clock. 
       if (wr_en='1') then 
        array_reg(to_integer(unsigned(write_ptr_reg))) <= push_data_i; -- It writes the incoming data (push_data_i) to the corresponding position in the FIFO. 
                             -- It expects an intiger as the position in the array. Therefore the 'to_intiger' function. 
       end if; 
       write_ptr_reg <= write_ptr_next; -- Current write position becomes the next one on clock event. 
       read_ptr_reg <= read_ptr_next; -- Current read position becomes the next one on clock event. 
       full_reg <= full_next;    -- Current full position becomes the next one on clock event. 
       empty_reg <= empty_next;   -- Current empty position becomes the next one on clock event. 
      end if; 
     end process; 
     -- Input port: 
     wr_en <= push_valid_i and (not full_reg); -- If FIFO is NOT full it is possible to write. 
     -- Output port: 
     -- It is done differently from the input port as the output data ('first-in', pointed by read_ptr_reg)has to be available all the time. 
     pop_data_o <= array_reg(to_integer(unsigned(read_ptr_reg))); 

     -- Successive values to read and write when requested. 
     write_ptr_succ <= STD_LOGIC_VECTOR(unsigned(write_ptr_reg)+1); 
     read_ptr_succ <= STD_LOGIC_VECTOR(unsigned(read_ptr_reg)+1); 

     -- ** Events and register control ** -- 
     operation <= (push_valid_i & pop_grant_i); -- Concatenates the two control inputs for the 'case, when' statement. 
     process(write_ptr_reg, write_ptr_succ, read_ptr_reg, read_ptr_succ, 
        operation, full_reg, empty_reg) 
     begin 
      write_ptr_next <= write_ptr_reg;  -- This four lines are to assure that the current state does not 
      read_ptr_next <= read_ptr_reg;  -- change in case none of the case-when statements happen. 
      full_next <= full_reg; 
      empty_next <= empty_reg; 
      case operation is 
       when "00" =>           -- Not write (push) or read (pop). 
       when "01" =>           -- Read. 
        if(empty_reg /= '1') then      -- If FIFO is NOT empty, it can be read. 
         read_ptr_next <= read_ptr_succ;   -- It points to the successive position to read. 
         full_next <= '0';        -- As one position is read, FIFO will NOT be full. 
         if(read_ptr_succ=write_ptr_reg) then -- Read 'reached' write. So the FIFO will be EMPTY. 
          empty_next <= '1'; 
         end if; 
        end if; 
       when "10" =>           -- Write. 
        if(full_reg /='1') then       -- If FIFO is NOT full, it can be written. 
         write_ptr_next <= write_ptr_succ; 
         empty_next <= '0';       -- The FIFO is written, so it will NOT be empty. 
         if(write_ptr_succ=read_ptr_reg) then -- Write 'reached' read, so the FIFO will be full. 
          full_next <= '1'; 
         end if; 
        end if; 
       when others =>          -- Write and Read at the same time. 
        write_ptr_next <= write_ptr_succ; 
        read_ptr_next <= read_ptr_succ; 
       end case; 
     end process; 

     -- Output STATUS 
     push_grant_o <= not full_reg; 
     pop_valid_o <= not empty_reg; 
end Behavioral; 

my_pkg.vhd:

library IEEE; 
use IEEE.STD_LOGIC_1164.all; 

--use IEEE.math_real."ceil"; 
--use IEEE.math_real."log2"; 

package my_pkg is 
     -- ** This should be used if math_real library available. Otherwise comment lines 24 and 25. Uncomment line 27 ** -- 
     --constant SLOTS : positive := 4;    -- This values has to be a power of two (2, 4, 8, 16, etc). 
     --constant FIFO_DEPTH : positive := integer(ceil(log2(real(SLOTS)))); 

     constant FIFO_DEPTH : positive := 2; -- The number of SLOTS of the FIFO will be 2^FIFO_DEPTH. In this case, 4 slots. 
     constant DATA_WIDTH : positive := 3; 
     constant FIFO_WIDTH : positive := DATA_WIDTH+1; --DATAWIDTH=WIDTH+1bitParity 
     constant PARITY  : bit   := '0'; -- EVEN or ODD. 
     constant PARITY_BIT : bit   := '0'; -- LSB or MSB. 
end my_pkg; 

Вот испытательный стенд:

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 

-- Uncomment the following library declaration if using 
-- arithmetic functions with Signed or Unsigned values 
--USE ieee.numeric_std.ALL; 

ENTITY Fifo_testbench IS 
END Fifo_testbench; 

ARCHITECTURE behavior OF Fifo_testbench IS 

    -- Component Declaration for the Unit Under Test (UUT) 

    COMPONENT Fifo 
    PORT(
     clk : IN std_logic; 
     rst_n : IN std_logic; 
     push_data_i : IN std_logic_vector(3 downto 0); 
     pop_data_o : OUT std_logic_vector(3 downto 0); 
     push_valid_i : IN std_logic; 
     pop_grant_i : IN std_logic; 
     push_grant_o : OUT std_logic; 
     pop_valid_o : OUT std_logic 
     ); 
    END COMPONENT; 


    --Inputs 
    signal clk : std_logic := '0'; 
    signal rst_n : std_logic := '0'; 
    signal push_data_i : std_logic_vector(3 downto 0) := (others => '0'); 
    signal push_valid_i : std_logic := '0'; 
    signal pop_grant_i : std_logic := '0'; 

    --Outputs 
    signal pop_data_o : std_logic_vector(3 downto 0); 
    signal push_grant_o : std_logic; 
    signal pop_valid_o : std_logic; 

    -- Clock period definitions 
    constant clk_period : time := 10 ns; 

BEGIN 

    -- Instantiate the Unit Under Test (UUT) 
    uut: Fifo PORT MAP (
      clk => clk, 
      rst_n => rst_n, 
      push_data_i => push_data_i, 
      pop_data_o => pop_data_o, 
      push_valid_i => push_valid_i, 
      pop_grant_i => pop_grant_i, 
      push_grant_o => push_grant_o, 
      pop_valid_o => pop_valid_o 
     ); 

    -- Clock process definitions 
    clk_process :process 
    begin 
     clk <= '1'; 
     wait for clk_period/2; 
     clk <= '0'; 
     wait for clk_period/2; 
    end process; 


    -- Stimulus process 
    stim_proc: process 
    begin   
     -- hold reset state for 100 ns. 
     wait for 20 ns; 

     rst_n <= '1'; 

     push_valid_i <= '1'; 
     push_data_i <= "1001"; 
     wait for clk_period; 
     push_data_i <= "1010"; 
     wait for clk_period; 
     push_data_i <= "1011"; 
     wait for clk_period; 
     push_data_i <= "1100"; 
     wait for clk_period; 
     push_data_i <= "1101"; 
     wait for clk_period; 
     push_valid_i <= '0'; 


     wait; 
    end process; 

END; 

А вот моделирование: Simulation

Идея состоит в том, что все 4 начальных значения (1001, 1010, 1011 и 1100) вставляются в FIFO, поскольку push_grant_i включен, а FIFO не заполнен. Для 5-го значения (1101) FIFO не может вытолкнуть его по мере его заполнения. Кажется, что он работает нормально, но после первого нарастающего фронта часов (30 нс в симуляции), когда первое значение (1001) было нажато, оно не находится на выходном порту (pop_data_o). Фактически, это второе значение, поэтому оно пропускает 1001. pop_data_o следует обновлять, только если pop_grant_i равен 1.

Спасибо за помощь.

+0

Если вы должны были использовать дисплей формы волны, чтобы всмотреться в блок испытываемого вы обнаружите, что записи собирались в [неправильном месте] (https://i.stack.imgur.com/zyvxg. PNG). – user1155120

+0

Да, он пишет не то место, но 'array_reg (to_integer (unsigned (write_ptr_reg))) <= push_data_i;' кажется прекрасным, поскольку 'write_ptr_reg' обновляет до тех пор, пока не будет нажата новая величина. Я не понимаю, почему первое значение не помещено в первую позицию 'array_reg'. – aripod

+1

В испытательном стенде стимулы стимуляции стимула до тех пор, пока не будет кратковременно. 'wait for 21 ns;' вместо 20 ns. Это творит чудеса для вашего [состояния FIFO] (https://i.stack.imgur.com/45P0E.png). – user1155120

ответ

0

В вашем испытательном стенде есть состояние гонки. То есть вы меняете push_data_i во время края часов. Это также не будет работать в реальной жизни, поскольку регистры имеют время установки и удержания. Вы должны использовать те же часы для тестового стенда, что и для UUT. Например.

-- Stimulus process 
stim_proc: process 
begin   
    -- hold reset state for 100 ns. 
    wait for 100 ns; 
    rst_n <= '1'; 

    wait until rising_edge(clk); 
    push_valid_i <= '1'; 
    push_data_i <= "1001"; 
    wait until rising_edge(clk); 
    push_data_i <= "1010"; 
    wait until rising_edge(clk); 
    push_data_i <= "1011"; 
    wait until rising_edge(clk); 
    push_data_i <= "1100"; 
    wait until rising_edge(clk); 
    push_data_i <= "1101"; 
    wait until rising_edge(clk); 
    push_valid_i <= '0'; 

    wait; 
end process; 
Смежные вопросы