Arithmetic, Fixed Point & DSP
Division: use shifts for powers of two; otherwise multiply by a reciprocal, use iterative (restoring/non-restoring) dividers, or vendor IP.
23.1 Integer arithmetic sizing rules
a + b (numeric_std) max(len(a), len(b)) — carry lost; resize first to keep it len(a) + len(b) a * constant len(a) × 2 (constant converted to same length) Accumulating N values of W bits W + ⌈log₂N⌉ bits
Division: use shifts for powers of two; otherwise multiply by a reciprocal, use iterative (restoring/non-restoring) dividers, or vendor IP. Square roots: CORDIC or iterative algorithms.
signal a, b : signed(15 downto 0);
signal p : signed(31 downto 0);
signal acc : signed(39 downto 0);
p <= a * b;
acc <= acc + resize(p, acc'length); -- MAC (multiply-accumulate) → DSP block23.2 Fixed-point with fixed_pkg (VHDL-2008)
Manual fixed point with signed is also common: interpret signed(15 downto 0) as Q1.15 and track the binary point yourself (p = a*b is Q2.30; take p(30 downto 15)).
library ieee;
use ieee.fixed_pkg.all;
signal x : sfixed(3 downto -12); -- Q4.12 signed: 4 integer bits (incl. sign), 12 fractional
signal y : sfixed(3 downto -12);
signal z : sfixed(7 downto -24); -- full-precision product
x <= to_sfixed(1.5, x); -- real → fixed (constant/simulation)
z <= x * y; -- widths grow automatically
y <= resize(z, y, fixed_saturate, fixed_round); -- back to Q4.12 with saturation & rounding
report to_string(to_real(y));23.3 Floating point with float_pkg
use ieee.float_pkg.all;
signal f1, f2, f3 : float32;
f3 <= f1 + f2; -- synthesizable but large; vendor floating-point IP is more efficient23.4 DSP building blocks
FIR filter (transposed or systolic form, maps to DSP slices):
IIR filters, CIC decimators/interpolators, NCO/DDS (phase accumulator + sine LUT), CORDIC (rotation for sin/cos/atan/magnitude), FFT (vendor IP or radix-2 butterflies), moving averages, PID controllers.
type coeff_t is array (0 to 3) of signed(15 downto 0);
constant H : coeff_t := (to_signed(1024, 16), to_signed(2048, 16), to_signed(2048, 16), to_signed(1024, 16));
type taps_t is array (0 to 3) of signed(15 downto 0);
signal taps : taps_t := (others => (others => '0'));
process (clk)
variable acc : signed(33 downto 0);
begin
if rising_edge(clk) then
if sample_valid = '1' then
taps <= x_in & taps(0 to 2); -- shift in new sample
acc := (others => '0');
for k in 0 to 3 loop
acc := acc + resize(taps(k) * H(k), acc'length);
end loop;
y_out <= acc(31 downto 16); -- scale
end if;
end if;
end process;23.5 Inferring DSP slices
Register inputs, the product, and the output (pipelining) so synthesis packs them into DSP48/DSP blocks; respect DSP widths (e.g., 25×18 or 27×18 multipliers); use use_dsp attributes to force/prevent mapping.