User Tools


State Machine Design

This tutorial will provide a basic overview of state machine design using Behavioral Verilog. It will simply consist of an example block of code for a generic state machine with explanations following.

A silly little state machine is designed that, for the purpose of being generic, very briefly and simply represents a growing tree. Here is a list of the inputs and outputs, along with the state graph that the code will be representing. Following these is the module's Verilog code. The code is explained afterwards.

Inputs
Plant Planting the seed
Water Watering the plant
Sun Giving the plant sunlight
Reset Start over
Outputs
getFruit Getting fruit from the tree
getSeeds Getting more seeds from the tree
Done Cycle is over

It is assumed that if no listed transition conditions are met, the state stays where its at and does not transition.

module state_machine (clock, reset, plant, water, sun, harvest, getFruit, getSeeds, done);
  input clock, reset, plant, water, sun, harvest;
  output getFruit, getSeeds, done;
 
  // stores the state
  reg[1:0] state;
  reg[1:0] next_state;
 
  // state parameters
  parameter seed = 2'd0;
  parameter sprout = 2'd1;
  parameter tree = 2'd2;
  parameter dead = 2'd3;
 
  always @(posedge clock)
    if (reset)
      state <= seed;
    else
      state <= next_state;
 
  // setting the state
  always @(*)
    case (state)
      seed:
        if (plant)
          next_state <= sprout;
        else
          // Keep the state the same
          // This is required because the Nexys 4 apparently
          // will reset the register if it is not given a value
          next_state <= state;
      sprout:
        if (water && sun)
          next_state <= tree;
        else
          next_state <= dead;
      tree:
        if (harvest)
          next_state <= seed;
        else
          // Keep the state the same
          // This is required because the Nexys 4 apparently
          // will reset the register if it is not given a value
          next_state <= state;
      default:
        next_state <= seed;
    endcase
  // note that the always block ends here
 
  // setting the outputs
  // moore outputs
  assign getFruit = state == tree;
  assign done = state == dead;
  //mealy output
  assign getSeeds = (state == tree) && harvest;
 
endmodule

As you can see, inputs and outputs as declared in a state machine module just like they would be in any Verilog module.

reg[1:0] state creates the register that will store the state. This must have enough bits to store all the states. In this example there are 4 different states thus state only needs 2 bits.

reg[1:0] next_state creates a register that stores the next state.

parameter is similar to const in C. This simply creates a constant variable with the value given. This allows you to encode your states with names. It is not necessary to do this, but it makes it incredibly easy to manage your states. If you don't do this, you'll have to remember which state encoding corresponds to each state, and when you transition states you'll have to store a number directly like state ⇐ 2'b10. It is highly recommended that you use parameters.

always @(posedge clock) is the block in which all the transitions occur. Note that begin and end are not necessary because this always block only contains one statement.

always @(*) is an always block that will always be operating. It is essentially combination logic but an easier way to code it. Setting the next state inside an always block like this allows states that don't need a clock cycle to be passed through. This will be particularly helpful in the last lab of this class, where the decode state should not take up a clock cycle.

case (state) is a switch statement. It acts just like a switch case statement in C. case looks at the value that is passed to it, in this example state, and then executes the option that state is equal to. So if state is equal to seed, it will execute if (plant) state ⇐ sprout;. If state doesn't match any of the given options, default is executed. In this case default is used to give the state machine an initial state even if reset is not asserted. Case does not need a begin but it needs an endcase.

else state <= dead; under state sprout doesn't need to be an else if statement because there are only 2 transitions leaving that state, and the second is actually an inversion of the first using DeMorgan's Law!

default: is the case that is selected if no others are met.


The outputs are described in lines of combinational logic at the end. You can set the outputs inside the always block, but the outputs must then be made registers and its harder to find problems in your code as statements for a single output will be spread out all over.

There are multiple ways to set an output to 1 given a condition. The first output line, assign getFruit = state == tree? 1 : 0; tests state == tree using a ternary operator. However, the statement state == tree will return a 1 or a 0 anyway, so it can be used on its own without a ternary operator as is done in the third output, assign done = state == dead;. This can only be done on single bit outputs.

The outputs getFruit and done are both only moore outputs, they only depend on the current state. This can be seen from the fact that their logic only depends on what state is. getSeeds, however, is a mealy output as it depends on the transition. This is done by checking the current state and the transition condition and then and'ing them together.