Every signal that crossed on-die for free now crosses dies through bumps, drivers and a link protocol, paying in latency, power and pins. The below-bridge seam from the previous lesson — one APB bundle at 19.2 MB/s sustained — is the cheapest link NanoSoC could have, which makes the pricing method visible: if even this link costs real bumps and cycles, a cut through the fabric would cost far more.
A die-to-die link spends four budgets at once. Bandwidth: the link must carry the seam's sustained rate with its own efficiency, including protocol overhead. Latency: pad drivers, flight time and link-layer pipelining add destination-clock cycles the on-die path never had. Power: every toggling bump burns I/O energy, far above an on-die wire. Bumps: each signal needs one, and the response direction counts as much as the request, so an APB seam is not 47 signals but 47 out, 34 back (32-bit read data, error, acknowledge) and about 15 of sideband, 96 in all, plus spares. Two directions, two buses: the 32-bit write data and the 32-bit read data are separate buses.
Budget | NanoSoC below-bridge seam | Result |
|---|---|---|
Bandwidth | 19.2 MB/s needed against 48.0 MB/s peak of the clk_per APB segment | 40% load: under half, as the rule asks |
Latency | Illustrative 2 link cycles each way at clk_per: 4 x 41.667 ns | +166.67 ns: a slow-peripheral read grows from 281.25 to 447.92 ns |
Power | Illustrative 2 pJ per bit moved (teaching value) | About 0.31 mW at 19.2 MB/s, 3.6% of die B's 8.42 mW |
Bumps | 96 signals plus 4 illustrative spares | 100 bumps; at an illustrative 0.10 mm pitch they need 1.0 mm2 of bump array |
The script prices all four budgets and then applies the same tests to a cut through the SRAM ports, which fails them. A check that can only pass proves nothing, so the failing case is part of the script.
required, apb_capacity = 19.2, 48.0 # MB/s: seam demand, clk_per APB peak (specification)
load = required / apb_capacity
assert abs(load - 0.40) < 0.001 and load < 0.5 # under half, as the review rule says
# The fabric seam fails the same test: 361.4 MB/s against a 384.0 MB/s link.
fabric_load = 361.4 / 384.0
assert fabric_load > 0.9 and not fabric_load < 0.5
# Added latency: 2 link cycles each way at the slow clock (illustrative).
added_ns = 4 * (1 / 24e6) * 1e9
assert abs(added_ns - 166.67) < 0.01, added_ns
assert abs(281.25 + added_ns - 447.92) < 0.01
# Power: illustrative 2 pJ per bit moved.
link_mw = required * 1e6 * 8 * 2e-12 * 1e3
assert abs(link_mw - 0.307) < 0.005, link_mw
assert link_mw / 8.42 < 0.05 # small against die B's RUN power
# Bumps: both directions plus sideband, not one bundle.
signals = (12 + 32 + 3) + (32 + 1 + 1) + 15 # request, response, sideband
assert signals == 96
bumps = signals + 4 # illustrative spares and test
pitch = 0.10 # mm, illustrative bump pitch
bump_area = bumps * pitch * pitch
die_b_core = 0.101 * 1.12 # blocks plus the 12% overhead
assert bump_area > die_b_core, (bump_area, die_b_core) # die B is bump-limited
assert 10 * pitch * pitch < die_b_core # a 10-signal seam would not be
print(f"PASS: load {load*100:.0f}%, +{added_ns:.0f} ns, {link_mw:.2f} mW, {bumps} bumps need {bump_area:.2f} mm2 vs die B {die_b_core:.3f} mm2")The last assertion is the finding: die B is a fraction of a square millimetre of logic and the link alone needs about nine times that in bumps, so it is bump-limited, not logic-limited. That is exactly why NanoSoC would never be split in practice, and why the section calls the split a teaching model.
Link load quoted as demand over capacity with protocol overhead included, under half for growth.
Added latency in destination clocks, attributed to the paths that cross, not averaged into the budget.
Bump count per die with spares and both directions, checked against the area or perimeter of the smaller die.
Measure the link separately from the logic: loop it back at the bumps and check rate, latency and error counts before any functional traffic crosses. The classic misdiagnosis blames the bridge for link errors, for example APB timeouts that are really link retries. Separate the loopback result from the functional result and the blame lands correctly.
It is narrow, slow (19.2 MB/s sustained) and latency-tolerant, so the load is only 40% and the extra 166.67 ns lands on peripheral registers, not on fetches. What still goes wrong is the bump count: 100 bumps do not fit on a 0.1 mm2-class die, so die B becomes bump-limited.