Skip to content
code0.HDL

A state machine from a state table

Turn a state table into a state register, a next-state case and output logic, run a two-state rise detector and check its trace and waveform against the table, repair a broken transition, and design a three-state machine yourself.

In this chapter

  • Write a state table with one row for every state and input combination before writing code
  • Translate the table into a state register, a next-state case with a default, and output logic
  • Tell a Moore output from a Mealy output and say which signals of the machine may change between edges
  • Predict a two-state machine cycle by cycle from its table, run it, and compare the trace and waveform line by line
  • Trace a wrong output back to the faulty transition and fix it
  • Design a three-state Moore machine from a contract and pass a grader that checks every cycle
Concepts in this chapter
  • State table, next state, output logic
Prerequisite concepts

1. A state machine is one register and two combinational blocks

Every sequential circuit in this course so far was a state machine with a number for a state: a counter whose state is its count. A state machine in the narrow sense has a small set of named states, and it is built from three parts you already know.

PartKindComputes
state registerregister, always @(posedge clock) with <=holds the current state; takes the next state at the edge
next-state logiccombinational, always @* with casenext state from the current state and the inputs
output logiccombinational, assign or always @*outputs from the current state, and in a Mealy machine also from the inputs

A machine whose outputs depend on the state alone is a Moore machine; one whose outputs also read the inputs directly is a Mealy machine. The assumptions are the same as everywhere in this course: one clock, rising edge, synchronous reset.

2. The state table says everything before any code exists

Take the rise detector from Register stages, observation and waveforms and give its memory a name. The one register prev has two values, so there are two states: LOW, meaning the last sampled level was 0, and HIGH, meaning it was 1. The input is level; the output rise is 1 when a rise is being seen right now.

Current statelevelNext staterise
LOW0LOW0
LOW1HIGH1
HIGH0LOW0
HIGH1HIGH0

Every row is one edge: the state and input before it, the state after it. rise reads the input, so this is a Mealy output. The table has 2 states × 2 input values = 4 rows, and like a truth table it must have a row for every combination before you write code.

Check

The machine is in HIGH and level is 1. What are the next state and rise?

Your answer

3. The code follows the table part by part

The table becomes three blocks of RiseFsm.v. Read it next to the table, one part at a time.

RiseFsm.v
// A two-state rise detector built from its state table.
module rise_fsm (
  input      clock,
  input      reset,
  input      level,
  output     rise,
  output reg pulse,
  output reg state
);
  localparam LOW = 1'b0, HIGH = 1'b1;
  reg next;

  // Next-state logic: one branch per current state, every path assigned.
  always @* begin
    case (state)
      LOW:     next = level ? HIGH : LOW;
      HIGH:    next = level ? HIGH : LOW;
      default: next = LOW;
    endcase
  end

  // State register: the only block that writes state.
  always @(posedge clock) begin
    if (reset) state <= LOW;
    else       state <= next;
  end

  // Mealy output: reads the state and the input of this cycle.
  assign rise = (state == LOW) & level;

  // Registered copy of rise: one edge later, one full period wide.
  always @(posedge clock) begin
    if (reset) pulse <= 1'b0;
    else       pulse <= rise;
  end
endmodule
LinesPartWhat to check against the table
localparam LOW = 1'b0, HIGH = 1'b1;state encodingone name per state; two states fit in one bit
always @* case (state)next-state logicone branch per state, each branch covers both values of level, plus a default
always @(posedge clock) writing statestate registerthe only block that writes state; reset first
assign rise = (state == LOW) & level;output logicthe rise column: 1 only in the row LOW, level 1
second always @(posedge clock)registered outputpulse is rise one edge later

localparam gives the states names; two states fit in one bit, three or four states need two bits, and so on. The case has one branch per state and a default, so next is assigned on every path, as Nets, variables and the combinational always required. The state register is the only clocked block that touches state, and reset puts the machine into a known state. Without reset, state is x at the start, case (state) matches no named state and takes the default branch, which sets next to LOW. The output rise can still be known when level is 0, because x & 0 is 0; when level is 1 it remains x until the state becomes known. The output rise is wired from state and input; pulse registers it, which is the version the Practice problem rise-pulse asked for. state is also a port here only so that the testbench can print it; a machine normally keeps its state inside.

Check

A machine has five named states. How many bits does its state register need at least?

4. Predict the machine cycle by cycle

The browser model rise-detect is this machine with prev as the state: prev 0 is LOW, prev 1 is HIGH. Its rise is the combinational output during a cycle, computed from the state at the start of the cycle and the input applied in it. Drive it a few cycles first.

Concept experiment · rise-detect

A browser model of the circuit, not a compiled design. The real toolchain runs in the examples.

Inputs

Outputs

prev
0
rise
0

No edge has happened yet. Set the inputs, then apply a clock edge.

Now fill in the table: prev after the edge that ends each cycle, and rise during the cycle.

Predict, then compare · rise-detect

Fill in each cell before comparing. Empty cells count as a mismatch.

State table
Cycleininputs sampled at the edgeprevafter the edgeriseOutputs
01
11
20
31
40
50

5. Run the machine and compare it with your table

The testbench drives the pattern 0111010011 into level, one value per cycle, after a reset that spans two rising edges. It changes level on a falling edge and prints one time unit later, so every line shows, for one cycle:

ColumnMeaning at the moment of printing
levelthe input applied in this cycle, which the next rising edge will sample
statethe state at the start of the cycle, before that edge
risethe Mealy output during the cycle, from state and level
pulsethe registered output, set by the previous edge

Predict from the table before you run: write the state, rise and pulse columns for the ten cycles. The pattern contains a run of three 1s, so a level that stays high must not count as a new rise.

Check

For level = 0 1 1 1 0 1 0 0 1 1, in how many of the ten cycles is rise 1?

Check

In which cycle does the printed pulse first become 1?

Tb.v
module tb;
  reg        clock = 0;
  reg        reset = 1;
  reg        level = 0;
  wire       rise, pulse, state;
  reg  [9:0] pattern = 10'b01110_10011;
  integer    i;
  integer    rises = 0;

  rise_fsm dut (.clock(clock), .reset(reset), .level(level), .rise(rise), .pulse(pulse), .state(state));

  always #5 clock = ~clock;

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars(0, tb);
    // Reset across two rising edges, released on a falling edge.
    @(negedge clock);
    @(negedge clock) reset = 0;
    for (i = 0; i < 10; i = i + 1) begin
      // Inputs change on the falling edge; one time unit later the line shows
      // the state before the next rising edge and the outputs of this cycle.
      level = pattern[9 - i];
      #1 $display("cycle %0d: level=%b state=%s rise=%b pulse=%b",
                  i, level, state ? "HIGH" : "LOW ", rise, pulse);
      rises = rises + rise;
      @(negedge clock);
    end
    $display("DONE rises=%0d", rises);
    $finish;
  end
endmodule

Practice this concept

Use this concept in a short Verilog problem as your next step.

Press Run and compare every line with your columns. The last line, DONE rises=3, is the testbench adding up rise over the ten cycles. Then open the waveform:

  • tb.dut.state changes only at rising edges, and after each edge it equals the level that edge sampled;
  • tb.rise goes high in the middle of a cycle, at the falling edge where level rises, and falls at the next rising edge when the state becomes HIGH;
  • tb.pulse is rise shifted to the following rising edge, one full period wide.

If a printed line disagrees with your table, find that cycle in the waveform first and ask which of the three parts produced the wrong value: the state, the next-state logic, or the output logic.

6. The waveform must show three different kinds of signal

Checking a state machine in a waveform means knowing in advance how each signal is allowed to move.

SignalKindAllowed to change
stateregisteronly at rising edges
riseMealy output, combinationalwhenever level or state changes, also between edges
pulseregistered outputonly at rising edges, one edge after rise

If state moves between rising edges, check for a wrong sensitivity list or an assignment outside its clocked block. Blocking = inside always @(posedge clock) can create a race, but does not by itself make that block run between edges. If rise flickers between edges while level is noisy, that is correct for a Mealy output, and the reason to register it when the output must be stable for a whole cycle.

Check

Which signal of rise_fsm may legitimately change between two clock edges?

Your answer

7. Break one transition, then verify again

A state machine is only as correct as every row of its table. Make these edits in the lab one at a time, predict, run, and restore the original before the next.

EditPredict first
HIGH: next = level ? HIGH : LOW; to HIGH: next = level ? HIGH : HIGH;how many rises the trace reports, and from which cycle on state stops changing
pattern = 10'b01110_10011 to 10'b11111_00000whether a level that is already 1 in the first cycle after reset counts as a rise

Check

With the HIGH branch changed to level ? HIGH : HIGH, what does the last line print?

Your answer

Check

With the pattern 1111100000, in which cycle is rise 1?

The first edit is the error the Practice problem below hides in its starter. The second shows why the reset value of the state is part of the contract: it decides what the first cycle after reset compares against.

8. Moore and Mealy in the same trace

rise and pulse in the trace you just ran mark the same event at two different moments.

OutputReadsWhen it shows a rise of levelKind
risestate and inputin the cycle where level is 1 after a 0, before the edgeMealy
pulseregisters onlyin the following cycle, from edge to edgeMoore-timed

A machine whose output reads the state alone needs a state that means "a rise was just sampled". Give the detector three states, LOW, ROSE and HIGH: LOW with level 1 goes to ROSE, ROSE goes to HIGH on 1 and back to LOW on 0, and the Moore output is 1 in ROSE. That output can only change at an edge, one cycle after the Mealy rise.

Check

Which column of the trace does the Moore output of the three-state LOW/ROSE/HIGH detector match cycle for cycle?

Your answer

Choose by what the receiver needs: a Mealy output answers in the same cycle but follows any glitch on the input; a Moore output is stable for whole cycles and costs one cycle of latency, and here one extra state.

9. Variation: a toggle as a two-state Moore machine

Change the table and the same three parts build a different machine. A toggle has states OFF and ON and input t: with t 1 the next state is the other one, with t 0 it is the same one. The output q is 1 in ON, read from the state alone, so this one is a Moore machine. In the code only the case branches and the assign change. Predict q after each edge.

Predict, then compare · toggle

Fill in each cell before comparing. Empty cells count as a mismatch.

State table
Cycletinputs sampled at the edgeqafter the edge
01
11
20
31
40

10. Apply it: repair a machine, then design one

Two Practice problems close the chapter, with less help in the second.

  • Find the broken transition. The starter is this chapter's detector with one wrong branch. The trace shows the symptom; you compare the case with the table, find the row that is missing, and fix it.
  • Design a three-state detector from its contract. Only the ports and the contract are given: seen is 1 while the last two sampled values of din were 1, as a Moore output. Write the state table first, then the state register, the next-state case and the output logic. Grading accepts any encoding that meets the contract and reports the first failing cycle, whether the check was before or after the edge, and the expected and actual value.

11. Summary

ElementMeaning
state tableone row per state and input: next state and outputs
localparam LOW = …named state encoding; n bits name up to 2ⁿ states
always @* case (state) with defaultnext-state logic, every path assigned
always @(posedge clock) with resetthe state register, the only writer of state
Moore / Mealyoutputs from state only, change at edges / from state and inputs, change inside a cycle
first wrong line of a tracea symptom; trace it back to the state, the next-state branch, or the output logic

The testbench techniques for driving such a machine are in Testbench techniques, and recording its signals in a VCD is in Recording waveforms.

Checkpoint

Submit the Practice problem for grading

Grading runs on the server against hidden tests; the result is recorded in this browser only.