Arithmetic that fits
Read what an operator costs on the flow, tell a free operator from an expensive one, and prove and measure a rewrite before it replaces the obvious line.
- Lesson
- R1.6
- Time
- 25 min
- Runs on
- Your browser
- Check
- 5 questions
An engineer read that division is expensive and replaced q = a / 3 with the textbook multiply-and-shift, (a * 171) >> 9. A bench proved the two equal for all 256 eight-bit inputs, and the rewrite shipped. On this flow the original line synthesizes to 40 cells and the rewrite to 150. The synthesizer had already reduced the constant divide to a small circuit; the rewrite asked it to add five shifted copies of a.
- Cycle 0
Both forms give 0 for a = 0, 1 and 2: a / 3 rounds down.
- Cycle 3
At a = 3 both step to 1. 3 x 171 = 513, and 513 shifted right by 9 is 1.
- Cycle 5
After the shown cycles the bench walks all 256 inputs. Both forms agree with a / 3 everywhere. Correct, and still the wrong choice.
Measured on the lesson's bench (Icarus Verilog 12.0). Equal output is half of the story; the cell count is the other half.
Two circuits for one function
With the divisor fixed at 3, every part of a divider that depends on the divisor becomes a constant. The synthesizer removes the constant logic and simplifies what is left. On this flow, 40 cells and 14 levels of logic remain: a function of the eight bits of a.
The multiply-and-shift computes the same function by a longer road. 171 is 128 + 32 + 8 + 2 + 1, so a * 171 is the sum of five shifted copies of a, at least 16 bits wide. Shifting right by 9 keeps the top bits. The synthesizer builds the sums it was given, 150 cells and 19 levels. It does not find the 40-cell circuit for the same function.
- The operator
a = 200 enters the reduced divider and leaves as 66. 40 cells on this flow.
Follow the calls, values and waits
- data a = 200: a[7:0] → a / 3
- data q = 66: a / 3 → q[7:0]
- The rewrite
200 x 171 = 34200. Dropping nine bits divides by 512: 34200 / 512 rounds down to 66. The same answer, from 150 cells.
Follow the calls, values and waits
- data a = 200: a[7:0] → a x 171
- data 34200: a x 171 → >> 9
- data q = 66: >> 9 → q[7:0]
Read the diagram as text
- a[7:0]: input
- a / 3: 40 cells, 14 levels
- a x 171: five shifted copies added
- >> 9: wires: keep bits 15..9
- q[7:0]: equal for all 256 inputs
- a[7:0] → a / 3
- a / 3 → q[7:0]: FORM 0
- a[7:0] → a x 171
- a x 171 → >> 9: 16-bit sum
- >> 9 → q[7:0]: FORM 1: 150 cells, 19 levels
Both circuits pass the same exhaustive proof. Only a measurement tells them apart.
What an operator costs on this flow
Every row below is one small module, synthesized on this flow. Read the cells for area and the levels for depth; neither is a delay in nanoseconds.
| Expression (a, b: 8 bits) | Cells | Levels | Why |
|---|---|---|---|
s ? a : b, a 2:1 mux | 8 | 1 | one mux cell per bit |
a + b, 8-bit sum | 34 | 14 | a carry ripples through the bits |
a + b, 9-bit sum | 38 | 15 | one more bit: the carry out |
a < b | 29 | 9 | a subtraction that keeps only the borrow |
a * 3, 10-bit result | 36 | 11 | a constant: a + 2a |
a * 4, 10-bit result | 0 | 0 | wires: a with two zero bits below |
a * b, 16-bit result | 330 | 30 | two variables: every bit pair |
a / 8 | 0 | 0 | wires: q is a[7:3] |
a / 3 | 40 | 14 | a constant divisor, reduced |
a / 8'd3 | 37 | 13 | the same with an 8-bit 3 (below) |
a % 3 | 28 | 12 | a constant again |
(a * 171) >> 9 | 150 | 19 | equals a / 3 for every a |
a / b | 202 | 70 | a variable divisor |
a % b | 229 | 77 | a variable divisor |
Measured with Yosys 0.70 on this flow (synth with ABC, levels from ltp). Outputs are 8 bits unless the row says otherwise.
Three rules follow from the table. Powers of two are free: dividing by 8 drops three bits, and multiplying by 4 adds two zero bits. A constant operand is the synthesizer's job, and here it beat the hand rewrite. A variable operand is where the cost lives: a / b is 202 cells and 70 levels, five times the constant divide.
Prove the rewrite, then measure it
Write the obvious operator
Start from
a / 3, the line a reader understands. Synthesize it and read cells and levels.Change the algorithm only if it misses
When the brief's budget is missed, change the method: a shift when the brief allows a power of two, a small look-up table, or a divider that takes several cycles.
Prove it for every input
An 8-bit input has 256 values, so one bench run can try them all. For wider inputs, compare against a model with random and corner values.
Measure it again
A proven rewrite can still be bigger. Keep it only if the count went down.
The proof matters as much as the count. (a * 85) >> 8 looks like the same trick, since 85 / 256 is also close to 1/3. It is wrong at a = 3, and the bench finds 85 wrong inputs out of 256.
(a * 85) >> 8. The divide operator is unchanged.- Cycle 3
3 x 85 = 255, and 255 shifted right by 8 is 0. The answer should be 1. The bench reports this input first.
- Cycle 4
At a = 4 the rewrite is right again. A few hand-picked tests could miss a = 3; the walk over all 256 inputs cannot.
Measured on the lesson's bench (Icarus Verilog 12.0): "FORM 1 (multiply-shift): 85 wrong of 256" and "FORM 1 first wrong: a=3 q=0 want=1".
This wrong version synthesizes to 91 cells: smaller than the right one, and still no use. Signed values need their own proof as well. For a signed -3, -3 / 2 is -1, because a divide rounds toward zero; -3 >>> 1 is -2, because an arithmetic shift rounds down.
| Port | Direction | Width | Meaning |
|---|---|---|---|
| a | input | [7:0] | the dividend, 0 to 255 |
| q | output | [7:0] | q = a / 3, rounded down, for every a from 0 to 255 |
- Latency
- combinational
- Parameters
FORMpicks the circuit; both forms must give the same q. Budget: the smaller of the two forms, measured- Corner cases
- a = 0 and a = 255; every multiple of 3, where q steps up
Run the lab: both forms print 0 wrong of 256. Synthesize: 40 cells, 14 levels of logic on this flow. Change the default of FORM to 1 and synthesize again: 150 cells, 19 levels. Then put 85 and 8 into FORM 1 and run: 85 wrong, the first at a = 3. Last, try a / 8, which reports 0 cells, and a divisor b as a second input port.
Asked in interviews
Why is division expensive in hardware, and when is it not?
Dividing by a variable is a chain of compare-and-subtract steps, one per quotient bit: 202 cells and 70 levels for 8 bits on this flow. Dividing by a power of two is wires. Dividing by another constant lets the synthesizer reduce the circuit: 40 cells for a / 3.
How would you divide by a constant?
Write the operator first and measure it; the synthesizer reduces a constant divide well. If it misses the budget, consider a reciprocal multiply, a table or a multi-cycle divider. Prove the rewrite over every input, then measure it again.
How do you prove a rewrite, and is that enough?
Compare it with the original for every input when the input is small, or against a model with random and corner values when it is wide. Then synthesize both: here a rewrite that passed the proof was nearly four times the size of the original.
Try it
The bench builds the design twice, once with each FORM, and drives both with the same a. The first six lines show the forms agreeing. The last two lines are the proof: each form against a / 3 for all 256 inputs, 0 wrong each.
Synthesize reads the default, FORM = 0: 40 cells, 14 levels. With FORM = 1 it reports 150 cells and 19 levels for the same function. Put 85 and 8 into FORM 1 and the bench prints FORM 1 (multiply-shift): 85 wrong of 256 and FORM 1 first wrong: a=3 q=0 want=1.
Synthesize the design to measure its cells and inspect the mapped gates.
e0 a=0 q_div=0 q_mul=0 want=0 e1 a=1 q_div=0 q_mul=0 want=0 e2 a=2 q_div=0 q_mul=0 want=0 e3 a=3 q_div=1 q_mul=1 want=1 e4 a=4 q_div=1 q_mul=1 want=1 e5 a=5 q_div=1 q_mul=1 want=1 FORM 0 (a / 3): 0 wrong of 256 FORM 1 (multiply-shift): 0 wrong of 256Original design · 40 cells · 0 flip-flops · 0 latches · 14 logic levels. Synthesis uses Yosys; counts depend on the toolchain.
Read included file: tb.sv
`timescale 1ns/1ps
module tb;
logic clk = 0;
always #5 clk = ~clk; // rising edges at 5, 15, 25, ...
int edge_n = -1;
always @(posedge clk) edge_n = edge_n + 1;
logic [7:0] a = 0;
logic [7:0] q_div, q_mul; // FORM 0 and FORM 1 of the same design
int want, bad_div = 0, bad_mul = 0, first_div = -1, first_mul = -1;
div3 #(.FORM(0)) u_div (.a(a), .q(q_div));
div3 #(.FORM(1)) u_mul (.a(a), .q(q_mul));
// Advance to the next rising edge, wait for the design to settle, then print one line.
task automatic tick();
@(posedge clk); #1;
$display("e%0d a=%0d q_div=%0d q_mul=%0d want=%0d", edge_n, a, q_div, q_mul, a / 3);
endtask
initial begin
// the first six inputs, one per edge, so you can watch the two forms side by side
for (int i = 0; i < 6; i++) begin a = i; tick(); end
// the proof: every 8-bit input, each form against a / 3 computed here
for (int i = 0; i < 256; i++) begin
a = i; #1;
want = i / 3;
if (q_div != want) begin bad_div++; if (first_div < 0) first_div = i; end
if (q_mul != want) begin bad_mul++; if (first_mul < 0) first_mul = i; end
end
$display("FORM 0 (a / 3): %0d wrong of 256", bad_div);
$display("FORM 1 (multiply-shift): %0d wrong of 256", bad_mul);
if (first_div >= 0) begin a = first_div; #1; $display("FORM 0 first wrong: a=%0d q=%0d want=%0d", a, q_div, a / 3); end
if (first_mul >= 0) begin a = first_mul; #1; $display("FORM 1 first wrong: a=%0d q=%0d want=%0d", a, q_mul, a / 3); end
$finish(0); // quiet: no "$finish called" line
end
endmodule
Check yourself
Remember
- Measured on this flow: a divide by 8 is 0 cells, a divide by the constant 3 is 40, a variable 8-bit divide is 202 and an 8 x 8 multiply is 330.
- A constant operand is the synthesizer's job, and it does it well; a variable operand is where the cost lives, and the fix there is a different algorithm.
- A rewrite needs a proof for every input (or a model check when the input is wide) and a second measurement;
(a * 171) >> 9passes the proof and is still 150 cells against 40. - Signed values need their own proof:
-3 / 2is -1 and-3 >>> 1is -2.