VHDL - FSM 未启动(仅在时序仿真中)
VHDL - FSM not starting (JUST in timing simulation)
我正在为我的硕士论文工作,我对 VHDL 还很陌生,但我仍然必须实现一些复杂的东西。这是我必须编写的最简单的结构之一,但我仍然遇到了一些问题。
这是一个 FSM,它实现了一个带有 active-low 同步信号的 24 位移位寄存器(用于对 DAC 进行编程)。这只是我为我的项目创建的复杂细化链的终点。我尽可能地遵循了 FSM 的示例模型。
行为模拟工作正常,实际上,就行为模拟而言,我创建的整个精化链工作得非常好。但是,一旦我尝试 Post-translate 模拟,事情就开始出错了:很多 'X' 输出信号。
使用这个简单的移位寄存器我没有得到任何 'X',但是我无法进入 load_and_prepare_data 阶段。 current_state 似乎发生了变化(通过检查一些信号),但详细说明没有继续进行。
请记住,由于我是该语言的新手,所以我不知道应该在此 FSM 上设置什么时间限制(而且我不知道如何将它们写在 top.ucf 无论如何)
你能看出哪里出了问题吗?
提前致谢
编辑
我听从了您的建议,使用单状态进程清理了 FSM。我仍然对 "where to put what" 有一些疑问,但我真的很喜欢新的实现。无论如何,我现在得到了一个干净的行为模拟,但是 'X' 在 post 翻译模拟中的所有输出。
是什么原因造成的?
我将 post 新代码和测试平台:
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 14:44:03 11/28/2014
-- Design Name:
-- Module Name: dac_ad5764r_24bit_sr_programmer_v2 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description: This is a PISO shift register that gets a 24bit parallel input word.
-- It outputs the 24bit input word starting from the MSB and enables
-- an active low ChipSelect line for 24 clock periods.
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
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;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity dac_ad5764r_24bit_sr_programmer_v2 is
Port ( clk : in STD_LOGIC;
start : in STD_LOGIC;
reset : in STD_LOGIC; -- Note that this reset is for the FSM not for the DAC
reset_all_dac : in STD_LOGIC;
data_in : in STD_LOGIC_VECTOR (23 downto 0);
serial_data_out : out STD_LOGIC;
sync_out : out STD_LOGIC; -- This is a chip select
reset_out : out STD_LOGIC;
busy : out STD_LOGIC
);
end dac_ad5764r_24bit_sr_programmer_v2;
architecture Behavioral of dac_ad5764r_24bit_sr_programmer_v2 is
-- Stati
type state_type is (idle, load_and_prepare_data, transmission);
--ATTRIBUTE ENUM_ENCODING : STRING;
--ATTRIBUTE ENUM_ENCODING OF state_type: TYPE IS "001 010 100";
signal state: state_type := idle;
--signal next_state: state_type := idle;
-- Clock counter
--signal clk_counter_enable : STD_LOGIC := '0';
signal clk_counter : unsigned(4 downto 0) := (others => '0');
-- Shift register
signal stored_data: STD_LOGIC_VECTOR (23 downto 0) := (others => '0');
begin
FSM_single_process: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
serial_data_out <= '0';
sync_out <= '1';
reset_out <= '1';
busy <= '0';
state <= idle;
else
-- Default
serial_data_out <= '0';
sync_out <= '1';
reset_out <= '1';
busy <= '0';
case (state) is
when transmission =>
serial_data_out <= stored_data(23);
sync_out <= '0';
busy <= '1';
clk_counter <= clk_counter + 1;
stored_data <= stored_data(22 downto 0) & "0";
state <= transmission;
if (clk_counter = 23) then
state <= idle;
end if;
when others => -- Idle
if start = '1' then
serial_data_out <= data_in(23);
sync_out <= '0';
reset_out <= '1';
busy <= '1';
stored_data <= data_in;
clk_counter <= "00001";
state <= transmission;
end if;
end case;
-- if (reset_all_dac = '1') then
-- reset_out <= '0';
-- end if;
end if;
end if;
end process;
end;
和测试平台:
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 dac_ad5764r_24bit_sr_programmer_tb IS
END dac_ad5764r_24bit_sr_programmer_tb;
ARCHITECTURE behavior OF dac_ad5764r_24bit_sr_programmer_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT dac_ad5764r_24bit_sr_programmer_v2
PORT(
clk : IN std_logic;
start : IN std_logic;
reset : IN std_logic;
data_in : IN std_logic_vector(23 downto 0);
serial_data_out : OUT std_logic;
reset_all_dac : IN std_logic;
sync_out : OUT std_logic;
reset_out : OUT std_logic;
--finish : OUT std_logic;
busy : OUT std_logic
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal start : std_logic := '0';
signal reset : std_logic := '0';
signal data_in : std_logic_vector(23 downto 0) := (others => '0');
signal reset_all_dac : std_logic := '0';
--Outputs
signal serial_data_out : std_logic;
signal sync_out : std_logic;
signal reset_out : std_logic;
--signal finish : std_logic;
signal busy : std_logic;
-- Clock period definitions
constant clk_period : time := 100 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: dac_ad5764r_24bit_sr_programmer_v2 PORT MAP (
clk => clk,
start => start,
reset => reset,
data_in => data_in,
reset_all_dac => reset_all_dac,
serial_data_out => serial_data_out,
sync_out => sync_out,
reset_out => reset_out,
--finish => finish,
busy => busy
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for clk_period*10;
reset <= '1' after 25 ns;
wait for clk_period*1;
reset <= '0' after 25 ns;
wait for clk_period*3;
reset_all_dac <= '1' after 25 ns;
wait for clk_period*1;
reset_all_dac <= '0' after 25 ns;
wait for clk_period*5;
data_in <= "111111111111111111111111" after 25 ns;
wait for clk_period*3;
start <= '1' after 25 ns;
wait for clk_period*1;
start <= '0' after 25 ns;
wait;
end process;
END;
更新 1
更新了最后一个设计:此代码不会导致任何 'X'(无法弄清楚为什么,这个不会,但以前的会)。然而,它并没有像前 3 个进程机器那样启动(在 POST-TRANSLATE 模拟中),并且信号 sync_out 卡在 0 而默认情况下它应该是 '1'。
更新 2
我一直在研究技术原理图,从 sync_out=0 的问题开始:它是用 FDS 实现的,S 是 FSM 复位信号,D 来自 LUT3 和 I = state&reset&start 和 INIT = 45 = "00101101"。我在模拟中寻找了这个 LUT3,我注意到它有 INIT = "00000000"!
关于如何 运行 这个模拟,我是否遗漏了什么?好像设计中的每一个LUT都没有设置好!
更新 3
似乎 Post-Translate 模拟在某些方面有问题,或者由于某种原因我没有正确配置它:Post-Map 和 Post-PAR 模拟工作并显示一些输出。
但是有一个奇怪的错误:stored_data 寄存器没有用完整的 data_in 向量更新,之后,FSM 正确运行并输出存储的数据。
我在综合后查看了技术原理图,由于某种原因,位 23、22、21、19、18 未连接到相应的 data_in 位。您可以在 Post-Map 模拟的此屏幕截图中看到效果。同样发生在Post-PAR,但似乎这个问题直接来自综合!
已解决:奇怪的输出来自综合优化。该工具意识到精化链中的前一个块永远不会为那些特定位输出与 0 不同的位。我的错误是假设我可以单独测试单个块:我真正测试的是为 FPGA 综合的块,同时考虑了设计中的所有其他内容!
感谢大家的帮助,我会听从大家的建议!
这里有一些改进代码的提示:
- 您可以删除 Xilinx 对 UNISIM 的依赖性,因为您没有使用任何 Xilinx Primitves。
- 应用属性 ENUM_ENCODING 对状态编码没有影响,除非您还定义属性 FSM_ENCODING 并将其值设置为用户。可以通过将 FSM_ENCODING 设置为 one-hot 来强制使用 One-Hot 编码。通常合成足够聪明,可以找到最好的编码。
read more ...
- None 个寄存器具有默认值:
signal current_state : state_type := idle;
- 你的FSM在Xilinx综合工具(XST)眼里不是FSM。我敢肯定,如果您查看综合报告,您不会发现 XST 报告了 current_state.
的 FSM
那么你的 FSM 出了什么问题?
- 您的 FSM 没有初始状态。
- 您的 FSM 有多个重置状态(空闲,load_and_prepare_data)
- 你的 FSM 没有从空闲到 load_and_prepare_data 的转换(重置是没有转换)
- 为当前状态编写 next_state 转换会导致 XST 认为它不是 FSM
默认分配 next_state <= current_state;
就足够了。
- 如果将信号类型 clk_counter 更改为无符号,则可以更轻松地进行算术运算。
增量:clk_counter <= clk_counter + 1;
清除:clk_counter <= (others => '0');
比较:if (clk_counter = 23) then
在 FSM 进程之外使用 FSM 的状态信号不是好的方式。
FSM_next_state_process: process(current_state, start, clk_counter, reset_all_dac)
begin
next_state <= current_state;
OutReg_busy <= '1';
OutReg_reset_out <= '1';
OutReg_sync_out <= '1';
clk_counter_enable <= '0';
case (current_state) is
when idle =>
OutReg_busy <= '0';
if (reset_all_dac = '1') then
OutReg_reset_out <= '0';
end if;
when load_and_prepare_data =>
next_state <= transmission;
when transmission =>
clk_counter_enable <= '1';
OutReg_sync_out <= '0';
if (clk_counter = 23) then
next_state <= idle;
end if;
when others =>
next_state <= idle;
end case ;
end process;
我更喜欢状态机的单进程形式,它更干净、更简单并且更不容易出现敏感列表错误等错误。我也赞同 Paebbels 的出色回答中的观点。但是我认为这些都不是这里的问题。
在 post-synth 和 post-PAR 模拟中需要注意的一件事是它们的时间模型与行为模型不同。行为模型遵循我在 this answer 中描述的简单规则,并确保在典型的设计流程中您可以直接进入硬件 - 无需 post-synth 仿真,无需担心。
事实上,如果我正在追查可疑的工具错误,我只会使用 post-synth 或 post-PAR 模拟。 (对于 FPGA 设计,不是 ASIC,就是这样!)
但是,这种简单的时序模型有其局限性。您可能熟悉诸如通过信号分配分配的时钟信号(通常隐藏在您不期望的第 3 方模型中)之类的问题,它消耗增量周期,并确保您的时钟数据在 [之前到达] =53=] 你的时钟而不是 在 之后,随后发生的一切都比预期提前一个周期...
在行为建模中,稍加纪律就可以避免这样的麻烦。但 post-PAR 建模并非如此。
您的测试平台可能与行为模型的设置方式相同。如果是这样,那很可能就是问题所在。
这是我在这种情况下所做的:我没有正式的授权,只是经验。在将 FPGA 连接到具有实际时序的外部存储器模型时,它也能很好地工作。
1) 我假设简单(行为)时序模型适用于设计内部的所有信号。
2) 我对设计的输入和输出不做任何假设。
3) 我注意到输入端的估计设置和保持时序,(a) 来自 FPGA 数据表或更好,(b) 来自 post-synth 中显示的最坏情况值或post-PAR 报告,并围绕它们构建 testbench。
工作示例:设置时间 1 ns,保持时间 2 ns,时钟周期 10 ns。这意味着保证正确读取时钟边沿后 2 ns 和 9 ns 之间的任何输入。我选择(任意)5 ns。
signal_to_fpga <= driving_value after 5 ns;
(请注意,Xilinx 通过将它们表示为 "offset in/out before/after" 来使这荒谬地违反直觉,它指的是前一个或未来时钟边沿的时序,而不是您正在查看的那个)
或者,如果输入来自 CPU 或现实世界中的内存,我会使用该设备的数据表时序规范。
4) 我注意到数据表或报告中报告的最坏情况 clk-out 时序,并围绕它们构建 design。 (比如说,7 纳秒)
fpga_output_pin <= driving_value after 7 ns;
注意这个"after"子句显然被综合忽略了;然而 post-synth 反向注释会引入一些非常相似的东西。
5) 如果结果证明这还不够好,那么(可能在包装器组件中以避免污染可合成代码)提高准确性,如
fpga_output_pin <= 'X' after 1 ps, driving_value after 7 ns;
6) 我重新运行行为模拟。通常,它现在失败了,因为它是在没有考虑实际时间的情况下编写的。
7) 我修复了这些故障。这可能包括在测试从设计输出的值之前添加实际延迟。它可以是一个迭代过程。
现在,我有一个合理的期望,即 post-PAR 仿真模型将直接进入测试平台并正常工作。
我正在为我的硕士论文工作,我对 VHDL 还很陌生,但我仍然必须实现一些复杂的东西。这是我必须编写的最简单的结构之一,但我仍然遇到了一些问题。
这是一个 FSM,它实现了一个带有 active-low 同步信号的 24 位移位寄存器(用于对 DAC 进行编程)。这只是我为我的项目创建的复杂细化链的终点。我尽可能地遵循了 FSM 的示例模型。
行为模拟工作正常,实际上,就行为模拟而言,我创建的整个精化链工作得非常好。但是,一旦我尝试 Post-translate 模拟,事情就开始出错了:很多 'X' 输出信号。
使用这个简单的移位寄存器我没有得到任何 'X',但是我无法进入 load_and_prepare_data 阶段。 current_state 似乎发生了变化(通过检查一些信号),但详细说明没有继续进行。
请记住,由于我是该语言的新手,所以我不知道应该在此 FSM 上设置什么时间限制(而且我不知道如何将它们写在 top.ucf 无论如何)
你能看出哪里出了问题吗? 提前致谢
编辑
我听从了您的建议,使用单状态进程清理了 FSM。我仍然对 "where to put what" 有一些疑问,但我真的很喜欢新的实现。无论如何,我现在得到了一个干净的行为模拟,但是 'X' 在 post 翻译模拟中的所有输出。 是什么原因造成的? 我将 post 新代码和测试平台:
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 14:44:03 11/28/2014
-- Design Name:
-- Module Name: dac_ad5764r_24bit_sr_programmer_v2 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description: This is a PISO shift register that gets a 24bit parallel input word.
-- It outputs the 24bit input word starting from the MSB and enables
-- an active low ChipSelect line for 24 clock periods.
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
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;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity dac_ad5764r_24bit_sr_programmer_v2 is
Port ( clk : in STD_LOGIC;
start : in STD_LOGIC;
reset : in STD_LOGIC; -- Note that this reset is for the FSM not for the DAC
reset_all_dac : in STD_LOGIC;
data_in : in STD_LOGIC_VECTOR (23 downto 0);
serial_data_out : out STD_LOGIC;
sync_out : out STD_LOGIC; -- This is a chip select
reset_out : out STD_LOGIC;
busy : out STD_LOGIC
);
end dac_ad5764r_24bit_sr_programmer_v2;
architecture Behavioral of dac_ad5764r_24bit_sr_programmer_v2 is
-- Stati
type state_type is (idle, load_and_prepare_data, transmission);
--ATTRIBUTE ENUM_ENCODING : STRING;
--ATTRIBUTE ENUM_ENCODING OF state_type: TYPE IS "001 010 100";
signal state: state_type := idle;
--signal next_state: state_type := idle;
-- Clock counter
--signal clk_counter_enable : STD_LOGIC := '0';
signal clk_counter : unsigned(4 downto 0) := (others => '0');
-- Shift register
signal stored_data: STD_LOGIC_VECTOR (23 downto 0) := (others => '0');
begin
FSM_single_process: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
serial_data_out <= '0';
sync_out <= '1';
reset_out <= '1';
busy <= '0';
state <= idle;
else
-- Default
serial_data_out <= '0';
sync_out <= '1';
reset_out <= '1';
busy <= '0';
case (state) is
when transmission =>
serial_data_out <= stored_data(23);
sync_out <= '0';
busy <= '1';
clk_counter <= clk_counter + 1;
stored_data <= stored_data(22 downto 0) & "0";
state <= transmission;
if (clk_counter = 23) then
state <= idle;
end if;
when others => -- Idle
if start = '1' then
serial_data_out <= data_in(23);
sync_out <= '0';
reset_out <= '1';
busy <= '1';
stored_data <= data_in;
clk_counter <= "00001";
state <= transmission;
end if;
end case;
-- if (reset_all_dac = '1') then
-- reset_out <= '0';
-- end if;
end if;
end if;
end process;
end;
和测试平台:
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 dac_ad5764r_24bit_sr_programmer_tb IS
END dac_ad5764r_24bit_sr_programmer_tb;
ARCHITECTURE behavior OF dac_ad5764r_24bit_sr_programmer_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT dac_ad5764r_24bit_sr_programmer_v2
PORT(
clk : IN std_logic;
start : IN std_logic;
reset : IN std_logic;
data_in : IN std_logic_vector(23 downto 0);
serial_data_out : OUT std_logic;
reset_all_dac : IN std_logic;
sync_out : OUT std_logic;
reset_out : OUT std_logic;
--finish : OUT std_logic;
busy : OUT std_logic
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal start : std_logic := '0';
signal reset : std_logic := '0';
signal data_in : std_logic_vector(23 downto 0) := (others => '0');
signal reset_all_dac : std_logic := '0';
--Outputs
signal serial_data_out : std_logic;
signal sync_out : std_logic;
signal reset_out : std_logic;
--signal finish : std_logic;
signal busy : std_logic;
-- Clock period definitions
constant clk_period : time := 100 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: dac_ad5764r_24bit_sr_programmer_v2 PORT MAP (
clk => clk,
start => start,
reset => reset,
data_in => data_in,
reset_all_dac => reset_all_dac,
serial_data_out => serial_data_out,
sync_out => sync_out,
reset_out => reset_out,
--finish => finish,
busy => busy
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for clk_period*10;
reset <= '1' after 25 ns;
wait for clk_period*1;
reset <= '0' after 25 ns;
wait for clk_period*3;
reset_all_dac <= '1' after 25 ns;
wait for clk_period*1;
reset_all_dac <= '0' after 25 ns;
wait for clk_period*5;
data_in <= "111111111111111111111111" after 25 ns;
wait for clk_period*3;
start <= '1' after 25 ns;
wait for clk_period*1;
start <= '0' after 25 ns;
wait;
end process;
END;
更新 1
更新了最后一个设计:此代码不会导致任何 'X'(无法弄清楚为什么,这个不会,但以前的会)。然而,它并没有像前 3 个进程机器那样启动(在 POST-TRANSLATE 模拟中),并且信号 sync_out 卡在 0 而默认情况下它应该是 '1'。
更新 2
我一直在研究技术原理图,从 sync_out=0 的问题开始:它是用 FDS 实现的,S 是 FSM 复位信号,D 来自 LUT3 和 I = state&reset&start 和 INIT = 45 = "00101101"。我在模拟中寻找了这个 LUT3,我注意到它有 INIT = "00000000"!
关于如何 运行 这个模拟,我是否遗漏了什么?好像设计中的每一个LUT都没有设置好!
更新 3
似乎 Post-Translate 模拟在某些方面有问题,或者由于某种原因我没有正确配置它:Post-Map 和 Post-PAR 模拟工作并显示一些输出。
但是有一个奇怪的错误:stored_data 寄存器没有用完整的 data_in 向量更新,之后,FSM 正确运行并输出存储的数据。
我在综合后查看了技术原理图,由于某种原因,位 23、22、21、19、18 未连接到相应的 data_in 位。您可以在 Post-Map 模拟的此屏幕截图中看到效果。同样发生在Post-PAR,但似乎这个问题直接来自综合!
已解决:奇怪的输出来自综合优化。该工具意识到精化链中的前一个块永远不会为那些特定位输出与 0 不同的位。我的错误是假设我可以单独测试单个块:我真正测试的是为 FPGA 综合的块,同时考虑了设计中的所有其他内容!
感谢大家的帮助,我会听从大家的建议!
这里有一些改进代码的提示:
- 您可以删除 Xilinx 对 UNISIM 的依赖性,因为您没有使用任何 Xilinx Primitves。
- 应用属性 ENUM_ENCODING 对状态编码没有影响,除非您还定义属性 FSM_ENCODING 并将其值设置为用户。可以通过将 FSM_ENCODING 设置为 one-hot 来强制使用 One-Hot 编码。通常合成足够聪明,可以找到最好的编码。
read more ... - None 个寄存器具有默认值:
signal current_state : state_type := idle;
- 你的FSM在Xilinx综合工具(XST)眼里不是FSM。我敢肯定,如果您查看综合报告,您不会发现 XST 报告了 current_state.
的 FSM 那么你的 FSM 出了什么问题?- 您的 FSM 没有初始状态。
- 您的 FSM 有多个重置状态(空闲,load_and_prepare_data)
- 你的 FSM 没有从空闲到 load_and_prepare_data 的转换(重置是没有转换)
- 为当前状态编写 next_state 转换会导致 XST 认为它不是 FSM
默认分配next_state <= current_state;
就足够了。
- 如果将信号类型 clk_counter 更改为无符号,则可以更轻松地进行算术运算。
增量:clk_counter <= clk_counter + 1;
清除:clk_counter <= (others => '0');
比较:if (clk_counter = 23) then
在 FSM 进程之外使用 FSM 的状态信号不是好的方式。
FSM_next_state_process: process(current_state, start, clk_counter, reset_all_dac) begin next_state <= current_state; OutReg_busy <= '1'; OutReg_reset_out <= '1'; OutReg_sync_out <= '1'; clk_counter_enable <= '0'; case (current_state) is when idle => OutReg_busy <= '0'; if (reset_all_dac = '1') then OutReg_reset_out <= '0'; end if; when load_and_prepare_data => next_state <= transmission; when transmission => clk_counter_enable <= '1'; OutReg_sync_out <= '0'; if (clk_counter = 23) then next_state <= idle; end if; when others => next_state <= idle; end case ; end process;
我更喜欢状态机的单进程形式,它更干净、更简单并且更不容易出现敏感列表错误等错误。我也赞同 Paebbels 的出色回答中的观点。但是我认为这些都不是这里的问题。
在 post-synth 和 post-PAR 模拟中需要注意的一件事是它们的时间模型与行为模型不同。行为模型遵循我在 this answer 中描述的简单规则,并确保在典型的设计流程中您可以直接进入硬件 - 无需 post-synth 仿真,无需担心。
事实上,如果我正在追查可疑的工具错误,我只会使用 post-synth 或 post-PAR 模拟。 (对于 FPGA 设计,不是 ASIC,就是这样!)
但是,这种简单的时序模型有其局限性。您可能熟悉诸如通过信号分配分配的时钟信号(通常隐藏在您不期望的第 3 方模型中)之类的问题,它消耗增量周期,并确保您的时钟数据在 [之前到达] =53=] 你的时钟而不是 在 之后,随后发生的一切都比预期提前一个周期...
在行为建模中,稍加纪律就可以避免这样的麻烦。但 post-PAR 建模并非如此。
您的测试平台可能与行为模型的设置方式相同。如果是这样,那很可能就是问题所在。
这是我在这种情况下所做的:我没有正式的授权,只是经验。在将 FPGA 连接到具有实际时序的外部存储器模型时,它也能很好地工作。
1) 我假设简单(行为)时序模型适用于设计内部的所有信号。
2) 我对设计的输入和输出不做任何假设。
3) 我注意到输入端的估计设置和保持时序,(a) 来自 FPGA 数据表或更好,(b) 来自 post-synth 中显示的最坏情况值或post-PAR 报告,并围绕它们构建 testbench。 工作示例:设置时间 1 ns,保持时间 2 ns,时钟周期 10 ns。这意味着保证正确读取时钟边沿后 2 ns 和 9 ns 之间的任何输入。我选择(任意)5 ns。
signal_to_fpga <= driving_value after 5 ns;
(请注意,Xilinx 通过将它们表示为 "offset in/out before/after" 来使这荒谬地违反直觉,它指的是前一个或未来时钟边沿的时序,而不是您正在查看的那个)
或者,如果输入来自 CPU 或现实世界中的内存,我会使用该设备的数据表时序规范。
4) 我注意到数据表或报告中报告的最坏情况 clk-out 时序,并围绕它们构建 design。 (比如说,7 纳秒)
fpga_output_pin <= driving_value after 7 ns;
注意这个"after"子句显然被综合忽略了;然而 post-synth 反向注释会引入一些非常相似的东西。
5) 如果结果证明这还不够好,那么(可能在包装器组件中以避免污染可合成代码)提高准确性,如
fpga_output_pin <= 'X' after 1 ps, driving_value after 7 ns;
6) 我重新运行行为模拟。通常,它现在失败了,因为它是在没有考虑实际时间的情况下编写的。
7) 我修复了这些故障。这可能包括在测试从设计输出的值之前添加实际延迟。它可以是一个迭代过程。
现在,我有一个合理的期望,即 post-PAR 仿真模型将直接进入测试平台并正常工作。