UCIe · Module 27
Integration Review Checklist
The package and system seam gate — the ten-column contract matrix that turns assumptions into negotiated facts, why six reset scopes need six owners, the readiness predicate that separates a trained link from a usable function, and how two dies that each pass their own sign-off produce a product that hangs.
27.3 proved one design correct; 27.4 proved it fast enough. This gate asks whether independently designed pieces can be one product — and it is the gate where being individually correct is not enough.
1. The One-Sentence Model
Integration failures are usually disagreements between individually valid assumptions — so this gate does not look for bugs, it looks for questions that two organisations have each answered privately and differently.
That reframes what a reviewer is doing. 27.2 and 27.3 hunt defects inside one design. Here, both sides can be defect-free and the product still hangs (§8) — because reset lifetime, configuration ownership, readiness definition, identity scope or the meaning of recovery differ between them, and nothing local is wrong.
Which makes the gate's instrument a matrix rather than a test suite (§6). Every cross-boundary assumption becomes a row with a producer, a consumer, an owner, a version and a piece of evidence — and a row that exists in only one organisation's documents is exactly the shape of §8's failure.
2. What This Gate Owns
| Gate | Asks | Not this chapter |
|---|---|---|
| 27.1 — Architecture | what are we building? | the decisions themselves |
| 27.2 — RTL | did we implement it safely? | code review, CDC in code |
| 27.3 — Verification | can we prove one side correct? | single-side functional closure |
| 27.4 — Performance | can it meet the workload? | throughput, counters, margin |
| 27.5 — Integration (this chapter) | can independent pieces operate as one product? | — |
| 27.6 — Debug | can we diagnose it in silicon? | first-failure capture, trace |
Three boundaries, and the first one is what makes this gate distinct.
A component passing its own sign-off is an input to this gate, not an output of it. Component VIP compliance is not interoperability (§20). Two dies verified against two VIPs that encode two different assumptions both pass, which is precisely how §8 happens — so "both sides are signed off" is the starting condition for this review, not its conclusion.
The mechanisms here were taught in 26.5; this gate reviews the evidence that they were built. Reset scopes, readiness hierarchies, two-phase commit, cross-die handshakes, identity versus route — 26.5 explains why each exists. The RTL below appears as review exhibits: compact, and framed by the question each one exposes rather than as a fresh teaching of the mechanism.
And 25.10 owns integration as an organisational process — contract ownership, versioning, the irreversibility of decisions. This gate owns the review event: what evidence closes each row, and what PASS, CONDITIONAL PASS and FAIL mean at a seam.
3. Gate Decisions at a Seam
| Decision | In this gate |
|---|---|
| PASS | every contract row closed with both sides' agreement recorded · owner named · evidence from a paired test, not two component tests |
| CONDITIONAL PASS | a row open with bounded risk, a named owner on the accountable side, a closure precondition, and no downstream gate assuming it closes |
| FAIL | a contract row with two different answers · a row present in only one side's documents · interop evidence is two component sign-offs · unresolved reset/readiness/config ownership · version compatibility unverified |
Three readings.
"Both sides' agreement recorded" is the PASS criterion unique to this gate. Our answer being written down is not closure — the other organisation's matching answer must exist, in their document, at a known version. A row where we are confident and they were never asked is the exact precondition for §8.
A CONDITIONAL PASS here has an extra requirement: the named owner must be on the accountable side. Assigning an open cross-boundary item to our engineer when the answer belongs to the supplier creates the appearance of ownership without the ability to close it — and it will be open again at the next gate, with a new date.
And the third FAIL row deserves emphasis because it contradicts a natural intuition. Two component sign-offs are not interop evidence. They are two proofs that each side matches its own reading. The evidence that counts is a paired test (§20), and a gate that accepts the former for the latter has not been held.
4. Statement Versus Evidence
| Review statement (worthless) | Evidence (accepted) |
|---|---|
| "both dies are compliant" | the paired configuration matrix, run, with results (§20) |
| "reset is handled" | the six-scope table, with retained/cleared per scope, agreed by both sides (§7) |
| "recovery works" | the retention answer, in writing, from both organisations (§8) |
| "the link comes up" | the readiness predicate, and what publishes the resource (§9) |
| "config is set by firmware" | one named owner, plus the epoch and quiesce mechanism (§11) |
| "they support our version" | the version/profile compatibility matrix, tested (§19) |
| "we tested it together" | which configurations, which faults, how long, with what asymmetry (§20) |
| "the package routing is fine" | the connectivity and clock/reset distribution assumptions, owned (§17) |
Three readings.
Every accepted answer has a second party in it. That is the structural difference from every earlier gate: an integration answer that only one organisation holds is not an answer, however carefully it is written.
Row 3 is the highest-value single row and it is one sentence long. "What survives a transport recovery — retained, or replayed?" Both answers are implementable (27.1 §15); the failure is not choosing. Asking both sides separately and comparing is a five-minute review action that prevents §8 entirely.
And row 7 is where interop claims are usually thinnest. "We tested it together" covers everything from a two-hour smoke test to a month of asymmetric fault injection. The evidence is the matrix of what was actually run, and §20 is what that matrix must contain.
5. Sourcing and Scope
6. Area A — The Contract Matrix
The chapter's core artefact. If a review produces one document, this is it.
| Column | What it records | A gap means |
|---|---|---|
| contract | the assumption, stated as a testable sentence | nothing to review |
| producer | which die/block guarantees it | no source of truth |
| consumer | which die/block depends on it | scope unknown |
| owner | a named person on the accountable side | it will not close (§3) |
| reset scope | which resets affect it (§7) | 26.5 §9's corruption |
| clock domain | which domains it crosses (§13) | §14's lost event |
| configuration owner | who may commit a change (§11) | two committers (27.1 §18) |
| version / profile | the revision both sides agreed (§19) | silent incompatibility |
| verification evidence | the paired test that closed it (§20) | component sign-off masquerading as interop |
| silicon observable | the register that shows its state in the lab | unobservable in the field (27.6) |
Four readings.
Columns 9 and 10 are what make this a gate artefact rather than a design document. Column 9 forces the question "which paired test closed this?"; column 10 forces the question "when this breaks in the lab, what do we read?" — and a row with a contract, an owner and a version but no silicon observable is a contract you cannot debug (27.6 §4).
Column 4's "on the accountable side" is doing real work (§3). An owner who cannot change the answer is a placeholder, and rows with placeholder owners are the ones still open three gates later.
The rows that must exist, at minimum: retention across recovery (§8), reset scope ownership (§7), the readiness predicate (§9), configuration ownership (§11), credit/outstanding depth (27.4 §17 — an interface-visible parameter granted by the far end), identity scope and stability (§15), route change behaviour (§16), version/profile (§19), and error and status reporting (§18).
And the review technique is comparison, not reading. Ask each side to produce its matrix independently, then diff them. Rows present on one side only, and rows present on both with different values, are the findings — and this exercise takes an afternoon and finds what months of component verification cannot.
7. Area B — Reset Ownership
| Scope | Clears | Must NOT disturb | Owner |
|---|---|---|---|
| system reset | everything | — | platform |
| die reset | one die's state | peers' state; the link | that die |
| subsystem reset | one block | the die's other blocks | subsystem |
| link reset | link/physical layer | semantic obligations (25.3 §14) | link owner |
| transport recovery | retransmission state | semantic identity and generation | transport |
| semantic reset | outstanding transactions | — | the semantic owner, by agreement |
| software/diagnostic clear | sticky status, first-fault | functional state (25.10 §14) | debug |
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| B1 | each scope has exactly one owner | the table above, filled in, agreed | a scope with two owners or none |
| B2 | retained/cleared is specified per scope | the retention table, both sides | 26.5 §8's table missing |
| B3 | a die can reset alone — or explicitly cannot | the recovery-domain statement | undefined |
| B4 | peers are notified where required | the notification mechanism | silent unilateral reset |
| B5 | outstanding work's fate is defined per scope | the answer, from both sides | §8 |
| B6 | first-fault capture survives all but system reset | the retention statement + a test | evidence destroyed (27.6) |
| B7 | reset release is synchronised into each domain | the synchroniser | undefined startup state |
Three readings.
B1 is checked by filling in the last column and finding the blanks. A scope with two owners will be asserted by both, at different times, for different reasons — and the resulting interaction is in neither specification. A scope with no owner is asserted by nobody until it is needed and then by whoever notices first.
B5 is §8 in checklist form, and it is the row this whole gate is built around.
And B6 is the item reviewers skip as a debug concern. It is not: if a link reset clears first-fault capture, the reset destroys the evidence for the fault that caused it (21.7 §14) — so the field will forever report the second failure. That is an integration contract because the reset and the capture are frequently owned by different organisations.
8. Flagship — Both Dies Correct, the Product Hangs
The failure that defines this gate.
Setup. Die A is a requester; die B a completer. Different teams, same interface specification, each passed its own sign-off against its own VIP.
| Die A's answer | Die B's answer | |
|---|---|---|
| what a transport recovery does to outstanding work | retained — the peer still owes it | discarded — the peer will re-issue |
| after recovery, behaviour | waits for the original response | waits for a re-issue |
| is the reasoning defensible? | yes — a transport event cannot discharge a semantic obligation | yes — completing against possibly-corrupt state is worse |
| what its VIP modelled | a peer that retains | a peer that replays |
| standalone sign-off | PASS | PASS |
The specification did not say. Neither side is wrong.
Failure — the timeline.
| Cycle | Die A | Link | Die B | Observable |
|---|---|---|---|---|
| 0 | issues sem_id=12, gen=1 | up | accepts, begins work | normal |
| 40 | — | error → recovery | — | recovery logged on both |
| 41 | retains entry 12; waits | recovering | discards work for 12 | the divergence — silent |
| 55 | waiting | ACTIVE | idle, expecting a re-issue | "recovery successful" |
| 56–4000 | still waiting | ACTIVE | still waiting | link healthy; both dies waiting |
| ~4000 | timeout on sem_id=12 | ACTIVE | never saw a re-issue | hang, no error anywhere |
And the mirror-image variant is worse. If A re-issues on timeout while B had in fact retained, B completes both — and if A's entry was reallocated in between, the second response retires an unrelated transaction. Corruption, with every integrity check passing.
Four readings.
No amount of component verification finds this, and the reason is structural: each VIP encodes its own die's assumption, so each die passes by construction (27.3 §14 E1). A drained-pipeline recovery test — what both teams naturally wrote — passes on both and proves nothing about the pair.
The review action is five minutes. Ask each organisation, separately, in writing: what survives a transport recovery? Compare the answers. That single question, asked at this gate, prevents the entire failure.
The discriminator, if it does reach silicon, is two counters on each side (§21): obligations_outstanding_at_recovery, reissued_after_recovery, completed_after_recovery. A shows 1 retained, 0 re-issued; B shows 1 discarded, 0 received. One read per die makes the disagreement explicit — without them it is a cross-company debug in which each team can prove its own die correct.
And the gate decision is FAIL, not CONDITIONAL PASS. By §3, an unresolved contract with two different answers is blocking: every downstream claim about recovery behaviour, availability and error handling rests on it.
9. Area C — Readiness Is Not Link State
A link reaching ACTIVE and a function being usable are separated by two more conditions, and the gap is where the "fails only on the first access after boot" bug lives.
| Level | Condition | Established by |
|---|---|---|
| 1 | present | discovery / enumeration |
| 2 | powered | power-good |
| 3 | clocked | clock detected, PLL locked |
| 4 | reset released | reset sequencing complete |
| 5 | link ready (ACTIVE) | link training |
| 6 | configuration valid | commit complete (§11) |
| 7 | semantically ready | the function has completed an operation |
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| C1 | the readiness predicate is written down | the full conjunction | "when the link is up" |
| C2 | publication happens at level 7, not level 5 | the publish condition in RTL/firmware | publishes on ACTIVE (§10) |
| C3 | both sides agree what "ready" means | both definitions, compared | one-sided definition |
| C4 | each input is synchronised into the consuming domain | the synchronisers | metastable readiness |
| C5 | a readiness high-water record exists | the sticky per-die level (26.5 §14) | bring-up failures cannot self-name |
| C6 | readiness is withdrawn if a condition regresses | the withdraw path | set-and-never-cleared |
Three readings.
C2 is the item, and the gap between levels 5 and 7 is the whole content. A trained link proves the transport works and nothing about whether the function behind it is configured (25.9 §5).
C3 is the integration half, and it is easy to miss because both definitions look complete. Our side may define ready as configuration committed; the peer may define it as link ACTIVE. Both are defensible, both are documented, and the product races.
And C5 is what turns a bring-up failure into a register read. A single "ready" bit carries no information about which condition failed — so every bring-up failure becomes a bisection instead of a lookup (25.9 §20).
10. Review Exhibit — Publishing on ACTIVE
// WRONG. REVIEW EXHIBIT. The resource manager publishes the function as soon as
// the link reports ACTIVE — level 5 of 7 (§9).
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) function_published_q <= 1'b0;
else if (link_state == LINK_ACTIVE) // BUG 1: level 5 asserted as 7
function_published_q <= 1'b1; // BUG 2: never withdrawn (C6)
endArchitecture. One condition, one bit. The reviewer's question is C1: "what exact predicate means usable?" — and this code answers "the link trained".
State. Set and never cleared, so a later regression leaves a stale publication (C6).
Event. Link entering ACTIVE — a transport event standing in for a semantic one.
Contract. Software assumes a published resource accepts work. Configuration commit is still in progress, on a different die, on a different timeline.
Failure — the timeline. The race is between configuration and the first access.
| Time | Link | Configuration | Manager | Software | Observable |
|---|---|---|---|---|---|
| t0 | training | not started | — | — | normal |
| t1 | ACTIVE | not started | publishes | — | looks successful |
| t2 | ACTIVE | in progress | — | enumerates | — |
| t3 | ACTIVE | in progress | — | first access | transport succeeds |
| t4 | ACTIVE | in progress | — | — | function rejects it |
| t5 | ACTIVE | completes | — | fault reported | every later access works |
Root cause. Two boundaries treated as one — the transport is usable and the function is usable.
And it is a race, so every observation perturbs it. Add tracing and the timing shifts; boot slowly and it passes; move to a faster die and it fails more. The classic non-fix is a delay in the driver, which hides it until the next respin changes the timing.
Corrected — and the review artefact is the predicate itself.
// CORRECT. REVIEW EXHIBIT. The predicate IS the contract (C1). A reviewer
// should be able to read this one expression and compare it, term by term,
// with the peer's definition (C3).
assign func_ready = power_good
& clk_valid // detected AND locked, in this domain
& reset_done
& link_active
& cfg_valid // committed (§11), not merely requested
& semantic_ready; // has COMPLETED an operation, not accepted one
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) function_published_q <= 1'b0;
else function_published_q <= func_ready; // withdraws too (C6)
end
// MANDATORY. English: a resource is never published unless every readiness
// term holds. This is C2 expressed as a property.
a_no_publish_before_ready: assert property (
@(posedge clk) disable iff (!rst_n)
function_published_q |-> func_ready
);
// MANDATORY. English: readiness terms are established in order — cfg_valid
// never asserts before link_active. Catches a status bit written out of
// sequence by firmware, which would defeat the conjunction above.
a_readiness_ordered: assert property (
@(posedge clk) disable iff (!rst_n)
cfg_valid |-> link_active
);Contract. Each input must be synchronised into this domain (C4) — a power_good from another die's domain sampled directly is a metastable readiness bit, which is the same class of defect as §14's.
DV/debug. The review question is one line: "show me the publish condition." And the corroborating evidence is 26.5 §14's sticky high-water level — link_ready set, cfg_valid clear, with a publish event recorded, names this failure in a single register read.
11. Area D — Configuration Ownership
| State | Meaning | Who may set it |
|---|---|---|
| supported | the capability exists | each side, for itself |
| requested | a change is proposed | any participant |
| prepared | every affected party has staged it and confirmed | each party, for itself |
| active | in effect, atomically | the configuration owner, once |
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| D1 | exactly one configuration owner, named | the name, agreed by both sides | two owners, or none |
| D2 | commit is atomic across the seam | shadow → prepare → all-ack → swap | each side self-commits |
| D3 | a configuration epoch exists | the epoch register and its width | stale requests silently reinterpreted |
| D4 | commit requires quiesce | the outstanding == 0 condition | in-flight work spans two configs |
| D5 | a prepare timeout ABORTS, never commits | the abort path | self-commit with extra steps |
| D6 | validity rules are checked before prepare | the rule set (26.3 §11) | an invalid config commits |
| D7 | stale-epoch requests are rejected and counted | the counter | violations invisible |
Three readings.
D1's answer must be a name and it must match on both sides. Two configuration owners is not a race condition, it is an unspecified system (27.1 §18) — neither organisation's sign-off covers the interleaving, so neither can be shown to be wrong.
D5 is the shortcut that reintroduces the whole problem. Committing on a prepare timeout makes bring-up smoother and means a party that never staged the change is now expected to honour it. A silent peer has prepared nothing.
And D4 is what makes D3 an assertion rather than a repair mechanism (26.5 §17). A design that commits without quiescing needs runtime detection of stale requests forever; one that quiesces needs an assertion that never fires.
12. Review Exhibit — Two-Phase Commit
// REVIEW EXHIBIT. ILLUSTRATIVE (§10). Taught in full at 26.5 §17. Shown here
// so the four review questions are concrete: who commits, is it atomic, is it
// quiesced, and does a timeout abort?
typedef enum logic [2:0] { C_IDLE, C_SHADOW, C_WAIT_ACK, C_COMMIT, C_ABORT } cfg_e;
cfg_e cfg_q;
logic [EPOCH_W-1:0] cfg_epoch_q;
logic [N_PEER-1:0] peer_prepared_q;
logic [15:0] prep_timer_q;
logic [31:0] stale_rejected_q; // D7 — should be zero forever
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cfg_q <= C_IDLE; cfg_epoch_q <= '0; stale_rejected_q <= '0;
end else begin
unique case (cfg_q)
C_IDLE: if (chg_req && is_config_owner) begin // D1: OWNER only
shadow_cfg_q <= proposed_cfg; // staged, not applied
cfg_q <= C_SHADOW;
end
C_SHADOW: cfg_q <= cfg_valid_rules(shadow_cfg_q) ? C_WAIT_ACK : C_ABORT;
// D5: a timeout ABORTS. Committing here would mean a peer that staged
// nothing is expected to honour the new configuration.
C_WAIT_ACK: if (&peer_prepared_q) cfg_q <= C_COMMIT;
else if (prep_timer_q == PREP_TO) cfg_q <= C_ABORT;
else prep_timer_q <= prep_timer_q + 16'd1;
// D2 + D4: one cycle, and only with nothing outstanding anywhere.
C_COMMIT: if (outstanding_total == '0) begin
active_cfg_q <= shadow_cfg_q;
cfg_epoch_q <= cfg_epoch_q + 1'b1;
cfg_q <= C_IDLE;
end
C_ABORT: cfg_q <= C_IDLE; // shadow discarded
default: cfg_q <= C_ABORT;
endcase
if (req_fire && (req_epoch != cfg_epoch_q))
stale_rejected_q <= stale_rejected_q + 32'd1; // D7
end
end
// MANDATORY. English: configuration becomes active only after every affected
// party confirmed preparation. Catches self-commit (D2).
a_commit_all_prepared: assert property (
@(posedge clk) disable iff (!rst_n)
$changed(cfg_epoch_q) |-> $past(&peer_prepared_q)
);
// MANDATORY. English: the epoch never advances while work is outstanding.
// This is what makes the epoch check provable rather than hopeful (D4).
a_commit_quiesced: assert property (
@(posedge clk) disable iff (!rst_n)
$changed(cfg_epoch_q) |-> ($past(outstanding_total) == '0)
);Architecture. Five states, a shadow copy, a per-peer prepared vector, a bounded timer, an epoch, and a counter for the case that should never occur.
State. active_cfg_q and shadow_cfg_q are physically separate — which is what makes the swap atomic. A single register updated field by field is the defect this structure prevents.
Event. Commit is one cycle, gated on owner, all-prepared and quiesced. Any one of the three missing reproduces a variant of the split-configuration window.
Contract. PREP_TO must come from the peer's stated worst-case preparation time, not from measurement — and it is a contract-matrix row (§6), because the number belongs to the other organisation.
Failure. The residual risk is a commit that cannot quiesce because something is permanently outstanding, turning a configuration change into a hang. outstanding_total non-zero with cfg_q == C_COMMIT is the diagnostic, and it names the blocking work rather than the configuration.
DV/debug. stale_rejected_q should be zero forever. Non-zero is proof that a_commit_quiesced was violated somewhere — a one-register diagnosis for a class of silent misconfiguration.
13. Area E — Clocks and Cross-Die Events
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| E1 | every cross-domain signal is enumerated | the CDC signal list | an unlisted crossing |
| E2 | only levels cross; no bare pulses | the signal's encoding | a single-cycle pulse (§14) |
| E3 | payload is held stable by protocol, not bit-synchronised | the handshake | a multi-bit bus through synchronisers |
| E4 | there is an acknowledgement | the ack path | the source is guessing |
| E5 | the four-phase deassert wait exists | the FSM state | back-to-back events merge |
| E6 | edge detection is on a stable stage | the synchroniser depth | metastable edge detect |
| E7 | the clock-ratio range is a contract-matrix row | the stated min/max ratio | assumed |
| E8 | reset convergence across domains is defined | the sequencing | one side resets alone |
Three readings.
E7 is the integration-specific item and it is almost always missing. A handshake's correctness depends on the ratio range between two dies' clocks — which is a fact owned by two organisations. If the peer later ships a variant with a slower clock, an unrecorded assumption becomes a field failure.
E3 is where well-intentioned code is wrong. Synchronising a multi-bit bus flop by flop feels safer and is the actual bug: independent synchronisers can resolve on different cycles, producing a value that was never sent.
And E1 is the enumeration that makes the rest possible. A crossing nobody listed is a crossing nobody reviewed — and the ones that get missed are typically status and error signals, not datapath.
14. Review Exhibit — the One-Cycle Pulse
// WRONG. REVIEW EXHIBIT. Die A signals a configuration event with a one-cycle
// pulse. Idiomatic within a domain; a coin flip across a die boundary.
always_ff @(posedge clk_a or negedge rst_a_n)
if (!rst_a_n) cfg_evt_pulse_q <= 1'b0;
else cfg_evt_pulse_q <= cfg_evt_req; // BUG: one clk_a cycle
// Die B, slower domain. The synchroniser is CORRECT; there is simply nothing
// for it to sample.
always_ff @(posedge clk_b or negedge rst_b_n)
if (!rst_b_n) cfg_applied_q <= 1'b0;
else if (sync2_q && !sync3_q) cfg_applied_q <= 1'b1; // BUG: no ack (E4)Failure — the arithmetic. clk_a at 2 GHz (500 ps); clk_b at 800 MHz (1250 ps). A 500 ps pulse against a 1250 ps sampling period is missed whenever it falls between two clk_b edges — most of the time, and dependent on a phase relationship that drifts.
| Instance | Phase | Result |
|---|---|---|
| bring-up, cold | pulse straddles an edge | works — and is signed off |
| after a PLL relock | shifted | event lost |
| after a frequency change | different ratio | lost more often |
| across temperature | drift | intermittent |
Root cause. A pulse's width is defined in the source's time base and consumed in the destination's, and nothing converts between them. A synchroniser fixes metastability, not the absence of a sampling opportunity.
Corrected — four-phase level handshake (26.5 §12 has the full FSM).
// CORRECT. REVIEW EXHIBIT. Source HOLDS the request until acknowledged, so no
// clock ratio can lose it. Payload is held stable and never synchronised (E3);
// only the control signal crosses. Timeout produces a NAMED error (E4).
always_ff @(posedge clk_a or negedge rst_a_n) begin
if (!rst_a_n) begin
src_q <= S_IDLE; req_level_q <= 1'b0;
end else begin
{ack_s2_q, ack_s1_q} <= {ack_s1_q, ack_level_b};
unique case (src_q)
S_IDLE: if (new_evt) begin
payload_q <= evt_payload; // stable for the whole txn
req_level_q <= 1'b1; // LEVEL, not a pulse
src_q <= S_REQ;
end
S_REQ: if (ack_s2_q) begin req_level_q <= 1'b0; src_q <= S_WAIT_DEASSERT; end
else if (timer_q == ACK_TO) src_q <= S_FAIL; // named, not silent
else timer_q <= timer_q + 16'd1;
// E5: without this, two back-to-back events merge into one at a slow
// destination — the same lost-event bug in a different disguise.
S_WAIT_DEASSERT: if (!ack_s2_q) src_q <= S_IDLE;
S_FAIL: if (diag_clear) src_q <= S_IDLE;
default: src_q <= S_IDLE;
endcase
end
end
// MANDATORY. English: the source holds the request stable until it observes an
// acknowledgement. Catches anyone "optimising" the level back into a pulse —
// a change that passes at one clock ratio and fails at another.
a_req_held_until_ack: assert property (
@(posedge clk_a) disable iff (!rst_a_n)
(req_level_q && !ack_s2_q) |=> req_level_q
);DV/debug. A single-clock-ratio simulation passes with the broken version. The test that finds it sweeps the ratio and the phase — and the review item is E7: is the supported ratio range written into the contract matrix, or assumed?
15. Area F — Identity Scopes
A single integer used for several scopes is one of the most productive sources of integration failure.
| Identity | Owned by | Changes when | Must survive |
|---|---|---|---|
| semantic transaction ID | the requester | on retirement | retry, recovery, route change |
| generation | the requester | on ID reuse | recovery |
| logical function ID | the architecture | never, for a live object | failover |
| physical route / link index | the platform | failover, remap | — |
| die ID | the platform | never | — |
| configuration epoch | the config owner | on commit (§11) | — |
| route epoch | the config owner | on route change | — |
| # | Must be true | FAIL if |
|---|---|---|
| F1 | each scope has a distinct field | one integer serving several scopes |
| F2 | semantic ID width and reuse rules agreed by both sides | one-sided |
| F3 | generation is present and checked | stale completion retires a live entry |
| F4 | identity survives retry, recovery and route change | any one breaks it |
| F5 | ID reuse rules across reset are agreed | 26.5 §9's corruption |
And F5 is the row that pairs with §8. When may an identifier be reused? has an obvious answer — when it completes — that is wrong across a reset, because the peer may still hold the old identities. Both sides must state the same rule.
16. Area G — Routing and Failover
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| G1 | logical identity is independent of physical route | the routing key in RTL | link index used as an identity (26.5 §19) |
| G2 | route is resolved at use time, not at request time | the resolution point | live entries carry stale routes |
| G3 | a route epoch exists and is checked | the epoch field | silent misroute |
| G4 | a route change quiesces, or stale entries are detected | the mechanism | failover causes the hang |
| G5 | outstanding work survives a route change | the paired test | untested |
| G6 | failover is tested with traffic in flight | the test and its outstanding count | idle failover only |
Two readings.
G4 names the perverse outcome that makes this worth a gate. The failover mechanism — the feature that exists to improve availability — becomes the trigger for a hang when responses are correlated on the physical link they arrived over (26.5 §19). Valid responses get rejected, and the investigation goes to the wrong die.
And G6 is 27.3 §14 E1's discipline applied to failover. "We test failover" with a drained pipeline proves the mechanism switches. It proves nothing about outstanding work, which is the only interesting part.
17. Area H — Package and Physical Assumptions
Reviewed as ownership and statedness, never as values (§5).
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| H1 | connectivity is documented and agreed | the connectivity map | assumed |
| H2 | lane/link availability and degraded modes are stated | the supported configurations | undefined behaviour on partial availability |
| H3 | clock distribution and sources are owned | the clocking plan, with an owner | assumed |
| H4 | reset distribution is owned | the reset tree and its owner | §7 B1 |
| H5 | power sequencing and domains are agreed | the sequence | first-access failures |
| H6 | thermal assumptions are stated | the operating envelope | performance surprises (27.4 §21) |
| H7 | test and debug access is planned | the DFx access path | unreachable in the lab (27.6) |
| H8 | electrical signoff owner is named | the applicable PHY/package spec and its owner | this gate inventing limits |
Three readings.
H8 is the discipline row and it protects the review from itself. Bump pitch, reach, insertion loss and signal-integrity budgets belong to the applicable PHY and package specifications and their owners — not to this gate. The review item is that a named owner and a named specification exist, not what the numbers should be.
H2 is the row most often left undefined. "What happens when only some lanes are available?" has real answers — degraded mode, refuse to train, train at reduced width — and if the two sides answer differently, a partially-assembled package behaves unpredictably rather than degrading.
And H7 belongs here rather than in 27.6 because access is a package decision. Debug registers that exist in RTL and cannot be reached through the assembled package are not observable, and that is discovered in the lab.
18. Area I — Firmware and Software Contract
Reviewed as required capabilities, not as an API (§5).
| # | Capability | FAIL if |
|---|---|---|
| I1 | capability discovery — what each side supports | hardcoded assumptions |
| I2 | active configuration is readable | software cannot know the current state |
| I3 | error and status reporting, with classes | one generic error bit |
| I4 | first-fault preserved and separately clearable | (27.6) evidence destroyed on clear |
| I5 | reset control with defined scope | software cannot request the scope it needs |
| I6 | version/profile compatibility is checkable at runtime | mismatch discovered by failure |
| I7 | recovery ownership is defined — who initiates, who observes | both or neither act |
| I8 | the register read protocol is documented | torn reads trusted (27.4 §13) |
Two readings.
I7 is the software mirror of §8. If both sides believe the other initiates recovery, nobody does; if both initiate, they interfere. The contract-matrix row is "who initiates recovery, and what does the other side do while it happens?"
And I4 is a hard integration requirement rather than a debug nicety. Diagnostic clear must be separable from functional reset (25.10 §14), or you cannot re-arm error capture on a live system — so the first fault after any recovery is unobservable, exactly when it matters.
19. Area J — Version and Profile Compatibility
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| J1 | the specification revision each side targets is recorded | the revision, in the matrix | "the spec" (27.1 §7 B6) |
| J2 | which permitted options each side chose | option-by-option, both sides | conformance claimed as compatibility |
| J3 | contract versions are explicit and comparable | the version fields | silent drift on a derivative |
| J4 | a compatibility check exists | the predicate (27.1 §20) | mismatch found by failure |
| J5 | mismatched versions are detected, not merely avoided | the runtime check (I6) | assumed correct pairing |
| J6 | a derivative product re-runs this matrix | the re-run record | assumptions inherited silently |
Three readings.
J2 is the row that distinguishes conformance from interoperability. Two blocks can both be fully conformant and not interoperate, because a specification deliberately leaves options open and each side chose legally and differently. The matrix must record the choices, not the conformance claim.
J4 turns the whole matrix into something mechanical. A compatibility predicate over the capability records (27.1 §20) returns X_RECOVERY_MODEL, X_TWO_CONFIG_OWNERS, X_DOUBLE_RETRY as a function call at design time, rather than as an integration discovery.
And J6 is the row that catches the second product. A block reused with an unversioned contract carries assumptions nobody re-checked — and the new partner may have made the other legal choice.
20. Area K — Interoperability Testing
Component sign-off is not interop evidence (§3). This area defines what is.
| # | Must be true | Evidence that counts | FAIL if |
|---|---|---|---|
| K1 | the actual pair was tested, not two models | the paired test report | two component sign-offs |
| K2 | the configuration/profile matrix was swept | the matrix with results | one configuration |
| K3 | reset mismatch scenarios tested | each scope, from each side | §7 untested |
| K4 | recovery with LIVE traffic, from both sides | the outstanding count at injection | §8 untested |
| K5 | version mismatch tested, including unsupported combinations | the results | only matched versions |
| K6 | asymmetric faults — one side degraded | the tests | symmetric only |
| K7 | long-duration stress, not smoke tests | the duration and failure rate | hours-long claims from minutes-long runs |
| K8 | failover with work in flight | §16 G6 | idle failover |
| K9 | both retention policies exercised if either is configurable | the results | one policy only |
Three readings.
K4 is the single test that prevents §8, and it must be run from both sides — injecting recovery while we hold obligations is a different test from injecting it while they do, and a design can be asymmetric.
K6 exists because real degradation is asymmetric. One direction degrading, one die thermally throttled, one link at reduced width — these produce behaviours that symmetric testing cannot reach, and they are the normal field condition rather than a corner.
And K7 is where claims outrun evidence most often. A slow credit leak of one per million transactions is invisible in a short run and fatal in a soak (25.6 §10). The evidence is the duration and the observed rate, not the fact that a stress test exists.
21. Area L — Observability Across the Seam
Commissioned here, owned by 27.6 — because a cross-die failure needs evidence from both dies.
| # | Must be true | FAIL if |
|---|---|---|
| L1 | a common time base or shared milestone counter | two traces cannot be interleaved |
| L2 | semantic ID, generation, config epoch and route epoch in both sides' traces | cannot correlate a transaction |
| L3 | obligations_outstanding_at_recovery on both sides | §8 undiagnosable |
| L4 | first-fault capture on both sides, independently clearable | one side's cause is lost |
| L5 | readiness high-water level per die | bring-up cannot self-name (C5) |
| L6 | contract-matrix version readable from silicon | which contract is actually present is unknown |
And L1 is a hard prerequisite for everything else. Without a correlated time base, two dies' traces cannot be aligned — and every failure in this chapter is a cross-die correlation problem. This is a design-time decision that cannot be added when the first silicon bug appears.
22. The Integration Gate Checklist
Forty-two items.
Contract matrix
| # | Question | FAIL if |
|---|---|---|
| 1 | Does a contract matrix exist with all ten columns? | no matrix |
| 2 | Did both sides produce one independently, and were they diffed? | one-sided |
| 3 | Any row present on only one side? | yes → FAIL |
| 4 | Any row where the two sides' values differ? | yes → FAIL |
| 5 | Does every row have an owner on the accountable side? | placeholder owners |
| 6 | Does every row cite a paired test? | component sign-off cited |
| 7 | Does every row have a silicon observable? | undebuggable contract |
Reset
| # | Question | FAIL if |
|---|---|---|
| 8 | Are all six scopes enumerated with one owner each? | a scope with two owners or none |
| 9 | Is retained/cleared specified per scope, both sides? | missing |
| 10 | What survives a transport recovery — from BOTH sides? | answers differ → FAIL |
| 11 | Can a die reset alone, and who must know? | undefined |
| 12 | Is outstanding work's fate defined per scope? | undefined |
| 13 | Does first-fault capture survive all but system reset? | evidence destroyed |
| 14 | Is reset release synchronised into each domain? | undefined startup |
Readiness
| # | Question | FAIL if |
|---|---|---|
| 15 | Show the publish predicate | publishes on link ACTIVE |
| 16 | Do both sides define "ready" the same way? | one-sided definition |
| 17 | Is every readiness input synchronised? | metastable readiness |
| 18 | Is readiness withdrawn if a condition regresses? | set-and-never-cleared |
| 19 | Is a readiness high-water level recorded per die? | bring-up bisection |
Configuration
| # | Question | FAIL if |
|---|---|---|
| 20 | Who is the configuration owner — one name, agreed? | two, or none |
| 21 | Is commit atomic across the seam? | each side self-commits |
| 22 | Does commit require quiesce? | in-flight work spans two configs |
| 23 | Does a prepare timeout abort? | commits on timeout |
| 24 | Are stale-epoch requests rejected and counted? | violations invisible |
Clocks and CDC
| # | Question | FAIL if |
|---|---|---|
| 25 | Is every cross-domain signal enumerated? | an unlisted crossing |
| 26 | Any single-cycle pulse crossing a die boundary? | yes → FAIL |
| 27 | Is any multi-bit bus passed through synchronisers? | yes → FAIL |
| 28 | Is there an acknowledgement for every cross-die event? | source guessing |
| 29 | Is the supported clock-ratio range a matrix row? | assumed |
Identity, routing, package, software
| # | Question | FAIL if |
|---|---|---|
| 30 | Does each identity scope have a distinct field? | one integer, several scopes |
| 31 | Are ID reuse rules across reset agreed by both sides? | one-sided |
| 32 | Is routing keyed on logical identity, resolved at use? | link index as identity |
| 33 | Does a route change quiesce or detect stale entries? | failover causes the hang |
| 34 | Is connectivity, clocking and reset distribution owned? | assumed |
| 35 | Is behaviour on partial lane/link availability defined? | undefined degradation |
| 36 | Is electrical signoff assigned to a named spec and owner? | this gate inventing limits |
| 37 | Is debug access reachable through the assembled package? | unreachable in the lab |
| 38 | Is recovery ownership defined — who initiates, who observes? | both or neither |
Version and interop
| # | Question | FAIL if |
|---|---|---|
| 39 | Is each side's specification revision and option set recorded? | "we follow the spec" |
| 40 | Was the actual pair tested, over a configuration matrix? | two component sign-offs |
| 41 | Was recovery injected with live traffic, from both sides? | idle only → FAIL |
| 42 | Were asymmetric faults and long-duration stress run? | symmetric smoke tests |
Run items 2, 3, 4, 10, 40 and 41 first. Diffing the two matrices and asking the retention question take an afternoon and decide most gates — everything else is detail once a row is found with two different answers.
23. How the Integration Review Itself Fails
| Failure mode | Looks like | Why it is fatal |
|---|---|---|
| reviewing one side's matrix | complete and confident | §8 — the disagreement is invisible |
| accepting component sign-offs as interop | two green reports | both prove self-consistency only |
| assigning cross-boundary items to internal owners | every row owned | the owner cannot close it (§3) |
| testing the pair only at idle | interop demonstrated | §20 K4 — the interesting state untested |
| inheriting a matrix into a derivative | efficient | J6 — the new partner chose differently |
| inventing electrical limits to fill a gap | thorough | H8 — the gate is not the signoff authority |
Two readings.
Row 1 is the defining failure of this gate. Every organisation's own matrix is internally consistent — that is what makes it publishable. The finding lives in the diff, and a review that never sees the other side's document cannot produce one.
And row 3 is subtle because it looks like diligence. Assigning an open supplier item to an internal engineer produces the appearance of ownership without the ability to close it. The item reappears at the next gate with a new date, and the pattern repeats until it becomes a field issue.
24. Red Flags
| Heard in review | Usually means | Ask |
|---|---|---|
| "both dies are compliant" | conformance offered as compatibility | "which options did each choose?" |
| "obviously it retains" | §8 — never asked of the peer | "where is their written answer?" |
| "we tested it together" | scope unknown | "which configurations, how long, what faults?" |
| "the link comes up fine" | readiness = link state | "show me the publish predicate" |
| "firmware handles config" | possibly two committers | "one name — whose?" |
| "it's just a status pulse" | a cross-die pulse | "what clock ratio does that assume?" |
| "we use the link number" | identity conflated with route | "what happens after failover?" |
| "their VIP passes" | component evidence | "was the actual pair tested?" |
| "same as the last product" | J6 — inherited assumptions | "was the matrix re-run with this partner?" |
| "the package team owns that" | possibly nobody | "named person, or nobody?" |
| "we'll sort it in bring-up" | an open contract | "which gate does that invalidate?" |
And the two highest-yield actions in the room are structural rather than technical. "Show me their matrix" and "what survives a transport recovery — in their words?" Both take minutes and both decide gates.
25. Common Misconceptions
"If both sides are compliant, they interoperate." §19 J2: a specification leaves options open. Two conformant blocks can choose legally and differently.
"Both dies passed sign-off, so integration is low risk." §8: that is the precondition for the failure, not protection from it — each VIP encoded its own side's assumption.
"Reset is a platform concern." §7: six scopes, six owners. A link reset that clears semantic obligations is a contract violation, not a reset detail.
"The link is ACTIVE, so the function is ready." §9: ACTIVE is level 5 of 7. Configuration and semantic readiness are two further conditions.
"Each side can commit its own configuration." §11 D1: two owners is an unspecified system — nobody's sign-off covers the interleaving.
"Committing on a prepare timeout keeps bring-up moving." §11 D5: a silent peer staged nothing. That is self-commit with extra steps.
"A pulse is fine, we synchronise it." §14: a synchroniser fixes metastability, not the absence of a sampling opportunity in a slower domain.
"Synchronise the bus to be safe." §13 E3: independent synchronisers can resolve on different cycles, producing a value that was never sent.
"Failover improves availability." §16 G4: not if responses are correlated on the physical link — then failover is the trigger for the hang.
"We tested interoperability." §20: with which configurations, which asymmetric faults, for how long, and with recovery injected from both sides while work was outstanding?
26. Understanding Check
27. Summary
Seven things.
The failures here are disagreements, not defects (§1, §8). Two dies can each be correct, each pass sign-off, and hang together — because the specification left a question open and each side answered it privately.
The contract matrix is the artefact (§6). Ten columns, including paired-test evidence and a silicon observable — and the findings come from diffing both sides' matrices, not from reading one.
Reset is six scopes with six owners (§7), and what survives a transport recovery must be answered by both organisations in writing — the single highest-value question in this chapter.
Readiness is seven ordered conditions (§9–§10). ACTIVE is level 5, publication belongs at level 7, and both sides must define it identically.
Configuration needs one named owner, atomic commit, an epoch, quiesce, and a timeout that aborts (§11–§12) — because two committers is an unspecified system.
Only levels cross a die boundary (§13–§14), with an acknowledgement, a deassert wait, and a recorded clock-ratio range — and a multi-bit bus through synchronisers can produce a value that was never sent.
And component sign-off is not interop evidence (§20). The actual pair, across a configuration matrix, with recovery injected under live traffic from both sides, asymmetric faults, and a stated duration.