You linted the code and the simulation passes. What does synthesis tell you at this stage, and what does it not?
The counter counts, the testbench reports its verdict, and Verilator is quiet. Before you trust the code further, you ask the next tool in the loop a narrower question: does this code describe hardware that a tool can build from? The answer comes from Yosys, an open-source synthesis tool, and it is smaller than you might expect.
Synthesis means translation from a description of behavior into gates. The full version of that translation maps your code onto a real factory library and answers hard questions about area, speed, and power. This lesson runs only the first part of that journey, on purpose.
The check reads the design, confirms the hierarchy, turns the clocked process into registers and logic, simplifies the result, looks for obvious problems, and counts what it found. Each of those jobs is one Yosys command, and the project Makefile runs them in order: read_verilog reads the code as SystemVerilog, hierarchy confirms the top module and its connections, proc turns the always block into registers and logic, opt simplifies, check looks for obvious problems, and stat reports the counts.
The cells in the report are generic, which means placeholders no factory built. The report names four of them, measured on Yosys 0.69+post on macOS: $add is an adder of some width, $not is an inverter, $reduce_or collapses many bits into one decision, and $sdffe is a flip-flop that holds one bit across each clock edge. Other Yosys versions report different names and counts for the same design. Any technology could implement these placeholders, which is exactly why this check cannot answer area, speed, or power. Those answers need a mapped netlist built from a real library, plus timing constraints, and that work belongs to the synthesis course.
So the check answers one question well: the code describes hardware with no structural surprise. It leaves the rest alone. Whether the hardware does the right thing is the testbench's job. How big it is, how fast it runs, and how much power it burns are questions for a mapped flow. A passing synthesis check next to a failing simulation is still a broken design.
The figure below draws the middle of the report as four boxes between the inputs and the count register. Look at the middle column first: one box per generic cell, with the job each one does inside the counter. Nothing in the picture comes from a factory library, so nothing in it has an area or a delay.
The listing below is the synth target from the project Makefile. It is the whole check in one command.
SHELL := /bin/bash
IVERILOG ?= iverilog
VVP ?= vvp
YOSYS ?= yosys
VERILATOR ?= verilator
RTL := rtl/mini_controller.sv
TB := tb/tb_mini_controller.sv
BUILD := build
.PHONY: help sim lint synth all clean check-tools
.DEFAULT_GOAL := all
help:
@echo "Targets: sim lint synth all check-tools clean"
all: lint sim synth
$(BUILD):
mkdir -p $(BUILD)
sim: | $(BUILD)
$(IVERILOG) -g2012 -Wall -s tb_mini_controller -o $(BUILD)/sim.vvp $(RTL) $(TB)
set -o pipefail; cd $(BUILD) && $(VVP) sim.vvp | tee sim.log
@grep -c "^PASS:" $(BUILD)/sim.log | grep -qx 1
lint:
$(VERILATOR) --lint-only -Wall --top-module mini_controller $(RTL)
synth: | $(BUILD)
$(YOSYS) -Q -T -p 'read_verilog -sv $(RTL); hierarchy -check -top mini_controller; proc; opt; check -assert; stat' > $(BUILD)/synth.log
check-tools:
@bash scripts/check_tools.sh
clean:
rm -rf $(BUILD)This listing is the project's synth target: one Yosys command over the design file, with its output saved to the build log.
# captured terminal output
$ make synth && tail -n 22 build/synth.log
mkdir -p build
yosys -Q -T -p 'read_verilog -sv rtl/mini_controller.sv; hierarchy -check -top mini_controller; proc; opt; check -assert; stat' > build/synth.log
5. Executing CHECK pass (checking for obvious problems).
Checking module mini_controller...
Found and reported 0 problems.
6. Printing statistics.
=== mini_controller ===
+----------Local Count, excluding submodules.
|
8 wires
14 wire bits
5 public wires
8 public wire bits
5 ports
8 port bits
4 cells
1 $add
1 $not
1 $reduce_or
1 $sdffeThis output came from Yosys 0.69+post on macOS. The first line creates the build folder, the second runs the six jobs and saves the log, and the third prints the tail of that log.
Read the code. read_verilog -sv parses the design file as SystemVerilog. Note what is missing: the testbench is never read, so none of its simulation-only code can confuse this check.
Confirm the structure. hierarchy -check -top mini_controller names the top module and verifies that every connection resolves.
Build and simplify. proc turns the clocked process into registers and logic, and opt removes what the translation left redundant.
Check for problems. The CHECK pass reports 0 problems, measured on Yosys 0.69+post on macOS. That number means no obvious structural defect, not a correct design.
Count the result. The stat block lists 4 cells, measured on Yosys 0.69+post on macOS: one $add, one $not, one $reduce_or, one $sdffe. Other Yosys versions report different names and counts, so treat the exact list as illustrative of this version.
You might expect a nonzero status, since the design has a real defect. It exits 0. The warning is real but the status says success, which is why the Makefile uses check -assert instead.
The module below is small and almost right. Output y follows input a, and output z follows wire w, but nothing ever drives w.
module bad (input logic a, output logic y, output logic z);
logic w;
assign y = a;
assign z = w;
endmoduleThis listing is the bad design the transcripts below check: a complete module with one wire that has no driver.
# captured terminal output
$ yosys -Q -T -p 'read_verilog -sv yodemo/bad.sv; hierarchy -check -top bad; proc; opt; check -assert' | tail -n 4
ERROR: Found 1 problems in 'check -assert'.
5. Executing CHECK pass (checking for obvious problems).
Checking module bad...
Warning: Wire bad.\z is used but has no driver.
Found and reported 1 problems.This output came from Yosys 0.69+post on macOS. The last line names the defect: wire w inside module bad is used but has no driver. In hardware that wire floats, so z is unknown.
# captured terminal output
$ yosys -Q -T -p 'read_verilog -sv yodemo/bad.sv; hierarchy -check -top bad; proc; opt; check; stat' > /dev/null; echo "without -assert: exit status $?"
without -assert: exit status 0Without -assert the same design exits with status 0, measured on Yosys 0.69+post on macOS. The warning printed, but the status says success, so a scripted loop would march on.
# captured terminal output
$ yosys -Q -T -p 'read_verilog -sv yodemo/bad.sv; hierarchy -check -top bad; proc; opt; check -assert; stat' > /dev/null 2>&1; echo "with -assert: exit status $?"
with -assert: exit status 1With -assert the same design exits with status 1, measured on Yosys 0.69+post on macOS. That one flag is why the Makefile uses check -assert: a warning you could miss becomes a failure you cannot. The fix is ordinary hardware thinking: drive w from a real source, or remove the output that needs it, then re-run until the report returns to 0 problems.
Reading stat as area. Four generic cells say the structure is small and regular. They say nothing about square microns, because no library was involved. Wait for the mapped flow before any area claim.
Ignoring a warning because the run exited 0. Plain check warns about the undriven wire and still reports success. Treat every Yosys warning as a defect until you understand it, and keep -assert in the command so the exit status agrees.
Calling a synthesized design a verified design. Synthesis never runs your testbench, so it cannot catch a wrong priority or a missed wrap. A green check plus a red simulation is a broken design; Tests That Can Fail shows how to earn trust in behavior.
Rule: a passing synthesis check means the code describes hardware; it says nothing about correct behavior, area, speed, or power.
No. The cells are generic placeholders counted before any mapping to a real library, measured on Yosys 0.69+post on macOS, and other versions report different names and counts. Area needs a mapped netlist plus library data, which this check never touches.
Plain check exits 0 on a design with an undriven wire, so a real defect looks like success. With -assert the same design exits 1, so the loop stops and the warning gets fixed instead of filed away.
A first synthesis check asks whether the code describes hardware; generic cells are placeholders, not silicon.
Read every line of the report: 0 problems from check and the cell list from stat, measured on your tool version.
Use check -assert so a warning becomes a failure; plain check exits 0 on a real defect.