Search code examples
vhdlfsmgray-code

3-bit finite state machine in VHDL


entity project4 is
    Port ( clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           x : in  STD_LOGIC_VECTOR (1 downto 0);
           myoutputs : out  STD_LOGIC_VECTOR (2 downto 0));
end project4;

architecture Behavioral of project4 is
type state_type is (s0,s1,s2,s3,s4,s5,s6,s7);
signal state: state_type;

begin
process1: process(clk,reset)
begin
     if (reset ='0') THEN state <= s0;
      myoutputs <= "000";
ELSE IF (clk'EVENT AND clk='1') THEN
    case state is
     when s0 =>
               if (x="00") THEN
                  state <= s1;
                  myoutputs <= "001";
                  ELSE IF (x="01") THEN
                  state <= s7;
                  myoutputs <= "111";
                  ELSE IF (x="10") THEN
                  state <= s2;
                  myoutputs <= "010";
                  ELSE
                  state <=s4;
                  myoutputs <= "100";
      END IF;

      when s1 =>
                if (x="00") THEN
                    state <= s2;
                    myoutputs <="010";
                    ELSE IF (x ="01") THEN
                    state <= s0;
                    myoutputs <= "000";
                    ELSE IF (x ="10") THEN
                    state <=s0;
                    myoutputs <= "000";
                    ELSE
                    state <= s0;
                    myoutputs <="000";
        END IF;

        when s2 =>
                  if (x="00") THEN
                     state <= s3;
                     myoutputs <="011";
                     ELSE IF (x="01") THEN
                     state <= s1;
                     myoutputs <="001";
                     ELSE IF (x="10") THEN
                     state <=s5;
                     myoutputs <="110";
                     ELSE
                     state <=s3;
                     myoutputs <="011";
        END IF;

        when s3 =>
                  if (x="00") THEN
                     state <=s4;
                     myoutputs <="100";
                     ELSE IF (x="01") THEN
                     state <= s2;
                     myoutputs <="010";
                     ELSE IF (x="10") THEN
                     state <= s1;
                     myoutputs <= "001";
                     ELSE
                     state <=s1;
                     myoutputs <= "001";
        END IF;

      when s4 =>
                if (x="00") THEN
                state <=s5;
                myoutputs <="101";
                     ELSE IF (x="01") THEN
                     state <= s3;
                     myoutputs <="011";
                     ELSE IF (x="10") THEN
                     state <= s5;
                     myoutputs <="101";
                     ELSE
                     state <= s5;
                     myoutputs <="101";
        END IF;

        when s5 =>
                  if (x="00") THEN
                     state <= s6;
                     myoutputs <="110";
                     ELSE IF (x="01") THEN
                     state <= s4;
                     myoutputs <= "100";
                     ELSE IF (x="10") THEN
                     state <= s7;
                     myoutputs <= "111";
                     ELSE
                     state <= s7;
                     myoutputs <= "111";
        END IF;

        when s6 =>
                  if (x="00") THEN
                     state <= s7;
                     myoutputs <= "111";
                     ELSE IF (x="01") THEN
                     state <= s5;
                     myoutputs <="101";
                     ELSE IF (x="10") THEN
                     state <= s4;
                     myoutputs <="100";
                     ELSE
                     state <= s2;
                     myoutputs <="010";
        END IF;

        when s7 =>
                  if (x="00") THEN
                     state <= s0;
                     myoutputs <="000";
                     ELSE IF (x="01") THEN
                     state <= s6;
                     myoutputs <="110";
                     ELSE IF (x="10") THEN
                     state <= s3;
                     myoutputs <="011";
                     ELSE
                     state <= s6;
                     myoutputs <= "110";
        END IF;
        end case;
        end process process1;

process2: process(state)
begin
      case state is
        when s0 => myoutputs <= "000";
        when s1 => myoutputs <= "001";
        when s2 => myoutputs <= "010";
        when s3 => myoutputs <= "011";
        when s4 => myoutputs <= "100";
        when s5 => myoutputs <= "101";
        when s6 => myoutputs <= "110";
        when s7 => myoutputs <= "111";
        end case;
end process process2;

end Behavioral;

Here's entire code.

Can someone tell me what causes the error? I'm just not getting it. (Syntax error near "when".)


Solution

  • Use elsif not else if

    Constructing a Minimal, Complete, and Verifiable example from your linked code by adding a context clause:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity project4 is
        port ( 
            clk:        in  std_logic;
            reset:      in  std_logic;
            x:          in  std_logic_vector (1 downto 0);
            myoutputs:  out std_logic_vector (2 downto 0)
        );
    end entity project4;
    
    architecture behavioral of project4 is
        type state_type is (s0,s1,s2,s3,s4,s5,s6,s7);
        signal state: state_type;
    begin
    process1: 
        process (clk, reset)
        begin
        if reset ='0' then 
            state <= s0;
            myoutputs <= "000";
        else if clk'event and clk='1' then
            case state is
                when s0 =>
                    if x = "00" then
                        state <= s1;
                        myoutputs <= "001";
                    else if x = "01" then
                        state <= s7;
                        myoutputs <= "111";
                    else if  x = "10" then
                        state <= s2;
                        myoutputs <= "010";
                    else
                        state <= s4;
                        myoutputs <= "100";
                    end if;
                when s1 =>
                    if  x = "00" then
                        state <= s2;
                        myoutputs <= "010";
                    else if  
                        x = "01" then
                        state <= s0;
                        myoutputs <= "000";
                    else if  x = "10" then
                        state <= s0;
                        myoutputs <= "000";
                    else
                        state <= s0;
                        myoutputs <= "000";
                    end if;
    
                when s2 =>
                    if  x = "00" then
                         state <= s3;
                         myoutputs <= "011";
                    else if  x = "01" then
                         state <= s1;
                         myoutputs <= "001";
                    else if  x = "10" then
                         state <= s5;
                         myoutputs <= "110";
                    else
                         state <= s3;
                         myoutputs <= "011";
            end if;
    
                when s3 =>
                    if  x = "00" then
                         state <= s4;
                         myoutputs <= "100";
                    else if  x = "01" then
                         state <= s2;
                         myoutputs <= "010";
                    else if  x = "10" then
                         state <= s1;
                         myoutputs <= "001";
                    else
                         state <= s1;
                         myoutputs <= "001";
                     end if;
    
                when s4 =>
                    if  x = "00" then
                        state <= s5;
                        myoutputs <= "101";
                    else if  x = "01" then
                         state <= s3;
                         myoutputs <= "011";
                    else if  x = "10" then
                         state <= s5;
                         myoutputs <= "101";
                     else
                         state <= s5;
                         myoutputs <= "101";
                     end if;
    
                when s5 =>
                    if  x = "00" then
                        state <= s6;
                        myoutputs <= "110";
                    else if  x = "01" then
                        state <= s4;
                        myoutputs <= "100";
                    else if  x = "10" then
                        state <= s7;
                        myoutputs <= "111";
                    else
                        state <= s7;
                        myoutputs <= "111";
                    end if;
    
                when s6 =>
                    if  x = "00" then
                         state <= s7;
                         myoutputs <= "111";
                    else if  x = "01" then
                        state <= s5;
                        myoutputs <= "101";
                    else if  x = "10" then
                        state <= s4;
                        myoutputs <= "100";
                    else
                        state <= s2;
                        myoutputs <= "010";
                    end if;
    
                when s7 =>
                    if  x = "00" then
                        state <= s0;
                        myoutputs <= "000";
                    else if  x = "01" then
                        state <= s6;
                        myoutputs <= "110";
                    else if  x = "10" then
                        state <= s3;
                        myoutputs <= "011";
                    else
                        state <= s6;
                        myoutputs <= "110";
                    end if;
                end case;
    
        end process process1;
    
    process2: 
        process(state)
        begin
            case state is
                when s0 => myoutputs <= "000";
                when s1 => myoutputs <= "001";
                when s2 => myoutputs <= "010";
                when s3 => myoutputs <= "011";
                when s4 => myoutputs <= "100";
                when s5 => myoutputs <= "101";
                when s6 => myoutputs <= "110";
                when s7 => myoutputs <= "111";
            end case;
        end process process2;
    end behavioral;
    

    And using a couple of different VHDL tools:

    ghdl -a project4.vhdl
    project4.vhdl:39:13: 'end' is expected instead of 'when'
    ghdl: compilation error

    and

    nvc -a project4.vhdl  
    ** Error: unexpected when while parsing if statement, expecting end  
      File project4.vhdl, Line 39  
                    when s1 =>  
                    ^^^^  
    ** Error: unexpected when while parsing if statement, expecting end  
      File project4.vhdl, Line 55  
                    when s2 =>  
                    ^^^^  
    ** Error: unexpected when while parsing if statement, expecting end  
      File project4.vhdl, Line 70  
                    when s3 =>  
                    ^^^^  
    >...
    

    explains what the problem is. You're using else if instead of elsif which results in the wrong number of end statements (end if;).

    Fixing those 17 instances of else if and we find you left out the end if for the first if statement:

    ghdl -a project4.vhdl
    project4.vhdl:146:9: 'if' is expected instead of 'process'
    ghdl: compilation error

    Adding that right before the end process:

            end if; -- added
        end process process1;
    

    and your design analyzes.

    Whether or not your code is functional is left to you.

    (Okay, there's another problem you drive myoutputs from two processes which will cause Xs, you should remove the second process. Each process that assigns a signal has a driver for that signal, and std_logic is a resolved type, meaning the two drivers values will presented to a resolution function, which for package std_logic_1164 will result in Xs for conflicting values on the two drivers.)

    So there were 18 syntax errors, plus the code isn't functional, myoutputs having driver conflicts.

    I removed superfluous parentheses and added spaces and indentation for readability.

    So adding a small testbench:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity project4_tb is
    end entity;
    
    architecture foo of project4_tb is
        signal clk:        std_logic := '0';
        signal reset:      std_logic;
        signal x:          std_logic_vector (1 downto 0);
        signal myoutputs:  std_logic_vector (2 downto 0);
    begin
    DUT: 
        entity work.project4
            port map (
                clk => clk,
                reset => reset,
                x => x,
                myoutputs => myoutputs
            );
    
    CLOCK:
        process
        begin
            wait for 5 ns;
            clk <= not clk;
            if now > 360 ns then
                wait;
            end if;
        end process;
    
    STIMULI:
        process
        begin
            wait for 6 ns;
            reset <= '0';
            wait for 10 ns;
            reset <= '1';
            for i in 0 to 3 loop
                x <= std_logic_vector(to_unsigned(i,x'length));
                wait for 80 ns;
            end loop;
            wait;
        end process;
    end architecture;
    

    We can see what your design does in simulation:

    project4_tb.png