Two small functions close this topic, each matching one compound cell exactly: the mux y = s ? b : a matches MUX2 at area 5, and y = NOT ((a AND b) OR c) matches AOI21 at area 3. Against the full library the pair should cost 8 units; against the three-cell library both must be rebuilt from NAND2 gates and inverters.
The script synthesises the pair once, saves the generic netlist, and maps it three times under typical.constr, which puts a 50 fF load on each output so ABC reports area and delay: first against course.lib, then against nand_only.lib from the identical generic gates, then against course.lib with only MUX2 banned. The first mapping asserts no generic mux survives plus at least one MUX2 and one AOI21. The second asserts no MUX2, AOI21, or OAI21 survives plus at least one NAND2. The third asserts no MUX2 survives while at least one AOI21 and one NAND2 stand: the AOI cone keeps its cell and only the mux is rebuilt. Every claim below names its library, because cell counts from one library never transfer to another.
read_liberty -lib course.lib
read_verilog <<EOV
module top(input a, b, c, s, output ym, output ya);
assign ym = s ? b : a;
assign ya = ~((a & b) | c);
endmodule
EOV
hierarchy -check -top top
synth -top top
design -save generic
tee -o abc_mux.txt abc -liberty course.lib -constr typical.constr -D 1000
tee -o stat_mux.txt stat -liberty course.lib
write_json net_mux.json
select -assert-none t:$mux
select -assert-none t:$_MUX_
select -assert-min 1 t:MUX2
select -assert-min 1 t:AOI21
design -load generic
tee -o abc_mux_nand.txt abc -liberty nand_only.lib -constr typical.constr -D 1000
tee -o stat_mux_nand.txt stat -liberty nand_only.lib
select -assert-none t:MUX2
select -assert-none t:AOI21
select -assert-none t:OAI21
select -assert-min 1 t:NAND2
check
design -load generic
tee -o abc_mux_nomux.txt abc -liberty course.lib -constr typical.constr -D 1000 -dont_use MUX2
tee -o stat_mux_nomux.txt stat -liberty course.lib
write_json net_mux_nomux.json
select -assert-none t:MUX2
select -assert-min 1 t:AOI21
select -assert-min 1 t:NAND2
check
log PASS: mux and AOI map to MUX2 and AOI21 and the MUX2 ban rebuilds only the muxMUX2 and AOI21 vanish entirely: the restricted report holds none of either, against at least one of each in the full report. Area rises from 8 to 13, because a mux and an AOI cone rebuilt from two-input NANDs and inverters need more cells than the two compound cells they replace.
Library | Cells | Area | Delay |
|---|---|---|---|
course.lib (15 cells) | 2 | 8 | 186.82 ps |
nand_only.lib (3 cells) | 8 | 13 | 235.26 ps |
course.lib, MUX2 banned | 4 | 9 | 200.99 ps |
The full cover spends exactly the menu prices: one MUX2 at 5 units and one AOI21 at 3 units, 1 of one and 1 of the other in the recorded histogram, for 2 cells at area 8 and 186.82 ps. The restricted cover rebuilds both functions from 8 cells at area 13 and 235.26 ps. Fewer choices, more gates, larger total: that is the whole economics of mapping in one pair of rows.
Before any mapping runs, synth lowers the two assigns to generic gates, and design -save stores that generic netlist, so all three ABC runs start from bit-identical logic and differ only in the library. The first mapping's assertions then prove the generic mux cells ($mux, $_MUX_) are gone and at least one MUX2 and one AOI21 stand in their place: the compound cells are entries the mapper selected, not optimisations the tool discovered.
This staging is why the comparison is fair. Had each library run started from its own synthesis, optimiser noise could have blurred the library effect. One generic netlist, three menus, three covers: each area gap belongs to the library alone, and the recorded histograms show exactly which cells each menu forced.
Full cover cells (recorded stat) | Count | Area |
|---|---|---|
AOI21 | 1 | 3 |
MUX2 | 1 | 5 |
Restricted cover cells (recorded stat) | Count | Area |
|---|---|---|
INV | 3 | 3 |
NAND2 | 5 | 10 |
The third run is the break-it: the full library minus MUX2, which answers this page's own follow-up question. Only the mux output changes. The AOI cone keeps its AOI21, while the mux is rebuilt from 1 NAND2, 1 OAI21, and 1 INV at 2 + 3 + 1 = 6 units against one MUX2 at 5, for 4 cells at area 9 and 200.99 ps. Set that step beside the three-cell step: banning one cell is a reroute worth 1 unit, shrinking the whole library to three cells is a rebuild worth 5 units, and the full restricted ratio is 13/8, about 1.6x from the recorded areas: the number to carry into interviews.
The script asserts lower bounds rather than exact totals: at least one MUX2 and one AOI21 with the full library, none of either plus at least one NAND2 with the restricted one. A bound survives a harmless remap that an exact count would not. The tables quote this build's recorded counts; assert the shape, quote the numbers with their build attached, and never copy either half to another library.
Eight library units: one MUX2 at 5 plus one AOI21 at 3. The recorded total matches because each function matched one cell with nothing left over.
The assertion guards structure, not arithmetic: the mux surviving as a listed cell is what matters. A lower bound stays true through a harmless remap, while an exact count could break on one. The tables still quote this build's recorded counts.
Every number and picture on this page comes from one Yosys 0.69 run of the script shown, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): one mux plus one AOI cone synthesised once, then mapped with ABC against course.lib, against nand_only.lib, and against course.lib with only MUX2 banned, all from the same generic gates, with stat -liberty areas and write_json netlist drawings.