Both registers below store eight bits on every clock edge, and both pay for reset somewhere. A synchronous reset is data-path logic in front of a plain flop; an asynchronous reset is a dedicated pin on the flop cell. In this library the chip-area totals come out equal while the sync data-path delay runs roughly twice the async one; the reset cost moves between the flop cell and the glue logic. Resets are the main lesson; the pin tri-state and the fixed-bound loop get one short recorded run each.
The sync register records 1 $sdff cell with no $adff, and the async register records 1 $adff cell with no $sdff. After mapping both report chip area 88 and 88: sync pays in plain DFFs plus gating, async in reset-pin DFFRs plus polarity inverters.
A clocked always block infers one flip-flop per bit, and branches inside it become data or enable logic, never latches. The reset style decides the family: tested inside a posedge-clk block it is synchronous ($sdff); in the sensitivity list beside the clock it is asynchronous ($adff). One vector cell covers all eight bits here.
read_verilog <<EOV
module reg_sync (
input wire clk,
input wire rst,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk) begin
if (rst)
q <= 8'd0;
else
q <= d;
end
endmodule
EOV
hierarchy -check -top reg_sync
proc
write_json net_sync_preopt.json
opt
tee -o stat_sync_generic.txt stat
write_json net_sync_generic.json
select -assert-count 1 t:$sdff
select -assert-none t:$adff
select -assert-none t:$dlatch
design -reset
read_verilog <<EOV
module reg_async (
input wire clk,
input wire arst,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk or posedge arst) begin
if (arst)
q <= 8'd0;
else
q <= d;
end
endmodule
EOV
hierarchy -check -top reg_async
proc
tee -o stat_async_generic.txt stat
write_json net_async_generic.json
select -assert-count 1 t:$adff
select -assert-none t:$sdff
select -assert-none t:$dlatch
design -reset
read_verilog <<EOV
module reg_sens (
input wire clk,
input wire arst,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk) begin
if (arst)
q <= 8'd0;
else
q <= d;
end
endmodule
EOV
hierarchy -check -top reg_sens
proc
opt
write_json net_syncsens.json
select -assert-count 1 t:$sdff
select -assert-none t:$adff
select -assert-none t:$dlatch
log PASS: sync reset infers one sdff while async reset infers one adff8-bit register | $sdff cells (recorded) | $adff cells (recorded) | Reading |
|---|---|---|---|
Sync reset | 1 | 0 | Reset is data-path logic in front of the flop. |
Async reset | 0 | 1 | Reset is a dedicated pin on the flop. |
Reset tested, clock-only sensitivity | 1 | 0 | Reads as sync: no reset edge, no $adff. |
Proc alone records 1 $dff, 1 $mux, and opt folds that mux into the flop to make 1 $sdff; the async form needs no opt because proc already detects the reset edge and emits $adff directly.
Generic families have no area, so the price question needs mapping. The second script maps each register through synth, dfflegalize, dfflibmap, abc with a loose -D 1000 target, and stat against course.lib. The cost comes from the recorded abc summaries and stat histograms below.
read_verilog <<EOV
module reg_sync (
input wire clk,
input wire rst,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk) begin
if (rst)
q <= 8'd0;
else
q <= d;
end
endmodule
EOV
read_liberty -lib course.lib
hierarchy -check -top reg_sync
synth -top reg_sync -flatten
dfflegalize -cell $_DFF_P_ 01 -cell $_DFF_PN0_ 01
dfflibmap -liberty course.lib
tee -o abc_sync.txt abc -liberty course.lib -constr typical.constr -D 1000
tee -o stat_sync_map.txt stat -liberty course.lib
write_json net_sync_map.json
select -assert-none t:$dlatch
design -reset
read_verilog <<EOV
module reg_async (
input wire clk,
input wire arst,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk or posedge arst) begin
if (arst)
q <= 8'd0;
else
q <= d;
end
endmodule
EOV
read_liberty -lib course.lib
hierarchy -check -top reg_async
synth -top reg_async -flatten
dfflegalize -cell $_DFF_P_ 01 -cell $_DFF_PN0_ 01
dfflibmap -liberty course.lib
tee -o abc_async.txt abc -liberty course.lib -constr typical.constr -D 1000
tee -o stat_async_map.txt stat -liberty course.lib
write_json net_async_map.json
select -assert-none t:$dlatch
design -reset
read_verilog <<EOV
module reg_sens (
input wire clk,
input wire arst,
input wire [7:0] d,
output reg [7:0] q
);
always @(posedge clk) begin
if (arst)
q <= 8'd0;
else
q <= d;
end
endmodule
EOV
read_liberty -lib course.lib
hierarchy -check -top reg_sens
synth -top reg_sens -flatten
dfflegalize -cell $_DFF_P_ 01 -cell $_DFF_PN0_ 01
dfflibmap -liberty course.lib
tee -o abc_sens.txt abc -liberty course.lib -constr typical.constr -D 1000
tee -o stat_sens_map.txt stat -liberty course.lib
select -assert-none t:$dlatch
log PASS: both reset styles map with no latches and their costs are recorded8-bit register | ABC logic area (glue only) | Chip area (stat -liberty) | Mapped delay (abc) |
|---|---|---|---|
Sync reset | 24 | 88 | 158.07 ps |
Async reset | 8 | 88 | 83.95 ps |
Clock-only sensitivity (recorded) | 24 | 88 | 158.07 ps |
Read the chip-area column as the corrected cost model: all three rows report the same total here, so neither reset costs more silicon. The delay column tells the rest: the sync forms pay roughly twice the data-path delay of the async form. ABC's area excludes the flops: quote chip area from stat -liberty whenever the design carries flops.
Library cell | Sync count | Sync area | Async count | Async area |
|---|---|---|---|---|
DFF | 8 | 64 | 0 | 0 |
INV | 8 | 8 | 8 | 8 |
NOR2 | 8 | 16 | 0 | 0 |
DFFR | 0 | 0 | 8 | 80 |
The sync form maps to 24 cells with the same total: plain DFFs plus data-path gating. The async INVs are polarity: the library clear is active-low while the RTL reset is active-high.
An output driven to high impedance infers a pin driver. The mini-run below elaborates the pin driver through proc. Keep tri-states at pins and the interior mux-only: two on-chip drivers fighting over one net is contention in physics. The Yosys tribuf pass turns $mux cells with 'z' inputs into tri-state buffers.
read_verilog <<EOV
module tri_pin (
input wire en,
input wire [7:0] d,
output wire [7:0] y
);
assign y = en ? d : 8'bz;
endmodule
EOV
hierarchy -check -top tri_pin
proc
tee -o stat_tri.txt stat
write_json net_tri.json
select -assert-none t:$dlatch
select -assert-none t:$dff
select -assert-none t:$adff
select -assert-none t:$sdff
design -reset
read_verilog <<EOV
module bus_top (
input wire a, b,
output wire y
);
drv u1 (.a(a), .y(y));
drv u2 (.a(b), .y(y));
endmodule
module drv (
input wire a,
output wire y
);
assign y = a;
endmodule
EOV
hierarchy -check -top bus_top
proc
tee -o check_multi.txt check
write_json net_fight.json
log PASS: boundary tri-state infers combinational cells and the bus fight is flaggedThe recorded tri_pin netlist holds 1 $mux: the high-impedance choice stays a mux input tied to high impedance, with no flop and no latch. The second half drives one net from two instances and runs check, which answers with the recorded warning:
Recorded check output for the two-driver net (Yosys check pass):
9. Executing CHECK pass (checking for obvious problems).
Checking module drv...
Checking module bus_top...
Warning: multiple conflicting drivers for bus_top.\y:
port y[0] of cell u2 (drv)
port y[0] of cell u1 (drv)Generic cell in tri_pin (recorded) | Count |
|---|---|
$mux | 1 |
Read the warning as the tool doing its job: synthesis does not silently keep both drivers. Simulate the overlap first and it reads as unknown. The fix is structural: give the net one driver, or move the sharing to pins.
A for loop with elaboration-fixed bounds is not a sequencer; it is shorthand for writing the body out once per iteration. A bound the tool cannot fix at elaboration cannot unroll, and fails before any cell is inferred.
read_verilog <<EOV
module loop_mux8 (
input wire sel,
input wire [7:0] a,
input wire [7:0] b,
output reg [7:0] y
);
integer i;
always @* begin
for (i = 0; i < 8; i = i + 1) begin
y[i] = sel ? b[i] : a[i];
end
end
endmodule
EOV
hierarchy -check -top loop_mux8
proc
opt
tee -o stat_loop.txt stat
write_json net_loop.json
select -assert-none t:$dlatch
select -assert-none t:$dff
log PASS: fixed-bound loop unrolls to combinational cells with no storageThe recorded loop netlist contains 8 $mux: select logic with no counter, no state machine, and no storage. That is the whole economics of unrolling: the loop saves typing, and the hardware pays per bit selected.
Take the async register and delete arst from its sensitivity list while keeping the if (arst) test inside: the sens row of the first table, not the async row, because without the reset edge the tool reads a clocked test and infers 1 $sdff. The sens variant is mapped and recorded too, at chip area 88 with delay 158.07 ps: the sync row. Every report hides the mistake except the generic cell family. The recorded bus fight above is the second break-it: rerun that half and read the check warning first.
Flop with an enable path. Clocked blocks infer storage with enables, never latches: both recorded registers show their reset family cell and record 0 latches between them, as the scripts assert.
Neither costs more silicon: both report chip area 88 and 88. The sync form pays in data-path gating (158.07 ps against 83.95 ps), the async form in reset-pin flops; the ABC-only gap measures excluded flops.
Every number on this page comes from Yosys 0.70+post runs recorded by the course checker: 8-bit sync and async registers run proc (plus opt on the sync form) for the $sdff-against-$adff proof, plus a clock-only-sensitivity variant that reads as sync; then synth with dfflegalize, dfflibmap, abc and stat -liberty, including the sensitivity variant, whose mapped cost follows the sync row. Totals come from the stat -liberty chip area, which includes flops; delays from the abc summaries. The tri-state mini-run records proc plus a two-driver bus fight answered by the recorded check warning, and the loop mini-run records proc. Mapped costs are read from the recorded abc and stat reports.