VHDL - FSM无法启动(仅限于时序仿真)

时间:2015-01-12 18:50:52

标签: vhdl timing fsm

我正在为我的硕士论文工作,而且我对VHDL很陌生,但我还是要实现一些复杂的东西。这是我必须编写的最简单的结构之一,但我仍然遇到了一些问题。

它是一个FSM,用于实现具有低电平有效同步信号的24位移位寄存器(用于编程DAC)。它只是我为我的项目创建的复杂精化链的结束。我尽可能地遵循FSM的示例模型。

行为模拟工作正常,实际上我创建的整个精细链对于行为模拟的关注完全正常。但是,一旦我尝试了翻译后模拟,事情就会出现问题:很多' X'输出信号。

使用这个简单的移位寄存器我不会得到任何'但是我无法进入load_and_prepare_data阶段。似乎current_state发生了变化(通过检查一些信号),但是详细说明还没有继续。

请记住,由于我是该语言的新手,我不知道我应该在此FSM上设置什么时序限制(我不知道如何在顶部编写它们。 ucf无论如何)

你能看出错误吗? 提前致谢

修改

我遵循了您的建议,并使用单个状态流程清理了FSM。我仍然怀疑"在哪里放什么"但我真的很喜欢新的实施。无论如何,我现在得到一个干净的行为模拟但是' X'在翻译后模拟中的所有输出。 是什么造成的? 我将发布新代码和测试平台:

----------------------------------------------------------------------------------
-- 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

更新了最后一个设计:此代码未导致任何&#39; X&#39; (不能弄明白为什么,这不是先前的做法)。然而,它没有像前3个处理机一样启动(在POST-TRANSLATE模拟中),并且信号sync_out被卡在0,而它应该是&#39; 1&#39;默认情况下。

simulation 1

更新2

我一直在研究技术原理图,从sync_out = 0的问题开始:它是用FDS实现的,S是FSM复位信号,D来自LUT3和I = state&amp; reset&amp; start和INIT = 45 =&#34; 00101101&#34;。我在模拟中找到了这个LUT3,我发现它有 INIT =&#34; 00000000&#34;

关于如何运行此模拟,我是否遗漏了一些东西?似乎设计中的每个LUT都没有设置好!

更新3 似乎Post-Translate模拟在某种程度上是错误的,或者由于某种原因我没有正确配置它:Post-Map和Post-PAR模拟工作并显示一些输出。 但是有一个奇怪的错误:stored_data寄存器没有使用完整的data_in向量更新,之后,FSM正常运行并输出存储的数据。 我刚刚在综合后查看了技术原理图,由于某种原因,位23,22,21,19,18没有连接到相应的data_in位。您可以在Post-Map模拟中看到此屏幕截图中的效果。在Post-PAR中也是如此,但似乎这个问题直接来自综合! Stored_Data =/= Data_in

解决:奇怪的输出来自综合优化。该工具意识到精化链中的前一个块永远不会为那些特定位输出与0不同的位。我的错误是假设我可以单独测试单个块:我真正测试的是为FPGA设计合成的块,并考虑到设计中的其他所有内容!

感谢大家帮助我,我会按照你的建议行事!

2 个答案:

答案 0 :(得分:1)

以下是一些改进代码的提示:

  1. 您可以删除Xilinx对UNISIM的依赖,因为您没有使用任何Xilinx Primitves。
  2. 应用属性ENUM_ENCODING对状态编码没有影响,除非您还定义属性FSM_ENCODING并将其值设置为user。可以通过将FSM_ENCODING设置为one-hot来强制进行One-Hot编码。通常,合成足够聪明,可以找到最佳编码 read more ...
  3. 您的所有寄存器都没有默认值:
        signal current_state : state_type := idle;
  4. 在Xilinx综合工具(XST)眼中,您的FSM不是FSM。我确定如果您查看综合报告,您就不会发现XST报告了current_state的FSM。
    那你的FSM有什么问题呢?
    • 您的FSM没有初始状态。
    • 您的FSM有多个重置状态(idle,load_and_prepare_data)
    • 您的FSM没有从空闲到load_and_prepare_data的转换(重置没有转换)
    • 为当前状态编写next_state转换可能会导致XST认为它没有FSM 默认作业next_state <= current_state;就足够了。
  5. 如果将clk_counter信号的类型更改为unsigned,则可以更轻松地进行算术运算    增量:clk_counter <= clk_counter + 1;
       明确:clk_counter <= (others => '0');
       比较:if (clk_counter = 23) then
  6. 在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;
    

答案 1 :(得分:1)

我更喜欢状态机的单进程形式,它更清晰,更简单,更不容易出现像敏感列表错误这样的错误。我也赞同Paebbels的优秀答案。但是我不认为这些都是问题。

合成后和后PAR模拟需要注意的一点是,他们的时间模型与行为模型不同。行为模型遵循我在this answer中描述的简单规则,并确保在典型的设计流程中您可以直接进入硬件 - 无需合成后仿真,无需担心。

事实上,如果我追逐一个可疑的工具bu​​g,我只会使用合成后或后PAR模拟。 (对于FPGA设计,而不是ASIC,即!)

然而,这种简单的时序模型有其局限性。您可能熟悉诸如通过信号分配分配的时钟信号(通常隐藏在您不期望它的第三方模型中)的问题,这会消耗增量周期,并确保您的时钟数据之前到达 >你的时钟而不是之后的,所有事情都会比预期提前一个周期......

在行为建模中,一点点纪律就能避免这种麻烦。但是后PAR模型也是如此。

您的测试平台可能与行为模型的设置方式相同。如果是这样,那可能就是问题所在。

这就是我在这种情况下所做的事情:我声称没有正式的权威,只有经验。当使用真实的时序将FPGA连接到外部存储器模型时,它也能很好地工作。

1)我假设简单(行为)时序模型适用于所有信号INTERNAL到设计。

2)我不假设设计的输入和输出。

3)我注意到输入上的估计设置和保持时序,(a)来自FPGA数据表或更好,(b)来自合成后或PAR后报告中显示的最坏情况值,以及围绕它们构建 testbench 。 工作示例:建立时间1 ns,保持时间2 ns,时钟周期10 ns。这意味着保证在时钟边沿之后2 ns和9 ns之间的任何输入都被正确读取。我选择(任意)5 ns。

signal_to_fpga <= driving_value after 5 ns;

(请注意,Xilinx通过将它们表示为“之前/之后的偏移输入/输出”,将时序引用到前一个或将来的时钟边缘而不是您正在查看的时钟边缘,这使得这种荒谬的反直觉变得非常直观。

或者,如果输入是从现实世界中的CPU或内存提供的,我使用该设备的数据表时序规范。

4)我注意到数据表或报告中报告的最坏情况clk-out时序,并围绕它们构建设计。 (比方说,7 ns)

fpga_output_pin <= driving_value after 7 ns;

请注意,这个“after”子句显然会被综合忽略;然而,合成后反向注释会引入非常类似的东西 5)如果结果不够好,那么(可能在包装器组件中避免污染可合成代码)可以提高准确度,如

fpga_output_pin <= 'X' after 1 ps, driving_value after 7 ns;

6)我重新运行行为模拟。通常情况下,它现在失败了,因为它的编写没有考虑到现实时间。

7)我解决了这些失败。这可能包括在测试设计输出值之前添加实际延迟。它可以是一个迭代过程。

现在,我有理由期望后PAR模拟模型将直接进入测试平台并开始工作。