VHDL coding tips and tricks: Simple vending machine using state machines in VHDL

Tuesday, July 5, 2011

Simple vending machine using state machines in VHDL

   A state machine, is a model of behavior composed of a finite number of states, transitions between those states, and actions.It is like a "flow graph" where we can see how the logic runs when certain conditions are met. state machines are used to solve complicated problems by breaking them into many simple steps. 
   There are many articles available in the web regarding this topic. I found sequential circuit design pretty useful. If you are new to state machines I suggest you read that article before proceeding here. 
   In the above said article they have explained a simple vending machine problem and how to create a state machine diagram to solve it. I am not going much into the theory behind it. I have written the VHDL code for the Mealy model they have given. Refer to Fig 11.10 for this.


The VHDL code is given below:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity vend_mach is
port(   Clk : in std_logic;
        x,y : out std_logic;
        i,j : in std_logic
    );     
end vend_mach;

architecture Behavioral of vend_mach is

--type of state machine and signal declaration.
type state_type is (a,b,c);
signal next_s : state_type;

begin

process(Clk)
begin
    if(rising_edge(Clk)) then
        case next_s is
            when a =>
                if(i='0' and j='0') then
                    x <= '0';
                    y <= '0';
                    next_s <= a;
                elsif(i='1' and j='0') then
                    x <= '0';
                    y <= '0';
                    next_s <= b;
                elsif(i='1' and j='1') then
                    x <= '0';
                    y <= '0';
                    next_s <= c;
                end if;
            when b =>
                if(i='0' and j='0') then
                    x <= '0';
                    y <= '0';
                    next_s <= b;
                elsif(i='1' and j='0') then
                    x <= '0';
                    y <= '0';
                    next_s <= c;
                elsif(i='1' and j='1') then
                    x <= '1';
                    y <= '0';
                    next_s <= a;
                end if;
            when c =>
                if(i='0' and j='0') then
                    x <= '0';
                    y <= '0';
                    next_s <= c;
                elsif(i='1' and j='0') then
                    x <= '1';
                    y <= '0';
                    next_s <= a;
                elsif(i='1' and j='1') then
                    x <= '1';
                    y <= '1';
                    next_s <= a;
                end if;        
        end case;      
    end if;
end process;
   
end Behavioral;

The testbench code tests the functionality of the code:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS
 
signal Clk,x,y,i,j : std_logic := '0';
constant Clk_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.vend_mach PORT MAP (
        Clk => Clk,
        x => x,
        y => y,
        i => i,
        j => j
        );

   -- Clock process definitions
   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;
   
   -- Stimulus process(applying inputs 'i' and 'j').
   stim_proc: process
   begin      
    wait for Clk_period*2;
    i <= '0';j <= '0'; wait for Clk_period*2;
    i <= '0';j <= '1'; wait for Clk_period*1;
    i <= '1';j <= '0'; wait for Clk_period*1;
    i <= '1';j <= '1'; wait for Clk_period*1;
         
    i <= '0';j <= '0'; wait for Clk_period*1;
    i <= '0';j <= '1'; wait for Clk_period*2;
    i <= '1';j <= '1'; wait for Clk_period*1;
    i <= '1';j <= '0'; wait for Clk_period*1;
         
    i <= '0';j <= '0'; wait for Clk_period*1;
    i <= '0';j <= '1'; wait for Clk_period*1;
    i <= '1';j <= '1'; wait for Clk_period*1;
    i <= '1';j <= '1'; wait for Clk_period*1;
         
    i <= '1';j <= '0'; wait for Clk_period*2;
    i <= '1';j <= '1'; wait for Clk_period*1;
    wait;
   end process;

END;

The simulation waveform is attached below. Carefully go through the various signal values to see how the flow works.

The code is synthesisable. To get a clear understanding of the concepts take another problem on state machines from web and write the vhdl code for it using state machines.

I have written some other articles related to state machines. You can browse through them here.

5 comments: