Search code examples
asynchronousvhdl

VHDL: signal cannot be synthesized


I am very new to VHDL and trying to write code for a project at school. What I want is to have a one dimensional pong game using the LEDs to act as the ball. Note that I do not have a structured understanding of VHDL, I wrote the following code by looking up state machine designs in VHDL and tried to come up with my own. I have an asynchronous RESET and two asynchronous inputs corresponding to the button presses of each player to return the ball. They are asynchronous because I want the players to be able to return the ball even if the button is pressed for a very short time during a clock cycle.

In Xilinx 10.1, simulation runs just the way I want but when I try to synthesise, this is the error I get for the following code:

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.

When I remove the elsif statements containing PAD1 and PAD2, it synthesizes, but loses its functionality.

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;

Solution

  • You're trying to use PAD1 and PAD2 as latch enables for present_state in addition to an asynchronous reset and clocked loads in the case statement.

    Your preferred implementation of the behavior you desire doesn't reflect hardware. For instance you are peering at present_state in the later two case statements while you are using PAD1 and PAD2 as latch enables, effectively combinatorial clocks.

    You may want to capture PAD1 and PAD2 as events that are cleared every clock sort of like catching edges for interrupts. Depending on your clock rate you may need to impulse filter them, the question being whether or not you can get both make and break bounce from the buttons. There's also the case of setup time to the clock edge to consider, meaning you might want to sample during a particular window insuring setup time. The model is a flip flop using either PAD1 and PAD2 as clocks followed by a latch.

    With event capture you'd merge all the case statements into one under the rising_edge(CLK) evaluation. The effect is to give two possible output states in some state cases, based on either PAD1 or PAD2 (stored) events.