Fixed-Point Multiplier (Q-Format)
Medium · Combinational · SystemVerilog
Design a purely combinational signed fixed-point multiplier in Q-format (QM.N) that multiplies two signed inputs and returns a result in the same format, with optional round-to-nearest and overflow detection.
The module is parameterized by INT_BITS ($M$) and FRAC_BITS ($N$), giving a total word width of $W = M + N$ bits. Both {a} and {b} are signed two's-complement values in QM.N format: the binary point is placed $N$ bits from the LSB, so the value of a bit vector $x$ is $x \cdot 2^{-N}$.
**Full product computation.** Multiply {a} and {b} as signed $W$-bit values to produce a $2W$-bit signed full product `full_product`. Because each operand carries $N$ fractional bits, the full product has $2N$ fractional bits: its value is $\text{full\_product} \cdot 2^{-2N}$.
**Result extraction.** To return to QM.N you must drop $N$ of the fractional bits, i.e. arithmetic-shift-right the full product by $N = $ {FRAC_BITS}. The $W$-bit {result} is therefore exactly the window $\text{result} = \text{full\_product}[\,N + W - 1 : N\,].$ With the default parameters $W = 8$, $N = 4$ this is `full_product[11:4]`. (Check: {a} $= 8$'h08 ($+0.5$), {b} $= 8$'h08 ($+0.5$) give raw product $8 \times 8 = 64$; $64 \gg 4 = 4$, so {result} $= 8$'h04 $= +0.25$.)
**Rounding.** When {round} $= 1$, apply round-to-nearest: if the guard bit — the most-significant dropped fractional bit, `full_product[N-1]` (bit $[3]$ for $N = 4$) — is $1$, add $1$ to the extracted $W$-bit window before presenting it on {result}. When {round} $= 0$, truncate: present the extracted window unchanged.
**Overflow detection.** Assert {overflow} $= 1$ when the true product does not fit in signed QM.N, i.e. when the bits above the kept window are not all equal to the result's sign bit. Concretely, the bits `full_product[2W-1 : N+W]` (the bits dropped off the top) must all equal `full_product[N+W-1]` (the kept-window sign bit); if any of them differs, set {overflow} $= 1$. Equivalently, the slice `full_product[2W-1 : N+W-1]` — the top bits together with the sign bit — must be all-$0$s or all-$1$s. When overflow is detected, {result} still reflects the extracted (and optionally rounded) window; the caller is responsible for handling it.