-1

I want to do VHDL programming of a state machine. In this state machine one state is itself another state machine. how can i call this state machine from the main state machine? Example of what i actually want to do is as follows:

main state machine (sm_main.vhd) :-

clk_process : process (clk, reset)   
begin  
if(reset = '1') then   
state_reg <= start;   
elsif (clk'event and clk =' 1'  ) then  
state_reg <= state_next;  
end if;  
end process;

state_process : process (state_reg,input,enable)  
begin  
case state_reg is   
 when start =>  
     if (input =1) then  
      state_next <= wait;     
      else
      state_next <= start;  
  end if;

 when wait =>
     if  (enable =1)  then
     output <= '1';
     state_next <= execute;
         else
 output <='0';
  state_next <= wait; 
  end  if ;


 when execute =>
    if (enable =1) then 
     state_next <= done;
     else

     state_next <= start;

 end if;

 when done =>
if(result = 1) then
state_next <= execute;
else
state_next <= start;
     end if;

end case;
end process;   

sub state machine (sm_execute.vhd):-

The execute state of the above state machine is itself another state machine program.

 state_process : process (state_reg,a,b)    
 begin    
 case state_reg is    
 when start =>    
     if (a=1) then    
      state_next <= s1;          
      else    
      state_next <= s2;     
  end if;     

 when s1 =>     
     if  (b =1)  then
     state_next <= s3;
         else
     state_next <= s3; 
  end  if ;


 when s3=>
if(c=1) then
 result <= '1';
state_next <= s3
else
 result <='0';
state_next <= start
 end case;
end process;

What i want is to call this sm_execute.vhd in the execute state of sm_main.vhd. The output from the sm_execute which is result, is to be used as an input to determine the next state after execute in sm_main.vhd. That means i want to call the sub state machine program and also return the value to main state machine program once the sub state machine program finishes its execution.

thanks in advance Sruthi Rajan

1 Answers1

1

Handshaking. The first machine signals the second one to start, and waits for it to acknowledge. Then it retracts the start signal and waits for the second one to complete.

This is not the only way, but where you can separate the second state machine into its own process, it is probably the simplest.

First SM (master):

SM_1 : process(clock,reset)
begin
   if reset = '1' then 
      State_1 <= Idle;
   elsif rising_edge(clock) then
      -- default actions
      Start <= '0';
      -- state machine proper
      case State_1 is
      ...
      when Need_Result => 
         Start <= '1'; 
         -- wait here until slave SM starts processing
         if Done = '0' then
            State_1 <= Wait_Result;
         end if;
      when Wait_Result =>
         if Done = '1' then
            State_1 <= Have_Result;
         end if;
      ...
      when others => State_1 <= Idle;
      end case;
   end if;
end process;

Second SM (slave) :

SM_2 : process(clock,reset)
begin
   if reset = '1' then 
      State_2 <= Idle;
   elsif rising_edge(clock) then
      case State_2 is
      when Idle => 
         Done <= '1';  
         if Start = '1' then
            Done <= '0';
            State_2 <= Start_Process;
         end if;
      when Start_Process =>
         State_2 <= Process_Done;
      when Process_Done =>
         Done <= '1';
         if Start = '0' then
            State_2 <= Idle;
         end if;
      when others => State_2 <= Idle;
      end case;
   end if;
end process;

Notice that in this implementation, the master waits for the slave to start processing (done = '0';). This covers cases where the slave may not be able to respond immediately. It does not cover cases where Done='0' already because the slave is processing data for another master.

Also the slave waits for the master to retract Start before returning to Idle. Usually Start will already be '0' but if it isn't, you probably don't want the slave to retrigger immediately.

If you can guarantee neither of these cases will happen you can simplify the handshaking a little, but the design becomes more sensitive to changes in signal timings.

Notice also that Start defaults to '0', because of the default assignment, but Done has no default assignment so it retains its state during processing. Unless you return to Idle (perhaps via an error path) when Done is set to indicate that processing has stopped.

If there is uncertainty about whether processing will complete, you may want the master to time out, rather than deadlock waiting for something that won't happen. I do this by adding a delay timer which can be used by different states for different purposes : here it detects a frozen slave and lets us handle the error.

First SM (master):

SM_1 : process(clock,reset)
   variable Delay : natural range 0 to 100;
   constant Timeout : natural := 50;
begin
   if reset = '1' then 
      State_1 <= Idle;
      Delay := 0;
   elsif rising_edge(clock) then
      -- default actions
      Start <= '0';
      if Delay > 0 then
         Delay := Delay - 1;
      end if;
      -- state machine proper
      case State_1 is
      ...
      when Need_Result => 
         Start <= '1'; 
         -- wait here until slave SM starts processing
         if Done = '0' then
            Delay := Timeout;
            State_1 <= Wait_Result;
         end if;
      when Wait_Result =>
         if Done = '1' then
            State_1 <= Have_Result;
         elsif Delay = 0 then
            State_1 <= Timed_Out;  -- do error processing
         end if;
      ...
      when others => State_1 <= Idle;
      end case;
   end if;
end process;