You hand a tool three things: RTL that says what the design does, constraints that say how fast and under what electrical conditions it must do it, and a cell library that says what it may build with. The tool hands back two things: a gate-level netlist built only from that library, and reports counting and pricing what it chose. Every surprise in synthesis is a surprise about how the three inputs steer the two outputs.
The design below is a 4-bit saturating adder: it adds two 4-bit numbers, raises a saturation flag on overflow, and clamps the sum at the maximum instead of wrapping. The script synthesises it once to generic gates, records that netlist, then maps it against the teaching library course.lib with a loose 1000 ps delay target and records the result. The assertions are the contract: no word-level arithmetic survives, generic gates are present before mapping, and none remains after while at least one library cell does.
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
synth -top satadd -flatten
tee -o stat_generic.txt stat
write_json net_generic.json
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
design -save mapped
design -load generic
select -assert-none t:$add t:$sub t:$mul %u
select -assert-min 1 t:$_AND_ t:$_OR_ t:$_XOR_ t:$_NOT_ t:$_MUX_ t:$fa %u
design -load 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: saturating adder synthesises to generic gates then maps to course.lib cellsThe delay target deserves one sentence. ABC takes -D 1000, a deliberately slack request for 1000 ps: this lesson is about what synthesis does, not about meeting a hard clock. In this ABC script the library offers one size per cell, so the recorded run has no upsizing to do; the target only decides whether this one covering meets the request, and the area line prices the covering this library allows. The constraints lesson's closing run shows it: against the same kind of single-size library, a tight target lands back on the loose covering.
About the same order here, one cell fewer. ABC re-strashes the generic netlist into an AIG and re-covers it, so mapping is never one generic gate to one library cell: some gates merge into wider cells such as AOI21 and OAI21, which is why the count falls from 21 generic gates to 20 library cells. The family changes completely, from unpriced generic gates to priced library cells.
Read the generic census first. Every entry is a bit-level gate: the adder and the saturation mux are gone as word-level cells, lowered before any library is involved. The next lesson watches that lowering stage by stage.
Generic cell type | Cells |
|---|---|
| 11 |
| 1 |
| 2 |
| 1 |
| 1 |
| 3 |
| 2 |
The generic census above is the gate total, and it knows nothing of area: without a library there is nothing to price with. Mapping changes that. ABC covers the same logic with cells from course.lib, and the stat report prices each family in library units of that library, a fictional teaching measure comparable only within this course.
Library cell | Cells |
|---|---|
AND2 | 3 |
AOI21 | 2 |
INV | 2 |
NAND2 | 3 |
NOR2 | 3 |
OAI21 | 2 |
OR2 | 1 |
XNOR2 | 3 |
XOR2 | 1 |
The stat report splits the mapped cells across 9 cell types. ABC reports the gate total at the area the comparison table below records, reaching 635 ps against the 1000 ps target. Area exists only here, on the mapped side: no generic count can price them, because price lives in the library.
Same function, same ports, different population: generic gates above, priced library cells below. That replacement, plus the reports that price it, is the whole job of synthesis.
Synthesis promises to preserve function while choosing cost. The netlist must still add, saturate, and clamp exactly as the RTL says; equivalence checking later proves that promise mechanically. Change any of the three inputs and the tool is entitled to a different answer.
RTL and constraints enter from above; the netlist and its reports leave toward placement. Placement cannot fix a missed target or supply a missing cell, so read the mapped report before handing off.
Change one operator and watch the cell mix change. The second script is identical except that the addition is now a bitwise exclusive-or, so the sum bits are parity instead of a sum. The assertions keep the same shape; only the recordings move.
read_verilog <<EOV
module satxor(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 satxor
synth -top satxor -flatten
tee -o stat_generic_xor.txt stat
write_json net_generic_xor.json
design -save generic_xor
tee -o abc_xor.txt abc -liberty course.lib -constr typical.constr -D 1000
tee -o stat_xor.txt stat -liberty course.lib
write_json net_xor.json
design -save mapped_xor
design -load generic_xor
select -assert-none t:$add t:$sub t:$mul %u
select -assert-min 1 t:$_AND_ t:$_OR_ t:$_XOR_ t:$_NOT_ t:$_MUX_ t:$fa %u
design -load mapped_xor
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: xor variant of the saturating adder maps to course.lib cells with a new mixThe parity variant synthesises to 4 generic gates and maps to 4 library cells at the area the table records. That sensitivity is the point: the mapper has no loyalty to yesterday's netlist, only to today's RTL.
Build | Generic gates | Mapped cells | Area (library units) |
|---|---|---|---|
Adder (`+`) | 21 | 20 | 58 |
Parity (`^`) | 4 | 4 | 20 |
Compare with the adder row in the table: one operator changed, the function changed. Why so few gates here? Here the sum is only four bits wide, so s[4] is always 0: the saturation flag is constant and the clamp mux has a constant select, and synthesis drops both before mapping. What remains is one XOR gate per sum bit, and the mapper covers each with one XOR2 library cell.
The cell family changed: the generic gates of the census became library cells in the comparison table. The function did not: same ports, same saturate-and-clamp behaviour, which is why the assertions pin absence of generics rather than exact cells.
In library units of course.lib. The generic netlist has no library attached, so its cells have no prices; only the mapped report can total an area.
Every number and picture on this page comes from two Yosys 0.69 runs of the shown scripts, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): a 4-bit saturating adder synthesised to generic gates, then mapped against the teaching library course.lib with a loose 1000 ps target, plus a parity-operator variant. The libraries are fictional, so absolute areas are teaching units.