A block clocked on one edge with nonblocking assignments infers D flops. One such block maps each bit to storage.
An if without an else still infers a flop here. Holding the old value is what a flop does, unlike combinational logic where it would infer a latch.
The script below infers a 4-bit plain register and pins its family. It asserts one $dff cell and no enabled or reset variants.
read_verilog <<EOV
module top(input clk, input [3:0] d, output reg [3:0] q);
always @(posedge clk) q <= d;
endmodule
EOV
hierarchy -check -top top
proc
select -assert-count 1 t:$dff
select -assert-none t:$dffe
select -assert-none t:$adff
select -assert-none t:$sdff
log PASS: plain 4-bit register infers one $dff cellYosys keeps the 4-bit vector in one $dff cell carrying four bits. Mapping later expands it to one library flop per bit.
course.lib EXAMPLE areas: DFF = 8 units per bit
32-bit plain register: 32 x 8 = 256 units
32-bit sync-reset register: 32 x 10 = 320 units
reset overhead = 320 - 256 = 64 units = 64 / 256 = 25% over plainBlocking assignments in clocked blocks simulate differently from the flop hardware. Keep nonblocking assignments for sequential loads.
$dff for a 4-bit register. Why one cell and not four?Pre-mapping vectors stay together in one cell with a width parameter. The four library flops appear only after mapping.
if (en) is added around the load with no other change. Which assertion in the script now fails?The select -assert-none t:$dffe line. The block now infers an enabled flop instead of a plain one.