RTL arithmetic is bit-accurate. Width, signedness, and overflow behavior are part of the specification — not afterthoughts.
Width rules of thumb
- Sum of two N-bit numbers needs N+1 bits if you care about carry-out.
- Multiply of N×M needs N+M bits for a full product.
- Truncation is silent in Verilog — lint and reviews should catch unintended shrinks.
logic [7:0] a, b;
logic [8:0] sum;
assign sum = {1'b0, a} + {1'b0, b}; // explicit zero-extend
Signed vs unsigned
| Declaration | Interpretation |
|---|---|
logic [7:0] u |
Unsigned |
logic signed [7:0] s |
Two’s complement |
Pitfalls:
- Mixing signed and unsigned in one expression often forces unsigned rules — extend carefully.
- Right shift: arithmetic (
>>>) vs logical (>>) differs for signed values. - Comparisons (
<,>) follow signedness of operands.
Comparators & equality
assign eq = (a == b);
assign lt_u = (a < b); // unsigned if a,b unsigned
assign lt_s = ($signed(a) < $signed(b));
For magnitude compares across clock domains, compare after synchronizing or use gray/handshake schemes (CDC).
Resource trade-offs
+/-→ adder / subtractor (fast paths in FPGA carry chains).*→ DSP blocks or large LUT arrays — pipeline wide multiplies./and%are expensive; prefer constants, reciprocals, or shift/add for powers of two.
Practical checklist
- Document overflow policy (wrap, saturate, flag).
- Keep intermediate widths explicit.
- Prefer SystemVerilog
logic+ sized literals (8'd3,8'shFF). - Simulate corner cases: max, min, sign flip, carry-out.