Mixed-Precision MAC Unit — TSMC 180nm ASIC

MSN-010 · 2026 · asic, verilog, rtl, vlsi

Fixed/floating-point merged MAC unit through full RTL-to-GDSII on TSMC 180nm. FP16×FP16→FP32 accumulation and dual INT8 multiplication on a shared datapath, 4.6% area overhead vs a standalone FP MAC, 157 MHz critical path.

The goal was a single MAC unit that handles both training and inference workloads on a shared datapath — FP16×FP16→FP32 accumulation for training, dual INT8 multiplication for inference — without paying for two separate units in area. Full RTL-to-GDSII on TSMC 180nm using Synopsys and Cadence tools. Implementation of Zhang, Lee & Ko (IEEE ISCAS 2018).

What the paper proposes

The paper's central observation is that the mantissa multiplier for FP16 and the two multipliers needed for dual-INT8 can be collapsed into the same hardware using the Karatsuba algorithm. A 11-bit FP16 mantissa is split into a 3-bit high half and an 8-bit low half. Karatsuba then needs exactly three sub-multiplications — one 3×3 and two 8×8 — to produce the full product. Those same two 8×8 multipliers, switched to signed mode by a single control signal, handle the dual-INT8 fixed-point path without any additional multiplier hardware.

The accumulator is kept at higher precision in both modes — FP32 for the floating-point path, INT32 for the fixed-point path — to avoid rounding loss during accumulation. The result is a fully pipelined 3-stage design (2 stages for fixed-point) with 4.6% area overhead over a standalone FP16 MAC and 21% smaller area than a naive FP+INT side-by-side combination.

Implementation

The design is plain Verilog-2001, partitioned into pipeline stages that follow the paper's block diagram. The first stage unpacks the operands, aligns the accumulator by the exponent difference, and runs the merged Karatsuba multiplier built from two Booth 8×8 cores. The second stage resolves the wide partial sum through a carry-propagate adder, completes the ones-complement subtraction, and detects and negates a negative result. The third stage normalises the result and rounds it to nearest-even per IEEE 754. A single control signal selects floating-point or fixed-point behaviour, switching the shared multipliers between unsigned and signed mode and enabling the normalise-and-round path only in floating-point mode.

The ones-complement subtraction produces an end-around carry that has to feed back into the low bit. Rather than spend another carry-propagate delay on it, the upper bits are pre-incremented in parallel and selected by a multiplexer once the carry is known, which keeps the adder out of the critical path. A leading-zero anticipator was built to run alongside the adder, but the shipped version falls back to an exact leading-zero count after the sum is final. The anticipator path is left in place for a future correction stage.

Translating from the paper's VHDL and STM-90nm target to Verilog-2001 on TSMC 180nm meant re-deriving every timing margin. The 90nm reference closed at 0.8 ns worst-case; on 180nm the same logic closes at 6.37 ns pre-layout and 8.34 ns post-layout with parasitics. Synthesis was constrained to a 4 ns clock period.

Verification and the bug

100,000 random test vectors across 12 directed-random batch categories, 24 parallel Icarus Verilog workers, bit-exact Python reference model implementing IEEE 754 arithmetic independently of the RTL. The fixed-point path (25,000 vectors) passed at 100%. The floating-point path (75,000 vectors) failed at a 47% rate on inputs that pushed the Karatsuba middle-term width past its representable range.

The root cause is in the Karatsuba formulation. The paper's Equation (2) uses a difference-form middle term — `(A1 − A2)(B2 − B1)` — rewritten in sign to avoid a subtractor in the CSA. This produces a signed intermediate product that requires one extra bit of accumulator width; the paper never specifies this, and the STM-90nm synthesis apparently never exercised the boundary.

The RTL avoids the signed-product hazard by switching to the sum-form equivalent: `(X0 + X1)(Y0 + Y1) − Z0 − Z2`. However, `X0 + X1` and `Y0 + Y1` are each 9-bit values — 8-bit mantissa low half plus 3-bit high half — and both are fed to an 8-bit Booth multiplier input. The MSB is silently dropped. For approximately 4.2% of normal FP16 operand pairs the truncated bit is set, corrupting the cross term and cascading through the CSA tree into the final 32-bit product.

Verification run before the fix — all FLP batches fail, FIX path passes cleanly

The two summed Karatsuba inputs each need 9 bits, but the middle multiplier they feed is only 8 bits wide, so the top bit is dropped. For the ~4.2% of FP16 input pairs where both of those carry bits are set, the cross term is corrupted and the error propagates to the final result. The fix is to widen the middle multiplier to a 9-bit path, or to handle the overflow case with a separate correction term. The paper's 90nm synthesis passed because the boundary operands were absent from its test suite.

FIX mode waveform — dual INT8×INT8→INT32; fixed-point output valid at 2-cycle latency, floating-point output held at zero

Post-fix FP mode waveform — pipelined FP16×FP16→FP32 accumulation running correctly across 100k vectors

Physical implementation

Synthesis in Synopsys Design Compiler, place-and-route in Cadence Innovus at 70% utilisation, post-layout simulation with back-annotated parasitics to verify timing closure with real wire loads.

Post-synthesis schematic from Design Compiler — merged multiplier block centre-left, pipeline registers and adder tree right

Cell area: 139,361 µm² across 6,250 cells. Max clock: ~157 MHz (8.34 ns critical path). Dynamic power: 85.64 mW at 3.3 V, which is 1.8x below the 90nm reference design when normalised for supply voltage. Area comes in more efficient than quadratic node-scaling would predict, partly due to the shared datapath reducing cell count vs two independent units.

Area overhead vs a standalone FP MAC: 4.6%. For that overhead, the fixed-point path doubles throughput by running two INT8 multiplications per cycle.

What I learned

Published papers omit constraints that are load-bearing. The Karatsuba formulation in Equation (2) carries a silent bit-width assumption: the two summed inputs need 9 bits, not 8. The paper never states this. The STM-90nm authors apparently never tested the boundary operands where both carry bits are set, so the errata never surfaced. Finding it required 75,000 FP vectors with a bit-exact Python reference model, not a reading of the paper. I started this project trusting the math in the paper and ended it trusting only simulation output.

A 47% failure rate is diagnostic; a 4% failure rate is invisible. Before the fix, the FP path failed on 47% of random inputs — obvious immediately. After switching to the sum-form Karatsuba and keeping the 8-bit multiplier, the failure dropped to 4.2%. That second failure mode would have passed most manual testbenches and any verification strategy without exhaustive random coverage. The lesson was to build the reference model first and run it at scale before declaring anything correct.

Porting to a different process node requires re-deriving timing from first principles. The paper's 90nm synthesis closed at 0.8 ns worst-case. On TSMC 180nm, the same logic was 6.37 ns pre-layout and 8.34 ns post-layout — a 31% increase from wire parasitics alone. None of the 90nm timing numbers transferred. I had to re-constrain synthesis at 4 ns, run back-annotated post-layout simulation, and verify that each pipeline stage cleared its setup requirement against the 180nm wire-load model. The physical implementation was effectively a new design problem on top of the RTL problem.

Leading-zero anticipation and leading-zero counting are different pieces of hardware solving the same problem in different orders. I implemented the full anticipation logic to run in parallel with the adder and predict the leading-zero count before the final sum is known. But the anticipator needs a one-bit corrector stage on the result to handle prediction errors, and I didn't implement that corrector. Normalisation therefore falls back to an exact leading-zero count, adding the latency the anticipator was supposed to remove. The anticipator path is kept because the corrector is a small addition, and the distinction between anticipating before the addition and counting after it became concrete rather than abstract by the end.

Ones-complement subtraction through the adder requires a structural choice up front. The end-around carry from ones-complement addition has to be fed back into the low bit. Doing that as a real adder adds another carry-propagate delay. The design pre-computes the incremented upper bits in parallel and selects them with a multiplexer once the carry is known, so no adder sits in the critical path. I understood this structurally from the paper but only understood why it was the right choice after seeing the post-synthesis timing report and watching where the slack disappeared.

Stack

- Verilog-2001 RTL, a 3-stage pipeline (2 stages for fixed-point) - UVM 1.2 testbench — directed (10 vectors), corner (~415), constrained-random (1000); functional coverage bins on mode, exponent, sign, and accumulator-zero; compiled clean on Questa FSE and VCS - Python co-simulation — 100k vectors, 24 parallel Icarus Verilog workers, 12 directed-random batch categories, bit-exact IEEE 754 reference model - Synopsys Design Compiler synthesis — 4 ns clock constraint, TSMC128K Conservative wire-load model - Cadence Innovus place-and-route — 70% utilisation target, post-layout SDF back-annotation - TSMC 180nm standard cell library (tcb018g3d3)

Hao Zhang, Hyuk Jae Lee, Seok-Bum Ko — "Efficient Fixed/Floating-Point Merged Mixed-Precision Multiply-Accumulate Unit for Deep Learning Processors." IEEE ISCAS 2018. University of Saskatchewan / Seoul National University.