Search code examples
vhdlfsmghdl

VHDL: Mealy FSM not producing state changes at clock edges?


I am fairly new to VHDL and am following this tutorial to implement the following Mealy Finite State Machine:

enter image description here

and have written the following code in VHDL:

library ieee;
use ieee.std_logic_1164.all;

entity fsm is
    port(clk, rst, in1 : in std_logic; o1 : out std_logic);
end fsm;

architecture mealy of fsm is
    type state is (state1, state2);
    signal current_state, next_state : state;
begin 

    comb: process(current_state, in1) begin
        next_state <= current_state; -- default case
        case current_state is
            when state1 =>
                o1 <= '0';
                if in1 = '1' then
                    o1 <= '1';
                    next_state <= state2;
                end if;

            when state2 =>
                o1 <= '1';
                if in1 = '0' then 
                    o1 <= '0';
                    next_state <= state1;
                end if;
        end case;
    end process;

    mem: process(clk, rst) begin
        if rst = '1' then
            current_state <= state1;
        else
            current_state <= next_state;
        end if;
    end process;

end mealy;

However on applying the following testbench:

library ieee;
use ieee.std_logic_1164.all;

entity fsm_tb is
end fsm_tb;

architecture sim of fsm_tb is
    constant clockperiod : time := 10 ns; -- 100 Mhz clock
    signal clk           : std_logic := '0';
    signal rst           : std_logic;
    signal in1, o_mealy  : std_logic;
begin
    uut_mealy : entity work.fsm(mealy) port map( clk => clk, rst => rst, in1 => in1, o1  => o_mealy);
    clk <= not clk after clockperiod/2;
    process begin
        -- initial reset
        in1 <= '0';
        rst <= '1';
        wait until rising_edge(clk);
        -- take device out of reset
        rst <= '0';
        -- apply same inputs to both the devices
        in1 <= '0'; wait for 23 ns;
        in1 <= '1'; wait for 32 ns;
        in1 <= '0'; wait for 7 ns;
        in1 <= '1'; wait for 15 ns;
        wait;
    end process;
end sim;

the waveforms that I have obtained do not make sense to me:

enter image description here

As you can see the output o_mealy changes even without clock edge. It simply seems to only be following the input. By contrast, I have implemented the equivalent Moore machine and it seems to be working just fine:

enter image description here

If anyone can point out what I am doing wrong, it would be highly appreciated. Again, I have used this video for reference. I am using GHDL with GTKWave.


Solution

  • Taking a look at your concurrent logic:

            case current_state is
                when state1 =>
                    o1 <= '0';
                    if in1 = '1' then
                        o1 <= '1';
                        next_state <= state2;
                    end if;
    
                when state2 =>
                    o1 <= '1';
                    if in1 = '0' then 
                        o1 <= '0';
                        next_state <= state1;
                    end if;
            end case;
    

    In any of the two states, if in1 = '1', the output is 1, if in1 = '0' the output is 0. So the FSM works fine, but looking from the outside in you just cannot see the difference between the two states.

    In terms of what are you doing wrong: I think this is correct, actually, looking at your drawing. In a mealy machine, the output is depended on the current state and the current input, which is exactly what is happening here.