A stat report looks like a wall of numbers, but it answers one question per line: how many wires the design holds, how many of them are public, how many cells implement it, and how those cells split by type. This lesson reads all three reports from one 4-bit adder line by line, and every number below is a recording. The script elaborates the adder, prints stat on the word-level netlist, synthesises it to generic gates, prints stat again, maps it against course.lib, and prints stat -liberty. Nothing here is typed by hand.
The design is a 4-bit adder with a 5-bit sum, small enough to read completely and big enough that each stage changes the report. The script saves the word-level design after elaboration, then runs synth to generic gates and abc to library cells. The select lines are the script's assertions: the word-level netlist holds exactly one $add, synthesis dissolves it into generic gates, and after mapping no generic gate remains while at least one library cell does.
read_verilog <<EOV
module adder4(input [3:0] a, b, output [4:0] s);
assign s = a + b;
endmodule
EOV
hierarchy -check -top adder4
proc
opt
tee -o stat_word.txt stat
write_json net_word.json
select -assert-count 1 t:$add
design -save word
synth -top adder4 -flatten
tee -o stat_gates.txt stat
write_json net_gates.json
select -assert-none t:$add
select -assert-min 1 t:$_AND_ t:$_XOR_ t:$_OR_ %u
design -save generic
tee -o abc_mapped.txt abc -liberty course.lib -constr typical.constr -D 1000
tee -o stat_mapped.txt stat -liberty course.lib
write_json net_mapped.json
select -assert-none t:$add t:$and t:$or t:$xor t:$not t:$mux t:$_AND_ t:$_OR_ t:$_XOR_ t:$_NOT_ t:$_MUX_
select -assert-min 1 t:NAND2 t:NOR2 t:AND2 t:OR2 t:XOR2 t:XNOR2 t:NAND3 t:NOR3 t:AOI21 t:OAI21 t:MUX2 t:INV t:BUF %u
design -load word
read_verilog <<EOV
module adder4x(input [3:0] a, b, output [4:0] s, output p);
assign s = a + b;
assign p = ^b;
endmodule
EOV
hierarchy -check -top adder4x
proc
opt
tee -o stat_breakit.txt stat
write_json net_breakit.json
select -assert-count 1 t:$add
select -assert-min 1 t:$reduce_xor
log PASS: adder4 word, gate and mapped reports recorded, one extra operator rereadA commercial flow shows the same three stages under different names: elaboration, technology-independent optimisation, and library mapping. The teaching library course.lib stands in for the foundry library, and its units measure relative cell cost rather than any real process.
Synthesis dissolves the single $add into 17 generic gates ($_AND_ 1, $_NAND_ 9, $_XOR_ 7), and mapping covers them with 18 library cells (AND2 1, AOI21 1, NAND2 5, NOR2 2, OAI21 2, OR2 1, XNOR2 3, XOR2 3). The area lives on the chip-area line of the mapped report: 59 library units. The word-level 3 wires become 15 once every bit operation is explicit.
The first report describes the adder before synthesis has touched its structure. It holds 3 wires, all 3 of them public, and 1 cell: $add 1. One operator, one cell, and the three wires are just the three ports a, b and s: there is no internal word at this stage. Public wires matter because they are the nets a later report, a constraint file, or a debugging session can name; internal generated nets may be renamed or dissolved by any pass.
5. Printing statistics.
=== adder4 ===
+----------Local Count, excluding submodules.
|
3 wires
13 wire bits
3 public wires
13 public wire bits
3 ports
13 port bits
1 cells
1 $addRead it top to bottom. The wire lines count every named connection, ports included: four bits of a, four of b and five of s, which is where the 13 wire bits come from. The by-type row confirms the cell total is the single $add the assertion pins. There is no area yet: without a library the tool has no cell areas to add, which is why this report ends without a chip-area line.
After synth the $add is gone and the report counts generic gates instead: 17 cells ($_AND_ 1, $_NAND_ 9, $_XOR_ 7) on 15 wires, of which 3 are public. The wire count grows because every bit-level net is now explicit, while the public count stays comparable because the ports never change. It describes logic, not cost: the tool-neutral structure the mapper starts from.
8. Printing statistics.
=== adder4 ===
+----------Local Count, excluding submodules.
|
15 wires
25 wire bits
3 public wires
13 public wire bits
3 ports
13 port bits
17 cells
1 $_AND_
9 $_NAND_
7 $_XOR_Each by-type row names a generic gate the mapper must cover, and their total matches the cell line. If a later mapping surprises you, return here: it separates what the logic needs from what the library choice did with it.
After abc -liberty the generic gates are library cells with a chip area of 59 library units for 18 cells on 41 wires. ABC's own summary agrees on the gate count and delay from its separate pass over the same netlist, so the two reports corroborate rather than repeat each other.
Cell type | Cells | Area (library units) | Share |
|---|---|---|---|
AND2 | 1 | 3 | 5.1% |
AOI21 | 1 | 3 | 5.1% |
NAND2 | 5 | 10 | 16.9% |
NOR2 | 2 | 4 | 6.8% |
OAI21 | 2 | 6 | 10.2% |
OR2 | 1 | 3 | 5.1% |
XNOR2 | 3 | 15 | 25.4% |
XOR2 | 3 | 15 | 25.4% |
Each row is count times cell area. NAND2 leads on count with 5 of those cells, but the area sits elsewhere: XNOR2 and XOR2 tie for the largest share at 25.4% each, 30 units combined. Restructuring starts with that pair, but function can fix cells in place: an adder's sum bits need XORs by function, so the actionable question is how those cones are covered, not the count leader or the total alone.
The last design in the script adds one operator: a parity output over one operand, alongside the unchanged adder. Its word-level report holds 2 cells ($add 1, $reduce_xor 1) on 4 wires. Against the original 1 cell on 3 wires, the delta is exactly what the operator adds: one $reduce_xor cell, its output wire, and nothing else. The habit: after a one-line RTL change the report should move by precisely the hardware you meant to add.
No. NAND2 leads on count with 5 cells, but XNOR2 and XOR2 hold 30 area units between them. Start with that pair, because it moves the total most; the count leader and the total alone do not identify it — unless function fixes those cells, as adder sum bits fix XORs.
It holds 2 cells on 4 wires against 1 on 3: exactly one $reduce_xor cell plus its output wire. The delta matches the one operator added, which confirms the change did nothing unintended.
Every number and the chart on this page come from one Yosys 0.69 run of the script shown, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): a 4-bit adder elaborated, synthesised and mapped against the teaching library course.lib, plus a parity-output variant. The library is fictional, so absolute values are teaching units.