1
\$\begingroup\$

I have 5 states : idle, state1, state2, state3, state4. I sometimes need to go to idle according to my design, and when I return from idle, I don't want to start from beginning, I want to start from the last state I was in. I thought about doing this in idle as

if (statereg = 2) then
my_state <= state2;
end if;

Is this a good approach or won't work? Are there better ways? How do VHDL gurus handle this kind of situation, what do we call this method in VHDL, does it have a name?

\$\endgroup\$
2
  • \$\begingroup\$ Please provide more information on what you are trying to achieve with the code and/or the full state machine code which you implemented. \$\endgroup\$
    – Avin
    Jun 6, 2014 at 10:16
  • \$\begingroup\$ The UML terminology for what you are describing is, "transitioning to the history state". Here is an example of the UML History pseudostate. \$\endgroup\$
    – kkrambo
    Jun 6, 2014 at 14:12

3 Answers 3

1
\$\begingroup\$

How complicated is your "idle" state?

If it's relatively simple, perhaps it would be better to simply replicate it; in other words, have separate idle1, idle2, etc. states, one for each of the active states.

\$\endgroup\$
1
\$\begingroup\$

The question is unclear, but assuming you want every other state than idle to be persistent, and idle to return to any such persistent state, the following approach will accomplish it without adding a lot of additional states...

type state_type is (idle, state1, state2, state3, state4);
signal state, saved_state : state_type;
signal reset, leave_idle, suspend, proceed : boolean;
procedure start_calculation;

process(clock)
begin
   if rising_edge(clock) then
      if reset then
         state       <= idle;
         saved_state <= state1;
      else
         -- default assignments : save current state
         saved_state <= state;

         -- main state machine
         case state is

         when idle =>
            -- override default assignment here; last assignment wins
            saved_state <= saved_state;
            if leave_idle then
               state <= saved_state;
            end if;

         when state1 =>
            if suspend then
               state <= idle;
            elsif proceed then
               start_calculation;
               state <= state2;
            -- else remain here
            end if;

         -- when state2 => 
         -- etcetera

         when others =>
            state <= idle;
         end case;
      end if;
   end if;
end process;
\$\endgroup\$
5
  • \$\begingroup\$ I go through states: 1,2,3,4 sequentially when idle case occurs I don't want to start from the beginning to scan but from where I left. \$\endgroup\$
    – Anarkie
    Jun 6, 2014 at 12:18
  • \$\begingroup\$ If I'm understanding your implementation correctly, saved_state is state delayed by 1cc, so if you remain in a state longer than 1cc then the saved one and the current one are the same. \$\endgroup\$
    – stanri
    Jun 6, 2014 at 12:24
  • \$\begingroup\$ @Stacey - yes (except of course for the Idle state), the idea is that you always return after Idle to the state which "called" it, treating Idle as a subroutine. That may not be what the poster actually wanted, which is still unclear to me. \$\endgroup\$ Jun 6, 2014 at 14:14
  • \$\begingroup\$ @Brian so your intention is to only live in idle for 1cc? Also, are you in chat much? I would love to speak to someone who has more hdl experience then me. It's one of the downsides of freelancing. \$\endgroup\$
    – stanri
    Jun 6, 2014 at 14:44
  • \$\begingroup\$ what does it do if "leave_idle" is false? ... I've never tried chat but I'll give it a go... \$\endgroup\$ Jun 6, 2014 at 16:11
1
\$\begingroup\$

I would save the previous state at the same time that you save your current state. For example, define two signal of the same state machine type:

 type states is (idle, state1, ... other states);

  signal current_state  : state;
  signal previous_state : state;

In your state machine, each time the current_state changes to a different state, set previous_state to current_state.

This make previous state always one step behind current state.

Then, in your initial state, just set current_state to previous_state when you want to go back to where you were.

  example_state_machine : process (clk, rst)
  begin 
    if rst = '1' then
      current_state  <= idle;
      previous_state <= state1; -- set this to the state you want to go to after first idle
    elsif clk'event and clk = '1' then  -- rising clock edge
      case current is
        when idle =>
          if (something = '1') then
            current_state  <= previous_state;
            previous_state <= current_state;
          else
            current_state <= idle;
          end if;
        when state1 =>
          if (something = '1') then
            current_state  <= state2;
            previous_state <= current_state;
          elsif something_else = '1' then
            current_state  <= idle;
            previous_state <= current_state;
          else
            current_state <= state1;
          end if;
          -- ... rest of states
        when others => null;
      end case;
    end if;
  end process;
\$\endgroup\$
3
  • \$\begingroup\$ How does this get out of Idle after reset? \$\endgroup\$ Jun 6, 2014 at 11:30
  • \$\begingroup\$ Snarky comment aside, the basic idea is sound. \$\endgroup\$ Jun 6, 2014 at 11:39
  • \$\begingroup\$ @BrianDrummond, huh, good point. Changed previous_state to state1 during reset. \$\endgroup\$
    – stanri
    Jun 6, 2014 at 12:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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