VHDL · Chapter 17.3 · FPGA-Oriented VHDL Design
Inferring DSP and Multiplier Blocks
A multiply is expensive in LUTs but cheap in a DSP block, the FPGA's dedicated arithmetic slice: a pipelined multiplier fused with an adder or accumulator and wrapped in input and output registers. Inferring it is mostly about the arithmetic shape, since a plain multiply infers the multiplier, a multiply-add infers a multiply-accumulate, and an accumulate infers the accumulator. The single most important habit is registering the inputs and outputs so the tool can use the DSP's internal pipeline registers, which is what unlocks its high speed; an unregistered multiply maps to a slow, large LUT version instead. This lesson also covers the per-DSP width limit and how wider multiplies combine several blocks, where signed and unsigned come from, the optional pre-adder, and forcing the mapping with an attribute.
Foundation15 min readVHDLFPGADSPMultiplierMACPipelining
1. Engineering intuition — feed the DSP the way it's built
A DSP slice is not just a multiplier; it is a multiplier wrapped in registers with an accumulator behind it, designed to run fast precisely because those registers pipeline the multiply. So inferring a DSP well is about handing it the shape it wants: a multiply (or multiply-add, or accumulate) with its inputs and outputs registered, so the tool slots your registers into the DSP's own pipeline stages. Give it an unregistered, combinational multiply and the synthesizer either builds a slow LUT multiplier or a DSP that can't run fast. Register generously around arithmetic and the DSP runs near its peak frequency; that registering — which on an FPGA is essentially free (16.6) — is the whole trick.
2. Formal explanation — multiplier, MAC, and accumulator inference
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
signal a, b : signed(17 downto 0); -- within a DSP's width (signed from the type)
-- MULTIPLY → DSP multiplier. REGISTER inputs + output → uses the DSP's internal pipeline registers.
process (clk) begin if rising_edge(clk) then
a_r <= a; b_r <= b; -- INPUT registers (DSP stage)
prod_r <= a_r * b_r; -- OUTPUT register (DSP stage) → high Fmax
end if; end process;
-- MULTIPLY-ADD → DSP MAC:
mac_r <= a_r * b_r + c_r; -- multiply then add, fused in the DSP
-- ACCUMULATE → DSP accumulator (e.g. FIR/dot-product):
process (clk) begin if rising_edge(clk) then
acc <= acc + a_r * b_r; -- multiply-accumulate in the DSP's adder
end if; end process;
-- WIDTH: each DSP has a max operand size (e.g. ~18x25/27); wider multiplies COMBINE several DSPs.
-- FORCE: attribute use_dsp of prod_r : signal is "yes"; -- (vendor-specific, 16.8)A numeric_std multiply infers the DSP multiplier; multiply-add infers a MAC; accumulate
infers the accumulator. Register inputs and outputs so the tool maps your registers to the DSP's internal
pipeline stages (the key to Fmax). Width limits per DSP; wider ops combine DSPs. Signed/unsigned from the
type; optional pre-adder; use_dsp to force.
3. Production usage — a pipelined multiply-accumulate
-- A dot-product / FIR tap: register inputs, multiply, accumulate — all in DSP slices.
process (clk) begin
if rising_edge(clk) then
x_r <= x; coef_r <= coef; -- DSP input registers
if start = '1' then acc <= (others => '0');
else acc <= acc + x_r * coef_r; -- DSP MAC: pipelined multiply-accumulate
end if;
end if;
end process;
result <= std_logic_vector(acc);
-- WIDE multiply needing more than one DSP: the tool stitches DSPs together automatically
-- when operands exceed a single DSP's width (e.g. 32x32 from several 18x25 blocks).What hardware does this become? A chain of DSP slices: the input registers (x_r, coef_r) become the
DSP's input pipeline stage, the x_r * coef_r the DSP multiplier, and acc + ... the DSP's accumulator — a
multiply-accumulate running at high Fmax because every stage is registered inside the block. A wider operand
than one DSP supports causes the tool to combine multiple DSPs transparently. Skip the registers, and the same
math falls into slow LUT logic or an underutilized DSP. So the design rule is simple and high-impact: register
around every multiply so it lands in a properly-pipelined DSP.
4. Structural interpretation — the DSP slice
5. Simulation interpretation — the pipelined MAC
Registered DSP MAC: pipeline latency, then one result per cycle
8 cycles6. Debugging example — the multiply that didn't use the DSP (or ran slow)
Expected: a fast multiply in a DSP block. Observed: synthesis builds a large LUT multiplier, or the
DSP is used but timing is poor (low Fmax on the multiply path). Root cause: the multiply was unregistered
(purely combinational), so the tool could not place registers in the DSP's internal pipeline stages — it either
fell back to LUT logic or used a DSP without its registers, capping speed; or the operands exceeded one DSP's
width without being structured to combine cleanly. Fix: register the inputs and output around the
multiply so they map to the DSP's pipeline stages (the key to Fmax), keep operands within the width limit (or
let the tool combine DSPs), match signed/unsigned to the type, and force with use_dsp if needed.
Engineering takeaway: to get a fast DSP multiply, register around it so the DSP's internal pipeline
registers are used — an unregistered multiply is slow and may not even land in a DSP.
-- BUG: combinational multiply → LUT multiplier or DSP without its pipeline regs → slow.
-- prod <= a * b; -- no registers around it
-- FIX: register inputs and output → DSP internal pipeline → high Fmax.
process (clk) begin if rising_edge(clk) then
a_r <= a; b_r <= b; prod_r <= a_r * b_r;
end if; end process;7. Common mistakes & what to watch for
- Unregistered multiplies. Register inputs/outputs so the DSP's internal pipeline registers are used — the key to Fmax; otherwise slow or LUT-mapped.
- Exceeding DSP width. Operands beyond one DSP's size combine several DSPs; keep widths in mind for resource count.
- Wrong signedness.
signed/unsigned(the type) sets the multiply; a mismatch gives wrong results or misses optimizations. - Multiply in a long combinational path. Pipeline it (register around it) so the critical path doesn't stall Fmax (16.6).
- Fighting inference. Prefer the registered
numeric_stdpattern; useuse_dsponly when the tool picks wrong.
8. Engineering insight & continuity
DSP inference maps arithmetic onto the FPGA's dedicated slices: a numeric_std multiply → the multiplier, a
multiply-add → a MAC, an accumulate → the accumulator — and the decisive habit is registering inputs and
outputs so the DSP's internal pipeline registers are used, unlocking high Fmax (with width limits combining
multiple DSPs as needed). Registers are cheap on an FPGA, so register generously around every multiply. With block
RAM and DSP — the two big dedicated resources — covered, the remaining FPGA concern is the clocking that drives
them: the next lesson, Clocking Resources and Clock Management — global buffers, PLLs/MMCMs, and generating the
clocks a design needs.