RTL sizes every operator from its context, often wider than needed. A sum assigned into a wide bus keeps a wide adder even when few result bits matter.
Only kept bits need hardware. A kept low slice never depends on input bits above it, so the carry chain above can go.
Kept result | What the adder needs |
|---|---|
Low 4 bits of an 8-bit sum | A 4-bit adder. Upper carries never reach kept bits. |
Full 8-bit sum | A 9-bit result. 255 + 255 = 510 fits 9 bits. |
One unsigned compare | A single decision bit from the shared subtract. |
The wreduce pass narrows operators toward the bits the design keeps. It trims result widths and drops logic that feeds only discarded bits.
The block below keeps only the low 4 bits of an 8-bit sum. Its assertions pin one adder before and after the pass.
read_verilog <<EOV
module wtrim(input [7:0] a, b, output [3:0] y);
wire [7:0] s = a + b;
assign y = s[3:0];
endmodule
EOV
hierarchy -top wtrim
proc
select -assert-count 1 t:$add
wreduce
select -assert-count 1 t:$add
opt_clean
select -assert-count 1 t:$add
stat -liberty course.lib
log PASS: wreduce keeps one trimmed adderThe assertions pin the adder count at one before and after. The width it keeps follows the kept result bits: 4 here, from the hand arithmetic below.
Extension must match the declared signedness before any compare or slice. Zero extension keeps the bit pattern; sign extension keeps the value.
8-bit unsigned addition: 255 + 255 = 510; 510 < 512 = 2^9, so the full sum needs 9 bits
keeping only y[3:0] of a + b needs a 4-bit adder: each kept bit depends only on input bits at or below it
extension changes value: 8'hff zero-extended to 16 bits = 255; sign-extended = 65535, which is -1 as signed 16-bit
so (signed) -1 < 1 is true while (unsigned) 255 < 1 is false for the same byte4 bits. Each kept bit depends only on input bits at or below it, so the upper carry chain goes.
True under zero extension, since both sides are 255. False under sign extension, since the extended value is 65535.