Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Logic Synthesis Glossary
  • Logic Synthesis Cheatsheet
  • Synthesis Foundations14
    • Synthesis Flow Overview
    • Synthesizable RTL and Inference
    • Reading Netlists and Reports
      • Cell Counts from stat
      • Area by Cell Type
      • Hierarchy, Fanout and Net Names
      • Longest Path, Write and Read Back
  • Logic Optimisation and Mapping20
  • Constraints and Timing15
  • Sequential, FSM and Memory19
  • Datapath Synthesis14
  • Area, Power and Test14
  • Verification, ECO and Handoff15
  • Flows and Debugging15
  • Interview and Judgment11
Loading lesson

←Reading Netlists and Reports
  1. Topics
  2. Logic Synthesis
  3. Synthesis Foundations
  4. Reading Netlists and Reports
  5. Cell Counts from stat
On this page

    Part 1 of 9, lesson 11 of 14Part 1 of 9/Synthesis Foundations/Lesson 11 of 14Intermediate

    Cell Counts from stat

    Read a stat report: cell counts by type, wires, and what each line answers.

    A stat total without a by-type breakdown hides what was built. Teams that read only the total argue about sizes while the report already names the cells.

    After this lesson you can: read a stat report line by line: wires, public wires, cells, per-type counts and chip area, on a word-level, gate-level and mapped netlist.

    The question

    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.

    One adder, three netlists

    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.

    yosys
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    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 reread

    A 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.

    Each stat report below is shown exactly as the tool printed it, then annotated line by line. The per-type tables are built from the recorded files at build time.

    Predict first Before reading on: the word-level netlist holds one $add cell. How many gates will synthesis produce, and which line of the final stat -liberty report gives the area?

    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 word-level report

    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.

    Diagram
    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   $add

    Read 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.

    The gate-level report

    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.

    Diagram
    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.

    The mapped report

    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.

    Mapped cell counts by type for the 4-bit adder: AND2 1, AOI21 1, NAND2 5, NOR2 2, OAI21 2, OR2 1, XNOR2 3, XOR2 3. The most common cell is NAND2 with 5 instances.

    Break it: add one operator

    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.

    Common mistakes

    A single total hides the mix: always read the by-type breakdown before deciding what to resize. A second trap is quoting the word-level cell count as the design size: one $add becomes many gates, and only the mapped report gives size and cost.

    How do you read a stat report, and what does each stage add?

    Weak: it says how many cells there are, and mapping makes it bigger. Strong: the word-level report for this adder shows 1 cell and 3 wires, which are just the three ports; synthesis expands it to 17 generic gates; mapping covers those with 18 library cells at 59 area units, where NAND2 leads on count with 5 but XNOR2 and XOR2 tie for the largest area share. Area appears only once a library is named.

    Follow-up: why does the wire count grow at each stage while the ports stay fixed? Because every finer-grained net becomes explicit while the module boundary never moves.

    Check yourself NAND2 is the most common mapped cell. Do you start restructuring there?

    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.

    Check yourself The break-it design adds a parity output. How does its word-level report differ, and why is that the expected move?

    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.

    • One adder is three reports: a word-level $add, generic gates after synth, library cells after abc.

    • Every per-type row is a recording; the table on this page is built from the stat files the script wrote.

    • Adding one operator changes the wire and cell counts by exactly what the operator adds.

    Rule of thumb: read the by-type rows before quoting any total.

    How this was checked

    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.

    • Interview: run a mock interview on this topic

    Related topics

    • Area by cell type

    • Cell Libraries and Liberty

    Previous

    13 / 139

    Next: Area by Cell Type

    Up next

    Up nextArea by Cell Type

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Hierarchy, Fanout and Net Names
    • Longest Path, Write and Read Back