Skip to content
VLSI Mentor

I²C · Module 20

The Protocol Feature Matrix — Deciding What Must Be Covered

How to decompose a protocol into features that can be individually broken, why clock stretching and repeated START are dimensions rather than rows, and why the uncovered table is the one that tells the truth. Includes the honest matrix for this environment — twenty-five verified rows and eleven features it does not exercise at all.

Chapter 20.1 produced twenty-one objectives. An objective says what must be true. It does not say which parts of the protocol it touches, whether anything else touches them, or who is responsible for proving it — and a plan that answers only the first question is a plan in which a whole protocol feature can go unmentioned without anyone noticing.

A feature matrix is the document that makes an omission visible. It is not a coverage report. A coverage report is produced by running the environment and says what was exercised; a matrix is written before the environment exists and says what should be. The difference matters because a coverage report can only ever report on features somebody thought to instrument.

1. What Counts as a Feature

The decomposition rule that makes a matrix useful, rather than a restatement of the table of contents:

A feature is something that can be individually broken.

Test it by asking whether you can describe a defect that breaks this feature and nothing else. "Addressing" fails the test — a defect in address matching and a defect in the direction bit are unrelated, fixed in different places, and caught by different observations. "Seven-bit address match" and "direction from the address byte's low bit" both pass it.

The rule cuts the other way too. Do not split a feature into pieces that cannot fail independently. "Bit 3 of the address matches" is not a feature; no plausible defect breaks bit 3 while leaving bits 2 and 4 correct — except one, a mask with a wrong constant, and that is caught by the seven-bit sweep the single feature already demands.

2. Where the Features Come From

Three sources, and conflating them is the most common structural error in a matrix.

The specification. NXP UM10204 defines framing, byte format, acknowledgement, addressing, arbitration, stretching, the reserved addresses and the bus modes. Features from here are true of every conforming device, so their checks are reusable across every I²C design you will verify. They belong in a monitor or a protocol checker, never in a test.

The device datasheet. The register map, which registers are read-only, what the pointer does after a refused write, whether the part supports repeated START mid-transfer. None of this is in UM10204. Module 18 recorded six such decisions as D1 to D6, and Chapter 20.8's reference model is a transcription of them.

The integration. How the block is clocked, what its reset does, which pins it uses, what happens at power-on before software configures anything. Module 19's subject. These features are real and are frequently absent from matrices entirely, because neither of the first two documents mentions them.

Keeping the three separated is what lets a matrix be reused. Swap the device and the datasheet column changes; the specification column does not.

3. The Features That Multiply Everything Else

Three I²C features are not rows. They are dimensions, and they are where matrices quietly fail.

Clock stretching can happen at any acknowledge boundary. Every other feature therefore has a stretched variant, and the stretched variant is a different test because it exercises different logic: a driver that counts cycles works perfectly until something stretches.

Repeated START can replace any STOP. So every feature has a variant in which the transfer ends without releasing the bus, and the question "what state survives" gets a different answer for each.

Arbitration loss can happen at any bit while transmitting. Every transmit-side feature has a variant in which the device stops mid-operation through no fault of its own.

Three dimensions across roughly twenty rows is sixty combinations at minimum, and the honest response is not to fill in a sixty-cell grid. It is to ask, for each combination, whether there is a mechanism by which the interaction could fail — and to test the ones where there is.

interactionis there a mechanism?in the matrix?
stretching × register writeyes — a driver that counts cycles clocks data into a busy targetyes, 20.9 T5b
stretching × address matchyes — the address is latched across the stretched acknowledgeyes, 20.6 T5
repeated START × pointer stateyes — framing may or may not clear application stateyes, 20.8 T9
repeated START × read directionyes — the classic write-pointer-then-read sequence depends on ityes, 20.3 T9
stretching × wired-AND resolutionno — resolution is combinational and has no notion of timeno, and say so
arbitration × register mapno — a lost arbitration ends the transfer before any register is touchedno, and say so

The last two rows are doing real work. A matrix cell marked "no mechanism" is a decision with a reason attached, which can be reviewed and overturned. A blank cell is indistinguishable from an oversight.

4. Ownership

Every row needs a named owner, and "the testbench" is not a name. The owner is the component that will contain the check, because that decides whether the check is written once or many times.

ownerwhat belongs therewhy
monitorprotocol rules true of every devicewritten once, reused for every I²C design, and cannot be forgotten by a test author
reference modeldevice-contract predictionsthe contract is one document; it should have one implementation
scoreboardthe comparison, and only the comparisonit owns no knowledge, which is what keeps it from acquiring the DUT's bugs
testthe situation, never the expected valuea test that contains expected values is a test that has to be updated when the device changes
nobody—this is the row to look at

That last line is the point of the column. A feature whose owner is a test is verified only in the tests that remember it. A feature with no owner is verified by nobody, and it will still be absent from the coverage report, because nothing was instrumented to notice.

5. How to Read a Status Column Honestly

Four statuses, and the distinction between the middle two is where most matrices overstate.

  • EXERCISED AND CHECKED — a simulation drove this feature and a check on its outcome could have failed.
  • EXERCISED, NOT CHECKED — it happened, and nothing looked. Common, and worse than not exercising it, because it produces coverage.
  • IMPLEMENTED, NOT EXERCISED — the environment can do it and no test asks. This module had two of these until Section 6 was written, and they are the reason this section exists.
  • NOT SUPPORTED — the environment cannot do it at all. Honest and fine, provided it is in the matrix.

6. The Matrix

Features, sources, owners and status for the environment built in this module against Module 18's target. The Source column is S for the specification, D for the datasheet or device contract, I for integration.

featuresrcownerstatusevidence
a released line reads high only when all have releasedSmonitorexercised and checked16.4
no participant drives a line highSstructuralexercised and checked20.6 T4, 20.9 T6
START is an SDA fall while SCL is highSmonitorexercised and checked20.7 T1
STOP is an SDA rise while SCL is highSmonitorexercised and checked20.7 T1
repeated START ends a transfer without releasing the busSmonitorexercised and checked20.3 T9
SDA changes only while SCL is low, except framingSmonitorexercised and checked20.7 T8
a byte is eight bits, most significant firstSmonitorexercised and checked20.7 T2
the ninth slot is the acknowledge, owned by the receiverSmonitorexercised and checked20.6 T1
a transfer interrupted mid-byte transfers nothingSmonitorexercised and checked20.7 T7, 20.9 T3
seven-bit address match, all seven bits discriminatedDreference modelexercised and checked18.4, 20.8 T11
direction from the address byte's low bitSreference modelexercised and checked20.3 T7
a foreign address is not answeredDreference modelexercised and checked20.8 T4, 20.3 T8
clock stretching by the targetSresponder, driverexercised and checked20.6 T5, 20.9 T5b
a stretch is bounded, and an unbounded hold is a timeoutIdriverexercised and checked20.9 T5, T5b
a write lands in the register the pointer selectsDreference modelexercised and checked20.8 T1
the pointer advances only on an accepted writeDreference modelexercised and checked20.8 T8
the pointer wraps modulo the register countDreference modelexercised and checked20.8 T10
the pointer survives framingDreference modelexercised and checked20.8 T9
a write to a read-only register is refusedDreference modelexercised and checked20.3 T1b, 20.8
after a read the pointer sits one past the last byteDreference modelexercised and checked20.3 T7
read data comes from the selected registerDreference modelexercised and checked20.8 T3
a stuck line is abandoned rather than waited onIdriver, targetexercised and checked20.9 T4, T5
a disturbance narrower than the sampling window is survivedIinjectorexercised and checked20.9 T2
a disturbance spanning a sampling edge corrupts data silentlyIinjectorexercised and checked20.9 T2b
the same DUT behaviour in three HDLsIenvironmentexercised and checkedenv_vs_dut, 3 languages

Twenty-five rows, every one with an observation behind it. That is the matrix's optimistic half, and on its own it is the half that misleads.

7. What This Environment Does Not Cover

This is the column that makes a matrix worth writing. Eleven features of I²C that the environment built in this module does not exercise, each with why and with what would be needed.

featurestatuswhy not, and what it would take
multi-master arbitrationnot supported by the environmentthe controller driver is the only controller on the bus and has no arbitration logic. Module 17 verified the target's response to arbitration loss; the environment cannot generate a contended bus. Needs a second driver and a bit-level arbitration check
10-bit addressingnot supportedthe reference model and responder both decode seven bits. A 10-bit address is two bytes with a reserved prefix, so this is a new framing case, not a wider field
general call address 0x00not supporteda reserved address with defined semantics. The target NACKs it, which is legal, but nothing checks that it does so deliberately rather than incidentally
START byte, CBUS address, device IDnot supportedreserved-address behaviours in UM10204 §3.1.12. No objective references them
SMBus and PMBus layersout of scopetimeouts, packet error checking and the ALERT line are a different specification layered on this one
bus timing parametersnot supportedthe bus is modelled in clock cycles, not nanoseconds. There is no tHD;STA anywhere in this environment, so no timing compliance is checked at all. Needs a timing-annotated model, and on real hardware, measurement
Fast-mode Plus, High-speed, Ultra-Fast modenot supportedmode differences are electrical and timing, and this environment has neither
software reset via the reserved sequencenot supportednot implemented in the target
two targets sharing one addressnot supportedthe bus model supports many devices, but no test creates the collision. The wired-AND result of two acknowledges is indistinguishable from one, which is exactly what makes it worth a test
power-on and reset-release behaviourpartlythe target is reset before every test. Nothing exercises reset during a transfer, which is the integration case that actually happens
metastability, and any real timing claimnot reachable herean RTL simulator has no sampling aperture. 19.4 argues this at length; no amount of stimulus changes it

Reading the two tables together is the point. The environment verifies the target's protocol and application behaviour thoroughly and in three languages, and it says nothing whatsoever about timing compliance, arbitration, or any addressing mode beyond plain seven-bit. Both halves are true, and only the first half is what "verified" is usually taken to mean.

The matrix said 100% covered, and the feature had never run

Pitfall — a feature with an owner, a parameter, an output, and no test
Buggy Code
// From this module's own environment, before the matrix was written.
//
// The responder model supports clock stretching. It has a policy parameter, a
// countdown, a release, and an exported count:
//
//    i2c_resp_bfm #(.MY_ADDR(ADDR), .ACK_ADDR(1'b1), .NACK_AFTER(0),
//                   .STRETCH_CLKS(0),          // <-- zero
//                   .READ_BASE(8'h00)) resp (...);
//
// The controller driver supports it too, correctly, with a bounded wait:
//
//    while (!scl_in && w < STRETCH_TIMEOUT) begin ... end
//
// And the Module 18 target has a stall input:
//
//    .stall_req(1'b0),                          // <-- tied low
//
// Every piece is present and every piece is correct. The feature has never
// executed. Line coverage on the responder shows the stretch block as unhit,
// which nobody looked at, because the component list said "stretching: resp_bfm"
// and the component existed.
Pitfall — the sixty-cell grid nobody filled in
Buggy Code
// A matrix with three cross-cutting dimensions, filled in by policy:
//
//                      | plain | stretched | rep-START | arb-loss
//   address match      |  yes  |    TODO   |   TODO    |  TODO
//   register write     |  yes  |    TODO   |   TODO    |  TODO
//   register read      |  yes  |    TODO   |   TODO    |  TODO
//   ... 20 rows ...
//
// Sixty cells, forty-five of them TODO. Six months later the TODOs are still
// there, and the review discussion is about whether to lower the target to 80%.
//
// The real problem is that the grid asserts all sixty interactions matter
// equally, which is false, and gives no way to say so. The team's actual
// knowledge -- that stretching cannot affect wired-AND resolution because
// resolution is combinational -- has nowhere to go except a TODO that looks
// identical to the ones that do matter.

8. What 20.2 Settled

A feature is something that can be individually broken. That single rule produces a decomposition fine enough to be useful and coarse enough to finish, and it rules out both "addressing" and "bit 3 of the address".

Features come from three documents, and they must stay separated. Specification rules are reusable across every I²C design; datasheet decisions change when the part changes; integration features appear in neither document and are the ones most often missing entirely.

Three features are dimensions, not rows. Stretching, repeated START and arbitration loss each multiply the table, and the way to handle the product honestly is to ask of each cell whether a mechanism exists — recording "no mechanism, because" as a reviewable decision rather than leaving a blank.

The status column is the one that finds things, and the uncovered table is the one that tells the truth. This module's matrix has twenty-five rows with observations behind them and eleven features it does not exercise at all, including every timing parameter in the specification. Writing the second table is what turned two complete, correct, idle stretch implementations into six killed mutations.

The next chapter takes the first architectural decision the matrix implies. Several rows are owned by a component that has to turn edges into transactions, and what a transaction is turns out to be the decision that determines whether the environment can check anything at all. Chapter 20.3 — What Should an I²C Transaction Object Represent?.

Continue learning