ISim没有运行完整的仿真时间[VHDL - Xilinx ISE]

时间:2017-02-11 03:07:21

标签: vhdl simulation fifo xilinx-ise

我正在尝试实现FIFO(在VHDL中)但是在我运行测试平台的那一刻,当我将时间设置为800ns时,模拟仅显示165ns。当我评论在测试平台中将push_valid_i分配给1的行时(在"周期2和#34;),我得到它运行800ns。这似乎是实施的问题,对吧?为了以防万一,我在ubuntu 64上运行Xilinx ISE 14.7。以下是其测试平台的实现。

实施:

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.

        -- TEST/DEBUG Purpose only
        PORT_write_ptr_reg : out STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);
        PORT_write_ptr_next : out STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);
        PORT_write_ptr_succ : out STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);

        PORT_read_ptr_reg : out STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);
        PORT_read_ptr_next : out STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);
        PORT_read_ptr_succ : out STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);

        PORT_full_reg, PORT_empty_reg, PORT_full_next, PORT_empty_next, PORT_wr_en : out STD_LOGIC;
        PORT_operation : out STD_LOGIC_VECTOR (1 downto 0)
        );
end Fifo;

architecture Behavioral of Fifo is
    type reg_type is array (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.
                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 if;
        end process;
        -- Input port:
        wr_en <= push_valid_i and (not full_reg);   -- If FIFO is NOT full it is possible to write.
        push_grant_o <=  (not full_reg);                    -- Outputs if the FIFO is FULL (push_grant_o=0)
        -- 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 for 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;

        -- TEST/DEBUG ONLY
        PORT_write_ptr_reg <= write_ptr_reg;
        PORT_write_ptr_next <= write_ptr_next;
        PORT_write_ptr_succ <= write_ptr_succ;
        PORT_read_ptr_reg <= read_ptr_reg;
        PORT_read_ptr_next <= read_ptr_next;
        PORT_read_ptr_succ <= read_ptr_succ;
        PORT_full_reg <= full_reg;
        PORT_empty_reg <= empty_reg;
        PORT_full_next <= full_next;
        PORT_empty_next <= empty_next;
        PORT_wr_en <= wr_en;
        PORT_operation <= (push_valid_i & pop_grant_i);
end Behavioral;

自定义库&#39; my_pkg&#39;:

library IEEE;
use IEEE.STD_LOGIC_1164.all;

package my_pkg is
        constant FIFO_DEPTH : positive := 4;
        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;
         PORT_write_ptr_reg : OUT  std_logic_vector(3 downto 0);
         PORT_write_ptr_next : OUT  std_logic_vector(3 downto 0);
         PORT_write_ptr_succ : OUT  std_logic_vector(3 downto 0);
         PORT_read_ptr_reg : OUT  std_logic_vector(3 downto 0);
         PORT_read_ptr_next : OUT  std_logic_vector(3 downto 0);
         PORT_read_ptr_succ : OUT  std_logic_vector(3 downto 0);
         PORT_full_reg : OUT  std_logic;
         PORT_empty_reg : OUT  std_logic;
         PORT_full_next : OUT  std_logic;
         PORT_empty_next : OUT  std_logic;
         PORT_wr_en : OUT  std_logic;
         PORT_operation : OUT  std_logic_vector(1 downto 0)
        );
    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;
   signal PORT_write_ptr_reg : std_logic_vector(3 downto 0);
   signal PORT_write_ptr_next : std_logic_vector(3 downto 0);
   signal PORT_write_ptr_succ : std_logic_vector(3 downto 0);
   signal PORT_read_ptr_reg : std_logic_vector(3 downto 0);
   signal PORT_read_ptr_next : std_logic_vector(3 downto 0);
   signal PORT_read_ptr_succ : std_logic_vector(3 downto 0);
   signal PORT_full_reg : std_logic;
   signal PORT_empty_reg : std_logic;
   signal PORT_full_next : std_logic;
   signal PORT_empty_next : std_logic;
   signal PORT_wr_en : std_logic;
   signal PORT_operation : std_logic_vector(1 downto 0);

   -- 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,
          PORT_write_ptr_reg => PORT_write_ptr_reg,
          PORT_write_ptr_next => PORT_write_ptr_next,
          PORT_write_ptr_succ => PORT_write_ptr_succ,
          PORT_read_ptr_reg => PORT_read_ptr_reg,
          PORT_read_ptr_next => PORT_read_ptr_next,
          PORT_read_ptr_succ => PORT_read_ptr_succ,
          PORT_full_reg => PORT_full_reg,
          PORT_empty_reg => PORT_empty_reg,
          PORT_full_next => PORT_full_next,
          PORT_empty_next => PORT_empty_next,
          PORT_wr_en => PORT_wr_en,
          PORT_operation => PORT_operation
        );

   -- 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';
        wait for clk_period;
        -- Cycle 2
        push_valid_i <= '1';
        push_data_i <= "0001";
        wait for clk_period;

      wait;
   end process;

END;

以下是push_valid_i&lt; =&#39; 1&#39;评论:https://ibb.co/koy0dv

以下是push_valid_i&lt; =&#39; 1&#39;未评论:https://ibb.co/mxiSQa

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我们可以看到的事实:

  

我正在尝试实现FIFO(在VHDL中)但是在我运行测试平台的那一刻,当我将时间设置为800ns时,模拟仅显示165ns。

     

当我评论在测试平台中将push_valid_i分配给1的行时(在&#34;周期2和#34;),我得到它运行800ns。

     

这似乎是实施的问题,对吧?为了以防万一,我在ubuntu 64上运行Xilinx ISE 14.7。

查看FIFO深度,它由FIFO_DEPTH设置:

    type reg_type is array (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地址指针由FIFO_DEPTH定义(以位为单位):

    signal write_ptr_reg, write_ptr_next, write_ptr_succ : STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0);
    -- Write control registers.

FIFO存储器的FIFO索引从这些指针派生为整数索引:

            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.

包numeric_std中的to_integer调用将二进制无符号值转换为范围为0的整数,以及由二进制值的位长表示的最大整数值。对于FIFO_DEPTH为4,指针范围为FIFO_DEPTH - 1 downto 0,表示0到15之间的自然数。

这与FIFO数组大小(字数,设置为4)形成对比。

查看ISE 14.7中找到的ISIM的Xilinx ISim User Guide (UG660)表明,索引范围绑定检查应始终发生:

rangcheck option.png

分析,详细说明和模拟您的设计,它在另一个VHDL工具(ghdl)中的测试平台显示索引写入的边界检查错误(上面显示的VHDL代码)。

IEEE Std 1076-2008 8.3索引名称,第3段最后一句:

  

如果索引值不属于数组的相应索引范围的范围,则会出错。

VHDL标准需要进行索引范围检查,执行时指示模拟器捕获的模型错误。对于4位二进制地址指针,应声明数组类型的索引范围

    type reg_type is array (2 ** FIFO_DEPTH - 1 downto 0) of STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0); 

其中,对于指针索引的每个值,将存在相应的FIFO阵列位置。

对reg_type声明进行此更改会导致模型运行到800 ns:

fifo_testbench.png

您可以从波形信息栏中看到标记显示在165 ns,这只与clk的下降沿重合,并且模型中的预视事件来自clk的上升沿,表示写入索引14(E)。

这与对数组类型索引范围之外的地址的第一次操作不一致。

我认为ISIM确实没有在这里执行索引范围检查(应该是)。除了模型写入数组类型索引范围之外的幻像元素对象之外,最终会破坏模拟模型到clk下降沿的失败点。

可以通过对reg_type类型声明进行上述更改来验证此争用。

虽然您自己的波形令人困惑,但您可以看到在测试平台的第2周期中注释掉push_valid_i <= '1';会导致没有指针增量:

fifo_testbench_valid_commented.png

模拟运行整个800 ns,因为没有索引操作超出原始reg_type索引范围的范围。

因此,您有一个范围检查错误,应该在模拟过程中捕获,而不是,并且可以通过更改类型reg_type的数组大小来解决。

从评论链到您的问题:

  

类型reg_type的大小错误,可以用作指针的地址吗?我将详细分析它,因为我现在还没有得到它并回复你

是的,reg_type类型声明中指定的数组大小是错误的。

随着时间的推移,我们会随时了解工具的问题。是否可以在ISIM中启用索引范围检查,尽管声称它始终启用可能是ISIM版本问题,否则可以通过实验验证。

在保留ISIM对模拟的有用性的同时,还有其他几种选择。您可以合成设计,应报告错误。您可以使用已知执行索引范围检查的其他模拟器,这不会妨碍您在完成所有边界检查并且已知有效(并且在影响边界的任何更改之后重新验证)时使用ISIM。

ISIM中的问题也可能出现在需要索引范围检查的可能案例的子集中。 (VHDL实现起来很复杂。)

如果存在缺陷,Xilinx会收到通知,他们会(最终)在以后的ISIM版本中解决问题。

如果更改reg_type数组大小,请告诉我们。