UCIe · Module 24
Modular Semiconductor Design
What changes in engineering methodology when the unit of composition becomes a chiplet with an explicit contract — why contracts must freeze before implementations, the partition that is functionally perfect and destroys system efficiency, the interface that leaks microarchitecture, and why two independently verified dies can still fail in combination.
Chapter 24.2 asked what must be exchanged between suppliers. This chapter asks what changes inside an engineering organisation when the unit of composition stops being an RTL module and becomes a separately-taped-out die.
1. The One-Sentence Model
Chiplet-first design moves contracts earlier than implementations. A monolithic SoC can defer a boundary decision until integration, timing closure or software bring-up, because one RTL change can still fix it. Separate dies tape out separately, may sit on different process nodes and different schedules, and cannot be reconciled by one ECO — so the contract must be right before either implementation is mature.
That single reordering causes most of what follows. Partitioning becomes a decision with a longer lifetime than any module boundary (§7), verification must run against a peer that does not exist yet (§16), and a partition that is functionally perfect can destroy system efficiency (§9) in a way no later fix repairs.
2. What This Chapter Owns
| Question | Where |
|---|---|
| The five ecosystem roles; what each publishes | 24.1 — Open Chiplet Ecosystems |
| The manifest, compatibility predicate, atomic commit, identity scopes | 24.2 — The Chiplet Marketplace Vision |
| The seven-layer integration contract | 22.5 — Future SoCs |
| The UCIe stack; FDI/RDI; protocol mapping | 19.1 · 19.2 |
| Reusable IP — parameterisation, collateral | 19.6 — Reusable UCIe IP |
| Link verification; UVM environments; scoreboards | 20.2 · 20.6 · 20.4 |
| Throughput diagnosis; silicon debug evidence | 21.5 · 21.7 |
| Multi-package, multi-scope composition | 24.4 (next) |
Four things are new here, and all of them are methodology rather than mechanism:
The freeze-order inversion (§5–§6) — what a chiplet-first flow must decide before it can start, and why.
Partition quality as an engineering measurement (§8–§11), including the chattering boundary that no buffer depth repairs and the RTL that would have caught it in a prototype.
Interfaces that leak microarchitecture (§12–§14) — the failure that welds two dies into one design split physically, and the semantic boundary that prevents it.
And verification against a peer that does not exist (§16–§18), where two independently correct dies fail in combination and each supplier's evidence exonerates itself.
3. Sourcing
4. What a Die Boundary Costs That a Module Boundary Does Not
| An RTL module boundary | A die boundary | |
|---|---|---|
| when it can change | any time before tape-out | effectively never, after contract freeze |
| who can change it | one team, one repository | two teams, possibly two companies |
| cost of getting it wrong | an ECO | a respin of one or both dies |
| what crosses it | wires, at zero marginal cost | a transport with real latency and energy |
| verification | one testbench sees both sides | each side verified against a model (§16) |
| debug | one waveform contains everything | two dies, two capture domains (21.7) |
| lifetime | one product | RTL, physical design, test, packaging, firmware, debug, and product updates |
And the last row is the argument for everything in this chapter. A module boundary lives for one design cycle. A die boundary persists through manufacturing, test, packaging, firmware and field debug — so a bad one is not merely expensive to fix, it is expensive continuously.
5. Contracts Freeze Before Implementations
Three things to read.
The two flows freeze the same commitment at different depths. Monolithic finalises boundaries at integration, with implementation knowledge in hand. Chiplet-first freezes at step 2, with far less knowledge — which is the methodology's central difficulty, not a criticism of it.
The red bar is what makes it irreversible. Two dies tape out separately; there is no single change that reconciles them, so the contract's cost of being wrong is a respin rather than an ECO (§4).
And the right column parallelises after the freeze, which is the compensating benefit: independent RTL and DV on separate schedules and nodes is exactly what the freeze buys.
6. The Two Flows
| Monolithic | Chiplet-first |
|---|---|
| architecture | system partition (§8) |
| RTL — boundaries still negotiable | interface contract frozen (24.2 §6) |
| integration — boundaries finalised | package and physical feasibility |
| physical design | per-die architecture |
| validation | independent per-die RTL and DV, in parallel |
| — | interoperability (§16) |
| — | package integration |
Two properties.
Package feasibility moves early. 22.1 §17: the packaging technology determines the reach class and therefore the D2D options — so a partition that the package cannot support is not a partition.
And this is Level E (§3). It is what separate tape-outs structurally require, not a claim that any organisation runs this exact flow.
7. Partitioning Is a Lifetime Decision
A die boundary persists through eight distinct activities, each with its own cost of change.
| Activity | What the boundary constrains |
|---|---|
| RTL | which signals may cross, and in what form |
| physical design | die edge, bump allocation, floorplan |
| manufacturing | which node each die uses |
| test | what is testable pre-package versus post-package (§20) |
| packaging | substrate routing, thermal placement |
| firmware | which resources appear where |
| debug | which evidence is available on which side (21.7) |
| product updates | which die can be respun independently |
And the eighth row is the one that motivates the whole exercise. The reason to partition is frequently so one die can be respun without the other — and a boundary that couples them defeats that, which is §12's failure.
8. The Partition Scorecard
Eleven dimensions. There is no single rule, and the popular one is wrong.
| Dimension | Favours keeping together | Favours splitting |
|---|---|---|
| traffic volume across the boundary | high | low |
| latency sensitivity | tight, dependent (22.4 §8) | tolerant |
| coherence / shared state coupling | strong | weak |
| process-node affinity | same needs | different needs |
| power delivery | shared domain | separable |
| thermal | co-located hotspots | separable |
| yield | small combined area | large area, poor yield |
| reuse potential | single-use | reusable across products |
| verification complexity | tightly coupled semantics | separable semantics |
| fault isolation | shared failure anyway | independent isolation wanted |
| software ownership | one abstraction | separable abstractions |
9. Wrong Partition — the Chattering Boundary
Two blocks were separated for organisational reasons. They exchange small state updates every cycle.
| Before (one die) | After (two dies) | |
|---|---|---|
| exchange rate | 1 update / cycle | 1 update / cycle |
| cost per exchange | a wire | a transport crossing (22.4 §7) |
| dependency | combinational or 1 cycle | round trip across the boundary |
| control loop | closes in 1–2 cycles | closes in 2 × crossing + processing |
| functional correctness | correct | correct |
| system efficiency | — | destroyed |
Worked, illustrative:
ILLUSTRATIVE. Symbolic units; no UCIe or vendor figure is used (§3).
BOUNDARY TRAFFIC MODEL:
required service = event_rate x bytes_per_event
event_rate = 1.0 / cycle (every cycle — "chattering")
bytes_per_event = 8 (a small state update)
required service = 8 bytes / cycle, SUSTAINED, in BOTH directions
That much is merely expensive. The fatal term is the DEPENDENCY:
dependency_depth = 1 (each update depends on the last)
crossing latency = c each way
loop time BEFORE = 1 cycle
loop time AFTER = 2c + processing
With c = 15 (illustrative), the control loop went from 1 cycle to >30.
The block's throughput is set by the loop, so it drops ~30x.
NO BUFFER DEPTH FIXES THIS. Buffering hides latency only when there is
INDEPENDENT work to overlap (21.5 §25). A dependent loop has none.Five readings.
The design is functionally perfect. Every transaction is correct; only the rate collapsed, which is why it survives every functional test.
The killing term is dependency_depth, not bandwidth. A boundary carrying 8 bytes per cycle is provisionable; a boundary inside a dependent control loop is not, because the loop time is the throughput (22.4 §8).
Deeper FIFOs cannot help (21.5 §25): buffering absorbs bursts and hides latency only when independent work exists to overlap. A serial dependent chain has none.
The partition was made for organisational reasons — two teams, two schedules — which is a legitimate pressure and the wrong input to rows 1–3 of §8.
And the fix is a re-partition, which after contract freeze means a respin of both dies (§5). This is the failure the scorecard exists to prevent, because it cannot be repaired later.
10. Illustrative — the Boundary Traffic Monitor
// ILLUSTRATIVE ONLY. Instrumentation you place on a CANDIDATE boundary in a
// monolithic prototype, BEFORE partitioning — so §9's failure is measured
// rather than discovered after tape-out.
module boundary_traffic_monitor #(
parameter int CNT_W = 48,
parameter int MAX_DEPTH = 64
) (
input logic clk,
input logic rst_n,
input logic diag_clear,
// observed at the CANDIDATE boundary — acceptance, not offering (21.5 §20)
input logic req_valid,
input logic req_ready,
input logic [15:0] req_bytes,
input logic rsp_valid, // the RETURN half of a round trip
input logic rsp_ready,
input logic [SEM_W-1:0] req_id,
input logic [SEM_W-1:0] rsp_id,
output logic [CNT_W-1:0] events_q, // event RATE numerator
output logic [CNT_W-1:0] bytes_q, // bytes/event denominator
output logic [CNT_W-1:0] cycles_q,
output logic [CNT_W-1:0] dependent_rt_q, // THE KILLER TERM (§9)
output logic [15:0] outstanding_q,
output logic [15:0] max_outstanding_q,
output logic [31:0] max_rt_latency_q
);
logic accept, complete;
assign accept = req_valid && req_ready; // acceptance, never valid alone
assign complete = rsp_valid && rsp_ready;
// Round-trip timestamps for outstanding requests. Depth-bounded on purpose:
// if outstanding exceeds MAX_DEPTH the boundary is not the shape we assumed.
logic [31:0] issue_time_q [MAX_DEPTH];
logic [31:0] now_q;
// Outstanding as ONE signed next-state expression so a same-cycle accept and
// completion nets correctly instead of one update being lost (19.5 §14).
logic signed [16:0] next_outstanding;
assign next_outstanding = $signed({1'b0, outstanding_q})
+ $signed({16'b0, accept})
- $signed({16'b0, complete});
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n || diag_clear) begin
events_q <= '0; bytes_q <= '0; cycles_q <= '0; dependent_rt_q <= '0;
outstanding_q <= '0; max_outstanding_q <= '0; max_rt_latency_q <= '0;
now_q <= '0;
end else begin
now_q <= now_q + 32'd1;
cycles_q <= cycles_q + CNT_W'(1);
if (accept) begin
events_q <= events_q + CNT_W'(1);
bytes_q <= bytes_q + CNT_W'(req_bytes);
if (outstanding_q < 16'(MAX_DEPTH)) issue_time_q[req_id[$clog2(MAX_DEPTH)-1:0]] <= now_q;
end
// A DEPENDENT round trip is one where the boundary was IDLE while the
// response was outstanding — i.e. nothing else could be issued. That is
// the signature that distinguishes a pipelined boundary from a loop.
if (complete) begin
automatic logic [31:0] rt =
now_q - issue_time_q[rsp_id[$clog2(MAX_DEPTH)-1:0]];
if (rt > max_rt_latency_q) max_rt_latency_q <= rt;
if (outstanding_q == 16'd1) dependent_rt_q <= dependent_rt_q + CNT_W'(1);
end
outstanding_q <= next_outstanding[15:0];
if (next_outstanding > $signed({1'b0, max_outstanding_q}))
max_outstanding_q <= next_outstanding[15:0];
end
end
endmoduleArchitecture. Instrumentation for a candidate boundary in a monolithic prototype, producing the three numbers §9's model needs before anyone commits to a partition.
State. Four wide counters, an outstanding count with a high-water mark, and a bounded issue-time array.
Event. Counts on acceptance (valid && ready), never on valid alone — 21.5 §20's offered-versus-accepted distinction, which here would inflate the event rate under back-pressure and make the boundary look worse than it is.
Contract. dependent_rt_q counts completions that occurred while outstanding was exactly one — the signature of a boundary where nothing else could be issued. That is the discriminator between a pipelined boundary (safe to split) and a dependent loop (fatal to split), and it is not derivable from bandwidth alone.
Failure. Two if statements writing outstanding_q would lose a same-cycle accept-and-complete pair, so the count drifts and max_outstanding becomes meaningless. Counting req_valid alone inflates the event rate and can condemn a boundary that is fine.
DV/debug. The three derived quantities are the partition decision: bytes_q / cycles_q is the sustained service required, max_outstanding_q says whether latency can be hidden at all, and dependent_rt_q / events_q near 1.0 is §9 — a boundary that must not be split, whatever the node-affinity argument says.
11. Reading the Monitor
max_outstanding | dependent_rt / events | Verdict |
|---|---|---|
| 1 | ≈ 1.0 | do not split — a dependent loop (§9) |
| small (2–4) | high | risky; latency mostly unhidden |
| large | ≈ 0 | safe to split — pipelined, latency hideable |
| large | moderate | split, and size the outstanding window (21.5 §26) |
And the top row is the finding that saves a respin. It costs a prototype and a few counters, and it is available months before the contract freeze — which is the only time it can change anything.
12. Wrong RTL — Leaking Microarchitecture
// WRONG — the producer publishes its internal state to the neighbouring die.
// Every signal here is genuinely useful to the consumer, which is why this
// gets written.
output logic fifo_almost_full; // "so you can pre-throttle"
output logic [3:0] arbiter_state; // "so you can predict grants"
output logic [7:0] retry_ptr; // "so you can align your replay"
output logic [2:0] pipeline_stage; // "so you can time your issue"What each one welds together:
| Signal | The coupling created | What breaks |
|---|---|---|
fifo_almost_full | consumer's throttling depends on producer's queue depth | resizing the FIFO changes the peer's behaviour |
arbiter_state | consumer predicts grants from internal arbitration | changing the arbiter is an interface change |
retry_ptr | consumer's replay logic tracks producer's retry pointer | the retry mechanism cannot be redesigned |
pipeline_stage | consumer times issue against producer's pipeline depth | adding a pipeline stage breaks the peer |
Five properties.
The interface now exposes microarchitecture, so the two dies are one design that happens to be split physically — which defeats the reason to partition (§7 row 8).
Every internal optimisation becomes an interface change, requiring the other die's agreement and possibly its respin. The independence the partition was supposed to buy is gone.
It fails silently at first. Both dies work; the cost appears at the second generation, when one team tries to improve their queue and discovers they cannot.
And it is written for good reasons — each signal genuinely helps the consumer make a better local decision. That is what makes it a plausible mistake rather than a careless one.
The corrected form does not remove the information; it abstracts it (§13) — the consumer still learns it should throttle, without learning why.
13. Corrected RTL — the Semantic Boundary
// CORRECTED. The same information, expressed as CONTRACT rather than as
// internal state. The consumer can still make every decision it needs.
typedef struct packed {
logic [SEM_W-1:0] sem_id;
logic [GEN_W-1:0] generation;
logic [3:0] txn_class;
logic [15:0] length;
logic [EPOCH_W-1:0] cfg_epoch; // 24.2 §11
} boundary_txn_t;
// PUBLISHED — a small, stable set with no microarchitectural content.
output logic can_accept; // replaces fifo_almost_full
output logic [15:0] accept_credit; // how much, not why (13.1)
output logic txn_accepted; // the ACCEPTANCE event
output logic txn_complete;
output logic [SEM_W-1:0] complete_id;
output logic [GEN_W-1:0] complete_gen;
output logic [3:0] fault_class; // a CLASS, not an internal code
// HIDDEN — and free to change every generation:
// queue depth, arbitration policy, retry mechanism, pipeline depth,
// internal state encoding, clock ratio, buffer organisation.
// MANDATORY. English: no internal microarchitectural signal influences the
// published interface except through the defined contract. Structural
// non-interference — best discharged formally (21.7 §17), because simulation
// only shows it held for the stimulus you ran.
a_no_microarch_leak: assert property (
@(posedge clk) disable iff (!rst_n)
$stable({fifo_level_q, arbiter_state_q, retry_ptr_q, pipe_stage_q})
|| $stable({can_accept, accept_credit, fault_class})
);Architecture. Seven published signals carrying decisions, not state — plus a transaction record that is semantic rather than structural.
State. None additional; the credit count derives from the same queue the wrong version exposed directly.
Event. txn_accepted is the acceptance; txn_complete is a separate, later event carrying identity. Two events because acceptance and completion are different facts (21.4 §5).
Contract. accept_credit says how much the consumer may send, never why. That single substitution is what lets the producer resize its queue, change its arbiter, redesign its retry and add pipeline stages without touching the interface.
Failure. Publishing accept_credit as a direct copy of a FIFO level re-creates the coupling in disguise — the number is now microarchitecture wearing a contract's name, and the peer will come to depend on its exact behaviour.
DV/debug. The non-interference assertion is the one that protects the architecture rather than a behaviour. Without it, the layering can regress in any later commit and nothing notices until the second generation tries to change something.
14. What Belongs on Each Side
| Published (contract) | Hidden (microarchitecture) |
|---|---|
| can I accept, and how much | queue depth and organisation |
| acceptance and completion events | pipeline depth, stage encoding |
| semantic identity and generation | internal tag allocation |
| transaction class | arbitration policy |
| fault class | internal error codes |
| configuration epoch | negotiation implementation |
| capability record (24.2 §6) | how capabilities are stored |
And the test is a question: if I changed this internally next generation, would the other die need to change? If yes, it is on the wrong side of the line.
15. Clocking, Reset and Domain Ownership
A die boundary must not silently assume a shared clock, a shared reset, or a shared power state.
| Question | Must be answered explicitly |
|---|---|
| who synchronises? | one side, named — not "both, defensively" |
| where does the domain crossing sit? | inside one die's boundary block |
| what survives a reset on each side? | 24.2 §18's reset_model |
| which reset scopes exist? | interface, function, whole die |
| may one side change power state independently? | and what does the peer observe? |
16. Verifying Against a Peer That Does Not Exist
The methodology's hardest practical problem: both dies are being designed simultaneously, and neither can wait for the other.
| Asset | What it must be |
|---|---|
| executable interface contract | the manifest and predicate (24.2 §8), runnable |
| a behavioural peer model | a model of the contract, not of the other die's RTL |
| protocol checker | derived from the contract text (20.3) |
| interface coverage | which contract states were exercised (20.5) |
| transaction traces | exchangeable between teams for comparison (21.6 §40) |
| compatibility matrix | which profiles and revisions are proven together |
17. Failure — Each Die Passes Alone
| Die A | Die B | |
|---|---|---|
| its own VIP and regression | passes | passes |
| link conformance | passes | passes |
| assumption about an optional contract feature | assumes enabled | implements it disabled |
| who is wrong? | neither | neither |
Four readings.
Component verification is not integration proof. Each environment tested its die against its own reading of the contract, and both readings are defensible.
The ambiguity is in the contract, not the RTL — 21.6 §34's interpretation problem, discovered at integration instead of at review.
The prevention is §16's contract-derived peer model plus mutation testing (21.6 §25): construct the legal exception and confirm each checker stays quiet. A checker tested only against violations cannot reveal that two teams read a rule differently.
And the cheapest prevention is earlier still: the compatibility predicate (24.2 §8) fails a pairing whose optional-feature expectations disagree — before either RTL exists.
18. Failure — Correct, and Slower
| Observation | Value |
|---|---|
| functional regression | passes fully |
| link errors | zero |
| conservation checks (21.4) | all close |
| measured system throughput | far below the monolithic baseline |
dependent_rt / events (§10) | 0.94 |
max_outstanding | 1 |
| deeper FIFOs tried | no improvement |
Four readings.
Every correctness instrument is clean, so the investigation starts in the wrong place — 21.5 §51's pattern: a healthy link and a slow system.
The two monitor values are the diagnosis (§11 row 1). max_outstanding = 1 means nothing could be issued while a response was outstanding, and 94% dependent round trips means the boundary is a loop, not a pipe.
No buffer depth helps (21.5 §25), and the team will try several before believing it.
And the fix is a re-partition, which after contract freeze is a respin of both dies (§5) — which is why §10's monitor belongs in the prototype, months earlier, where it costs a few counters.
19. Physical and Test Constraints on Partitioning
Partition cannot be purely RTL-driven. Four physical realities constrain it:
| Constraint | Effect on partitioning |
|---|---|
| bump availability and die edge | limits how wide a boundary can be |
| package routing | limits which dies can be adjacent |
| power delivery | a die's power budget is a partition input |
| thermal placement | hot dies cannot be arbitrarily co-located |
And test adds a fifth (§20): a chiplet may be tested pre-package, post-package and at system level, and what is observable at each stage is a contract decision made at partition time — 21.7 §4's point that observability cannot be added after tape-out.
No packaging, physical-design or manufacturing-test rule is asserted here (§3). These constrain the partition; how they are satisfied is another discipline.
20. Debug Must Correlate Across Dies
Each die captures its own evidence. Correlating them requires four things to be common — and that is a design-time decision.
| Must be common across dies | Otherwise |
|---|---|
| semantic transaction identity | two traces cannot be joined (21.6 §18) |
| configuration epoch | events cannot be attributed to a contract (24.2 §11) |
| a time reference | ordering across dies is ambiguous (21.7 §16) |
| fault class encoding | each side reports in its own vocabulary |
And the consequence is that 21.7's instrumentation is a partitioning requirement, not a debug-team preference: if the two dies do not share an identity and an epoch, no amount of later effort joins their traces.
21. Configuration Ownership
24.2 §11 covered how to commit atomically. The methodology question is who decides.
| Decision | Owner |
|---|---|
| requested configuration | one system-level owner |
| validation | each die, against its own manifest |
| prepare acknowledgement | each die |
| commit | the owner, once both prepared |
| active configuration | derived — no die writes it independently |
And the failure to avoid is every die deciding for itself. A die that sees a configuration write and immediately changes behaviour produces 24.2 §12's partial commit — and in a multi-die system the window is longer, because the dies are further apart in time.
22. Assertions
// MANDATORY. Illustrative architectural properties (§3) — not normative.
// (1) NO MICROARCHITECTURAL LEAK. English: published interface signals depend
// on internal state only through the defined contract. Structural
// non-interference; discharge formally (§13).
// [see a_no_microarch_leak in §13]
// (2) ACTIVE CONFIG CHANGES ONLY ON COMMIT.
// English: no die alters its active contract without the system commit.
// Fires on §21's independent self-commit.
a_active_only_on_commit: assert property (
@(posedge clk) disable iff (!rst_n)
$changed(active_cfg_q) |-> $past(system_commit_fire)
);
// (3) ACCEPTED WORK SURVIVES A LOCAL RECOVERY.
// English: a die's internal recovery does not retire obligations it accepted
// across the boundary. Sampled on recovery EXIT, because that is when
// retention is observable. Catches 23.1 §17 / 24.2 §18.
a_accepted_survives_local_recovery: assert property (
@(posedge clk) disable iff (!rst_n)
($fell(local_recovering) && contract_retains_across_recovery)
|-> (oblig_live_q == $past(oblig_live_q, RECOVERY_DEPTH))
);
// (4) NO TRAFFIC BEFORE THE PEER CONTRACT IS VALID.
// English: nothing is issued until the peer's capability record has been
// received and validated. Catches a die that starts on link-up alone.
a_no_traffic_before_contract: assert property (
@(posedge clk) disable iff (!rst_n)
txn_accepted |-> peer_contract_valid_q
);
// (5) ROUTE / DESTINATION STABLE FOR A LIVE TRANSACTION.
// English: an in-flight transaction's destination cannot change underneath it
// (24.2 §15).
a_dest_stable_while_live: assert property (
@(posedge clk) disable iff (!rst_n)
(txn_live && $changed(route_epoch_q)) |-> $stable(txn_dst_logical_id)
);Architecture. One structural property protecting the layering, and four behavioural ones protecting contract lifetime.
State. The active contract, obligation set, peer-contract validity, and route epoch.
Sampled timing. Property (3) samples on $fell(local_recovering) — the exit edge, because retention is only observable once recovery completes; sampling during it compares against a transient. Properties (2) and (5) use $changed guarded by the event that legitimises the change.
Contract. RECOVERY_DEPTH must be derived from the recovery's own duration. A guessed value makes (3) vacuous or constantly false (21.6 §29).
Failure if omitted. Without (1), the boundary silently re-couples and the second generation discovers it. Without (4), a die issues traffic against defaults on link-up — and the peer interprets it under a contract that was never agreed.
DV/debug. Property (1) belongs in a formal flow. Non-interference is a proof obligation, and it is the only one of the five that protects the methodology rather than a behaviour.
23. Common Misconceptions
"Chiplet design is SoC design plus a PHY." §4, §5: the freeze order inverts, and a die boundary persists through eight activities rather than one design cycle.
"Partition after the RTL architecture is mature." §5: separate tape-outs mean the contract must freeze before implementations mature, because no single change reconciles them afterwards.
"A good RTL module boundary is automatically a good die boundary." §8, §9: a module boundary costs a wire; a die boundary costs a transport crossing and, if the boundary is a dependent loop, the system's throughput.
"Independent verification means integration will work." §17: both dies passed, both readings of an optional feature were defensible, and the ambiguity was in the contract.
"Expose more internal state to make integration easier." §12: it welds the dies into one design split physically, and every internal optimisation becomes an interface change.
"Configuration can be committed independently on each die." §21, 24.2 §12: the window is longer in a multi-die system, and mixed interpretation misclassifies traffic.
"More buffers repair a bad partition." §9, §18: buffering hides latency only when independent work exists to overlap. A dependent loop has none.
"CDC is purely a synchroniser problem." §15: the hard part is semantic lifetime across the crossing — what a reset on one side destroys on the other.
"Software can ignore physical partitioning." §20, 22.4 §21: frequently yes for the device model, and never for locality, fault domains and debug correlation.
24. Understanding Check
25. Summary
Five things.
Contracts freeze before implementations (§5). Monolithic finalises boundaries at integration with knowledge in hand; chiplet-first freezes at step two with far less — and no ECO reconciles two tape-outs.
A die boundary is a lifetime decision (§4, §7), persisting through RTL, physical design, manufacturing, test, packaging, firmware, debug and product updates.
Partition quality is measurable before you commit (§8–§11). Node affinity is one dimension of eleven, and max_outstanding = 1 with a high dependent-round-trip ratio means do not split — whatever the node argument says.
An interface that leaks microarchitecture welds two dies together (§12–§14). Publish decisions, hide state, and test each signal with: would a peer need to change if I changed this internally?
And two independently verified dies can still fail (§17), because component verification contains only one reading of the contract — which is what a contract-derived peer model and a compatibility predicate exist to catch.
On evidence: the UCIe stack and mapping facts are Level B; the flows, scorecards and partition heuristics are Level E engineering judgement (§3), derived from what separate tape-outs require and not a report of any company's methodology.