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.
- Cycle 1
Edge 3: the state is READY.
reqrises 1 ns later andackrises with it, 1 ns after the edge. The handshake happens at edge 4. - Cycle 3
Edge 5: the late request.
reqrises 3 ns after the edge andackrises at the same moment, 3 ns into the cycle. On a board, every extra nanosecond ofreqis a nanosecond less forack. - Cycle 4
Edge 6: the state is DONE, so
ackfalls 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.
- Mealy
The output belongs to the arc.
ackis 1 while READY seesreq, in that same cycle, and the arc to DONE is taken at the next edge. - Moore
The output belongs to the state.
reqmoves the machine to DONE at the next edge, andackis 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.
- Cycle 1
Cycle e3: both see
req. The Mealyackis 1 in this cycle; the Mooreackis 0. - Cycle 2
Cycle e4: the Moore machine is in DONE and its
ackis 1 for the whole cycle. One cycle later than Mealy. - Cycle 5
The late request: the Moore
ackrises at edge 7, at the start of the cycle, whereverreqarrived 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 coding | ack after req | Can move inside a cycle | Cells (flops) | Levels of logic |
|---|---|---|---|---|
Mealy: (st_q == READY) && req | same cycle | yes, with req | 2 (1) | 1 |
Moore: st_q == DONE | one cycle later | no | 2 (1) | 1 |
| registered Mealy: a flop on the Mealy value | one cycle later | no | 2 (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
Find the input in the output equation
Here
ackreadsreq. That input is what makes the output Mealy.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.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.
| Port | Direction | Width | Meaning |
|---|---|---|---|
| clk | input | 1 | clock |
| rst_n | input | 1 | reset, asynchronous, active-low |
| req | input | 1 | the requester holds req until it samples ack = 1 |
| ack | output | 1 | one ack per request |
- Clock
- rising edge
- Reset
rst_nasynchronous, active-low, state READY- Latency
- Mealy:
ackin the cycle ofreq; 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
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.
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.
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.
Synthesize the design to measure its cells and inspect the mapped gates.
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 ackOriginal 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
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.