0
\$\begingroup\$

I'm trying to build a Mealy Finite State Machine in VHDL. each time a button 'btn' is pressed, the FSM should go to the next state. There are 4 states, s0, s1, s2 & s3. s0 is the state at which the FSM starts and it flashes a LED with a definite period. if btn is pressed, FSM moves to state s1, at which it outputs the sum of inputs x1 and x2. Again, if btn is pressed, it goes to state s2, where it outputs the multiplication of inputs x1 and x2. Finally, if the button is pressed, it goes to state s3 where it outputs the 8-bit Gray counter. Here's the code, the testbench and the waveforms. I have written the problems after the waveform picture.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity abc is
Port ( clk  : IN std_logic;
   srst : IN std_logic;
   x1   : IN std_logic_vector (2 downto 0);
   x2   : IN std_logic_vector (2 downto 0);
   btn  : IN std_logic;
   y    : OUT std_logic_vector (7 downto 0));
end entity abc ;

architecture rtl of abc is

type state_type is (s0, s1, s2, s3);

signal current_state : state_type;
signal next_state : state_type;

signal y_cld : std_logic_vector (7 downto 0);

signal sum   : std_logic_vector (7 downto 0);
signal mult  : std_logic_vector (7 downto 0);
signal gcntr : std_logic_vector (7 downto 0);
signal led   : std_logic;

signal ibtn : std_logic;

component led_flasher is
  Port ( clk  : IN std_logic;
         dout : OUT std_logic);
end component led_flasher;

component addition is
Port ( x1      : IN std_logic_vector (2 downto 0);
       x2      : IN std_logic_vector (2 downto 0);
   add_out : OUT std_logic_vector (7 downto 0));
end component addition;

component multiplication is
Port ( x1       : IN std_logic_vector (2 downto 0);
   x2       : IN std_logic_vector (2 downto 0);
   mult_out : OUT std_logic_vector (7 downto 0));
end component multiplication;

component gray_cntr is
Port (  clk   : IN std_logic;
       srst  : IN std_logic;
         gcntr : OUT std_logic_vector (7 downto 0));
end component gray_cntr;

begin

ibtn <= btn; 

main_process : process(clk) begin
if rising_edge(clk) then
    if srst = '1' then
        current_state <= s0;
        y <= "0000000" & led;
    else
        current_state <= next_state;
        y <= y_cld;
    end if;
end if;
end process;

state_control : process(current_state, ibtn) begin
next_state <= current_state;
case (current_state) is
    when(s0) =>
        if ibtn = '1' then
            next_state <= s1;
        end if;
    when(s1) =>
        if ibtn = '1' then
            next_state <= s2;
        end if;
    when(s2) =>
        if ibtn = '1' then
            next_state <= s3;
        end if;
    when(s3) =>
        if ibtn = '1' then
            next_state <= s0;
        end if;
    when others =>
        next_state <= s0;
end case;
end process state_control;

output_control : process(current_state, led, mult, sum, gcntr, next_state) begin
case(current_state) is
    when(s0) =>
        y_cld <= "0000000" & led;
    when(s1) =>
        y_cld <= sum;
    when(s2) =>
        y_cld <= mult;
    when(s3) =>
        y_cld <= gcntr;
    when others =>
        y_cld <= (others => '0');
    end case;
end process output_control;

-------------------------------------------------------------
-- Instantiate the DUT
-------------------------------------------------------------

state0 : led_flasher port map ( clk => clk,
                            dout => led);

state1 : addition port map ( x1 => x1,
                         x2 => x2,
                         add_out => sum );

state2 : multiplication port map ( x1 => x1,
                           x2 => x2,
                           mult_out => mult );

state3 : gray_cntr port map ( clk => clk,
                          srst => srst,
                          gcntr => gcntr );

end rtl;

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity led_flasher is
Port ( clk : IN std_logic;
       dout : OUT std_logic);
end entity led_flasher;

architecture rtl of led_flasher is

signal cntr : std_logic_vector ( 27 downto 0 ) := (others => '0');

begin

dout <= cntr(7);

counter : process(clk) begin
    if rising_edge(clk) then
        cntr <= std_logic_vector(unsigned(cntr) + 1);
    end if;
end process counter;

end rtl;
-- Addition for 3-Bit input numbers

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity addition is
Port ( x1      : IN std_logic_vector (2 downto 0);
       x2      : IN std_logic_vector (2 downto 0);
       add_out : OUT std_logic_vector (7 downto 0));
end entity addition;

architecture rtl of addition is
begin
add_out <= std_logic_vector(resize(unsigned(x1),8) + resize(unsigned(x2),8));

 end rtl;
-- 3-bit multiplication in VHDL

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity multiplication is
Port ( x1       : IN std_logic_vector (2 downto 0);
       x2       : IN std_logic_vector (2 downto 0);
       mult_out : OUT std_logic_vector (7 downto 0));
end entity multiplication;

architecture rtl of multiplication is

begin

mult_out <= "00" & std_logic_vector(unsigned(x1) * unsigned(x2));
end rtl;


-- 8-Bit Gray Counter in VHDL

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity gray_cntr is
Port ( clk   : IN std_logic;
       srst  : IN std_logic;
       gcntr : OUT std_logic_vector (7 downto 0));
end entity gray_cntr;

architecture rtl of gray_cntr is

signal cntr : std_logic_vector (7 downto 0) := (others => '0');

begin

process(clk) begin
    if rising_edge(clk) then
        if srst = '1' then
            cntr <= (others => '0');
        else
            cntr <= std_logic_vector(unsigned(cntr) + 1);
        end if;
    end if;
end process;

gcntr(7) <= cntr(7);
gcntr(6) <= cntr(7) xor cntr(6);
gcntr(5) <= cntr(6) xor cntr(5);
gcntr(4) <= cntr(5) xor cntr(4);
gcntr(3) <= cntr(4) xor cntr(3);
gcntr(2) <= cntr(3) xor cntr(2);
gcntr(1) <= cntr(2) xor cntr(1);
gcntr(0) <= cntr(1) xor cntr(0);

end rtl;

Here is the testbench.

--Testbench for abc in VHDL, Mealy Finite State machine 

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity abc_tb is
--Port ();
end entity abc_tb;

architecture rtl_tb of abc_tb is

component abc is
Port ( clk  : IN std_logic;
       srst : IN std_logic;
       x1   : IN std_logic_vector (2 downto 0);
       x2   : IN std_logic_vector (2 downto 0);
       btn  : IN std_logic;
   y    : OUT std_logic_vector (7 downto 0));
end component abc ;

signal clk  : std_logic;
signal srst : std_logic;
signal x1   : std_logic_vector (2 downto 0);
signal x2   : std_logic_vector (2 downto 0);
signal btn  : std_logic;
signal y    : std_logic_vector (7 downto 0);

signal period : time := 1 ns;

begin

clk_gen : process begin
clk <= '0';
loop
    clk <= '1';
    wait for period;
    clk <= '0';
    wait for period;
end loop;
end process clk_gen;

x1_gen : process begin
x1 <= "000";
wait for period;
loop
    x1 <= std_logic_vector(unsigned(x1) + 1);
    wait for period;
end loop;
end process x1_gen;

x2_gen : process begin
x2 <= "000";
wait for period;
loop
    x2 <= std_logic_vector(unsigned(x2) + 1);
    wait for period;
end loop;
end process x2_gen;

reset_proc : process begin
srst <= '1';
wait for period * 1.5;
srst <= '0';
wait;
end process reset_proc; 

btn_proc : process begin
btn <= '0',
       '1' after 20 ns,
       '0' after 23 ns,
       '1' after 40 ns,
       '0' after 43 ns,
       '1' after 60 ns,
       '0' after 63 ns,
       '1' after 80 ns,
       '0' after 83 ns,
       '1' after 100 ns,
       '0' after 103 ns,
       '1' after 120 ns,
       '0' after 123 ns;
       wait;
end process btn_proc;


---------------------------------------------------------------------
-- Instantiate the DUT
---------------------------------------------------------------------

dut : abc port map  ( clk => clk,
                      srst => srst,
                      x1 => x1,
                      x2 => x2,
                      btn => btn,
                      y => y);

end rtl_tb;

Here's the waveform for the first 30 ns.

enter image description here

At 20 ns, the btn goes up, the output should be sum of x1 and x2, but its not happening. The output continuously remains at s0. When ibtn rises, it goes into s1, whenever ibtn falls, it goes back to s0. I could not make it go forward. I suspect the problem is in the sensitivity list but could not figure it out. Any help will be greatly appreciated.

\$\endgroup\$
5
  • \$\begingroup\$ @Eugene Sh. the button on the board is pressed results in logic 1 at the input, so, it should go on, otherwise i dont follow what you sdaid. \$\endgroup\$
    – Zzz
    Commented Apr 24 at 20:01
  • \$\begingroup\$ @Eugene Sh. you are absolutely right, how could I not see that :( \$\endgroup\$
    – Zzz
    Commented Apr 24 at 20:04
  • \$\begingroup\$ @toolic, I added the states, mult and add too. It seems whenever the btn is pressed, s0 goes to s1, then when the button is released, it goes back to s0. How can this issue be fixed? \$\endgroup\$
    – Zzz
    Commented Apr 24 at 20:22
  • \$\begingroup\$ Why do you have this line next_state <= current_state; in your state control process? You are making the transition in the main processs \$\endgroup\$
    – Eugene Sh.
    Commented Apr 24 at 20:36
  • \$\begingroup\$ @Eugene Sh. as a default, & not to change the current state. \$\endgroup\$
    – Zzz
    Commented Apr 24 at 20:42

1 Answer 1

2
\$\begingroup\$

Looking at your waveform, you only asserted btn for about half a clock cycle. You can see next_state change during that time, but there's no clock edge that would transfer next_state to current_state, so the actual state machine never updates.

Keep in mind that all inputs to a state machine must be synchronized to the state machine's clock. Your btn signal is not.

\$\endgroup\$
4
  • \$\begingroup\$ I added clock to the state_control process, if I understood correctly your answer, but nothing changed. \$\endgroup\$
    – Zzz
    Commented Apr 24 at 20:46
  • 1
    \$\begingroup\$ ibtn is just a copy of btn. You still haven't captured it with a clock edge. \$\endgroup\$
    – Dave Tweed
    Commented Apr 25 at 0:49
  • 1
    \$\begingroup\$ Perhaps try a tool like HDL-FSM-Editor \$\endgroup\$ Commented Apr 25 at 6:43
  • \$\begingroup\$ Ok, i added "ibtn" to the sensitivity list, now the state transition is working, this situation is now fixed! Thanks a lot @Dave Tweed. \$\endgroup\$
    – Zzz
    Commented Apr 25 at 12:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.