Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

A concept about State Machine using process in VHDL

Status
Not open for further replies.

beginner_EDA

Full Member level 4
Full Member level 4
Joined
Aug 14, 2013
Messages
191
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,296
Activity points
3,854
Hi,
This is how a state machine is normally written using process.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
type STATES is (
        Idle, FIFO_Flush, FIFO_FlushFinish,
        state1, state2, state3
    );
    
signal State                        : STATES;
signal StateNext                    : STATES;
 
Prc_StateMem: process(clk, Reset)
    begin
        if rising_edge(clk) then
            if Reset = '1' then
                State               <= Idle;
            else
                State               <= StateNext;
            end if;
        end if;
    end process Prc_StateMem;
 
Prc_Transition: process(State, input1, input2, input3)
    begin
        
        -- Defaults
        StateNext                   <= State;
        
        case State is
            
        when Idle =>
            
            if input1 = '1' then
                
                StateNext               <= FIFO_Flush;
                
            end if;
            
        -- clean FIFO.
        when FIFO_Flush =>
            
            StateNext                   <= FIFO_FlushFinish;
            
        when FIFO_FlushFinish => 
            
            if input2 = '0' then
                StateNext                   <= state1;
            end if;
            
        
        when state1 =>
            
            StateNext                   <= state2;
            
        when state2 =>
                      StateNext                 <= state3;
           
               when state3 =>
                     if input3 = '0' then
                StateNext                   <= Idle;
            end if;
             
               when others =>
            
            StateNext   <= Idle;
            
        end case;
        
    end process Prc_Transition;
 
Prc_Output: process(State, StateNext, input4, constant1, constant2, Tx_FIFO_WrReq)
    begin
        
        -- Defaults
        Busy                <= '1';
        FlushFIFO           <= '0';
        FIFO_WrReq          <= Tx_FIFO_WrReq;
        FIFO_WrData     <= input4;
        
        case State is
            
        when Idle =>
            
            Busy                <= '0';
            
        when FIFO_Flush =>
            
            FlushFIFO           <= '1';
            
        when FIFO_FlushFinish =>
            
        when state1 =>
            
                FIFO_WrReq          <= '1';
                    FIFO_WrData     <= constant1;
            
        when state2 =>
                      FIFO_WrReq            <= '1';
             FIFO_WrData        <= constant2;
           
               when state3 =>
                    FIFO_WrReq          <= Tx_FIFO_WrReq;
            FIFO_WrData     <= input4;
 
             when others =>
            
        end case;
        
          end process Prc_Output;



What I have not understood here default (before Idle state start). What is default ? What happened in default case? how default case affect output both in transition process and output decoding process?
 
Last edited:

The defaults for the outputs are what the outputs should be unless otherwise specified by a specific case selection. This avoids problems with not defining an output in every case and if-elsif-else-endif branch.
 
Thanks adsee.
one more thing,
We also don't get any output (not even Default output) from the state machine(process) unless value of one of the parameter inside the sensitivity list of process change??
 

Thanks adsee.
one more thing,
We also don't get any output (not even Default output) from the state machine(process) unless value of one of the parameter inside the sensitivity list of process change??

yes and no
You are correct for simulation, if you forget to add an input to the process to the sensitivity list it wont change the output
The problem here is you must assume sensitivity list will be ignored for synthesis, so anything no there will cause a missmatch between the real hardware and the simulated code.

Your code shows a 2 process state machine style. This is considered "old" style and gives you unregistered outputs that are usually not recommended. Much better to have a single process state machine so that all outputs are registered, and you never have problems creating latches unintentionally (because you forgot to assign all your outputs in all branches.)
 

IMO, for new developers working on small projects, two-process is a good choice. If you are interested in getting a job in (or being successful in) RTL design, you should then convert that design into a single-process design to become familiar with the more popular coding style.

I say this because the common errors in two-process designs -- sensitivity list mismatch, latches, and undriven registers -- are all logged in the synthesis report. The common errors in one-process designs -- pipeline mismatches, excessive latency in feedback paths, and mixed sample/cycle delays -- are not caught by any automated tool. This isn't to say it is impossible to write good single-process designs, only that it is easy to write barely functional designs. For a new developer, the latter is a bit more likely.
 

I say this because the common errors in two-process designs -- sensitivity list mismatch, latches
Just use VHDL-2008 and process(all) and these particular woes disappear completely. There is no need to ever list any signals in the sensitivity list, just use 'all'.

The common errors in one-process designs -- pipeline mismatches, excessive latency in feedback paths, and mixed sample/cycle delays -- are not caught by any automated tool.
But they are all caught by a self-checking testbench, as they should be.

Kevin Jennings
 

But they are all caught by a self-checking testbench, as they should be.

Kevin Jennings

That is the issue, they usually are not caught in simulation. These issues often only show up in corner cases that require a specific stimulus.
 

To my humble opinion 2 process state machine are as good as 1 process.
The outputs of the 2 process style are directly related (and so probably taken as well) from the state registers.

grtz

ST
 

The outputs of the 2 process style are directly related (and so probably taken as well) from the state registers.
By chance, an output signal might be a direct copy of a state register, in most cases it's formed by combinational logic, thus possibly involving glitches. These output signals are fine if further processed in synchronous logic but a potential cause of unexpected behavior if they are driving external devices. That's the "unregistered output" problem mentioned in post #4.
 
  • Like
Reactions: sythe

    sythe

    Points: 2
    Helpful Answer Positive Rating
With a loose definition of "state" you can ensure two process state machines have appropriately registered outputs. Eg, if "state" is defined to include the output bits, then the output bits will exactly match some of the state bits.
 

Believe you can do that. But should we?

Optimal coding of state variables is one of the tasks that's performed by a high-level synthesis tool according to straight forward rules (minimization of combinational logic and delay), why should I disrupt it?
 

With a loose definition of "state" you can ensure two process state machines have appropriately registered outputs. Eg, if "state" is defined to include the output bits, then the output bits will exactly match some of the state bits.

I have seen this done, and I have seen it done very neatly in VHDL. But as output number gets larger, so does the state variable, the possibility of state encoding and would probably hinder debugging.

Pipelining is something all FPGA engineers understand, so isnt that hard to debug. If you have some corner cases you missed in your testbench, then I would argue that your testbench isnt good enough.
 

Regarding FSM, you should be aware of Mealy type & MOORE type.

I noticed earlier you said
We also don't get any output (not even Default output) from the state machine(process) unless value of one of the parameter inside the sensitivity list of process change??

Read up about the types of state machines & you will understand the affect of having combinatorial or synchronous logic.
 

Regarding FSM, you should be aware of Mealy type & MOORE type.

I noticed earlier you said


Read up about the types of state machines & you will understand the affect of having combinatorial or synchronous logic.

This question has nothing to do wiht the type of state machine. It is simply a VHDL simulation question.
If a signal is missing from a sensitivity list, then the signals in the process will not get updated when that input signal changes. This will affect mealy and moore state machines equally, along with any other logic!
 

The default values are applicable if none of the case statements are satisfied. They are essential for the "next state logic" to be purely combinational which is how it must be.
For a purely combinational circuit block defined in a process, all the outputs must be assigned a value EVERY TIME the process executes which will happen if any signal in the sensitivity list changes. For processes defining purely combinational circuit using conditional statements like the "next state" process above, if any output is *only* assigned a value under a certain conditional statement being statisfied, than it means that if the process executes again and it is not assigned a value, it shall have to retain its old value. This infers that the previous value of must be stored! This will result in latch being inferred for that signal and not flip flops since the process is not "edge triggered".

Thus, the default value code block is there to make the process behave expectedly i.e any signal not assigned a value in a conditional (if-else or select case) shall take the value assigned under "default"! It is a good... rather an essential coding guideline for processes.

Note:
Please always remember, in a process we may assign a value to a signal multiple multiple times. However, it shall be updated *ONLY* once the process reaches its end and that also with the *last assigned value*! Thus a signal may be assigned a default value at the start but it shall not become that until it reaches the end of process. This can be proven via simulation.
 
  • Like
Reactions: ads-ee

    ads-ee

    Points: 2
    Helpful Answer Positive Rating
The default values are applicable if none of the case statements are satisfied. They are essential for the "next state logic" to be purely combinational which is how it must be.
For a purely combinational circuit block defined in a process, all the outputs must be assigned a value EVERY TIME the process executes which will happen if any signal in the sensitivity list changes. For processes defining purely combinational circuit using conditional statements like the "next state" process above, if any output is *only* assigned a value under a certain conditional statement being statisfied, than it means that if the process executes again and it is not assigned a value, it shall have to retain its old value. This infers that the previous value of must be stored! This will result in latch being inferred for that signal and not flip flops since the process is not "edge triggered".

Thus, the default value code block is there to make the process behave expectedly i.e any signal not assigned a value in a conditional (if-else or select case) shall take the value assigned under "default"! It is a good... rather an essential coding guideline for processes.

Note:
Please always remember, in a process we may assign a value to a signal multiple multiple times. However, it shall be updated *ONLY* once the process reaches its end and that also with the *last assigned value*! Thus a signal may be assigned a default value at the start but it shall not become that until it reaches the end of process. This can be proven via simulation.
This is pretty much what I stated back in post #2, but in a more verbose manner with full explanation of why you need the defaults.
 

Believe you can do that. But should we?

Optimal coding of state variables is one of the tasks that's performed by a high-level synthesis tool according to straight forward rules (minimization of combinational logic and delay), why should I disrupt it?

My comment was intended more as a comment towards the abstract model, not something that you would actually create a single specific HDL construct for. (that said, the state encoding for most tools is primitive and almost certainly easy to improve on. That is another thread, though unless a synthesis tool developer reads it there would be no point.) My point was that you could consider fsm state + registered outputs to be part of "state" if you wanted to view it that way for any conceptual reason.

Pipelining is something all FPGA engineers understand, so isnt that hard to debug. If you have some corner cases you missed in your testbench, then I would argue that your testbench isnt good enough.
I am forming my opinion on the topic based on my experience debugging both my own code as well as others. While FPGA engineers generally understand pipelining, there is a difference between connecting the concepts with small changes in RTL.

As highlights:
Code:
always @(posedge clk) begin
  //other code including a case statement has been removed.  The idle state transitions to multiple states, and multiple states can transition to idle.
  isIdle <= (state == IDLE) ? 1'b1 : 1'b0;
end

Not all developers will spot both errors in the above logic, especially if the process is 100 lines or longer. In the event that "isIdle" is rarely used, a simulation may not pick up either of the errors.

The other common issues were:
1.) addition of register stages as an attempt to break up a long line of code. (resulting in a pipelined sign extend with comparators and muxes...)
2.) mixing of different types of delays (eg, some additional register stages were qualified by an enable, while some were not)
3.) manually recreating the logic for a signal in one process within another. (ok, not a single process in this case. the developer wanted to have smaller clocked processes near the logic they interacted with)
4.) forgetting about feedback paths. (eg, using empty to generate the _registered_ fifo read signal.)

As long as the developer is aware of these design aspects, everything is fine. But the amount of damage caused by a small error like the one in my example may not be obvious to a new developer who is also new to the language.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top