When sizing and buffering are exhausted, the remaining lever is logic structure: re-associating an expression, moving a late input closer to the output, duplicating logic to cut fanout. These changes can save hundreds of picoseconds but alter the netlist, so function equivalence must be proven afterwards.
import heapq
gate = 40.0 # ps per 2-input gate
arrivals = [0.0] * 7 + [100.0] # eight inputs, the last arriving 100 ps late
def chain(arr):
t = arr[0]
for a in arr[1:]:
t = max(t, a) + gate
return t
def balanced(arr): # fixed balanced tree, inputs paired in order
level = list(arr)
while len(level) > 1:
level = [max(level[i], level[i + 1]) + gate for i in range(0, len(level), 2)]
return level[0]
def arrival_aware(arr): # always combine the two earliest signals
h = list(arr); heapq.heapify(h)
while len(h) > 1:
a, b = heapq.heappop(h), heapq.heappop(h)
heapq.heappush(h, max(a, b) + gate)
return h[0]
res = (chain(arrivals), balanced(arrivals), arrival_aware(arrivals))
assert res == (280.0, 220.0, 160.0)
print("PASS: output arrival for chain, balanced and arrival-aware trees:", res)Structure | Output arrival (ps) |
|---|---|
Chain of 7 gates | 280 |
Balanced tree, late input at a leaf | 220 |
Arrival-aware tree (late input joins last) | 160 |
The same function (an 8-input associative operation) arrives at 280 ps as a chain, 220 ps as a balanced tree and 160 ps when the late input is combined last. The arrival-aware tree is 120 ps faster than the chain and 60 ps faster than the textbook-balanced one, because depth is measured from the latest input. Only associative and commutative functions can be re-associated freely; for anything else the change must preserve the exact function.
Equivalence checking before and after the change, run on the final netlist and not on a model.
New logic is placed and routed in the same flow as everything else; timing, SI and power are rerun.
Logical ECOs are limited to cones with timing evidence; changing logic for convenience reopens verification.
The balanced tree and the arrival-aware tree would tie at 120 ps (three levels of 40 ps); the chain would still take 280 ps.