A die boundary is the most expensive partition in the book: every signal across it pays in bumps, power and latency, so the cut must follow the seam with the fewest and slowest crossings. NanoSoC already has a seam that looks ready-made: the power cut between PD_SW and PD_AON, which carries 114 isolation clamps. It is tempting to draw the die boundary there, with the CPU, fabric, DMA and SRAM1 on one die and everything always-on on the other. The crossing count shows why that cut is wrong, and what to draw instead.
Count what crosses, in both directions, before choosing a cut. At the power seam the 114 isolated signals are only the outbound half: 47 from the APB bridge, 52 into the SRAM0 macro port and 13 into the ROM port, plus the 2 interrupts. The return half carries the APB response (32-bit read data, error and acknowledge), the SRAM0 read data and the ROM read data, and clocks, resets and power controls cross as well. Worse, SRAM0 and the ROM are the memories the CPU fetches from and the stream bridge copies through, so the 361.4 MB/s datapath and the 93.75 ns fetch would run across the link. The alternative cut sits below the APB bridge: SRAM0 and the ROM stay on the compute die, and only the slow peripherals, the interrupt controller, the reset and power controller and the PLL move to the second die.
Crossing group | Cut 1: power seam (SRAM0 and ROM on die B) | Cut 2: below the APB bridge (SRAM0 and ROM on die A) |
|---|---|---|
APB request (paddr 12, pwdata 32, pwrite, psel, penable) | 47 | 47 |
APB response (prdata 32, pslverr, ack) | 34 | 34 |
SRAM0 port, outbound (addr 14, wdata 32, be 4, ce, we) | 52 | 0 |
SRAM0 read data (derived from the 32-bit port) | 32 | 0 |
ROM port, outbound (addr 12, ce) | 13 | 0 |
ROM read data (derived from the 32-bit port) | 32 | 0 |
Sideband: 3 clocks, 3 resets, pll_lock, 2 clock enables, 3 power controls, 3 interrupts | 15 | 15 |
Total signals across the cut | 225 | 96 |
Fast datapath crossing? | Yes: CPU fetch and the 361.4 MB/s stream | No: only the 19.2 MB/s peripheral path |
Cut 2 is the teaching split. Die A holds everything except the five slow peripherals, the interrupt controller, the reset and power controller and the PLL: 0.484 mm2 of blocks. Die B holds those: 0.101 mm2. The cost of choosing it is honest: the power domains no longer coincide with the dies, because die A keeps SRAM0 and the ROM always powered while its CPU and fabric switch off, so die A needs its own always-on rail and its own isolation, and die B is always-on. The 47 request signals keep their clamps at die A's edge, so the isolation intent travels with the cut.
Reason | Strength in general | At NanoSoC (0.585 mm2) |
|---|---|---|
Process mismatch (analog, non-volatile memory or high-voltage I/O on a mature node, dense logic on an advanced one) | Strong when a block really needs the other process | Weak: the PLL is the only analog block, and the peripherals are small |
Yield or reticle limit | Strong for large dies | Does not apply: the calculator below gives a 1.6% silicon saving at an illustrative defect density |
Reuse of an existing die | Strong when the die already exists | Not applicable: no such die exists |
Convenience (parallel teams) | Never a reason: the link costs more | Never a reason |
The script counts the crossings of both cuts from the NanoSoC groups, checks the block areas and the RUN power per die against the totals, and prices the yield gain with an illustrative defect density (a Poisson model, 0.1 defects per mm2, deliberately pessimistic). Each assertion can fail: change a port width or a block area and the totals stop adding up.
# Isolation groups at the power seam (specification 7.4) and the return half.
apb_req, sram0_out, rom_out, irq_out = 47, 52, 13, 2
assert apb_req + sram0_out + rom_out + irq_out == 114
apb_rsp = 32 + 1 + 1 # prdata, pslverr, ack
sram0_rd, rom_rd = 32, 32 # read data, derived from the 32-bit port width
sideband = 3 + 3 + 1 + 2 + 3 + 3 # clocks, resets, pll_lock, clk enables, power controls, irqs
assert sideband == 15
cut1 = apb_req + sram0_out + rom_out + apb_rsp + sram0_rd + rom_rd + sideband
cut2 = apb_req + apb_rsp + sideband
assert (cut1, cut2) == (225, 96)
assert cut2 < cut1 / 2 # the better cut halves the signals and removes the fast paths
# Blocks per die (specification 10.1): die B = slow peripherals, INTC, RSTPWR, PLL.
die_a = [0.150, 0.025, 0.015, 0.040, 0.012, 0.010, 0.006, 0.004, 0.100, 0.010, 0.100, 0.012]
die_b = [0.008, 0.008, 0.006, 0.004, 0.015, 0.060]
area_a, area_b = round(sum(die_a), 3), round(sum(die_b), 3)
assert (area_a, area_b) == (0.484, 0.101) and round(area_a + area_b, 3) == 0.585
# RUN power per die (dynamic + leakage): the split must still add to 82.74 mW.
run_b = (0.30 + 0.06) + (0.40 + 0.06) + (0.20 + 0.05) + (0.20 + 0.03) + (0.50 + 0.12) + (6.00 + 0.50)
run_a = 82.74 - run_b
assert abs(run_b - 8.42) < 0.005 and abs(run_a - 74.32) < 0.005
# Yield: with Poisson yield the product of two die yields equals the monolithic yield,
# so the only gain is not wasting good silicon when one die is bad (known-good-die).
import math
d0 = 0.1 # illustrative defects per mm2
y_a, y_b, y_m = math.exp(-d0 * area_a), math.exp(-d0 * area_b), math.exp(-d0 * 0.585)
assert abs(y_a * y_b - y_m) < 1e-12
silicon_mono = 0.585 / y_m
silicon_split = area_a / y_a + area_b / y_b
gain = (silicon_mono - silicon_split) / silicon_mono
assert 0.01 < gain < 0.03, gain # about 1.6%: barely changes at this size
print(f"PASS: cut1 {cut1} signals, cut2 {cut2}; dies {area_a}/{area_b} mm2, {run_a:.2f}/{run_b:.2f} mW; yield saves {gain*100:.1f}% silicon")The split reason named as process, yield or reuse, with the NanoSoC column honest that most reasons do not apply at this size.
A crossing count for every candidate cut, both directions, including clocks, resets and power controls, not just the data buses.
Each die has its own power intent: where the power domains and the dies do not coincide (die A here), the always-on rail and its isolation are listed.
Count the crossings at the proposed cut and price each with the link lesson before approving the split: a cut through the SRAM0 or ROM ports needs a link that carries 361.4 MB/s and adds latency to every fetch. Move the cut to the slower, narrower seam first; only then price the dies. A cut that leaves one die at 0.101 mm2 of blocks is also a flag: check that die against its bump count before going further.
Because the power seam also carries the SRAM0 and ROM ports and their read data: 225 signals instead of 96, with the CPU fetch and the 361.4 MB/s stream running across the link. Below the bridge only the 19.2 MB/s peripheral path crosses.