VHDL · Chapter 16.7 · Synthesis and RTL Implementation
Resource Sharing and Optimization
Resource sharing lets synthesis reuse one expensive unit, such as a multiplier or a wide adder, across operations that never run at the same time, spending a multiplexer instead of the area of a second unit. The key idea is mutual exclusion: operations in different branches of an if or case, or in different cycles of a state machine, can share one unit, while operations that run simultaneously need separate hardware. You steer where the design sits on the area-versus-speed trade through structure, time-multiplexing one unit across many operations for less area or using many units for fewer cycles. On top of this, the tool automatically applies constant folding, common-subexpression elimination, dead-logic removal, and Boolean minimization. This lesson covers what is shareable and the optimizations you get for free.
Foundation14 min readVHDLSynthesisResource SharingAreaOptimizationTrade-off
1. Engineering intuition — one expensive tool, used in turns
A multiplier is costly silicon. If your design has two multiplies that can never happen in the same cycle —
say one in the ADD branch and one in the SUB branch of a case, or one used in state A and another in state B
— building two multipliers wastes area, because only one is ever active. Like sharing one expensive power tool
between jobs that are never done at the same moment, you can build one multiplier and route the right
operands to it each time with a multiplexer. The condition is strictly mutual exclusion: things used at the same
instant cannot share. Recognizing which operations are exclusive — and deciding whether to share (save area) or
duplicate (save time) — is the core of the area/speed trade.
2. Formal explanation — what is shareable, and the trade
-- MUTUALLY EXCLUSIVE operations (different branches) → SHAREABLE: one unit + a mux.
process (all) begin
case op is
when MUL_AB => result <= a * b; -- only one of these
when MUL_CD => result <= c * d; -- multiplies runs at a time
when others => result <= (others => '0');
end case;
end process;
-- Synthesis can build ONE multiplier, muxing {a,b} vs {c,d} into it → ~half the multiplier area.
-- SIMULTANEOUS operations → NOT shareable: both needed the same cycle → TWO units.
result <= (a * b) + (c * d); -- two multiplies in one expression, same cycle → 2 multipliers
-- The TRADE is controlled by STRUCTURE:
-- TIME-MULTIPLEX: one unit reused over several cycles (FSM sequences operands) → less area, +latency.
-- PARALLEL/UNROLL: many units operate at once → more area, fewer cycles (higher throughput).Operations that are mutually exclusive (different if/case branches, different cycles) can share one
unit through a multiplexer; operations that are simultaneous need separate units. You steer the trade by
structure — time-multiplex one unit (less area, more cycles) or parallelize many (more area, fewer
cycles).
3. Production usage — steering the area/speed trade
-- TIME-MULTIPLEXED (area-efficient): one multiplier reused over cycles via an FSM.
process (clk) begin
if rising_edge(clk) then
case step is
when 0 => prod <= x(0) * coeff(0); step <= 1; -- ONE multiplier, used each cycle
when 1 => prod <= x(1) * coeff(1); step <= 2; -- N cycles for N products
when others => null;
end case;
end if;
end process;
-- PARALLEL (speed-efficient): many multipliers, all at once — fewer cycles, more area.
gen : for i in 0 to N-1 generate
prod(i) <= x(i) * coeff(i); -- N multipliers in parallel, one cycle
end generate;
-- AUTOMATIC optimizations the tool does regardless:
-- constant folding (a*1→a), common-subexpression (compute a+b once), dead-logic removal, boolean min.What hardware does this become? The time-multiplexed version is one multiplier plus an FSM and muxes — small area, but it takes N cycles for N products (lower throughput). The parallel version is N multipliers working simultaneously — large area, but all products in one cycle (high throughput). Same computation, opposite ends of the area/speed trade, and you choose by how you structure the RTL. Separately, the synthesizer always applies constant folding, common-subexpression elimination, dead-logic removal, and Boolean minimization — free optimizations that shrink and speed the result without changing behavior.
4. Structural interpretation — two exclusive operations sharing one unit
5. Why this is structural, not timing
Resource sharing is an area/speed trade in the structure — how many physical units exist and how operations map onto them — so the sharing diagram above is the right picture, not a waveform. It does not change what is computed (behavior is preserved); it changes how much hardware and over how many cycles. The choice between one shared unit and many parallel ones is a design-time structural decision about area versus throughput, not a property of any single signal trace — which is exactly why it is shown as structure.
6. Debugging example — duplicated units (or a false share)
Expected: efficient area use. Observed (a): the design uses far more multipliers/adders than expected
and overflows the DSP budget. Observed (b): a "shared" unit produces wrong results because two operations
collided. Root cause (a): operations that are mutually exclusive were coded so they appear
simultaneous (separate parallel statements), so synthesis built separate units instead of sharing — or
sharing was simply not possible given the structure. Root cause (b): operations that actually run at the same
time were forced to share one unit, so they conflict. Fix: make exclusive operations clearly exclusive
(one case/branch, or sequence them across cycles with an FSM) so the tool can share; keep genuinely
simultaneous operations on separate units. Engineering takeaway: sharing requires mutual exclusion —
structure exclusive operations into branches/cycles to share one unit and save area, but never share across
operations that must run in the same cycle.
-- BUG: two multiplies written as parallel statements → tool builds TWO multipliers (no sharing).
-- p1 <= a*b; p2 <= c*d; -- if only one is ever needed at a time, this wastes a multiplier
-- FIX: make exclusivity explicit (one shared result via case) → one multiplier + mux.
case op is when 0 => p <= a*b; when 1 => p <= c*d; when others => p <= (others=>'0'); end case;7. Common mistakes & what to watch for
- Coding exclusive ops as parallel. If only one runs at a time, put them in one
case/branch (or sequence them) so the tool can share a unit. - Forcing a share on simultaneous ops. Operations needed the same cycle cannot share; they need separate units.
- Ignoring the throughput cost of time-multiplexing. One shared unit over N cycles lowers throughput; size the trade to the data rate.
- Over-parallelizing. N units cut cycles but cost N× area/DSP; balance against the budget and required throughput.
- Hand-doing the tool's job. Constant folding, CSE, dead-logic removal, and Boolean minimization are automatic; focus your effort on the share/parallel structure.
8. Engineering insight & continuity
Resource sharing trades area for speed by reusing one expensive unit across mutually-exclusive operations through a multiplexer, while simultaneous operations need separate units — and you steer the trade by structure: time-multiplex (less area, more cycles) or parallelize (more area, fewer cycles), atop the tool's automatic folding, CSE, and minimization. With pipelining (speed) and sharing (area), you can place a design anywhere on the area/speed/throughput surface. Sometimes, though, you need to direct the tool explicitly — keep a signal, force a RAM style, mark an FSM encoding — which is the next lesson, Synthesis Attributes and Constraints.