Moore, Mealy and when the output changes

Tell a Moore output from a Mealy output by when it can change, convert one into the other, and choose which one may leave a module.

Lesson
R3.1
Time
25 min
Runs on
Your browser
Check
5 questions

A controller acknowledged requests with ack = (st_q == READY) && req, and the receiver sampled ack at its clock edge. On the board, req sometimes arrived late in the cycle, so ack rose late too and the receiver caught a pulse whose width depended on that arrival. In simulation req changed right after the edge, so ack looked clean.

The Mealy acknowledge follows req inside the cycleOne request raised 1 ns after edge 3, one raised 3 ns after edge 5, one 1 ns after edge 7. Each value is the one the receiver samples at the next edge.
012345678clkstREADYDONEREADYDONEREADYDONEREADYreqack
  1. Cycle 1

    Edge 3: the state is READY. req rises 1 ns later and ack rises with it, 1 ns after the edge. The handshake happens at edge 4.

  2. Cycle 3

    Edge 5: the late request. req rises 3 ns after the edge and ack rises at the same moment, 3 ns into the cycle. On a board, every extra nanosecond of req is a nanosecond less for ack.

  3. Cycle 4

    Edge 6: the state is DONE, so ack falls at the edge itself. The output moved twice in two cycles: once with the input, once with the state.

Measured on the bench, cycles e2 to e10. No request waited: ack answered in the same cycle as req.

Where the output comes from

A finite state machine (FSM) is a state register, a next-state function and an output function. In a Moore machine the outputs depend on the state alone, so they change only when the state does: at a clock edge. In a Mealy machine the outputs depend on the state and the current inputs, so they also change whenever an input changes.

The same controller drawn twiceTop: Mealy, with the output written on the arc that req takes. Bottom: Moore, with the output written inside the DONE state. The next-state arcs are the same.
The same controller drawn twiceTop: Mealy, with the output written on the arc that req takes. Bottom: Moore, with the output written inside the DONE state. The next-state arcs are the same. state READY (Mealy) ack = req state DONE (Mealy) ack = 0 state READY (Moore) ack = 0 state DONE (Moore) ack = 1 req / ack = 1next edgereqnext edge
  1. Mealy

    The output belongs to the arc. ack is 1 while READY sees req, in that same cycle, and the arc to DONE is taken at the next edge.

  2. Moore

    The output belongs to the state. req moves the machine to DONE at the next edge, and ack is 1 for the whole DONE cycle.

Read the diagram as text
  • READY (Mealy): ack = req
  • DONE (Mealy): ack = 0
  • READY (Moore): ack = 0
  • DONE (Moore): ack = 1
  • READY (Mealy) → DONE (Mealy): req / ack = 1
  • DONE (Mealy) → READY (Mealy): next edge
  • READY (Moore) → DONE (Moore): req
  • DONE (Moore) → READY (Moore): next edge

Converting this machine is one line: ack = (st_q == DONE) instead of ack = (st_q == READY) && req.

Both machines on the same benchThe requester holds req until it samples ack = 1 at an edge, so the Moore run holds each request one cycle longer.
012345678clkreq_mealyack_mealyreq_mooreack_moore
  1. Cycle 1

    Cycle e3: both see req. The Mealy ack is 1 in this cycle; the Moore ack is 0.

  2. Cycle 2

    Cycle e4: the Moore machine is in DONE and its ack is 1 for the whole cycle. One cycle later than Mealy.

  3. Cycle 5

    The late request: the Moore ack rises at edge 7, at the start of the cycle, wherever req arrived in the cycle before.

Measured, cycles e2 to e10. Mealy: 3 requests, 0 cycles waiting. Moore: 3 requests, 3 cycles waiting.

What the gates and the timing say

Moore costs a cycle of latency here, and Mealy costs a clean output. A third choice, the registered Mealy output, computes the Mealy value and stores it in a flop: one cycle late like Moore, and steady for the whole cycle.

Output codingack after reqCan move inside a cycleCells (flops)Levels of logic
Mealy: (st_q == READY) && reqsame cycleyes, with req2 (1)1
Moore: st_q == DONEone cycle laterno2 (1)1
registered Mealy: a flop on the Mealy valueone cycle laterno2 (1)1

Measured with Yosys 0.70 on this flow. The registered ack and the DONE state bit have the same next value, so the synthesizer merged the two flops.

The cell counts are equal because this machine is tiny. The difference is where ack comes from. In the Moore version it is the output of a flop. In the Mealy version it is an AND gate fed by req, so any change of req, early, late or a glitch, reaches ack.

The rule this track follows: an output that leaves the module is Moore or registered, so the next block sees a value that changes only at the edge. A Mealy output is fine inside a module, where the logic that reads it is timed with it.

Converting Mealy to Moore

  1. Find the input in the output equation

    Here ack reads req. That input is what makes the output Mealy.

  2. Move it into the next state

    The arc READY to DONE already fires on req, so DONE means "req was seen". Some machines need a new state for this.

  3. Decode the output from the state

    ack = (st_q == DONE). The output now waits for the edge, one cycle later, and is steady for the whole cycle.

Design brief
PortDirectionWidthMeaning
clkinput1clock
rst_ninput1reset, asynchronous, active-low
reqinput1the requester holds req until it samples ack = 1
ackoutput1one ack per request
Clock
rising edge
Reset
rst_n asynchronous, active-low, state READY
Latency
Mealy: ack in the cycle of req; Moore: the cycle after
Corner cases
a request raised late in the cycle; requests back to back

Run the lab: three requests, no waiting, and the two lines that say ack moved 1 ns and 3 ns after the edge. Then change the assign to ack = (st_q == DONE) and run again. Each ack now comes one cycle later, the notes about moving inside the cycle are gone, and the summary counts 3 cycles of waiting. Synthesize both: 2 cells each.

Asked in interviews
  1. Moore or Mealy: what is the difference?

    A Moore output depends on the state only, so it changes at the clock edge. A Mealy output also depends on inputs, so it reacts in the same cycle and carries whatever timing and glitches those inputs carry.

  2. Which would you use for an output that leaves the chip?

    A registered one: Moore, or Mealy followed by a flop. It changes only at the edge, so the receiver sees a steady value for the whole cycle. The price is one cycle of latency.

  3. How do you convert a Mealy machine to Moore?

    Move the input from the output equation into the next-state logic, adding a state if the machine must remember that the input was seen. Then decode the output from the state. The output moves one cycle later.

Try it

Each line shows a cycle as the receiver will sample it at the next edge. Three times ack rose inside the cycle, as late as req did: 1 ns, 3 ns and 1 ns after the edge. Each handshake took one edge and no request waited.

Change the assign to ack = (st_q == DONE) and run: ack is 1 in cycles e4, e7 and e10, never moves inside a cycle, and the summary reads 3 cycles waiting for ack. The bench file prints the state through dut.st_q, so keep the state names.

RTLIcarus Verilog · in your browser · Lint: Verilator service · Synthesize: Yosys service
Edit the design, then Run, Lint or Synthesize
Expected: e2 st=READY req=0 ack=0 e3 st=READY req=1 ack=1 (ack moved 1 ns after the edge) e4 st=DONE req=0 ack=0 e5 st=READY req=1 ack=1 (ack moved 3 ns after the edge) e6 st=DONE req=0 ack=0 e7 st=READY req=1 ack=1 (ack moved 1 ns after the edge) e8 st=DONE req=0 ack=0 e9 st=READY req=0 ack=0 e10 st=READY req=0 ack=0 3 requests, 0 cycles waiting for ack

Original design · 2 cells · 1 flip-flops · 0 latches · 1 logic levels. Synthesis uses Yosys; counts depend on the toolchain.

Read included file: tb.sv
`timescale 1ns/1ps
module tb;
  logic clk = 0;
  always #5 clk = ~clk;                   // rising edges at 5, 15, 25, ...
  logic rst_n = 1;                        // falls at 1 ns: a real edge, so an asynchronous reset acts before any clock
  int edge_n = -1;
  always @(posedge clk) edge_n = edge_n + 1;
  logic req = 0;
  logic ack;
  int   served = 0, waited = 0;
  time  t_edge = 0, t_ack = 0;
  always @(ack) t_ack = $time;           // when ack last moved
  // One line per cycle, printed 9 ns after edge k: the values the receiver samples at edge k+1.
  always @(posedge clk) begin
    t_edge = $time;
    #9 if (edge_n >= 2) begin
      if (t_ack > t_edge)
        $display("e%0d st=%s req=%b ack=%b  (ack moved %0d ns after the edge)", edge_n, dut.st_q ? "DONE " : "READY", req, ack, t_ack - t_edge);
      else
        $display("e%0d st=%s req=%b ack=%b", edge_n, dut.st_q ? "DONE " : "READY", req, ack);
    end
  end
  // Raise req `at` ns after the next edge; hold it until ack is 1 at an edge.
  task automatic request(input int at);
    @(posedge clk); #(at) req = 1;
    @(posedge clk);
    while (ack !== 1'b1) begin           // not yet: wait one more edge
      waited++;
      @(posedge clk);
    end                                  // this edge is the handshake
    served++;
    #1 req = 0;
  endtask
  req_ack dut (.clk(clk), .rst_n(rst_n), .req(req), .ack(ack));
  // Advance to the next rising edge, wait for the design to settle, then print one line.
  task automatic tick();
    @(posedge clk); #1;
    
  endtask
  initial begin
    #1 rst_n = 0; tick(); tick(); rst_n = 1;   // asserted at 1 ns, edges 0 and 1 in reset, released 1 ns after edge 1
    @(posedge clk);                       // cycle 2: idle
    request(1);                           // req rises 1 ns after edge 3
    request(3);                           // a late req: 3 ns after the edge
    request(1);
    repeat (2) @(posedge clk); #9.5;
    $display("%0d requests, %0d cycles waiting for ack", served, waited);
    $finish(0);                             // quiet: no "$finish called" line
  end
endmodule

Check yourself

Predict the outputThe Moore version: ack = (st_q == DONE). The requester raises req 1 ns after edge 4 and samples ack at each later edge. What does the program print?
// req_ack: acknowledges each request once, then takes one cycle (DONE) before the next.
// The requester holds req until it sees ack = 1 at a rising edge.
module req_ack (
  input  logic clk,
  input  logic rst_n,      // asynchronous, active-low
  input  logic req,
  output logic ack
);
  typedef enum logic {READY, DONE} state_e;
  state_e st_q, st_d;

  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) st_q <= READY;
    else        st_q <= st_d;

  always_comb begin
    st_d = st_q;
    unique case (st_q)
      READY:   if (req) st_d = DONE;
      DONE:    st_d = READY;
      default: st_d = READY;
    endcase
  end

  // Moore: ack depends on the state only.
  assign ack = (st_q == DONE);
endmodule

`timescale 1ns/1ps
module tb;
  logic clk = 0;
  always #5 clk = ~clk;                   // rising edges at 5, 15, 25, ...
  logic rst_n = 1;                        // falls at 1 ns: a real edge, so an asynchronous reset acts before any clock
  int edge_n = -1;
  always @(posedge clk) edge_n = edge_n + 1;
  logic req = 0;
  logic ack;
  req_ack dut (.clk(clk), .rst_n(rst_n), .req(req), .ack(ack));
  // Advance to the next rising edge, wait for the design to settle, then print one line.
  task automatic tick();
    @(posedge clk); #1;
    
  endtask
  initial begin
    #1 rst_n = 0; tick(); tick(); rst_n = 1;   // asserted at 1 ns, edges 0 and 1 in reset, released 1 ns after edge 1
    repeat (3) @(posedge clk);
    #1 req = 1;                          // req rises 1 ns after edge 4
    @(posedge clk);
    while (ack !== 1'b1) @(posedge clk); // the requester samples ack at each edge
    #1 $display("ack seen at edge e%0d", edge_n);
    $finish(0);                             // quiet: no "$finish called" line
  end
endmodule
Spot the bugEach option drives ack, which leaves the module. The bench raises req 3 ns or 6 ns after an edge and requires three acknowledgements with no change of ack inside a cycle. Which option fails?
ConceptAn output of your block drives a flop in a block another team designs. Which output coding is the safe default?
ConceptIn the lab, the registered Mealy version synthesized to 2 cells with 1 flop, the same as Moore. Where did the extra flop go?
Read the waveformIn the measured trace, the requests start in cycle e3. In which cycle does ack_moore first rise?
Mealy and Moore acknowledges
012345678req_mealyack_mealyreq_mooreack_moore

One value per cycle, cycles e2 to e10 from the left.

Remember

  • A Moore output depends on the state alone and changes only at the clock edge; a Mealy output also depends on inputs and changes when they do.
  • Mealy answers in the same cycle; Moore and registered Mealy answer one cycle later with an output that is steady for the whole cycle.
  • Convert Mealy to Moore by moving the input into the next-state logic and decoding the output from the state.
  • Outputs that leave a module should be Moore or registered; here all three codings measured 2 cells, so the choice is about timing, not area.