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.
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 loadThe 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.
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. |
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 |
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.
P4 is deep priority logic by rule 4. P5 is unshared arithmetic by rule 5.
Ease only the ask on P2 and rerun. If the violation scales with the ask, over-constraint is confirmed; otherwise the failure is genuine.