Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Logic Synthesis Glossary
  • Logic Synthesis Cheatsheet
  • Synthesis Foundations14
  • Logic Optimisation and Mapping20
  • Constraints and Timing15
  • Sequential, FSM and Memory19
  • Datapath Synthesis14
  • Area, Power and Test14
  • Verification, ECO and Handoff15
  • Flows and Debugging15
    • Scripted Flows and Regression
    • Debugging QoR
      • The QoR Debug Method
      • Reading Reports to Localise
      • Constraint Causes
      • RTL Structure Causes
      • Fanout, Black Boxes and Classifying Paths
    • Simulation-Synthesis Mismatch
  • Interview and Judgment11
Loading lesson

‹Debugging QoR
  1. Topics
  2. Logic Synthesis
  3. Flows and Debugging
  4. Debugging QoR
  5. Fanout, Black Boxes and Classifying Paths

Part 8 · Flows and Debugging · Intermediate

Fanout, Black Boxes and Classifying Paths

Huge fanout, black boxes, and a runnable worst-path classifier.

On this page

    Huge fanout

    One net driving a hundred loads moves slowly no matter how simple its logic is. The driver sees the sum of every load, so delay follows the total.

    EXAMPLE parameters keep the sum plain. A net with 120 loads at 2 load units each presents 240 load units.

    Diagram
    EXAMPLE parameters: 120 loads, 2 load units each
    total load = 120 x 2 = 240 load units
    fanout bound in this topic: 32 loads need a buffer tree past this point
    lesson: the driver sees 240 units, not one load

    The fix is a buffer tree or duplicated drivers, plus a fanout bound in the ask. Exact buffering varies between tools and libraries.

    Here 32 is this topic's EXAMPLE ask. The classifier below treats 50 or more loads as a coarse suspect ranker, not the sign-off bound.

    Black boxes and library gaps

    A black box is a block with no mapped internals: an unmapped memory, an analog macro, or a missing library cell. The tool cannot see through it, so paths around it report odd slacks.

    Shape

    Sign

    Fix

    Black box on the path

    Unmapped cell with flat timing across it

    Provide the model or bound the path with an explicit ask.

    Missing drive option

    Weak driver on a heavy net

    Widen the cell choice or restructure the load.

    Tool mapping choice

    Result shifts with pass order at fixed RTL

    Narrow the flow change and compare against the pinned baseline.

    A small classifier

    The program below sorts an inline table of 7 paths by the stated rules in order. Each path carries the fields the rules test.

    Order

    Condition

    Probable cause

    1

    blackbox is true

    black box

    2

    constrained is false

    missing constraint

    3

    latch is true

    unintended latch

    4

    prio is 6 or more

    deep priority logic

    5

    arith is 2 or more and shared is false

    unshared arithmetic

    6

    fanout is 50 or more (coarse ranker)

    huge fanout

    7

    slack below 0

    needs a deeper look

    8

    none of the above

    needs a deeper look

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    import sys
    
    PATHS = [
        {"name": "P1", "slack": 0.0, "levels": 2, "fanout": 8, "constrained": False, "blackbox": False, "latch": False, "prio": 1, "arith": 1, "shared": True},
        {"name": "P2", "slack": -2.1, "levels": 3, "fanout": 6, "constrained": True, "blackbox": False, "latch": False, "prio": 1, "arith": 1, "shared": True},
        {"name": "P3", "slack": -0.4, "levels": 4, "fanout": 10, "constrained": True, "blackbox": False, "latch": True, "prio": 1, "arith": 1, "shared": True},
        {"name": "P4", "slack": -1.8, "levels": 9, "fanout": 12, "constrained": True, "blackbox": False, "latch": False, "prio": 7, "arith": 1, "shared": True},
        {"name": "P5", "slack": -0.9, "levels": 5, "fanout": 9, "constrained": True, "blackbox": False, "latch": False, "prio": 2, "arith": 2, "shared": False},
        {"name": "P6", "slack": -1.2, "levels": 4, "fanout": 120, "constrained": True, "blackbox": False, "latch": False, "prio": 2, "arith": 1, "shared": True},
        {"name": "P7", "slack": -3.0, "levels": 1, "fanout": 4, "constrained": True, "blackbox": True, "latch": False, "prio": 1, "arith": 1, "shared": True},
    ]
    
    EXPECTED = {
        "P1": "missing constraint",
        "P2": "needs a deeper look",
        "P3": "unintended latch",
        "P4": "deep priority logic",
        "P5": "unshared arithmetic",
        "P6": "huge fanout",
        "P7": "black box",
    }
    
    def classify(p):
        if p["blackbox"]:
            return "black box"
        if not p["constrained"]:
            return "missing constraint"
        if p["latch"]:
            return "unintended latch"
        if p["prio"] >= 6:
            return "deep priority logic"
        if p["arith"] >= 2 and not p["shared"]:
            return "unshared arithmetic"
        if p["fanout"] >= 50:
            return "huge fanout"
        if p["slack"] < 0:
            return "needs a deeper look"
        return "needs a deeper look"
    
    if len(PATHS) != 7:
        print("FAIL: table holds " + str(len(PATHS)) + " rows, want 7")
        sys.exit(1)
    
    for p in PATHS:
        got = classify(p)
        want = EXPECTED[p["name"]]
        if got != want:
            print("FAIL: " + p["name"] + " got " + got + " want " + want)
            sys.exit(1)
    
    print("PASS: classifier places 7 paths into stated causes")

    Its verdicts read P1 missing constraint, P2 needs a deeper look, P3 unintended latch, P4 deep priority logic, P5 unshared arithmetic, P6 huge fanout, and P7 black box. Each verdict follows the first matching rule above.

    P2 needs a deeper look: a genuine timing failure is still possible. Over-constraint is confirmed only by easing the ask and watching the violation scale with it.

    Common mistakes

    Common pitfall

    Treating the classifier verdict as proof closes the debug too early. The rules rank suspects only; the fix still needs its own rerun against the pinned baseline.

    Interview

    Likely probes: reading one classifier row aloud.

    • P6 has fanout 120 past the coarse ranker of 50, so huge fanout outranks later rules.

    • P2 is shallow with 3 levels yet misses by 2.1 ns, so it needs a deeper look: ease the ask and watch whether the violation scales with it.

    • P7 is a black box, so no structural fix applies until the model exists.

    Check yourself P4 shows 9 levels with prio 7 and P5 shows 2 unshared arithmetic units. What does each classify as?

    P4 is deep priority logic by rule 4. P5 is unshared arithmetic by rule 5.

    Check yourself The classifier flags P2 for a deeper look instead of naming over-constraint. What rerun confirms over-constraint?

    Ease only the ask on P2 and rerun. If the violation scales with the ask, over-constraint is confirmed; otherwise the failure is genuine.

    Related topics

    • RTL structure causes

    • Cell libraries and liberty

    • Muxes, decoders and encoders

    Previous

    123 / 139

    Next: Simulation-Synthesis Mismatch

    Up next

    Up nextSimulation-Synthesis Mismatch

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The QoR Debug Method
    • Reading Reports to Localise
    • Constraint Causes