Skip to content
VLSI Mentor

I²C · Module 9

Multi-Byte I²C Reads — ACK Policy, Timing and Waveforms

A well-formed read of n bytes contains exactly n−1 ACKs and one NACK, always last. That pattern is narrow enough to check in hardware — and narrow enough to predict a bus hang before the STOP that cannot form is even attempted.

Chapter 9.1 established that a master ends a read by withholding an acknowledge, and Chapter 9.2 established that the slave has no say in the matter. Put those together across a burst and something useful falls out: the acknowledge pattern of a correct read is completely determined by its length.

Not constrained. Determined. There is exactly one legal pattern for a read of n bytes, which means a passive observer can check the policy with no knowledge of the device, the driver, or what the data means — and can do something better than check it. It can predict the bus hang before it happens, because the hang is caused by the acknowledge pattern and the acknowledge pattern is visible one byte before the STOP is attempted.

This chapter derives that pattern, prices a read against the equivalent write, and builds the instrument.

1. The Pattern Is Determined by the Length

A read of n payload bytes puts n + 1 bytes on the wire and therefore has n + 1 acknowledge slots. Their owners and required values are fixed:

slotbelongs torequired valuewhy
byte 0 — address + Rthe slaveACKotherwise nobody is at that address
bytes 1 … n−1the masterACK"send me another"
byte n — the lastthe masterNACKthe fifth NACK condition: end the transfer

So for any n ≥ 1 the master produces exactly one NACK and exactly n−1 ACKs, and the NACK is always in the final slot. For n = 0 — the address-only probe with R/W = 1 — the master produces nothing at all, because it never became a receiver of data and there is no slot that belongs to it.

nmaster ACKsmaster NACKsthe pattern, in order
000— (the slave's ACK only)
101N
211A N
321A A N
871A A A A A A A N

The n = 1 row is the one that breaks naive checkers. A one-byte read contains zero master ACKs — its only acknowledge is the NACK, because the first byte is also the last. An instrument that assumed "at least one ACK, then a NACK" reports a policy violation on the single most common read in existence, and §9's mutation C10 is the sibling error for n = 0.

2. What a Read Costs, and Why It Costs More Than a Write

The pulse arithmetic is identical to Chapter 8.3's. Nine pulses per byte, no pulses for framing, n + 1 bytes on the wire for a plain read:

quantityclosed form
bytes on the wiren + 1
SCL pulses9(n + 1)
payload bits8n
overhead pulsesn + 9

Identical to a write, and for the same reason: the acknowledge costs one pulse in nine whichever direction the data is going, and the address byte costs nine pulses and carries no payload whichever direction follows it. The 8/9 ceiling is direction-independent.

But that is the plain read, and a plain read is rare. Almost every real read is a register read, which means the combined format of Chapter 9.1 §1: write the pointer, repeated START, read the data. And that costs one more byte-slot than the equivalent write.

transferbytes on the wireSCL pulses
write n bytes to a register pointerS, addr+W, ptr, n data, P → n + 29(n + 2)
read n bytes from a register pointerS, addr+W, ptr, Sr, addr+R, n data, P → n + 39(n + 3)

A register read always costs exactly nine pulses more than the equivalent write — one extra byte-slot, which is the second address byte. The repeated START itself is free in pulses, as all framing is. Here is what that does to the numbers:

nwrite pulseswrite efficiencyread pulsesread efficiency
12729.6%3622.2%
23644.4%4535.6%
45459.3%6350.8%
89071.1%9964.6%
1616279.0%17174.9%
3230683.7%31581.3%
→ ∞—88.9%—88.9%

Three readings worth having.

A single-byte register read is 22% efficient. Four bytes on the wire to move one. This is the most-issued transaction on many real buses — read one status register — and it is the least efficient thing I²C does. At 100 kHz it takes 360 µs to retrieve eight bits.

The penalty shrinks fast and the asymptote is the same. The extra nine pulses are a fixed cost, so they matter enormously at n = 1 and hardly at all at n = 32. Both directions converge on 8/9, because in the limit the acknowledges dominate and the acknowledges are symmetric.

The engineering conclusion is the same as Chapter 8.3's, only more so. Do not read status registers one at a time in a loop. Most devices lay related registers out contiguously precisely so that one burst can fetch them, and the gain is larger for reads than for writes because the fixed cost being amortised is larger.

3. Reading an Annotated Burst

Here is a six-byte register read at byte resolution — one interval per byte slot. At bit resolution this frame would be 81 intervals wide.

Register read: write the pointer, Sr, then read six bytes

10 cycles
Ten intervals at byte resolution. The first is a START and consumes no SCL pulses. The second is the address byte with write direction, acknowledged by the slave. The third is the register pointer, acknowledged by the slave. The fourth is a repeated START, consuming no pulses. The fifth is the address byte again with read direction, acknowledged by the slave. The next four intervals are payload bytes, acknowledged by the master except the last which is not acknowledged. A pulse row reads zero for the three framing intervals and nine for every byte interval.pointer writepointer writere-address, Rre-addre…Rpayloadpayloadwrite phase: sets the pointerwrite phase: sets thepointerSr: direction reverses hereSr: direction reverses hereNACK ends the readNACK ends the readbyteS0x90ptrSr0x91d0d1d2d3P9th bit0AAAAAAANNdriven by0SSSSMMMMMpulses0990999990t0t1t2t3t4t5t6t7t8t9
A six-byte register read in the combined format. Two address bytes, two framing events, and an acknowledge row whose owner changes twice. The pulse row reads zero for framing, which consumes no clock.

The figure has no clock row, deliberately: at byte resolution one interval is nine SCL pulses, so a clock row would draw one period where nine belong. The pulses row carries that information in the correct units, as it does in Chapter 8.3 §5.

The driven by row is what makes this figure worth the space. Read it across: S S S for three byte slots, then M M M M. The acknowledge changes owner once, at the transition from the second address byte to the first data byte — and that is the handover the specification places "at the moment of the first acknowledge". Note also that the row reads S for the address byte after the Sr, even though that byte requests a read: at the moment of its acknowledge slot the slave is still the receiver, because it has just received an address. That is Chapter 9.1 §1's clause drawn rather than argued, and it is the single most common source of monitor off-by-one.

Four things to read off a capture of this shape, in order:

Count the intervals between framing events. Ten intervals, three of which are framing, so seven bytes on the wire. The pulse total is 7 × 9 = 63 — and 63 divides by nine, which is the sanity check that costs one division.

Find the Sr and check what follows it. A byte following a repeated START is an address, not data. Reading it as data shifts the interpretation of everything after it, which Chapter 7.5 §10 documents as the most expensive structural misreading available.

Read the ninth-bit row as a pattern. One N, in the last data slot. Any other arrangement is malformed, and §1's callout covers the two ways it can be.

Check who drove each acknowledge. Three slave acknowledges then four master ones. A monitor reporting five master acknowledges for this frame has attributed the second address byte's slot to the master, and its byte accounting will be wrong by one on every read it ever sees.

4. The Hang, Derived From the Pattern

Chapter 7.4 introduced the read hang and Chapter 9.1 §3 explained why it is unrecoverable. Here it is as a derivation, because the instrument in §6 implements exactly this reasoning.

Premise 1. A master that ACKs a byte has told the slave to send another (§1).

Premise 2. A slave-transmitter that has been told to send another will drive the next byte's eight data bits (Chapter 9.2 §2). It cannot decline — it has no NACK.

Premise 3. Driving a bit means pulling SDA low or releasing it; no device drives SDA high (Chapter 2.3). So whenever a driven bit is 0, SDA is held low by the slave.

Premise 4. A STOP requires SDA to rise while SCL is high (Chapter 5.3).

Conclusion. If the master ACKs what it intended to be the final byte, the slave drives another byte, and for any byte whose most significant bit is 0 the master cannot form its STOP. Not delayed, not corrupted — impossible, because the master has no way to overpower a device pulling low.

Two consequences of the derivation matter for the instrument:

The fault is visible one byte early. The acknowledge that causes the hang happens in the slot before the byte that holds the line. So an observer that watches the acknowledge pattern knows the transfer is doomed before the STOP is attempted, which is the difference between a diagnosis and an autopsy.

The hang is data-dependent, and that makes it worse. It manifests only when the extra byte's MSB is 0 — so roughly half the time, depending on what the device happens to hold. A driver with this bug works intermittently, and "works intermittently on a shared bus" is the hardest class of fault to attribute, because the symptom lands on whichever device is unlucky enough to need the bus next.

5. Why the Instrument Is Passive

The design below observes and never participates. It has no output that reaches SDA or SCL, so it cannot be the cause of a bus problem — which is the entire requirement for a debug block that ships in silicon. A monitor that can perturb the bus is a monitor people disable, and then it is not there on the day it is needed.

It measures four quantities and produces two verdicts:

outputwhat it is
bytes_seen, scl_pulses, payload_bytesthe cost accounting of §2
master_acks, master_nacksthe pattern of §1, with the address slot excluded
addr_ackedthe slave's answer to the address byte, kept separate
policy_okthe pattern was n−1 ACKs then exactly one NACK
hang_riskthe final data byte was ACKed — the derivation of §4

6. The Instrument in Three Languages

Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_ack_policy.sv — a passive instrument that checks the policy and predicts the hang
   // A PASSIVE instrument that checks a read transfer's acknowledge policy and measures
   // what the transfer cost. It drives nothing and cannot perturb what it observes.
   //
   // A read of n payload bytes has the same shape on the wire as a write -- n+1 bytes and
   // 9(n+1) SCL pulses -- and a completely different acknowledge pattern:
   //
   //     byte 0  (address + R) : ninth bit driven by the SLAVE   -> must be ACK
   //     bytes 1 .. n-1        : ninth bit driven by the MASTER  -> ACK  "send another"
   //     byte n   (the last)   : ninth bit driven by the MASTER  -> NACK "no more"
   //
   // so a well-formed read contains EXACTLY ONE master NACK and it is always in the final
   // slot. That is the fifth NACK condition of section 3.1.6 -- "a master-receiver must
   // signal the end of the transfer to the slave transmitter" -- and it is the only
   // mechanism the protocol offers for saying so: there is no length field and no command
   // for "stop".
   //
   // The instrument therefore checks two things a simple pass/fail monitor cannot:
   //   policy_ok  -- the pattern was n-1 ACKs then one NACK, nothing else
   //   hang_risk  -- the final data byte was ACKED, which means the slave will transmit
   //                 ANOTHER byte and hold SDA low through the window in which SDA must
   //                 rise to form the STOP. The STOP cannot form and the bus hangs.
   //                 This is Chapter 7.4's failure, detected from the acknowledge pattern
   //                 alone, before the hang has happened.
   module i2c_read_ack_policy #(
       parameter int CNT_W = 16
   )(
       input  logic clk,
       input  logic rst_n,
       input  logic scl_in,          // observed bus level
       input  logic frame_start,     // pulse: S or Sr
       input  logic frame_stop,      // pulse: P
       input  logic byte_done,       // pulse: a byte AND its ninth slot completed
       // The ninth bit AS OBSERVED ON THE WIRE: 0 means SDA was pulled LOW, which is an
       // ACK; 1 means SDA stayed HIGH, which is a NACK. The polarity is the bus's, not a
       // convenience -- section 3.1.6 defines the acknowledge as the receiver pulling the
       // line low, so "low is yes" is the physical fact and inverting it here would put a
       // translation between the instrument and the thing it measures.
       input  logic ack_bit,

       output logic [CNT_W-1:0] scl_pulses,
       output logic [CNT_W-1:0] bytes_seen,      // INCLUDING the address byte
       output logic [CNT_W-1:0] payload_bytes,   // bytes_seen - 1, floored at zero
       output logic [CNT_W-1:0] master_acks,     // "send me another"
       output logic [CNT_W-1:0] master_nacks,    // should be exactly one
       output logic             addr_acked,      // the slave answered the address
       output logic             policy_ok,       // n-1 ACKs then exactly one final NACK
       output logic             hang_risk,       // the final data byte was ACKed
       output logic             transfer_active,
       output logic             metrics_valid    // pulse: a STOP closed the transfer
   );
       logic scl_q;
       logic scl_rise;
       assign scl_rise = !scl_q && scl_in;

       // The first byte after an S or Sr is the address byte. Nothing in the frame marks
       // it, so position is the only way to know -- which is exactly why a decoder that
       // misses a repeated START reads an address byte as data (Chapter 7.5, section 10).
       logic expect_address;

       // Whether the most recent DATA byte was acknowledged. This is the whole basis of
       // the hang prediction, and it must be the LAST one rather than "any of them".
       logic last_data_acked;

       // The address byte carries no payload, so it is excluded -- and the subtraction is
       // guarded, because bytes_seen is zero before the first byte completes and an
       // unguarded 0 - 1 would wrap to a very large number rather than to zero.
       assign payload_bytes = (bytes_seen == '0) ? '0 : (bytes_seen - 1'b1);

       // A well-formed read: every data byte but the last was ACKed, the last was NACKed,
       // and there was exactly one NACK in total. An address-only probe (no data bytes at
       // all) is well-formed too and produces no master acknowledges whatsoever, so it is
       // admitted explicitly rather than falling out of the arithmetic by accident.
       assign policy_ok = (payload_bytes == '0)
                        ? ((master_acks == '0) && (master_nacks == '0))
                        : ((master_nacks == {{(CNT_W-1){1'b0}}, 1'b1})
                           && (master_acks == (payload_bytes - 1'b1))
                           && !last_data_acked);

       // The prediction. If the final data byte was ACKed, the slave-transmitter has been
       // told "send another" and will drive the next byte's MSB. Whenever that bit is a
       // zero the slave holds SDA low, so the master's STOP -- which needs SDA to RISE
       // while SCL is high -- cannot be formed at all.
       assign hang_risk = (payload_bytes != '0) && last_data_acked;

       always_ff @(posedge clk) begin
           if (!rst_n) begin
               scl_q           <= 1'b1;   // idle bus: SCL released, therefore high
               scl_pulses      <= '0;
               bytes_seen      <= '0;
               master_acks     <= '0;
               master_nacks    <= '0;
               addr_acked      <= 1'b0;
               expect_address  <= 1'b1;
               last_data_acked <= 1'b0;
               transfer_active <= 1'b0;
               metrics_valid   <= 1'b0;
           end else begin
               metrics_valid <= 1'b0;
               scl_q         <= scl_in;

               if (frame_stop) begin
                   // The counters are deliberately NOT cleared here: a consumer reads them
                   // AFTER the transfer. The next frame_start clears them instead.
                   if (transfer_active) metrics_valid <= 1'b1;
                   transfer_active <= 1'b0;
               end else if (frame_start) begin
                   // An S or Sr begins a new measurement AND a new addressing. Both halves
                   // matter: the byte after an Sr is an address again, so expect_address
                   // must be re-armed or every post-Sr read would be counted as data.
                   scl_pulses      <= '0;
                   bytes_seen      <= '0;
                   master_acks     <= '0;
                   master_nacks    <= '0;
                   addr_acked      <= 1'b0;
                   expect_address  <= 1'b1;
                   last_data_acked <= 1'b0;
                   transfer_active <= 1'b1;
               end else if (transfer_active) begin
                   if (scl_rise) scl_pulses <= scl_pulses + 1'b1;

                   if (byte_done) begin
                       bytes_seen <= bytes_seen + 1'b1;

                       if (expect_address) begin
                           // The address byte's ninth bit is the SLAVE's, not the master's.
                           // Counting it as a master acknowledge is the single easiest way
                           // to get this instrument wrong, and it would make every read
                           // report one acknowledge too many.
                           addr_acked     <= !ack_bit;
                           expect_address <= 1'b0;
                       end else begin
                           // From here the ninth bit is the master's.
                           last_data_acked <= !ack_bit;
                           if (!ack_bit) master_acks  <= master_acks  + 1'b1;
                           else          master_nacks <= master_nacks + 1'b1;
                       end
                   end
               end
           end
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_ack_policy_tb.sv — ten scenarios, including both malformed patterns and the hang
   `timescale 1ns/1ps
   module i2c_read_ack_policy_tb;
       localparam int CNT_W = 16;

       logic clk = 1'b0;
       always #5 clk = ~clk;

       logic rst_n = 1'b0;
       logic scl_in = 1'b1;
       logic frame_start = 1'b0, frame_stop = 1'b0, byte_done = 1'b0, ack_bit = 1'b0;
       logic [CNT_W-1:0] scl_pulses, bytes_seen, payload_bytes, master_acks, master_nacks;
       logic addr_acked, policy_ok, hang_risk, transfer_active, metrics_valid;

       int errors = 0;

       i2c_read_ack_policy #(.CNT_W(CNT_W)) dut (.*);

       initial begin #400000; $display("FAIL: watchdog expired"); $finish; end

       int n_valid;
       logic obs_clear = 1'b0;
       always @(posedge clk) if (rst_n) begin
         if (obs_clear) n_valid = 0;
         else if (metrics_valid) n_valid++;
       end
       task automatic clear_obs();
           obs_clear = 1'b1; @(negedge clk); obs_clear = 1'b0; @(negedge clk);
       endtask

       task automatic scl_pulse();
           scl_in = 1'b0; @(negedge clk);
           scl_in = 1'b1; @(negedge clk);
           scl_in = 1'b0; @(negedge clk);
       endtask

       // One byte: nine SCL pulses, then the byte_done the engine of Chapter 7.1 emits,
       // carrying the ninth bit AS OBSERVED -- 0 for ACK, 1 for NACK.
       task automatic wire_byte(input logic ninth);
           repeat (9) scl_pulse();
           ack_bit   = ninth;
           byte_done = 1'b1; @(negedge clk); byte_done = 1'b0; @(negedge clk);
       endtask

       task automatic pulse_start(); frame_start = 1'b1; @(negedge clk); frame_start = 1'b0; @(negedge clk); endtask
       task automatic pulse_stop();  frame_stop  = 1'b1; @(negedge clk); frame_stop  = 1'b0; @(negedge clk); endtask

       // A WELL-FORMED read of n payload bytes: address ACKed by the slave, then n-1
       // master ACKs, then one master NACK.
       task automatic read_burst(input int n);
           pulse_start();
           wire_byte(1'b0);                                     // address + R, slave ACKs
           for (int i = 0; i < n; i++)
               wire_byte((i == n - 1) ? 1'b1 : 1'b0);           // NACK only the last
           pulse_stop();
       endtask

       task automatic check_read(input int n);
           int exp_pulses, exp_acks;
           exp_pulses = 9 * (n + 1);
           exp_acks   = (n == 0) ? 0 : n - 1;
           if (bytes_seen !== CNT_W'(n + 1)) begin
               $display("FAIL: n=%0d -- bytes_seen %0d, expected %0d", n, bytes_seen, n + 1);
               errors++; end
           if (scl_pulses !== CNT_W'(exp_pulses)) begin
               $display("FAIL: n=%0d -- scl_pulses %0d, expected 9(n+1) = %0d",
                        n, scl_pulses, exp_pulses); errors++; end
           if (payload_bytes !== CNT_W'(n)) begin
               $display("FAIL: n=%0d -- payload_bytes %0d, expected %0d", n, payload_bytes, n);
               errors++; end
           if (master_acks !== CNT_W'(exp_acks)) begin
               $display("FAIL: n=%0d -- master_acks %0d, expected n-1 = %0d",
                        n, master_acks, exp_acks); errors++; end
           if (master_nacks !== CNT_W'((n == 0) ? 0 : 1)) begin
               $display("FAIL: n=%0d -- master_nacks %0d, expected %0d",
                        n, master_nacks, (n == 0) ? 0 : 1); errors++; end
           if (addr_acked !== 1'b1) begin
               $display("FAIL: n=%0d -- addr_acked not set", n); errors++; end
           if (policy_ok !== 1'b1) begin
               $display("FAIL: n=%0d -- a well-formed read was reported as policy violation", n);
               errors++; end
           if (hang_risk !== 1'b0) begin
               $display("FAIL: n=%0d -- spurious hang_risk on a well-formed read", n);
               errors++; end
       endtask

       initial begin
           repeat (3) @(negedge clk);
           if (transfer_active !== 1'b0) begin $display("FAIL: active out of reset"); errors++; end
           if (payload_bytes !== '0) begin
               $display("FAIL: payload_bytes %0d before any byte -- the guarded subtraction wrapped",
                        payload_bytes); errors++; end
           if (hang_risk !== 1'b0) begin
               $display("FAIL: hang_risk out of reset"); errors++; end
           rst_n = 1'b1; @(negedge clk);
           clear_obs();

           // ---- 1: well-formed reads across a range of lengths.
           read_burst(1); check_read(1);
           read_burst(2); check_read(2);
           read_burst(4); check_read(4);
           read_burst(8); check_read(8);

           // ---- 2: a ONE-byte read. Its only master acknowledge is the NACK, so
           //      master_acks is ZERO. An instrument that assumed at least one ACK per
           //      read reports a policy violation here and nowhere else.
           read_burst(1);
           if (master_acks !== '0) begin
               $display("FAIL: a 1-byte read reported %0d master ACKs, expected 0", master_acks);
               errors++; end
           if (master_nacks !== 16'd1 || policy_ok !== 1'b1) begin
               $display("FAIL: a 1-byte read is well-formed and was not reported so"); errors++; end

           // ---- 3: an ADDRESS-ONLY probe with R/W = 1. One byte, the slave's ACK, and NO
           //      master acknowledges at all -- the master never became a receiver.
           pulse_start();
           wire_byte(1'b0);
           pulse_stop();
           check_read(0);
           if (master_acks !== '0 || master_nacks !== '0) begin
               $display("FAIL: a read probe produced master acknowledges"); errors++; end

           // ---- 4: THE HANG. The master ACKs the final byte instead of NACKing it. The
           //      slave has been told "send another", will drive the next byte, and holds
           //      SDA low -- so the STOP cannot form. The instrument must predict this
           //      from the acknowledge pattern, before the hang happens.
           pulse_start();
           wire_byte(1'b0);                       // address + R, slave ACKs
           wire_byte(1'b0); wire_byte(1'b0);      // two data bytes, BOTH ACKed
           if (hang_risk !== 1'b1) begin
               $display("FAIL: the final byte was ACKed and hang_risk was not raised"); errors++; end
           if (policy_ok !== 1'b0) begin
               $display("FAIL: ACKing the final byte is a policy violation and was not flagged");
               errors++; end
           if (master_acks !== 16'd2 || master_nacks !== '0) begin
               $display("FAIL: hang case counted %0d ACKs and %0d NACKs, expected 2 and 0",
                        master_acks, master_nacks); errors++; end
           pulse_stop();

           // ---- 5: TWO NACKs. A master that NACKs a middle byte and then keeps reading
           //      has violated the policy even though the final slot is a NACK, so the
           //      final-slot check alone is not sufficient.
           pulse_start();
           wire_byte(1'b0);                       // address
           wire_byte(1'b1);                       // data byte 1 NACKed -- ends it, but...
           wire_byte(1'b1);                       // ...another byte read anyway
           if (master_nacks !== 16'd2) begin
               $display("FAIL: counted %0d NACKs, expected 2", master_nacks); errors++; end
           if (policy_ok !== 1'b0) begin
               $display("FAIL: two NACKs in one read is a violation and was not flagged");
               errors++; end
           pulse_stop();

           // ---- 6: the ADDRESS was NACKed. Nobody is there. addr_acked must be clear,
           //      and this must NOT be counted as a master acknowledge -- the address
           //      byte's ninth bit belongs to the slave.
           pulse_start();
           wire_byte(1'b1);                       // address + R, NOBODY answers
           pulse_stop();
           if (addr_acked !== 1'b0) begin
               $display("FAIL: addr_acked set on an unanswered address"); errors++; end
           if (master_nacks !== '0 || master_acks !== '0) begin
               $display("FAIL: the address byte's NACK was counted as the master's (%0d/%0d)",
                        master_acks, master_nacks); errors++; end
           if (bytes_seen !== 16'd1) begin
               $display("FAIL: bytes_seen %0d after an unanswered address", bytes_seen); errors++; end

           // ---- 7: the metrics must SURVIVE the STOP, because that is when they are read.
           if (transfer_active !== 1'b0) begin $display("FAIL: still active after the STOP"); errors++; end
           if (bytes_seen === '0) begin
               $display("FAIL: the counters were cleared by the STOP"); errors++; end

           // ---- 8: a repeated START re-arms the ADDRESS expectation. The byte after an Sr
           //      is an address again, so a design that did not re-arm would count it as a
           //      data byte and report one master acknowledge too many.
           pulse_start();
           wire_byte(1'b0); wire_byte(1'b0); wire_byte(1'b1);   // a 2-byte read
           pulse_start();                                        // Sr
           if (bytes_seen !== '0) begin
               $display("FAIL: a repeated START did not restart the measurement"); errors++; end
           wire_byte(1'b0);                                      // the post-Sr ADDRESS
           wire_byte(1'b0); wire_byte(1'b1);                     // two data bytes
           pulse_stop();
           check_read(2);

           // ---- 9: an IDLE BUS must not be measured. Between transfers SCL keeps moving,
           //      and counting any of it would corrupt the totals a consumer reads.
           begin
               int snap_pulses, snap_bytes;
               snap_pulses = scl_pulses; snap_bytes = bytes_seen;
               repeat (6) scl_pulse();
               wire_byte(1'b0);
               if (scl_pulses !== snap_pulses[CNT_W-1:0] || bytes_seen !== snap_bytes[CNT_W-1:0]) begin
                   $display("FAIL: idle-bus activity was counted -- %0d/%0d, expected %0d/%0d",
                            scl_pulses, bytes_seen, snap_pulses, snap_bytes); errors++; end
               if (transfer_active !== 1'b0) begin
                   $display("FAIL: clocking an idle bus opened a transfer"); errors++; end
           end

           // ---- 10: a STOP that closed nothing must not announce a measurement.
           begin
               int snap_valid;
               snap_valid = n_valid;
               pulse_stop();
               if (n_valid !== snap_valid) begin
                   $display("FAIL: a STOP that closed nothing produced metrics_valid"); errors++; end
           end

           // one metrics_valid per completed transfer: 4 bursts + 1 + probe + hang + two-NACK
           // + addr-NACK + the Sr transfer = 10.
           if (n_valid !== 10) begin
               $display("FAIL: %0d metrics_valid pulses, expected 10", n_valid); errors++; end

           if (errors == 0)
               $display("PASS: ack pattern is n-1 ACKs then one NACK, the address byte's answer is the slave's, the hang is predicted, both malformed patterns rejected");
           else $display("FAIL: %0d error(s)", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_ack_policy.v — the same instrument in Verilog-2001
   // A PASSIVE instrument  (Verilog-2001) that checks a read transfer's acknowledge policy and measures
   // what the transfer cost. It drives nothing and cannot perturb what it observes.
   //
   // A read of n payload bytes has the same shape on the wire as a write -- n+1 bytes and
   // 9(n+1) SCL pulses -- and a completely different acknowledge pattern:
   //
   //     byte 0  (address + R) : ninth bit driven by the SLAVE   -> must be ACK
   //     bytes 1 .. n-1        : ninth bit driven by the MASTER  -> ACK  "send another"
   //     byte n   (the last)   : ninth bit driven by the MASTER  -> NACK "no more"
   //
   // so a well-formed read contains EXACTLY ONE master NACK and it is always in the final
   // slot. That is the fifth NACK condition of section 3.1.6 -- "a master-receiver must
   // signal the end of the transfer to the slave transmitter" -- and it is the only
   // mechanism the protocol offers for saying so: there is no length field and no command
   // for "stop".
   //
   // The instrument therefore checks two things a simple pass/fail monitor cannot:
   //   policy_ok  -- the pattern was n-1 ACKs then one NACK, nothing else
   //   hang_risk  -- the final data byte was ACKED, which means the slave will transmit
   //                 ANOTHER byte and hold SDA low through the window in which SDA must
   //                 rise to form the STOP. The STOP cannot form and the bus hangs.
   //                 This is Chapter 7.4's failure, detected from the acknowledge pattern
   //                 alone, before the hang has happened.
   module i2c_read_ack_policy #(
       parameter CNT_W = 16
   )(
       input  wire  clk,
       input  wire  rst_n,
       input  wire  scl_in,          // observed bus level
       input  wire  frame_start,     // pulse: S or Sr
       input  wire  frame_stop,      // pulse: P
       input  wire  byte_done,       // pulse: a byte AND its ninth slot completed
       // The ninth bit AS OBSERVED ON THE WIRE: 0 means SDA was pulled LOW, which is an
       // ACK; 1 means SDA stayed HIGH, which is a NACK. The polarity is the bus's, not a
       // convenience -- section 3.1.6 defines the acknowledge as the receiver pulling the
       // line low, so "low is yes" is the physical fact and inverting it here would put a
       // translation between the instrument and the thing it measures.
       input  wire  ack_bit,

       output reg   [CNT_W-1:0] scl_pulses,
       output reg   [CNT_W-1:0] bytes_seen,      // INCLUDING the address byte
       output wire  [CNT_W-1:0] payload_bytes,   // bytes_seen - 1, floored at zero
       output reg   [CNT_W-1:0] master_acks,     // "send me another"
       output reg   [CNT_W-1:0] master_nacks,    // should be exactly one
       output reg               addr_acked,      // the slave answered the address
       output wire               policy_ok,       // n-1 ACKs then exactly one final NACK
       output wire               hang_risk,       // the final data byte was ACKed
       output reg               transfer_active,
       output reg               metrics_valid    // pulse: a STOP closed the transfer
   );
       reg  scl_q;
       wire scl_rise;
       assign scl_rise = !scl_q && scl_in;

       // The first byte after an S or Sr is the address byte. Nothing in the frame marks
       // it, so position is the only way to know -- which is exactly why a decoder that
       // misses a repeated START reads an address byte as data (Chapter 7.5, section 10).
       reg expect_address;

       // Whether the most recent DATA byte was acknowledged. This is the whole basis of
       // the hang prediction, and it must be the LAST one rather than "any of them".
       reg last_data_acked;

       // The address byte carries no payload, so it is excluded -- and the subtraction is
       // guarded, because bytes_seen is zero before the first byte completes and an
       // unguarded 0 - 1 would wrap to a very large number rather than to zero.
       assign payload_bytes = (bytes_seen == {CNT_W{1'b0}}) ? {CNT_W{1'b0}} : (bytes_seen - 1'b1);

       // A well-formed read: every data byte but the last was ACKed, the last was NACKed,
       // and there was exactly one NACK in total. An address-only probe (no data bytes at
       // all) is well-formed too and produces no master acknowledges whatsoever, so it is
       // admitted explicitly rather than falling out of the arithmetic by accident.
       assign policy_ok = (payload_bytes == {CNT_W{1'b0}})
                        ? ((master_acks == {CNT_W{1'b0}}) && (master_nacks == {CNT_W{1'b0}}))
                        : ((master_nacks == {{(CNT_W-1){1'b0}}, 1'b1})
                           && (master_acks == (payload_bytes - 1'b1))
                           && !last_data_acked);

       // The prediction. If the final data byte was ACKed, the slave-transmitter has been
       // told "send another" and will drive the next byte's MSB. Whenever that bit is a
       // zero the slave holds SDA low, so the master's STOP -- which needs SDA to RISE
       // while SCL is high -- cannot be formed at all.
       assign hang_risk = (payload_bytes != {CNT_W{1'b0}}) && last_data_acked;

       always @(posedge clk) begin
           if (!rst_n) begin
               scl_q           <= 1'b1;   // idle bus: SCL released, therefore high
               scl_pulses      <= {CNT_W{1'b0}};
               bytes_seen      <= {CNT_W{1'b0}};
               master_acks     <= {CNT_W{1'b0}};
               master_nacks    <= {CNT_W{1'b0}};
               addr_acked      <= 1'b0;
               expect_address  <= 1'b1;
               last_data_acked <= 1'b0;
               transfer_active <= 1'b0;
               metrics_valid   <= 1'b0;
           end else begin
               metrics_valid <= 1'b0;
               scl_q         <= scl_in;

               if (frame_stop) begin
                   // The counters are deliberately NOT cleared here: a consumer reads them
                   // AFTER the transfer. The next frame_start clears them instead.
                   if (transfer_active) metrics_valid <= 1'b1;
                   transfer_active <= 1'b0;
               end else if (frame_start) begin
                   // An S or Sr begins a new measurement AND a new addressing. Both halves
                   // matter: the byte after an Sr is an address again, so expect_address
                   // must be re-armed or every post-Sr read would be counted as data.
                   scl_pulses      <= {CNT_W{1'b0}};
                   bytes_seen      <= {CNT_W{1'b0}};
                   master_acks     <= {CNT_W{1'b0}};
                   master_nacks    <= {CNT_W{1'b0}};
                   addr_acked      <= 1'b0;
                   expect_address  <= 1'b1;
                   last_data_acked <= 1'b0;
                   transfer_active <= 1'b1;
               end else if (transfer_active) begin
                   if (scl_rise) scl_pulses <= scl_pulses + 1'b1;

                   if (byte_done) begin
                       bytes_seen <= bytes_seen + 1'b1;

                       if (expect_address) begin
                           // The address byte's ninth bit is the SLAVE's, not the master's.
                           // Counting it as a master acknowledge is the single easiest way
                           // to get this instrument wrong, and it would make every read
                           // report one acknowledge too many.
                           addr_acked     <= !ack_bit;
                           expect_address <= 1'b0;
                       end else begin
                           // From here the ninth bit is the master's.
                           last_data_acked <= !ack_bit;
                           if (!ack_bit) master_acks  <= master_acks  + 1'b1;
                           else          master_nacks <= master_nacks + 1'b1;
                       end
                   end
               end
           end
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_ack_policy_tb.v — the Verilog testbench, structurally identical
   `timescale 1ns/1ps
   module i2c_read_ack_policy_tb;   // Verilog-2001
       localparam CNT_W = 16;

       reg clk = 1'b0;
       always #5 clk = ~clk;

       reg rst_n = 1'b0;
       reg scl_in = 1'b1;
       reg frame_start = 1'b0, frame_stop = 1'b0, byte_done = 1'b0, ack_bit = 1'b0;
       wire [CNT_W-1:0] scl_pulses, bytes_seen, payload_bytes, master_acks, master_nacks;
       wire addr_acked, policy_ok, hang_risk, transfer_active, metrics_valid;

       integer errors = 0;
       integer i;
       integer exp_pulses, exp_acks;
       integer snap_pulses, snap_bytes, snap_valid;

       i2c_read_ack_policy #(.CNT_W(CNT_W)) dut (
           .clk(clk), .rst_n(rst_n), .scl_in(scl_in), .frame_start(frame_start),
           .frame_stop(frame_stop), .byte_done(byte_done), .ack_bit(ack_bit),
           .scl_pulses(scl_pulses), .bytes_seen(bytes_seen), .payload_bytes(payload_bytes),
           .master_acks(master_acks), .master_nacks(master_nacks), .addr_acked(addr_acked),
           .policy_ok(policy_ok), .hang_risk(hang_risk), .transfer_active(transfer_active),
           .metrics_valid(metrics_valid));

       initial begin #400000; $display("FAIL: watchdog expired"); $finish; end

       integer n_valid = 0;
       reg obs_clear = 1'b0;
       always @(posedge clk) if (rst_n) begin
         if (obs_clear) n_valid = 0;
         else if (metrics_valid) n_valid = n_valid + 1;
       end
       task clear_obs; begin
           obs_clear = 1'b1; @(negedge clk); obs_clear = 1'b0; @(negedge clk);
       end endtask

       task scl_pulse; begin
           scl_in = 1'b0; @(negedge clk);
           scl_in = 1'b1; @(negedge clk);
           scl_in = 1'b0; @(negedge clk);
       end endtask

       // One byte: nine SCL pulses, then the byte_done the engine of Chapter 7.1 emits,
       // carrying the ninth bit AS OBSERVED -- 0 for ACK, 1 for NACK.
       task wire_byte;
           input ninth;
           begin
           repeat (9) scl_pulse;
           ack_bit   = ninth;
           byte_done = 1'b1; @(negedge clk); byte_done = 1'b0; @(negedge clk);
           end
       endtask

       task pulse_start; begin frame_start = 1'b1; @(negedge clk); frame_start = 1'b0; @(negedge clk); end endtask
       task pulse_stop;  begin frame_stop  = 1'b1; @(negedge clk); frame_stop  = 1'b0; @(negedge clk); end endtask

       // A WELL-FORMED read of n payload bytes: address ACKed by the slave, then n-1
       // master ACKs, then one master NACK.
       task read_burst;
           input integer n;
           begin
               pulse_start;
               wire_byte(1'b0);                                 // address + R, slave ACKs
               for (i = 0; i < n; i = i + 1)
                   wire_byte((i == n - 1) ? 1'b1 : 1'b0);       // NACK only the last
               pulse_stop;
           end
       endtask

       task check_read;
           input integer n;
           begin
           exp_pulses = 9 * (n + 1);
           exp_acks   = (n == 0) ? 0 : n - 1;
           if (bytes_seen !== (n + 1)) begin
               $display("FAIL: n=%0d -- bytes_seen %0d, expected %0d", n, bytes_seen, n + 1);
               errors = errors + 1; end
           if (scl_pulses !== exp_pulses) begin
               $display("FAIL: n=%0d -- scl_pulses %0d, expected 9(n+1) = %0d",
                        n, scl_pulses, exp_pulses); errors = errors + 1; end
           if (payload_bytes !== n) begin
               $display("FAIL: n=%0d -- payload_bytes %0d, expected %0d", n, payload_bytes, n);
               errors = errors + 1; end
           if (master_acks !== exp_acks) begin
               $display("FAIL: n=%0d -- master_acks %0d, expected n-1 = %0d",
                        n, master_acks, exp_acks); errors = errors + 1; end
           if (master_nacks !== ((n == 0) ? 0 : 1)) begin
               $display("FAIL: n=%0d -- master_nacks %0d, expected %0d",
                        n, master_nacks, (n == 0) ? 0 : 1); errors = errors + 1; end
           if (addr_acked !== 1'b1) begin
               $display("FAIL: n=%0d -- addr_acked not set", n); errors = errors + 1; end
           if (policy_ok !== 1'b1) begin
               $display("FAIL: n=%0d -- a well-formed read was reported as policy violation", n);
               errors = errors + 1; end
           if (hang_risk !== 1'b0) begin
               $display("FAIL: n=%0d -- spurious hang_risk on a well-formed read", n);
               errors = errors + 1; end
           end
       endtask

       initial begin
           repeat (3) @(negedge clk);
           if (transfer_active !== 1'b0) begin $display("FAIL: active out of reset"); errors = errors + 1; end
           if (payload_bytes !== {CNT_W{1'b0}}) begin
               $display("FAIL: payload_bytes %0d before any byte -- the guarded subtraction wrapped",
                        payload_bytes); errors = errors + 1; end
           if (hang_risk !== 1'b0) begin
               $display("FAIL: hang_risk out of reset"); errors = errors + 1; end
           rst_n = 1'b1; @(negedge clk);
           clear_obs;

           // ---- 1: well-formed reads across a range of lengths.
           read_burst(1); check_read(1);
           read_burst(2); check_read(2);
           read_burst(4); check_read(4);
           read_burst(8); check_read(8);

           // ---- 2: a ONE-byte read. Its only master acknowledge is the NACK, so
           //      master_acks is ZERO. An instrument that assumed at least one ACK per
           //      read reports a policy violation here and nowhere else.
           read_burst(1);
           if (master_acks !== {CNT_W{1'b0}}) begin
               $display("FAIL: a 1-byte read reported %0d master ACKs, expected 0", master_acks);
               errors = errors + 1; end
           if (master_nacks !== 16'd1 || policy_ok !== 1'b1) begin
               $display("FAIL: a 1-byte read is well-formed and was not reported so"); errors = errors + 1; end

           // ---- 3: an ADDRESS-ONLY probe with R/W = 1. One byte, the slave's ACK, and NO
           //      master acknowledges at all -- the master never became a receiver.
           pulse_start;
           wire_byte(1'b0);
           pulse_stop;
           check_read(0);
           if (master_acks !== {CNT_W{1'b0}} || master_nacks !== {CNT_W{1'b0}}) begin
               $display("FAIL: a read probe produced master acknowledges"); errors = errors + 1; end

           // ---- 4: THE HANG. The master ACKs the final byte instead of NACKing it. The
           //      slave has been told "send another", will drive the next byte, and holds
           //      SDA low -- so the STOP cannot form. The instrument must predict this
           //      from the acknowledge pattern, before the hang happens.
           pulse_start;
           wire_byte(1'b0);                       // address + R, slave ACKs
           wire_byte(1'b0); wire_byte(1'b0);      // two data bytes, BOTH ACKed
           if (hang_risk !== 1'b1) begin
               $display("FAIL: the final byte was ACKed and hang_risk was not raised"); errors = errors + 1; end
           if (policy_ok !== 1'b0) begin
               $display("FAIL: ACKing the final byte is a policy violation and was not flagged");
               errors = errors + 1; end
           if (master_acks !== 16'd2 || master_nacks !== {CNT_W{1'b0}}) begin
               $display("FAIL: hang case counted %0d ACKs and %0d NACKs, expected 2 and 0",
                        master_acks, master_nacks); errors = errors + 1; end
           pulse_stop;

           // ---- 5: TWO NACKs. A master that NACKs a middle byte and then keeps reading
           //      has violated the policy even though the final slot is a NACK, so the
           //      final-slot check alone is not sufficient.
           pulse_start;
           wire_byte(1'b0);                       // address
           wire_byte(1'b1);                       // data byte 1 NACKed -- ends it, but...
           wire_byte(1'b1);                       // ...another byte read anyway
           if (master_nacks !== 16'd2) begin
               $display("FAIL: counted %0d NACKs, expected 2", master_nacks); errors = errors + 1; end
           if (policy_ok !== 1'b0) begin
               $display("FAIL: two NACKs in one read is a violation and was not flagged");
               errors = errors + 1; end
           pulse_stop;

           // ---- 6: the ADDRESS was NACKed. Nobody is there. addr_acked must be clear,
           //      and this must NOT be counted as a master acknowledge -- the address
           //      byte's ninth bit belongs to the slave.
           pulse_start;
           wire_byte(1'b1);                       // address + R, NOBODY answers
           pulse_stop;
           if (addr_acked !== 1'b0) begin
               $display("FAIL: addr_acked set on an unanswered address"); errors = errors + 1; end
           if (master_nacks !== {CNT_W{1'b0}} || master_acks !== {CNT_W{1'b0}}) begin
               $display("FAIL: the address byte's NACK was counted as the master's (%0d/%0d)",
                        master_acks, master_nacks); errors = errors + 1; end
           if (bytes_seen !== 16'd1) begin
               $display("FAIL: bytes_seen %0d after an unanswered address", bytes_seen); errors = errors + 1; end

           // ---- 7: the metrics must SURVIVE the STOP, because that is when they are read.
           if (transfer_active !== 1'b0) begin $display("FAIL: still active after the STOP"); errors = errors + 1; end
           if (bytes_seen === {CNT_W{1'b0}}) begin
               $display("FAIL: the counters were cleared by the STOP"); errors = errors + 1; end

           // ---- 8: a repeated START re-arms the ADDRESS expectation. The byte after an Sr
           //      is an address again, so a design that did not re-arm would count it as a
           //      data byte and report one master acknowledge too many.
           pulse_start;
           wire_byte(1'b0); wire_byte(1'b0); wire_byte(1'b1);   // a 2-byte read
           pulse_start;                                        // Sr
           if (bytes_seen !== {CNT_W{1'b0}}) begin
               $display("FAIL: a repeated START did not restart the measurement"); errors = errors + 1; end
           wire_byte(1'b0);                                      // the post-Sr ADDRESS
           wire_byte(1'b0); wire_byte(1'b1);                     // two data bytes
           pulse_stop;
           check_read(2);

           // ---- 9: an IDLE BUS must not be measured. Between transfers SCL keeps moving,
           //      and counting any of it would corrupt the totals a consumer reads.
           begin
               snap_pulses = scl_pulses; snap_bytes = bytes_seen;
               repeat (6) scl_pulse;
               wire_byte(1'b0);
               if (scl_pulses !== snap_pulses[CNT_W-1:0] || bytes_seen !== snap_bytes[CNT_W-1:0]) begin
                   $display("FAIL: idle-bus activity was counted -- %0d/%0d, expected %0d/%0d",
                            scl_pulses, bytes_seen, snap_pulses, snap_bytes); errors = errors + 1; end
               if (transfer_active !== 1'b0) begin
                   $display("FAIL: clocking an idle bus opened a transfer"); errors = errors + 1; end
           end

           // ---- 10: a STOP that closed nothing must not announce a measurement.
           begin
               snap_valid = n_valid;
               pulse_stop;
               if (n_valid !== snap_valid) begin
                   $display("FAIL: a STOP that closed nothing produced metrics_valid"); errors = errors + 1; end
           end

           // one metrics_valid per completed transfer: 4 bursts + 1 + probe + hang + two-NACK
           // + addr-NACK + the Sr transfer = 10.
           if (n_valid !== 10) begin
               $display("FAIL: %0d metrics_valid pulses, expected 10", n_valid); errors = errors + 1; end

           if (errors == 0)
               $display("PASS: ack pattern is n-1 ACKs then one NACK, the address byte's answer is the slave's, the hang is predicted, both malformed patterns rejected");
           else $display("FAIL: %0d error(s)", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_ack_policy.vhd — the same instrument in VHDL
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;

   -- A PASSIVE instrument that checks a read transfer's acknowledge policy and measures
   -- what the transfer cost. It drives nothing and cannot perturb what it observes.
   --
   -- A read of n payload bytes has the same shape on the wire as a write -- n+1 bytes and
   -- 9(n+1) SCL pulses -- and a completely different acknowledge pattern:
   --
   --     byte 0  (address + R) : ninth bit driven by the SLAVE   -> must be ACK
   --     bytes 1 .. n-1        : ninth bit driven by the MASTER  -> ACK  "send another"
   --     byte n   (the last)   : ninth bit driven by the MASTER  -> NACK "no more"
   --
   -- so a well-formed read contains EXACTLY ONE master NACK and it is always in the final
   -- slot. That is the fifth NACK condition of section 3.1.6 -- "a master-receiver must
   -- signal the end of the transfer to the slave transmitter" -- and it is the only
   -- mechanism the protocol offers for saying so: there is no length field and no command
   -- for "stop".
   --
   -- The instrument therefore checks two things a simple pass/fail monitor cannot:
   --   policy_ok  -- the pattern was n-1 ACKs then one NACK, nothing else
   --   hang_risk  -- the final data byte was ACKED, which means the slave will transmit
   --                 ANOTHER byte and hold SDA low through the window in which SDA must
   --                 rise to form the STOP. The STOP cannot form and the bus hangs.
   entity i2c_read_ack_policy is
       generic (
           CNT_W : positive := 16
       );
       port (
           clk         : in std_logic;
           rst_n       : in std_logic;
           scl_in      : in std_logic;      -- observed bus level
           frame_start : in std_logic;      -- pulse: S or Sr
           frame_stop  : in std_logic;      -- pulse: P
           byte_done   : in std_logic;      -- pulse: a byte AND its ninth slot completed
           -- The ninth bit AS OBSERVED ON THE WIRE: 0 means SDA was pulled LOW, which is an
           -- ACK; 1 means SDA stayed HIGH, which is a NACK. The polarity is the bus's, not
           -- a convenience -- section 3.1.6 defines the acknowledge as the receiver pulling
           -- the line low, so "low is yes" is the physical fact.
           ack_bit     : in std_logic;

           scl_pulses      : out unsigned(CNT_W - 1 downto 0);
           bytes_seen      : out unsigned(CNT_W - 1 downto 0);   -- INCLUDING the address
           payload_bytes   : out unsigned(CNT_W - 1 downto 0);   -- bytes_seen - 1, floored
           master_acks     : out unsigned(CNT_W - 1 downto 0);   -- "send me another"
           master_nacks    : out unsigned(CNT_W - 1 downto 0);   -- should be exactly one
           addr_acked      : out std_logic;
           policy_ok       : out std_logic;
           hang_risk       : out std_logic;
           transfer_active : out std_logic;
           metrics_valid   : out std_logic
       );
   end entity;

   architecture rtl of i2c_read_ack_policy is
       constant ZERO : unsigned(CNT_W - 1 downto 0) := (others => '0');
       constant ONE  : unsigned(CNT_W - 1 downto 0) := to_unsigned(1, CNT_W);

       signal scl_q    : std_logic := '1';   -- idle bus: SCL released, therefore high
       signal scl_rise : std_logic;

       signal pulses  : unsigned(CNT_W - 1 downto 0) := (others => '0');
       signal nbytes  : unsigned(CNT_W - 1 downto 0) := (others => '0');
       signal n_ack   : unsigned(CNT_W - 1 downto 0) := (others => '0');
       signal n_nack  : unsigned(CNT_W - 1 downto 0) := (others => '0');
       signal active  : std_logic := '0';
       signal payload : unsigned(CNT_W - 1 downto 0);

       -- The first byte after an S or Sr is the address byte. Nothing in the frame marks
       -- it, so position is the only way to know -- which is exactly why a decoder that
       -- misses a repeated START reads an address byte as data (Chapter 7.5, section 10).
       signal expect_address : std_logic := '1';

       -- Whether the most recent DATA byte was acknowledged. This is the whole basis of
       -- the hang prediction, and it must be the LAST one rather than "any of them".
       signal last_data_acked : std_logic := '0';
   begin
       scl_rise <= (not scl_q) and scl_in;

       scl_pulses      <= pulses;
       bytes_seen      <= nbytes;
       master_acks     <= n_ack;
       master_nacks    <= n_nack;
       transfer_active <= active;

       -- The address byte carries no payload, so it is excluded -- and the subtraction is
       -- guarded, because nbytes is zero before the first byte completes and an unguarded
       -- 0 - 1 would wrap to a very large number rather than to zero.
       payload       <= ZERO when nbytes = ZERO else nbytes - 1;
       payload_bytes <= payload;

       -- A well-formed read: every data byte but the last was ACKed, the last was NACKed,
       -- and there was exactly one NACK in total. An address-only probe (no data bytes at
       -- all) is well-formed too and produces no master acknowledges whatsoever, so it is
       -- admitted explicitly rather than falling out of the arithmetic by accident.
       policy_ok <= '1' when (payload = ZERO and n_ack = ZERO and n_nack = ZERO)
                          or (payload /= ZERO and n_nack = ONE and n_ack = payload - 1
                              and last_data_acked = '0')
                        else '0';

       -- The prediction. If the final data byte was ACKed, the slave-transmitter has been
       -- told "send another" and will drive the next byte's MSB. Whenever that bit is a
       -- zero the slave holds SDA low, so the master's STOP -- which needs SDA to RISE
       -- while SCL is high -- cannot be formed at all.
       hang_risk <= '1' when payload /= ZERO and last_data_acked = '1' else '0';

       process (clk)
       begin
           if rising_edge(clk) then
               if rst_n = '0' then
                   scl_q           <= '1';
                   pulses          <= (others => '0');
                   nbytes          <= (others => '0');
                   n_ack           <= (others => '0');
                   n_nack          <= (others => '0');
                   addr_acked      <= '0';
                   expect_address  <= '1';
                   last_data_acked <= '0';
                   active          <= '0';
                   metrics_valid   <= '0';
               else
                   metrics_valid <= '0';
                   scl_q         <= scl_in;

                   if frame_stop = '1' then
                       -- The counters are deliberately NOT cleared here: a consumer reads
                       -- them AFTER the transfer. The next frame_start clears them.
                       if active = '1' then metrics_valid <= '1'; end if;
                       active <= '0';
                   elsif frame_start = '1' then
                       -- An S or Sr begins a new measurement AND a new addressing. Both
                       -- halves matter: the byte after an Sr is an address again, so
                       -- expect_address must be re-armed or every post-Sr read would be
                       -- counted as data.
                       pulses          <= (others => '0');
                       nbytes          <= (others => '0');
                       n_ack           <= (others => '0');
                       n_nack          <= (others => '0');
                       addr_acked      <= '0';
                       expect_address  <= '1';
                       last_data_acked <= '0';
                       active          <= '1';
                   elsif active = '1' then
                       if scl_rise = '1' then pulses <= pulses + 1; end if;

                       if byte_done = '1' then
                           nbytes <= nbytes + 1;

                           if expect_address = '1' then
                               -- The address byte's ninth bit is the SLAVE's, not the
                               -- master's. Counting it as a master acknowledge is the
                               -- single easiest way to get this instrument wrong, and it
                               -- would make every read report one acknowledge too many.
                               addr_acked     <= not ack_bit;
                               expect_address <= '0';
                           else
                               -- From here the ninth bit is the master's.
                               last_data_acked <= not ack_bit;
                               if ack_bit = '0' then n_ack  <= n_ack  + 1;
                               else                  n_nack <= n_nack + 1; end if;
                           end if;
                       end if;
                   end if;
               end if;
           end if;
       end process;
   end architecture;
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_ack_policy_tb.vhd — the VHDL testbench, single-writer throughout
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;

   -- Every signal here has exactly ONE driving process, because VHDL permits one driver
   -- per signal -- and the SystemVerilog and Verilog testbenches were written to the same
   -- discipline so that the matching finish time between the three means something.
   entity i2c_read_ack_policy_tb is
   end entity;

   architecture sim of i2c_read_ack_policy_tb is
       constant CNT_W : positive := 16;

       signal clk         : std_logic := '0';
       signal rst_n       : std_logic := '0';
       signal scl_in      : std_logic := '1';
       signal frame_start : std_logic := '0';
       signal frame_stop  : std_logic := '0';
       signal byte_done   : std_logic := '0';
       signal ack_bit     : std_logic := '0';

       signal scl_pulses, bytes_seen, payload_bytes : unsigned(CNT_W - 1 downto 0);
       signal master_acks, master_nacks             : unsigned(CNT_W - 1 downto 0);
       signal addr_acked, policy_ok, hang_risk      : std_logic;
       signal transfer_active, metrics_valid        : std_logic;

       -- owned solely by the observe process
       signal n_valid   : natural := 0;
       signal obs_clear : std_logic := '0';

       signal test_done : std_logic := '0';
   begin
       dut : entity work.i2c_read_ack_policy
           generic map (CNT_W => CNT_W)
           port map (clk => clk, rst_n => rst_n, scl_in => scl_in,
                     frame_start => frame_start, frame_stop => frame_stop,
                     byte_done => byte_done, ack_bit => ack_bit,
                     scl_pulses => scl_pulses, bytes_seen => bytes_seen,
                     payload_bytes => payload_bytes, master_acks => master_acks,
                     master_nacks => master_nacks, addr_acked => addr_acked,
                     policy_ok => policy_ok, hang_risk => hang_risk,
                     transfer_active => transfer_active, metrics_valid => metrics_valid);

       clk <= not clk after 5 ns;

       watchdog : process
       begin
           wait for 500 us;
           if test_done = '0' then
               report "watchdog expired -- the design never reached the expected state"
                   severity failure;
           end if;
           wait;
       end process;

       observe : process (clk)
       begin
           if rising_edge(clk) and rst_n = '1' then
               if obs_clear = '1' then
                   n_valid <= 0;
               elsif metrics_valid = '1' then
                   n_valid <= n_valid + 1;
               end if;
           end if;
       end process;

       stim : process
           variable errs : natural := 0;
           variable snap_pulses, snap_bytes : unsigned(CNT_W - 1 downto 0);
           variable snap_valid : natural;

           procedure waitn (n : in positive) is
           begin
               for i in 1 to n loop wait until falling_edge(clk); end loop;
           end procedure;

           procedure clear_obs is
           begin
               obs_clear <= '1'; waitn(1); obs_clear <= '0'; waitn(1);
           end procedure;

           procedure scl_pulse is
           begin
               scl_in <= '0'; waitn(1);
               scl_in <= '1'; waitn(1);
               scl_in <= '0'; waitn(1);
           end procedure;

           -- One byte: nine SCL pulses, then the byte_done the engine of Chapter 7.1
           -- emits, carrying the ninth bit AS OBSERVED -- 0 for ACK, 1 for NACK.
           procedure wire_byte (ninth : in std_logic) is
           begin
               for i in 1 to 9 loop scl_pulse; end loop;
               ack_bit   <= ninth;
               byte_done <= '1'; waitn(1); byte_done <= '0'; waitn(1);
           end procedure;

           procedure pulse_start is
           begin
               frame_start <= '1'; waitn(1); frame_start <= '0'; waitn(1);
           end procedure;

           procedure pulse_stop is
           begin
               frame_stop <= '1'; waitn(1); frame_stop <= '0'; waitn(1);
           end procedure;

           -- A WELL-FORMED read of n payload bytes: address ACKed by the slave, then n-1
           -- master ACKs, then one master NACK.
           procedure read_burst (n : in natural) is
           begin
               pulse_start;
               wire_byte('0');                          -- address + R, slave ACKs
               for i in 0 to n - 1 loop
                   if i = n - 1 then wire_byte('1');    -- NACK only the last
                   else              wire_byte('0'); end if;
               end loop;
               pulse_stop;
           end procedure;

           procedure check_read (n : in natural) is
               variable exp_pulses, exp_acks, exp_nacks : natural;
           begin
               exp_pulses := 9 * (n + 1);
               if n = 0 then exp_acks := 0; exp_nacks := 0;
               else          exp_acks := n - 1; exp_nacks := 1; end if;
               if bytes_seen /= to_unsigned(n + 1, CNT_W) then
                   report "n=" & integer'image(n) & ": bytes_seen wrong" severity error;
                   errs := errs + 1; end if;
               if scl_pulses /= to_unsigned(exp_pulses, CNT_W) then
                   report "n=" & integer'image(n) & ": scl_pulses is not 9(n+1)" severity error;
                   errs := errs + 1; end if;
               if payload_bytes /= to_unsigned(n, CNT_W) then
                   report "n=" & integer'image(n) & ": payload_bytes wrong" severity error;
                   errs := errs + 1; end if;
               if master_acks /= to_unsigned(exp_acks, CNT_W) then
                   report "n=" & integer'image(n) & ": master_acks is not n-1" severity error;
                   errs := errs + 1; end if;
               if master_nacks /= to_unsigned(exp_nacks, CNT_W) then
                   report "n=" & integer'image(n) & ": master_nacks wrong" severity error;
                   errs := errs + 1; end if;
               if addr_acked /= '1' then
                   report "n=" & integer'image(n) & ": addr_acked not set" severity error;
                   errs := errs + 1; end if;
               if policy_ok /= '1' then
                   report "n=" & integer'image(n) & ": a well-formed read was reported as a "
                        & "policy violation" severity error;
                   errs := errs + 1; end if;
               if hang_risk /= '0' then
                   report "n=" & integer'image(n) & ": spurious hang_risk" severity error;
                   errs := errs + 1; end if;
           end procedure;
       begin
           waitn(3);
           if transfer_active /= '0' then
               report "active out of reset" severity error; errs := errs + 1; end if;
           if payload_bytes /= to_unsigned(0, CNT_W) then
               report "payload_bytes nonzero before any byte -- the guarded subtraction wrapped"
                   severity error; errs := errs + 1; end if;
           if hang_risk /= '0' then
               report "hang_risk out of reset" severity error; errs := errs + 1; end if;
           rst_n <= '1'; waitn(1);
           clear_obs;

           -- 1: well-formed reads across a range of lengths.
           read_burst(1); check_read(1);
           read_burst(2); check_read(2);
           read_burst(4); check_read(4);
           read_burst(8); check_read(8);

           -- 2: a ONE-byte read. Its only master acknowledge is the NACK, so master_acks
           -- is ZERO. An instrument that assumed at least one ACK per read reports a policy
           -- violation here and nowhere else.
           read_burst(1);
           if master_acks /= to_unsigned(0, CNT_W) then
               report "a 1-byte read reported master ACKs, expected none" severity error;
               errs := errs + 1; end if;
           if master_nacks /= to_unsigned(1, CNT_W) or policy_ok /= '1' then
               report "a 1-byte read is well-formed and was not reported so" severity error;
               errs := errs + 1; end if;

           -- 3: an ADDRESS-ONLY probe with R/W = 1. One byte, the slave's ACK, and NO
           -- master acknowledges at all -- the master never became a receiver.
           pulse_start;
           wire_byte('0');
           pulse_stop;
           check_read(0);
           if master_acks /= to_unsigned(0, CNT_W) or master_nacks /= to_unsigned(0, CNT_W) then
               report "a read probe produced master acknowledges" severity error;
               errs := errs + 1; end if;

           -- 4: THE HANG. The master ACKs the final byte instead of NACKing it. The slave
           -- has been told "send another", will drive the next byte, and holds SDA low --
           -- so the STOP cannot form. The instrument must predict this from the
           -- acknowledge pattern, before the hang happens.
           pulse_start;
           wire_byte('0');                    -- address + R, slave ACKs
           wire_byte('0'); wire_byte('0');    -- two data bytes, BOTH ACKed
           if hang_risk /= '1' then
               report "the final byte was ACKed and hang_risk was not raised" severity error;
               errs := errs + 1; end if;
           if policy_ok /= '0' then
               report "ACKing the final byte is a policy violation and was not flagged"
                   severity error; errs := errs + 1; end if;
           if master_acks /= to_unsigned(2, CNT_W) or master_nacks /= to_unsigned(0, CNT_W) then
               report "hang case counted the wrong acknowledges" severity error;
               errs := errs + 1; end if;
           pulse_stop;

           -- 5: TWO NACKs. A master that NACKs a middle byte and then keeps reading has
           -- violated the policy even though the final slot is a NACK, so the final-slot
           -- check alone is not sufficient.
           pulse_start;
           wire_byte('0');                    -- address
           wire_byte('1');                    -- data byte 1 NACKed -- ends it, but...
           wire_byte('1');                    -- ...another byte read anyway
           if master_nacks /= to_unsigned(2, CNT_W) then
               report "counted the wrong number of NACKs, expected 2" severity error;
               errs := errs + 1; end if;
           if policy_ok /= '0' then
               report "two NACKs in one read is a violation and was not flagged" severity error;
               errs := errs + 1; end if;
           pulse_stop;

           -- 6: the ADDRESS was NACKed. Nobody is there. addr_acked must be clear, and this
           -- must NOT be counted as a master acknowledge -- the address byte's ninth bit
           -- belongs to the slave.
           pulse_start;
           wire_byte('1');                    -- address + R, NOBODY answers
           pulse_stop;
           if addr_acked /= '0' then
               report "addr_acked set on an unanswered address" severity error;
               errs := errs + 1; end if;
           if master_nacks /= to_unsigned(0, CNT_W) or master_acks /= to_unsigned(0, CNT_W) then
               report "the address byte's NACK was counted as the master's" severity error;
               errs := errs + 1; end if;
           if bytes_seen /= to_unsigned(1, CNT_W) then
               report "bytes_seen wrong after an unanswered address" severity error;
               errs := errs + 1; end if;

           -- 7: the metrics must SURVIVE the STOP, because that is when they are read.
           if transfer_active /= '0' then
               report "still active after the STOP" severity error; errs := errs + 1; end if;
           if bytes_seen = to_unsigned(0, CNT_W) then
               report "the counters were cleared by the STOP" severity error;
               errs := errs + 1; end if;

           -- 8: a repeated START re-arms the ADDRESS expectation. The byte after an Sr is
           -- an address again, so a design that did not re-arm would count it as a data
           -- byte and report one master acknowledge too many.
           pulse_start;
           wire_byte('0'); wire_byte('0'); wire_byte('1');   -- a 2-byte read
           pulse_start;                                       -- Sr
           if bytes_seen /= to_unsigned(0, CNT_W) then
               report "a repeated START did not restart the measurement" severity error;
               errs := errs + 1; end if;
           wire_byte('0');                                    -- the post-Sr ADDRESS
           wire_byte('0'); wire_byte('1');                    -- two data bytes
           pulse_stop;
           check_read(2);

           -- 9: an IDLE BUS must not be measured. Between transfers SCL keeps moving, and
           -- counting any of it would corrupt the totals a consumer reads.
           snap_pulses := scl_pulses; snap_bytes := bytes_seen;
           for i in 1 to 6 loop scl_pulse; end loop;
           wire_byte('0');
           if scl_pulses /= snap_pulses or bytes_seen /= snap_bytes then
               report "idle-bus activity was counted" severity error; errs := errs + 1; end if;
           if transfer_active /= '0' then
               report "clocking an idle bus opened a transfer" severity error;
               errs := errs + 1; end if;

           -- 10: a STOP that closed nothing must not announce a measurement.
           snap_valid := n_valid;
           pulse_stop;
           if n_valid /= snap_valid then
               report "a STOP that closed nothing produced metrics_valid" severity error;
               errs := errs + 1; end if;

           -- one metrics_valid per completed transfer: 4 bursts + 1 + probe + hang +
           -- two-NACK + addr-NACK + the Sr transfer = 10.
           if n_valid /= 10 then
               report "wrong number of metrics_valid pulses, expected 10" severity error;
               errs := errs + 1; end if;

           if errs = 0 then
               report "i2c_read_ack_policy self-check complete: ack pattern is n-1 ACKs then "
                    & "one NACK, the address byte's answer is the slave's, the hang is "
                    & "predicted, both malformed patterns rejected" severity note;
           else
               report "i2c_read_ack_policy self-check FAILED" severity error;
           end if;
           test_done <= '1';
           wait;
       end process;
   end architecture;

6a. Five Decisions Worth Defending

ack_bit uses the bus's polarity, not a convenient one. Zero means SDA was pulled low, which is an ACK. The specification defines the acknowledge as the receiver pulling the line low, so "low is yes" is the physical fact; inverting it at the instrument's boundary would insert a translation between the measurement and the thing measured. Mutation C4 inverts it and is killed immediately, but the real argument is reviewability: a reader comparing this port against §3.1.6 should not have to hold an inversion in their head.

expect_address is re-armed on every S and Sr. The first byte after a framing event is an address byte, and nothing in the frame marks it as one — position is the only evidence. So a repeated START must re-arm the expectation or every post-Sr address byte is counted as data, inflating master_acks by one for the rest of the transfer. Mutation C5 removes the re-arm and the failure is master_acks 2, expected n-1 = 1. This is the same structural fact that makes a missed repeated START the most expensive misreading of a capture (Chapter 7.5 §10), appearing here as a hardware requirement.

last_data_acked is the state of the LAST data byte, not "any byte was ACKed". The hang derivation in §4 turns entirely on the final acknowledge, so an accumulating flag would raise hang_risk on every multi-byte read — every read of two or more bytes contains an ACK. Mutation C2 makes exactly that change and is killed by a well-formed read being reported as a violation, which is the right failure: a checker that fires on correct behaviour is worse than no checker.

The subtraction is guarded and the guard is tested before any stimulus. payload_bytes is bytes_seen − 1, and bytes_seen is zero on an idle bus. Unguarded, that is not −1 but 65535 on a 16-bit unsigned counter. The hazard lives in the reset state, which is the state a stimulus-driven test passes through on its way to doing something interesting and never asserts on. Chapter 8.3 §7a made the same point; it recurs because unsigned subtraction recurs.

An address-only probe is admitted explicitly rather than by arithmetic. For n = 0 the policy expression would compute master_acks == payload_bytes − 1 — a comparison against a wrapped value. So policy_ok has a separate branch: zero payload bytes is well-formed if and only if there were no master acknowledges at all. Mutation C10 makes that branch return false and is killed by the probe test. Writing the degenerate case as its own clause costs two lines and removes a class of accidental correctness.

6b. Verified Execution

Azvya Education Pvt. Ltd.VLSI Mentor
terminal — three simulators, one result, one finish time
   $ iverilog -g2012 -o c0 i2c_read_ack_policy.sv i2c_read_ack_policy_tb.sv && ./c0
   PASS: ack pattern is n-1 ACKs then one NACK, the address byte's answer is the slave's,
   the hang is predicted, both malformed patterns rejected
   i2c_read_ack_policy_tb.sv:216: $finish called at 11120 (1ps)

   $ iverilog -g2005 -o c1 i2c_read_ack_policy.v i2c_read_ack_policy_tb.v && ./c1
   PASS: ack pattern is n-1 ACKs then one NACK, the address byte's answer is the slave's,
   the hang is predicted, both malformed patterns rejected
   i2c_read_ack_policy_tb.v:231: $finish called at 11120 (1ps)

   $ nvc -a i2c_read_ack_policy.vhd i2c_read_ack_policy_tb.vhd
   $ nvc -e i2c_read_ack_policy_tb && nvc -r i2c_read_ack_policy_tb --stop-time=600us
   ** Note: 11120ns+0: i2c_read_ack_policy self-check complete: ack pattern is n-1 ACKs
      then one NACK, the address byte's answer is the slave's, the hang is predicted,
      both malformed patterns rejected

All three at 11120 ns. Every closed form in §2 is checked against arithmetic the testbench computes from n — exp_pulses = 9 * (n + 1), not a table of constants — so these are checks on the formulas rather than on a transcription of them.

7. What the Testbench Proves

#stimuluswhat it establishes
1well-formed reads, n = 1, 2, 4, 8all closed forms, and the pattern is n−1 ACKs then one NACK
2a 1-byte readmaster_acks is zero — the boundary case of §1
3an address-only probe, n = 0one byte, one slave ACK, and no master acknowledges
4the final byte ACKedhang_risk raised and policy_ok cleared, before any STOP
5two NACKs in one readmalformed, even though the final slot is a NACK
6the address NACKedaddr_acked clear, and not counted as a master acknowledge
7after the STOPthe counters survive, because that is when they are read
8an Sr mid-transferthe measurement restarts and the address expectation re-arms
9SCL toggled on an idle busnothing counted, no transfer opened
10a STOP that closed nothingno metrics_valid; ten transfers produce ten pulses

Tests 2 and 3 are the boundary pair, and they fail in opposite directions. A checker built around "some ACKs then a NACK" breaks on test 2, where there are no ACKs. A checker built around "at least one acknowledge" breaks on test 3, where there are none. Both are single-line mistakes and both describe reads that happen constantly in real systems.

Test 6 is the one that keeps the instrument honest about §3's driven by row. The address byte's ninth bit belongs to the slave, so when nobody answers an address, that NACK must not appear in master_nacks. Mutation C1 removes the distinction and every read reports one acknowledge too many — uniformly, which is what makes it look like a convention difference rather than a bug.

Tests 9 and 10 exist because the equivalent mutations survived the first version of Chapter 8.3's testbench, for a reason worth carrying forward: a suite that only exercises the active case cannot test the gate that defines "active". Any design with an enable, a valid, or a state predicate needs stimulus that occurs while that predicate is false. Here those tests were written from the start rather than discovered by a survivor.

8. Mutation Testing

Ten defects injected into the SystemVerilog instrument.

#injected defectoutcome
C1the address byte's acknowledge counted as the master'skilled — master_acks 1, expected 0
C2hang_risk keys off any ACKed byte, not the lastkilled — a well-formed read flagged as a violation
C3policy_ok does not check the NACK countkilled — two NACKs accepted
C4the acknowledge polarity is invertedkilled
C5a repeated START does not re-arm the address expectationkilled — master_acks 2, expected 1
C6pulses counted while no transfer is activekilled — idle clocking counted, 42 where 27 stood
C7the guard is dropped, so a zero byte count wrapskilled — payload_bytes 65535 before any byte
C8the STOP clears the counterskilled — bytes_seen 0 after the transfer
C9metrics_valid fires on a STOP that closed nothingkilled
C10an address-only probe is not admitted as well-formedkilled

Across all three of this module's designs: 30 injected, 30 killed, no survivors and no invalid mutants. Two of the thirty needed work before they reported honestly, and both are recorded in the chapters they belong to — Chapter 9.1 §8 has the mutation whose anchor matched two sites and the one that required a new progress test.

C2's kill is the instructive one, because of the direction it fails in. Changing last_data_acked <= !ack_bit to an accumulating || makes the instrument report hang_risk on every read of two or more bytes — since every such read contains at least one ACK. The kill message is a well-formed read was reported as a policy violation, which is a false positive rather than a missed fault.

That is worth dwelling on. A checker that misses faults is inadequate; a checker that fires on correct behaviour is actively harmful, because it trains people to ignore it. Within a few weeks a monitor that cries wolf on every burst read is a monitor whose output nobody looks at, and at that point it is worse than absent — it occupies the place where a working checker would have gone. So the testbench asserts hang_risk == 0 on every well-formed read, not merely hang_risk == 1 on the broken one, and that is why C2 dies.

C6 and C7 are the two "nobody is looking" mutations and they fail in regions a stimulus-driven test naturally skips: the idle bus between transfers, and the reset state before any transfer. Both regions are where a design spends most of its life.

9. Verification Connection — The Policy Is an Assertion, the Lengths Are Coverage

The read's acknowledge policy is the clearest case in this course of a property that must be an assertion rather than a check: it holds at every moment of every read, including reads written years later by somebody who never opened this chapter.

Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_policy_props.sv — the policy as continuous properties
   // THE property. A read's final data byte must be NACKed. Written on the
   // TERMINATOR rather than on "the last byte", because nothing in the frame marks a
   // byte as last -- there is no length field, so "last" is only knowable once the
   // STOP or repeated START arrives. The property therefore looks backwards from the
   // framing event, which is the general move for any property about the final
   // element of an unbounded sequence.
   property p_read_ends_with_nack;
      @(posedge clk) disable iff (!rst_n)
      (is_read && (frame_stop || frame_restart) && data_bytes_seen > 0)
        |-> last_ack_was_nack;
   endproperty
   assert property (p_read_ends_with_nack)
      else $error("a read ended without NACKing its final byte -- the bus will hang");

   // Exactly ONE master NACK per read. The final-slot check above does not imply
   // this: a master that NACKs a middle byte and keeps clocking satisfies it while
   // reading bytes off an undriven bus, because the slave stopped transmitting at
   // the first NACK. See section 1.
   property p_one_nack_per_read;
      @(posedge clk) disable iff (!rst_n)
      (is_read && (frame_stop || frame_restart)) |-> (master_nack_count <= 1);
   endproperty
   assert property (p_one_nack_per_read)
      else $error("%0d master NACKs in one read -- bytes were read off a silent bus",
                  master_nack_count);

   // The address byte's acknowledge is the SLAVE's, even in a read. A monitor that
   // attributes it to the master is wrong by exactly one on every read, uniformly --
   // which makes it look like a convention difference rather than a defect.
   property p_address_ack_is_slaves;
      @(posedge clk) disable iff (!rst_n)
      (byte_done && byte_index == 0) |-> !master_drove_ack;
   endproperty
   assert property (p_address_ack_is_slaves)
      else $error("the address byte's acknowledge was attributed to the master");

   // A master-receiver must have RELEASED SDA in a slot it is NACKing. This is the
   // structural half of the hang: the NACK is the absence of an action, so a master
   // that is still driving low cannot express one at all.
   property p_nack_means_released;
      @(posedge clk) disable iff (!rst_n)
      (ack_slot && is_read && !master_acking) |-> !master_drives_sda_low;
   endproperty
   assert property (p_nack_means_released)
      else $error("the master intended a NACK while still pulling SDA low");

And the coverage. For reads the interesting axis is length, because §1 showed the pattern is a function of it and §2 showed the cost is too.

Azvya Education Pvt. Ltd.VLSI Mentor
i2c_read_len_cov.sv — the lengths where a read's behaviour changes
   covergroup i2c_read_len_cg with function sample(int n, bit combined, bit ended_with_sr);
      // The bins follow the SHAPE of section 1's table rather than being spread
      // evenly. Everything structurally distinctive happens at 0 and 1: a probe has
      // no master acknowledges at all, and a one-byte read has a NACK and no ACK.
      // Past 2 the pattern is self-similar and one bin covers it.
      read_len: coverpoint n {
         bins probe     = {0};        // no master acknowledges whatsoever
         bins single    = {1};        // exactly one acknowledge, and it is a NACK
         bins pair      = {2};        // the shortest read with both an ACK and a NACK
         bins burst     = {[3:16]};
         bins long      = {[17:255]};
      }

      // A plain read and a combined register read are different frames with
      // different costs -- section 2's nine extra pulses -- and a suite that only
      // ever issued one of them has not exercised the format real devices use.
      combined_fmt: coverpoint combined;

      // Terminating with Sr rather than P is the other half of the specification's
      // requirement, and the acknowledge policy is identical for both. Covering it
      // is how you know the identical-policy claim was actually exercised.
      sr_terminated: coverpoint ended_with_sr;

      // The crosses are the point. A probe that is never combined and a long burst
      // that always is would fill both coverpoints while leaving the interesting
      // combinations untried.
      len_x_combined: cross read_len, combined_fmt;
      len_x_sr:       cross read_len, sr_terminated;
   endgroup

10. FPGA and ASIC Implications

Two counters and two comparators. At CNT_W = 16 the instrument is roughly 50 flops — two byte/pulse counters, two acknowledge counters, an edge detector and five state bits. payload_bytes, policy_ok and hang_risk are all combinational.

Size CNT_W from the pulse count, not the byte count. A read of n bytes generates 9(n+1) pulses, so the pulse counter overflows nine times sooner than intuition based on bytes suggests. At CNT_W = 8 that is 27 bytes — reachable — and an overflow reports a small number rather than an error, which is the worst failure mode a counter has.

hang_risk is the output worth wiring to something. It is the one signal here that predicts a fault rather than recording one, and it is available a full byte before the STOP is attempted. Wiring it to an interrupt or a capture trigger turns it from a register somebody might read into a mechanism that catches the intermittent version of the fault — the one where the extra byte's MSB happened to be 1 and the bus survived by luck. That is the case a person will never reproduce on purpose.

It is genuinely passive, and keeping it so is the point. No output goes near SDA or SCL. This is the property that makes it safe to leave enabled in production silicon, and a debug block that could perturb the bus would be switched off in exactly the situations where it was needed.

In simulation the arithmetic is checked independently; in silicon nothing checks it. The testbench computes 9(n+1) from n. Nothing in the chip does, so the instrument's outputs are only as trustworthy as the verification that shipped with it. That is the argument for §9's assertions living in the environment permanently rather than being a one-off bring-up exercise.

11. Debugging — The Read Loop That Hung the Bus Every Few Hours

Pitfall — a data-dependent hang from an acknowledge policy that is right most of the time
Buggy Code
// A monitoring task polls a sensor's four status registers once a second, using a
// register read: write the pointer, repeated START, read four bytes.
//
// The acknowledge policy was written as a loop with the NACK outside it:
//
//     for (i = 0; i < len; i++)
//        data[i] = i2c_read_byte(ACK);        // ACK every byte...
//     i2c_nack();                            // ...then NACK
//
// which looks right and is not. The NACK is issued as a SEPARATE ninth slot, so the
// master reads len bytes with an ACK each and then clocks a FIFTH byte in order to
// have something to NACK. The capture:
//
//     S 0x90 A ptr A Sr 0x91 A d0 A d1 A d2 A d3 A d4 N P
//                                                    ^^ ^
//                                    a FIFTH byte, read only to be NACKed
Symptom

It worked. For hours, and then the whole bus stopped -- not just the sensor. Other devices' transfers began failing, and the failures were reported by whichever driver happened to need the bus next, which was rarely the monitoring task.

The logs pointed everywhere. A display driver reported a timeout. An EEPROM write failed mid-page. The sensor task itself usually reported success, because by the time it noticed anything the bus had already been power-cycled by a watchdog.

And it was not reproducible on demand. Running the monitoring task in a tight loop for twenty minutes produced nothing. The hang needed the fifth byte -- register 4, whatever happened to be there -- to have its most significant bit CLEAR, and that register held a slowly-changing measurement that was usually above the midpoint. So the fault rate tracked a sensor reading, which is not a hypothesis anybody forms early.

What resolved it was a bus monitor with the hang_risk output of section 6. It flagged EVERY poll -- all of them, not one in a few hundred -- because the final byte of every read was ACKed. The flag fires on the CAUSE, which was present every time, rather than on the hang, which needed the data to cooperate.

Root Cause

The acknowledge is not a separate operation from reading a byte -- it IS the ninth slot of the byte being read. Issuing a NACK "after the loop" clocks an extra byte to attach it to, so the transfer reads len+1 bytes and ACKs the byte the driver believes was its last.

The slave, told to send another, drove a fifth byte. Whenever that byte's MSB was zero the slave held SDA low through the window in which the master's STOP needed SDA to rise, so no STOP could be formed and the bus stayed held -- for every device on it.

12. Common Misconceptions

"A read of n bytes contains n ACKs." It contains n−1 master ACKs and one master NACK, plus one slave ACK for the address byte. A one-byte read contains zero master ACKs.

"Checking that the last slot is a NACK is enough." It misses a master that NACKs a middle byte and keeps clocking — the final slot is a NACK there too, while the bytes after the first NACK were read off an undriven bus. Check the count.

"Reads and writes cost the same." A plain read does. A register read costs nine pulses more than the equivalent write, because it carries a second address byte after the repeated START. At one payload byte that is the difference between 30% and 22% efficiency.

"A repeated START costs clock pulses." No framing condition does. The nine extra pulses of a register read are the second address byte, not the Sr.

"Forgetting the final NACK produces a failed read." It produces a held bus, affecting every device — and only when the extra byte's MSB happens to be 0, so it is intermittent. §11 is that fault in the field.

"The address byte after a repeated START is answered by the master, since it requests a read." The slave answers it. At the moment of that slot the slave is still the receiver, having just received an address. The handover is at that acknowledge, not before it.

"An instrument should report a hang when the STOP fails." By then it is an autopsy. The acknowledge that causes the hang is visible a full byte earlier and is deterministic, while the failure itself is data-dependent. Flag the cause.

13. Reason It Through

A capture shows S, 0x90, A, one byte, A, Sr, 0x91, A, then five nine-clock groups, then P. The driver asked for four bytes. What happened?

Five data bytes were read for a four-byte request — the acknowledge was issued as a separate operation after the loop, so the master clocked a fifth byte to attach the NACK to and ACKed the byte it believed was its last. The frame is well-formed and the STOP did form, so this particular transfer succeeded; whether the next one does depends on whether the fifth byte's MSB was 1. §11 is this bug.

A well-formed read of one byte and a well-formed probe both have zero master ACKs. How does an instrument tell them apart?

By the NACK count and the byte count. The one-byte read has one master NACK and two bytes on the wire; the probe has zero master acknowledges of either kind and one byte on the wire. That is why policy_ok has a separate branch for zero payload bytes rather than deriving it — the two cases agree on master_acks and differ on everything else.

Why does a register read of one byte cost four bytes on the wire, and what does that imply for a polling loop?

S, address+W, pointer, Sr, address+R, data, P — four byte-slots for one payload byte, so 36 SCL pulses for 8 bits: 22% efficient, 360 µs at 100 kHz. For a polling loop the implication is direct: reading four status registers as four separate register reads costs 4 × 36 = 144 pulses, while reading them as one burst from a single pointer costs 9 × 7 = 63. The burst is better than twice as fast, and most devices lay related registers out contiguously precisely to make that possible.

An instrument reports hang_risk on every read, but the bus hangs only occasionally. Is the instrument wrong?

No — it is working exactly as designed, and the discrepancy is the point. The acknowledge pattern that causes the hang is present on every transfer and is deterministic; whether it manifests depends on the extra byte's most significant bit. An instrument that only flagged the transfers that actually hung would be as intermittent as the bug and correspondingly useless for finding it.

Why must expect_address be re-armed on a repeated START and not only on a START?

Because the byte after any framing event is an address byte, and nothing in the frame says so — position is the only evidence. Without the re-arm, the post-Sr address byte is counted as a data byte, its slave-driven acknowledge is attributed to the master, and every count after it is wrong by one for the rest of the transfer. It is the hardware form of the most expensive capture-reading error there is.

14. Understanding Check

15. Summary

The acknowledge pattern of a correct read is determined by its length, not merely constrained by it. n−1 master ACKs, then exactly one NACK in the final slot, with the address byte's acknowledge belonging to the slave. That narrowness is what makes a passive instrument able to verify the policy with no knowledge of the device.

Count the NACKs, not just the last one. A NACK in the final slot is necessary and not sufficient: a master that NACKs a middle byte and keeps clocking reads the remainder off an undriven bus and gets 0xFF, while satisfying any final-slot check.

A plain read costs the same as a write; a register read costs nine pulses more. The second address byte after the repeated START is one extra byte-slot. At one payload byte that is 22% efficiency — four bytes on the wire to move one — which is why polling status registers one at a time is the most wasteful common use of this bus.

The hang is derivable and predictable. ACKing the final byte tells the slave to send another; a slave that cannot refuse drives it; a driven zero holds SDA low; a STOP needs SDA to rise. So the fault is visible one byte early, and it is deterministic even though the hang it causes is data-dependent.

Flag the cause, not the symptom. The acknowledge pattern is present on every affected transfer; the hang appears only when the extra byte's MSB is zero. A checker on the pattern turns an unreproducible bus-wide failure into something visible on the first attempt.

A false positive is worse than a miss. A monitor that fires on correct behaviour gets ignored, and then it is worse than absent. Assert that the flag is clear on well-formed traffic, not only that it sets on broken traffic.

16. What Comes Next

Module 9 is complete, and with it both of I²C's transactions. Every claim in it was compiled and run in three languages, all three designs are at exact timing parity, and the mutation suite closed thirty out of thirty with the two awkward cases documented rather than smoothed over.

What remains is the composition. Module 10 builds the combined transaction properly — the format this chapter has been using informally since §2, where a write phase and a read phase are joined by a repeated START and the bus is never released between them. The pieces are all present now: Chapter 5.4 framed it, Chapter 9.2 §4 established the one piece of slave state that must survive it, and this chapter priced it. What Module 10 adds is the reason it exists at all — atomicity. On a multi-master bus, releasing the bus between the pointer write and the data read allows another master to change the pointer in between, and the repeated START is how a transaction becomes indivisible rather than merely adjacent.

Continue learning