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
      • What Synthesis Does
      • The Five Flow Stages
      • Why Constraints Change the Netlist
      • A Small Design Through Yosys
      • Concepts, Not Commands
    • Synthesizable RTL and Inference
    • Reading Netlists and Reports
  • 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

←Synthesis Flow Overview
  1. Topics
  2. Logic Synthesis
  3. Synthesis Foundations
  4. Synthesis Flow Overview
  5. The Five Flow Stages
On this page

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

    The Five Flow Stages

    The five synthesis stages from reading to reporting, with a recorded stop after each.

    Stage confusion is the oldest synthesis bug: elaboration blamed for mapping choices, generic counts quoted as area. The fix is a boundary you can point at in a recording.

    After this lesson you can: run one design through elaboration, optimisation with lowering, and mapping, chart the cell count per stage, and prove that generic gates appear at techmap and area appears only after mapping.

    The five stages

    Every synthesis tool runs the same five ideas in roughly this order, even when it iterates, merges steps, or renames them. This topic uses one stage list on every page: read, elaborate, optimise, map, report. Read the model once and every later lesson has somewhere to hang: each new pass or report belongs to exactly one stage, and each stage owns a specific netlist shape.

    Stage

    Command here

    What the netlist contains

    1. Read

    read_verilog, hierarchy -check

    RTL loaded and checked, top set; the netlist starts here.

    2. Elaborate

    proc

    Word-level cells: operators, muxes, and flops as the RTL wrote them.

    3. Optimise

    opt, then techmap

    Word-level cells simplified, then lowered to bit-level generic gates; technology-independent, still no library, still no area.

    4. Map

    abc -liberty

    Real library cells chosen for the constraints; area exists only from here on.

    5. Report

    stat, stat -liberty

    Counts and area for review. Reporting never changes the netlist.

    Elaboration builds word-level cells and nothing else: after proc and coarse opt the design still holds one $add and one $mux with zero generic gates, and bit-level gates appear only once techmap runs the lowering half of optimisation. The script below pins both halves of that boundary, so read the assertions.

    Watch one design move

    The script runs the saturating adder from the previous lesson through three recording stops: after proc and opt, after techmap, and after abc -liberty with a loose 1000 ps target. Each stop writes a stat report and a JSON netlist under its own name, and design -save freezes the netlist so a later stage cannot disturb an earlier recording. The assertions then reload each frozen stage and pin exactly what may and may not be present.

    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
    read_verilog <<EOV
    module satadd(input [3:0] a, b, output [3:0] y, output sat);
    wire [4:0] s = a + b;
    assign sat = s[4];
    assign y = s[4] ? 4'hF : s[3:0];
    endmodule
    EOV
    hierarchy -check -top satadd
    proc
    opt
    tee -o stat_opt.txt stat
    write_json net_opt.json
    design -save after_opt
    techmap
    tee -o stat_tech.txt stat
    write_json net_tech.json
    design -save after_tech
    tee -o abc_stage.txt abc -liberty course.lib -constr typical.constr -D 1000
    tee -o stat_mapped.txt stat -liberty course.lib
    write_json net_mapped.json
    design -save after_map
    design -load after_opt
    select -assert-count 1 t:$add
    select -assert-count 1 t:$mux
    select -assert-none t:$_AND_ t:$_OR_ t:$_NOT_ t:$_MUX_ t:$_XOR_ t:$fa %u
    design -load after_tech
    select -assert-none t:$add
    select -assert-none t:$mux
    select -assert-min 1 t:$_AND_ t:$_OR_ t:$_XOR_ t:$_NOT_ t:$_MUX_ t:$fa %u
    design -load after_map
    select -assert-none t:$and t:$or t:$xor t:$mux t:$not t:$add t:$sub %u
    select -assert-none t:$_AND_ t:$_OR_ t:$_NOT_ t:$_MUX_ t:$_XOR_ t:$_NAND_ t:$_NOR_ %u
    select -assert-min 1 t:INV t:BUF t:NAND2 t:NOR2 t:AND2 t:OR2 t:NAND3 t:NOR3 t:XOR2 t:XNOR2 t:AOI21 t:OAI21 t:MUX2 %u
    check
    log PASS: adder word cells survive opt, become bit cells at techmap, library cells after abc
    Predict first Three stops, three cell counts. The first stop holds word-level cells and the script pins one $add and one $mux. What happens to the cell count at the second stop, and what happens again at the third?

    It jumps, then it falls well below the peak. Lowering one 5-bit adder and one 4-bit mux to bit-level gates creates many gates from two cells, so the second stop counts 58 cells against 2 word-level cells at the first. Mapping then merges and re-covers those gates into 24 library cells: wider cells such as AOI21 and OAI21 each absorb several generic gates, and ABC re-optimises while covering.

    What the three reports say

    Cell count per stage: expansion at lowering, consolidation at mapping; the exact counts sit in the table below.

    Stage

    Command

    Cells recorded

    Area recorded

    Stages 1–3 (coarse)

    read_verilog, hierarchy, proc, opt

    2 word-level cells

    None: no library attached yet

    Stage 3 (lowering)

    techmap

    58 bit-level gates

    None: generic gates have no prices

    Stages 4–5

    abc -liberty, stat -liberty

    24 library cells

    65 library units of course.lib

    Read the table left to right. Area appears only in the last row, priced at 65 library units of course.lib. The first two rows cannot quote an area at any price: word-level cells and generic gates are library-neutral by construction, so any area attached to them would be fiction. That is why quoting a stage-3 count as final area misleads, and why the only area this topic ever quotes comes from a stat -liberty report after mapping. Do not confuse this generic-gate total with the previous page's area, which happens to share its digits: there the number is library units after mapping, here it is a gate count before any library is involved.

    The boundary is pinned twice. After proc; opt the script asserts one $add, one $mux, and zero generic gates: elaboration builds word-level cells, full stop. After techmap it asserts the reverse: no $add, no $mux, and at least one bit-level gate. Bit-level gates appear at techmap, the lowering tail of optimisation, never before.

    A learner comparing with the previous lesson will notice a different covering there: the previous lesson maps this same adder through synth and records fewer cells at a smaller area, while this page runs proc, opt, techmap, and abc as separate passes and records its own covering. Same RTL, two scripts, two coverings: synth runs its own optimisation and abc first, so its techmap input already differs. Every number on a page belongs to the script beside it.

    Check: skip optimisation, and mapping converges anyway

    This variant converges by design rather than breaking anything. The second script uses a small cone with a duplicated product term, (a & b) | (a & b) | (c & d), and runs it twice: once through proc and opt, once with opt deleted. Nothing else changes, so any difference in the recordings belongs to the missing pass alone.

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    read_verilog <<EOV
    module or_redundant(input a, b, c, d, output y);
    assign y = (a & b) | (a & b) | (c & d);
    endmodule
    EOV
    hierarchy -check -top or_redundant
    proc
    opt
    tee -o stat_red_opt.txt stat
    write_json net_red_opt.json
    design -save red_opt
    techmap
    tee -o abc_red_opt.txt abc -liberty course.lib -constr typical.constr -D 1000
    tee -o stat_red_opt_mapped.txt stat -liberty course.lib
    write_json net_red_opt_mapped.json
    design -save red_opt_mapped
    design -load red_opt
    select -assert-count 2 t:$and
    select -assert-count 1 t:$or
    select -assert-none t:$_AND_ t:$_OR_ t:$_NOT_ t:$_MUX_ t:$_XOR_ t:$fa %u
    design -load red_opt_mapped
    select -assert-none t:$and t:$or t:$xor t:$mux t:$not t:$add t:$sub %u
    select -assert-none t:$_AND_ t:$_OR_ t:$_NOT_ t:$_MUX_ t:$_XOR_ t:$_NAND_ t:$_NOR_ %u
    select -assert-min 1 t:INV t:BUF t:NAND2 t:NOR2 t:AND2 t:OR2 t:NAND3 t:NOR3 t:XOR2 t:XNOR2 t:AOI21 t:OAI21 t:MUX2 %u
    design -reset
    read_verilog <<EOV
    module or_redundant(input a, b, c, d, output y);
    assign y = (a & b) | (a & b) | (c & d);
    endmodule
    EOV
    hierarchy -check -top or_redundant
    proc
    tee -o stat_red_noopt.txt stat
    write_json net_red_noopt.json
    design -save red_noopt
    techmap
    tee -o abc_red_noopt.txt abc -liberty course.lib -constr typical.constr -D 1000
    tee -o stat_red_noopt_mapped.txt stat -liberty course.lib
    write_json net_red_noopt_mapped.json
    design -save red_noopt_mapped
    design -load red_noopt
    select -assert-count 3 t:$and
    select -assert-count 2 t:$or
    select -assert-none t:$_AND_ t:$_OR_ t:$_NOT_ t:$_MUX_ t:$_XOR_ t:$fa %u
    design -load red_noopt_mapped
    select -assert-none t:$and t:$or t:$xor t:$mux t:$not t:$add t:$sub %u
    select -assert-none t:$_AND_ t:$_OR_ t:$_NOT_ t:$_MUX_ t:$_XOR_ t:$_NAND_ t:$_NOR_ %u
    select -assert-min 1 t:INV t:BUF t:NAND2 t:NOR2 t:AND2 t:OR2 t:NAND3 t:NOR3 t:XOR2 t:XNOR2 t:AOI21 t:OAI21 t:MUX2 %u
    check
    log PASS: opt merges the duplicated product term that proc leaves behind

    With optimisation the design elaborates to 3 coarse cells: opt merges the two identical product terms into one, leaving two $and cells feeding one $or. Without optimisation the merger never runs and 5 coarse cells reach techmap. In this ABC script mapping reconverges both halves to 3 library cells at area 6 library units: abc re-optimises while covering, so the duplicated term costs nothing at the mapped endpoint. Optimisation earns its keep before mapping, handing techmap a smaller coarse netlist even when the mapped endpoint coincides.

    Common mistakes

    Reading a stage-3 count as final area misleads. Generic gates are not library cells, so only the post-map report gives library area. Quote counts per stage, and area only after mapping.

    Where do library cells first appear, and what proves it on this page?

    Weak answer: optimisation already picks library cells, so I would quote the stage-2 count as the final area.

    Strong answer: library cells first appear at mapping, and the page proves the boundary twice. After coarse optimisation the script still pins one $add and one $mux with zero generic gates, so elaboration builds word-level cells only. After techmap it pins zero $add and at least one bit-level gate, so the lowering half of optimisation builds them there. The counts 2, 58, and 24 trace expansion then consolidation across the two boundaries.

    Follow-up: optimisation shrank only the coarse netlist here, from 5 coarse cells to 3, while the mapped endpoint stayed put. When would it change the mapped endpoint too? When the redundancy is one abc cannot re-cover for free; compare the two mapped areas to check.

    Check yourself Where in the five-stage model do library cells first appear, and what did this page assert about everything before?

    In stage 4, map. Before it the page asserts one $add, one $mux, and zero generic gates, so stages 1 and 2 work only with word-level cells that carry no area.

    Check yourself A report after generic optimisation counts 2 cells. Why is quoting those as final area wrong, and which number is the area?

    Those 2 are word-level cells with no library attached, so they have no prices. The area is the mapped row's figure in library units of course.lib, quoted only after mapping; read it from the table, never from a stage-2 count.

    • Elaboration builds word-level cells; generic gates appear only at techmap.

    • Cell counts expand at lowering and consolidate at mapping.

    • Optimisation only pays when it finds something to fold.

    Rule of thumb: quote counts per stage and area only after mapping.

    How this was checked

    Every number and the bar chart on this page come from two Yosys 0.69 runs of the shown scripts, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): the saturating adder recorded after proc and opt, after techmap, and after abc against course.lib, plus a redundant cone run twice, with and without opt. The library is fictional, so absolute areas are teaching units.

    • Interview: run a mock interview on this topic

    Related topics

    • Why constraints change the netlist

    • Technology Mapping

    • Reading Netlists and Reports

    Previous

    4 / 139

    Next: Why Constraints Change the Netlist

    Up next

    Up nextWhy Constraints Change the Netlist

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • A Small Design Through Yosys
    • Concepts, Not Commands