VHDL:信号无法合成

时间:2013-12-25 09:11:56

标签: asynchronous vhdl

我是VHDL的新手并试图为学校的项目编写代码。我想要的是使用LED充当球的一维乒乓球比赛。请注意,我没有对VHDL的结构化理解,我通过在VHDL中查找状态机设计编写了以下代码,并试图提出我自己的。我有一个异步RESET和两个异步输入,对应每个玩家的按钮按下以返回球。它们是异步的,因为即使在时钟周期内按下按钮很短的时间,我也希望玩家能够返回球。

在Xilinx 10.1中,模拟以我想要的方式运行,但是当我尝试合成时,这是我得到的以下代码的错误:

ERROR:Xst:827 - "C:/Users/Emre/LED_pong/pong.vhd" line 49: Signal present_state cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.

当我删除包含PAD1和PAD2的elsif语句时,它会合成,但会失去其功能。

entity pong is
Port ( CLK : in  STD_LOGIC;
       RST : in  STD_LOGIC;
       PAD1 : in  STD_LOGIC;
       PAD2 : in  STD_LOGIC;
       LEDS : out  STD_LOGIC_VECTOR (7 downto 0));
end pong;

architecture Behavioral of pong is

type state is ( P1_SERVE, A1, A2, A3, A4, A5, A6, A7,
                     B0, B1, B2, B3, B4, B5, B6, P2_SERVE,
                     WAIT_FOR_P1, WAIT_FOR_P2, P1_HIT_EARLY, P2_HIT_EARLY,
               P1_SCORED, P2_SCORED );
signal present_state: state;
signal temp : STD_LOGIC_VECTOR (7 downto 0) := "00000000";

begin

process (CLK, RST, PAD1, PAD2) begin

    if (RST = '1') then
        temp <= "10000000";
        present_state <= P1_SERVE;

    elsif (rising_edge(CLK)) then
        case present_state is

            when P1_SERVE =>
                temp <= "10000000";
            when P2_SERVE =>
                temp <= "00000001";

            when P1_SCORED =>
                temp <= "00000000";
           present_state <= P2_SERVE;
            when P2_SCORED =>
           temp <= "00000000";
           present_state <= P1_SERVE;

            when A1 =>
                temp <= "01000000";
                present_state <= A2;
            when A2 =>
                temp <= "00100000";
                present_state <= A3;
            when A3 =>
                temp <= "00010000";
                present_state <= A4;
            when A4 =>
                temp <= "00001000";
                present_state <= A5;
            when A5 =>
                temp <= "00000100";
                present_state <= A6;
            when A6 =>
                temp <= "00000010";
           present_state <= A7;
            when A7 =>
                temp <= "00000001";
           present_state <= WAIT_FOR_P2;
        when WAIT_FOR_P2 =>
           temp <= "00000000";
           present_state <= P2_SERVE;

            when B6 =>
                temp <= "00000010";
                present_state <= B5;
            when B5 =>
                temp <= "00000100";
                present_state <= B4;
            when B4 =>
                temp <= "00001000";
                present_state <= B3;
            when B3 =>
                temp <= "00010000";
                present_state <= B2;
            when B2 =>
                temp <= "00100000";
                present_state <= B1;
            when B1 =>
                temp <= "01000000";
           present_state <=  B0;
            when B0 =>
                temp <= "10000000";
           present_state <= WAIT_FOR_P1;
        when WAIT_FOR_P1 =>
           temp <= "00000000";
           present_state <= P1_SERVE;

            when P1_HIT_EARLY =>
                temp <= "10000000";
                present_state <= P2_SCORED;
            when P2_HIT_EARLY =>
                temp <= "00000001";
                present_state <= P1_SCORED;

        when others =>
           null;
        end case;

  elsif (PAD1 = '1') then
     case present_state is 
        when P1_SERVE =>
           present_state <= A1;
        when B0 =>
           present_state <= P1_HIT_EARLY;
        when WAIT_FOR_P1 =>
           present_state <= A1;
        when others =>
           null;    
     end case;

    elsif (PAD2 = '1') then
        case present_state is
            when P2_SERVE =>
                present_state <= B6;
            when A7 =>
                present_state <= P2_HIT_EARLY;
            when WAIT_FOR_P2 =>
                present_state <= B6;
        when others =>
           null;
        end case;

    end if;
end process;

   LEDS <= temp;

end Behavioral;

2 个答案:

答案 0 :(得分:2)

除了case语句中的异步复位和时钟加载之外,您还尝试使用PAD1和PAD2作为present_state的latch启用。

您所希望的行为的首选实现并不反映硬件。例如,当您使用PAD1和PAD2作为锁存器启用时,您正在后两个case语句中查看present_state,实际上是组合时钟。

您可能希望将PAD1和PAD2捕获为每个时钟类清除的事件,例如捕获中断的边缘。根据您的时钟频率,您可能需要对它们进行脉冲滤波,问题在于您是否可以从按钮获得成功和中断反弹。还有时钟边缘的设置时间要考虑,这意味着您可能希望在特定窗口期间进行采样以确保设置时间。该模型是一个触发器,使用PAD1和PAD2作为时钟,然后是锁存器。

通过事件捕获,您可以在rising_edge(CLK)评估下将所有case语句合并为一个。根据PAD1或PAD2(存储)事件,效果是在某些状态情况下给出两种可能的输出状态。

答案 1 :(得分:1)

您的代码中存在一个概念性问题(它不是VHDL的错误)。

您正在尝试实现有限状态机,并且,如在任何FSM中一样,必须注册当前状态(即,存储到触发器组中)。您在第一个 case 语句中执行此操作,因为present_state的赋值由时钟转换控制(即,它们位于 if rising_edge(clk)语句下)。

问题在于,在接下来的两个 case 语句中(由PAD1和PAD2声明),您试图异步修改present_state 的值。回想一下,present_state的值已经注册,因此它是由一个触发器组产生的。由于触发器的输出值只能通过作用于其复位输入或修改其数据输入来修改,并且这些情况都不符合最后两个 case 语句中的情况,代码可以简单地不被翻译成硬件(正如大卫已正确指出的那样)。

我的建议:为您的FSM绘制详细的状态转换图(永远不要跳过任何FSM设计中的这个阶段),这将清楚所涉及的所有信号(包括PAD1和PAD2)的作用。然后重写代码应该很简单。