.. role:: raw-html-m2r(raw)
:format: html
.. _state_machine:
State machine
=============
Introduction
------------
In SpinalHDL you can define your state machine like in VHDL/Verilog, by using enumerations and switch cases statements. But in SpinalHDL you can also use a dedicated syntax.
The following state machine is implemented in following examples :
.. image:: /asset/picture/fsm_simple.svg
:align: center
:width: 300
Style A :
.. code-block:: scala
import spinal.lib.fsm._
class TopLevel extends Component {
val io = new Bundle{
val result = out Bool
}
val fsm = new StateMachine{
val counter = Reg(UInt(8 bits)) init (0)
io.result := False
val stateA : State = new State with EntryPoint{
whenIsActive (goto(stateB))
}
val stateB : State = new State{
onEntry(counter := 0)
whenIsActive {
counter := counter + 1
when(counter === 4){
goto(stateC)
}
}
onExit(io.result := True)
}
val stateC : State = new State{
whenIsActive (goto(stateA))
}
}
}
Style B :
.. code-block:: scala
import spinal.lib.fsm._
class TopLevel extends Component {
val io = new Bundle{
val result = out Bool
}
val fsm = new StateMachine{
val stateA = new State with EntryPoint
val stateB = new State
val stateC = new State
val counter = Reg(UInt(8 bits)) init (0)
io.result := False
stateA
.whenIsActive (goto(stateB))
stateB
.onEntry(counter := 0)
.whenIsActive {
counter := counter + 1
when(counter === 4){
goto(stateC)
}
}
.onExit(io.result := True)
stateC
.whenIsActive (goto(stateA))
}
}
StateMachine
------------
StateMachine is the base class that will manage the logic of your FSM.
.. code-block:: scala
val myFsm = new StateMachine{
// Here will come states definition
}
The StateMachine class also provide some utils :
.. list-table::
:header-rows: 1
:widths: 1 1 5
* - Name
- Return
- Description
* - isActive(state)
- Bool
- Return True when the state machine is in the given state
* - isEntering(state)
- Bool
- Return True when the state machine is entering the given state
States
------
There is multiple kinds of states that you can use.
* State (the base one)
* StateDelay
* StateFsm
* StateParallelFsm
In each of them you have access the following utilities :
.. list-table::
:header-rows: 1
:widths: 1 10
* - Name
- Description
* - | onEntry{
| yourStatements
| }
- yourStatements is executed the cycle before entering the state
* - | onExit{
| yourStatements
| }
- yourStatements is executed when the state machine will be in another state the next cycle
* - | whenIsActive{
| yourStatements
| }
- yourStatements is executed when the state machine is in the state
* - | whenIsNext{
| yourStatements
| }
- yourStatements is executed when the state machine will be in the state the next cycle
* - goto(nextState)
- Set the state of the state machine by nextState
* - exit()
- Set the state of the state machine to the boot one
For example, the following state could be defined in SpinalHDL by using the following syntax :
.. image:: /asset/picture/fsm_stateb.svg
:align: center
:width: 300
.. code-block:: scala
val stateB : State = new State{
onEntry(counter := 0)
whenIsActive {
counter := counter + 1
when(counter === 4){
goto(stateC)
}
}
onExit(io.result := True)
}
You can also define your state as the entry point of the state machine by extends the EntryPoint trait.
.. code-block:: scala
val stateA: State = new State with EntryPoint {
whenIsActive {
goto(stateB)
}
}
StateDelay
^^^^^^^^^^
StateDelay allow you to create a state which wait a fixed number of cycles before executing statments in your ``whenCompleted{...}``. The standard way to write it is :
.. code-block:: scala
val stateG : State = new StateDelay(cyclesCount=40){
whenCompleted{
goto(stateH)
}
}
But you can also write it like that :
.. code-block:: scala
val stateG : State = new StateDelay(40){whenCompleted(goto(stateH))}
StateFsm
^^^^^^^^
StateFsm Allow you to describe a state which contains a nested state machine. When the nested state machine is done, your statments in ``whenCompleted{...}`` are executed.
There is an example of StateFsm definition :
.. code-block:: scala
val stateC = new StateFsm(fsm=internalFsm()){
whenCompleted{
goto(stateD)
}
}
As you can see in the precedent code, it use a ``internalFsm`` function to create the inner state machine. There is an example of definition bellow :
.. code-block:: scala
def internalFsm() = new StateMachine {
val counter = Reg(UInt(8 bits)) init (0)
val stateA: State = new State with EntryPoint {
whenIsActive {
goto(stateB)
}
}
val stateB: State = new State {
onEntry (counter := 0)
whenIsActive {
when(counter === 4) {
exit()
}
counter := counter + 1
}
}
}
In the precedent example, the ``exit()`` call will make the state machine jump to the boot state (a internal hidden state). This notify the StateFsm about the completion of the inner state machine.
StateParallelFsm
^^^^^^^^^^^^^^^^
This state is able to handle multiple nested state machines. When all nested state machine are done, your statments in ``whenCompleted{...}`` are executed.
There is an example of declaration :
.. code-block:: scala
val stateD = new StateParallelFsm (internalFsmA(), internalFsmB()){
whenCompleted{
goto(stateE)
}
}