In a latch-based pipeline, alternate stages use opposite clock phases, and borrowing flows through them. A stage that borrows hands a later launch to the next, which may borrow in turn. The chain is checked as a whole, because the end must meet its final capture edge.
# Alternating phases fed by a rising-edge flop, period 10: L1 negative-level opens 5 closes 10; L2 positive-level opens 10 closes 15; L3 negative-level opens 15 closes 20.
windows = [(5.0, 10.0), (10.0, 15.0), (15.0, 20.0)]
dq, setup = 0.30, 0.10
logic = [7.0, 5.6, 5.0] # logic delay entering each latch (illustrative)
t = 0.40 # data leaves the launching rising-edge flop (clock-to-Q)
borrowed, slacks = [], []
for (op, cl), lg in zip(windows, logic):
arrive = t + lg
slacks.append(round((cl - setup) - arrive, 2))
assert slacks[-1] >= 0, "latch setup violated"
borrowed.append(round(max(0.0, arrive - op), 2))
t = max(arrive, op) + dq # leaves at the arrival if transparent, else at the opening edge
assert borrowed == [2.4, 3.3, 3.6]
assert slacks == [2.5, 1.6, 1.3]
assert abs(t - 18.9) < 1e-9
print("PASS: borrowed", borrowed, "slacks", slacks, "chain leaves L3 at", round(t, 2), "ns")Latch | Opens / closes | Arrival | Borrowed | Setup slack |
|---|---|---|---|---|
L1 | 5 / 10 | 7.4 | 2.4 | 2.5 |
L2 | 10 / 15 | 13.3 | 3.3 | 1.6 |
L3 | 15 / 20 | 18.6 | 3.6 | 1.3 |
L1 and L3 are negative-level latches and L2 is positive-level, so the phases alternate, and the first latch is fed by a rising-edge flop. Each stage's arrival time feeds the next: when a stage arrives before its latch opens (no borrowing) the chain restarts from the opening edge, otherwise the data keeps moving and borrowing accumulates through the chain. The check is end-to-end: the final stage must meet its closing edge less setup, and every intermediate latch must too.
Chains are listed with total borrowed time and the end-to-end slack; a single stage's slack is not enough.
Loops containing latches are analysed with the loop's total delay against the available phases.
Maximum borrow constraints, where the tool supports them, are set to prevent unbounded borrowing from hiding problems.
Because borrowing shifts every later launch time: the third stage starts from a later time than its opening edge, so its slack depends on what the first two borrowed.