-->

Difference in initializing a state machine between

2019-07-27 02:20发布

问题:

My question is regarding the first state used in a synthesized state machine.

I'm working with a Lattice iCE40 FPGA, the EDA Playground for simulation and Lattice's Diamond Programmer for synthesizing.

In the following example I am generating a series of signals (the example only shows the lines referring to the state machine). This works fine in simulation; i.e. the first case accessed is sm_init_lattice and the required signals are produced). However, the synthesized version goes straight to sm_end and stays there. As a result the output signal stays low.

-- state machine
type t_SM_peaks is (sm_init_lattice,
                    sm_high_start_up, sm_low_start_up, sm_peaks, sm_end);

signal r_SM_peaks : t_SM_peaks;

p_ARRAY_INTS_STDLOG_2D : process (i_Clk) is
begin
  if rising_edge(i_Clk) then
    case r_SM_peaks is
      when sm_init_lattice =>
        ...
        r_SM_peaks <= sm_high_start_up;
      when sm_high_start_up =>
        ...
        r_SM_peaks <= sm_low_start_up;  
      when sm_low_start_up =>
        ...
        r_SM_peaks <= sm_peaks;
      when sm_peaks =>
        ...
        r_SM_peaks <= sm_end;                        -- peaks completed
      when sm_end =>
        ...
        r_SM_peaks <= sm_end;
      when others =>
        r_SM_peaks <= sm_high_start_up;
    end case;
  end if;

end process p_ARRAY_INTS_STDLOG_2D;

However, if I make one change as follows (indicated with 'CHANGE') then I get the set of signals that I require.

type t_SM_peaks is (sm_init_lattice,
                    sm_high_start_up, sm_low_start_up, sm_end, sm_peaks);

signal r_SM_peaks : t_SM_peaks;

p_ARRAY_INTS_STDLOG_2D : process (i_Clk) is
begin
  if rising_edge(i_Clk) then 
    case r_SM_peaks is
      when sm_init_lattice =>
        ...
        r_SM_peaks <= sm_high_start_up;
      when sm_high_start_up =>
        ...
        r_SM_peaks <= sm_low_start_up;
      when sm_low_start_up =>
        ...
        r_SM_peaks <= sm_peaks;
      when sm_peaks =>
        ...
        r_SM_peaks <= sm_end;                        -- peaks completed
      when sm_end =>
        ...
        -- CHANGE - swapped 'sm_end' for 'sm_init_lattice'
        --r_SM_peaks <= sm_end;
        r_SM_peaks <= sm_init_lattice;             
      when others =>
        r_SM_peaks <= sm_high_start_up;             
    end case;
  end if;

end process p_ARRAY_INTS_STDLOG_2D;

Can anyone explain what is happening, please? Am I doing something wrong? I'll be grateful for any suggestions.

回答1:

In simulation, a everything in VHDL defaults to its left hand value. In your code, that would be sm_init_lattice, which explains why your simulation passes.

However, I see no reset signal. So, in your hardware, the flip-flops that store the state of your FSM will be reset to some states, but that probably isn't the combination that represents the sm_init_lattice state.

Without your change, in hardware, the FSM is perhaps initialising to some state near sm_end and and when it gets into that state, it will stay there. By making your change, you are allowing the FSM to take more laps round the track, so it will progress through all the states whatever state it initially finds itself.

The solution is to implement a proper reset (either asynchronous or synchronous - FPGA people seem to prefer synchronous).

The use of enumerated types to code state machines is nice, because the code is easy to read and maintain, you don't have to commit to any state encoding and you get to see what state you're in on a waveform display. However, using enumerated types to code state machines does not enable you to model an unitialised state, which is probably the cause of your problem. System-Verilog is superior to VHDL in this respect, because it is possible to declare an enumerated type which can also be unknown.