How do you identify and debug runaway buffer insertion (buffer bloat) during `place_opt`?
From PDVerse PnR Interview Handbook · pdVerse Mentor Guide
Short Answer
Buffer bloat is what happens when place_opt inserts so many buffers to fix electrical or timing problems that your standard-cell count balloons 20–40% — and the instinct to just throw more area at it is usually treating the symptom, not the disease. Root cause #1 — unrealistic input transitions: if set_input_transition 5.0 is declared on a port feeding a 0.5 ns clock domain, the tool has to build a chain of 10+ cascaded buffers just to slew that edge down to something usable. Check your SDC input transitions against your actual clock period before blaming the placer.
Technical Explanation
- Buffer bloat is what happens when
place_optinserts so many buffers to fix electrical or timing problems that your standard-cell count balloons 20–40% — and the instinct to just throw more area at it is usually treating the symptom, not the disease. - Root cause #1 — unrealistic input transitions: if
set_input_transition 5.0is declared on a port feeding a 0.5 ns clock domain, the tool has to build a chain of 10+ cascaded buffers just to slew that edge down to something usable. Check your SDC input transitions against your actual clock period before blaming the placer. - Root cause #2 — missing false paths on async CDC: an unconstrained asynchronous path reporting −15 ns of slack looks to
place_optlike a real timing problem it must chase, so it dumps hundreds of delay buffers trying to close something that was never meant to close in one cycle. This is a false-path/exception-declaration bug wearing a buffering-bug costume. - Root cause #3 — high-fanout nets missing HFNS budgeting: a test control or reset net with no
max_fanoutconstraint gets brute-force buffered wherever the tool happens to be optimizing, often landing on unrelated critical paths. - Root cause #4 — macro placement creating long flylines: if standard-cell logic sits on the far side of a 2 mm macro from its driver, the tool has no choice but to drop repeaters every ~150 µm just to physically span the distance — this is a floorplan problem showing up as a buffering symptom.
- Diagnosis, not guesswork: run
report_qorandreport_design -bufferingto see exactly which net groups are eating the extra buffer instances, then match that back to one of the four root causes above rather than reflexively re-running placement with more area margin.
Common Mistake
The Trap: Blindly placing set_dont_touch on all buffers to stop bloat. This leaves severe max-transition violations unaddressed and causes timing closure to fail completely.
Follow-up Question & Model Response
"How do you check which nets received the highest number of inserted buffers?"
Candidate Model Response: Use report_net -all -sort_by fanout or inspect the report_qor buffering breakdown to find nets with abnormally high repeater counts.
Practical Example
Auditing Buffer Insertion Statistics:
# Synopsys ICC2: Report buffer instance count by reason
report_qor -summary
report_design -buffering
# Find top violating nets with runaway repeater counts
get_nets -filter "number_of_buffers > 10"Physical Design & Planning Handbook
Master ASIC Physical Design Planning & Floorplanning
Dive into 14 comprehensive chapters covering netlist sanity, FinFET grids, macro placement, power grids, CTS, and timing budgeting.
Continue practising