我正在尝试实现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
感谢您的帮助。
答案 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)表明,索引范围绑定检查应始终发生:
分析,详细说明和模拟您的设计,它在另一个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:
您可以从波形信息栏中看到标记显示在165 ns,这只与clk的下降沿重合,并且模型中的预视事件来自clk的上升沿,表示写入索引14(E)。
这与对数组类型索引范围之外的地址的第一次操作不一致。
我认为ISIM确实没有在这里执行索引范围检查(应该是)。除了模型写入数组类型索引范围之外的幻像元素对象之外,最终会破坏模拟模型到clk下降沿的失败点。
可以通过对reg_type类型声明进行上述更改来验证此争用。
虽然您自己的波形令人困惑,但您可以看到在测试平台的第2周期中注释掉push_valid_i <= '1';
会导致没有指针增量:
模拟运行整个800 ns,因为没有索引操作超出原始reg_type索引范围的范围。
因此,您有一个范围检查错误,应该在模拟过程中捕获,而不是,并且可以通过更改类型reg_type的数组大小来解决。
从评论链到您的问题:
类型reg_type的大小错误,可以用作指针的地址吗?我将详细分析它,因为我现在还没有得到它并回复你
是的,reg_type类型声明中指定的数组大小是错误的。
随着时间的推移,我们会随时了解工具的问题。是否可以在ISIM中启用索引范围检查,尽管声称它始终启用可能是ISIM版本问题,否则可以通过实验验证。
在保留ISIM对模拟的有用性的同时,还有其他几种选择。您可以合成设计,应报告错误。您可以使用已知执行索引范围检查的其他模拟器,这不会妨碍您在完成所有边界检查并且已知有效(并且在影响边界的任何更改之后重新验证)时使用ISIM。
ISIM中的问题也可能出现在需要索引范围检查的可能案例的子集中。 (VHDL实现起来很复杂。)
如果存在缺陷,Xilinx会收到通知,他们会(最终)在以后的ISIM版本中解决问题。
如果更改reg_type数组大小,请告诉我们。