Skip to content
VLSI Mentor

I²C · Module 6

Reserved Addresses and the I²C Address Map

Sixteen of the 128 seven-bit addresses are spoken for, two carry outright prohibitions on responding, and one address means two opposite things depending on a single direction bit. Lay out the map, decode it in hardware, and verify it exhaustively against an independent model.

Chapter 6.2 used the prefix 11110XX as though its reserved status were established, and referred twice to an escape hatch it did not quote. Both debts are paid here.

This chapter is the map. It is short on mechanism and long on consequence, because the reserved address space is the part of I²C where knowing the table is genuinely the skill — and where a plausible-looking assumption produces a device that either never answers or answers when it must not.

1. Two Groups of Eight

UM10204 §3.1.12 opens with one sentence that fixes the shape of the whole map:

Two groups of eight addresses (0000XXX and 1111XXX) are reserved for the purposes shown in Table 3.

So the reserved space is the bottom eight and the top eight seven-bit addresses. Everything between them is available.

Azvya Education Pvt. Ltd.VLSI Mentor
MATHEMATICAL DERIVATION — how much address space a board actually has
   total seven-bit addresses                      2^7  =  128

   reserved group 1:  0000XXX  =  0x00 .. 0x07           8
   reserved group 2:  1111XXX  =  0x78 .. 0x7F           8
                                              reserved  16

   allocatable                              128 - 16  =  112

   The 112 is the number worth remembering, and it is smaller than it looks:
   every part from every vendor draws from the same 112, and a great many of
   them ship with a fixed address chosen from a narrow customary range.

Two things about that arithmetic are worth stating explicitly, because both get assumed wrongly.

Reservation is a property of the address, not of the direction bit. The groups are defined as seven-bit patterns. The R/W bit then selects among purposes within an entry — it never determines whether an address is reserved. §3 is an entire chapter's worth of confusion resting on this distinction.

112 is the ceiling, not the budget. A real board's usable count is lower still, because most parts do not let you choose freely: a fixed-address part occupies whatever address it was built with, and a strapped part offers a small window. Chapter 6.4 is about that narrower reality.

2. The Whole Table

UM10204 Table 3, transcribed. X means don't care.

slave addressR/Wpurposenotes
00000000general call address§4; also carries software reset
00000001START byteno device may acknowledge
0000001XCBUS addressI²C devices may not respond
0000010Xreserved for a different bus formatonly devices that implement that format may respond
0000011Xreserved for future purposes
00001XXXHs-mode master codefour addresses; High-speed mode, Module 14
11110XXX10-bit slave addressingfour addresses; Chapter 6.2
11111XX1device IDfour addresses

Notice what that table accounts for, and what it does not.

The lower group is fully described: 0000000, 0000001, 0000010, 0000011 and the four 00001XX add to eight. The upper group is not: 11110XX and 11111XX are four each, which covers all eight addresses, but the device-ID row specifies only R/W = 1. The four combinations 11111XX with R/W = 0 fall inside a reserved group with no purpose assigned to them.

That is not an omission to be tidied away. It is a real state, and a decoder has to have somewhere to put it — which is why the classifier in §6 carries a distinct class for it rather than lumping it in with usable addresses. Calling it usable would be wrong: the address is reserved. Calling it device ID would also be wrong: the table says device ID is R/W = 1.

3. One Address, Two Opposite Meanings

The sharpest edge in the whole map is the first two rows, and it is worth seeing the two bytes next to each other.

Address 0000000 with R/W = 0 is the general call — a broadcast that every device on the bus may answer. Address 0000000 with R/W = 1 is the START byte, and its footnote is a prohibition:

No device is allowed to acknowledge at the reception of the START byte.

Same seven address bits. One bit of difference on the wire. One means everybody listen; the other means nobody answer.

General call — seven zeros and R/W = 0

8 cycles
Eight clock periods, one per bit. SDA is low for all seven address bits and low again for the eighth bit, the write direction bit, giving the byte zero on the wire.address 0000000address 0000000broadcastbroadcastseven zero address bitsseven zero address bitsR/W = 0: general callR/W = 0: general callsclsda00000000t0t1t2t3t4t5t6t7
Figure 1 — the general call address, 0x00 on the wire. Seven zero address bits and a write direction bit. Every device that implements general call support may acknowledge this, and the meaning of the call is carried in the byte that follows.

START byte — the same seven zeros and R/W = 1

8 cycles
Eight clock periods, one per bit. SDA is low for all seven address bits, exactly as in the previous figure, and high for the eighth bit, the read direction bit, giving the byte one on the wire.address 0000000address 0000000prohibitedprohibit…the same seven address bitsthe same seven address bitsR/W = 1: no device may ACKR/W = 1: no device may ACKsclsda00000001t0t1t2t3t4t5t6t7
Figure 2 — the START byte, 0x01 on the wire. Identical to Figure 1 in all seven address bits; only the direction bit differs. This one carries an outright prohibition: no device is allowed to acknowledge it. One bit separates a broadcast every device may answer from a byte no device may answer.

The design consequence is direct: a decoder cannot classify an address without the direction bit. Any implementation that compares only the seven address bits and decides afterwards what to do about direction will treat the START byte as a general call, and will acknowledge a byte the specification forbids acknowledging. §6's classifier takes both as one eight-bit input for exactly this reason.

4. The Two Prohibitions

Most of Table 3 is descriptive — it says what an address is for. Two footnotes are different: they say what a device must not do, and a compliant device has to obey them in hardware.

The START byte. "No device is allowed to acknowledge at the reception of the START byte." The START byte exists so that a bit-banging master, which polls SDA in software, can generate a long recognisable low period that gives a sampling slave time to notice bus activity. It is a wake-up pattern, not an address, and answering it would defeat the purpose.

The CBUS address. "The CBUS address has been reserved to enable the inter-mixing of CBUS compatible and I²C-bus compatible devices in the same system. I²C-bus compatible devices are not allowed to respond on reception of this address." CBUS was a different Philips bus; the address is fenced off so that the two device families can share wires without I²C parts answering CBUS traffic.

A third row is close to a prohibition but is conditional rather than absolute:

A different bus format. "The address reserved for a different bus format is included to enable I²C and other protocols to be mixed. Only I²C-bus compatible devices that can work with such formats and protocols are allowed to respond to this address." So an ordinary device must not respond, but a device that genuinely implements the other format may. That is a permission gated on capability, not a blanket ban — which is why the classifier in §6 does not fold it into must_not_ack.

5. The Escape Hatch

The specification then says something that surprises people, and it is the sentence Chapter 6.2 kept pointing at:

Assignment of addresses within a local system is up to the system architect who must take into account the devices being used on the bus and any future interaction with other conventional I²C-buses. For example, a device with seven user-assignable address pins allows all 128 addresses to be assigned. If it is known that the reserved address is never going to be used for its intended purpose, a reserved address can be used for a slave address.

So the reserved space is not sealed. A closed system that provably contains no CBUS devices, never uses High-speed mode, and never issues a general call may reclaim those addresses for ordinary slaves.

Three things to be careful about before doing it.

"Never going to be used" is a claim about the whole life of the system, including the variant nobody has designed yet and the field upgrade that adds a part. It is a system-architecture commitment, not a board-revision convenience.

The two prohibitions are not symmetric with the rest. Reclaiming 0000010 (a different bus format) is a straightforward decision about whether that format is present. Reclaiming 0000000 or 0000001 means deliberately building a device that answers an address the specification forbids answering, which breaks any future interoperation with a compliant master that uses them.

A reclaimed address should be flagged, not silently allowed. This is precisely why the strap resolver in Chapter 6.4 separates "this address is reserved" — a fact about the bus — from "this configuration is illegal" — a judgement the system may override. The fact does not change when you opt in. Only the judgement does.

6. The General Call, and What Its Second Byte Means

The general call deserves its own treatment because it is the one reserved address ordinary devices routinely implement.

UM10204 §3.1.13:

The general call address is for addressing every device connected to the I²C-bus at the same time. However, if a device does not need any of the data supplied within the general call structure, it can ignore this address by not issuing an acknowledgment. If a device does require data from a general call address, it acknowledges this address and behave as a slave-receiver. The master does not actually know how many devices acknowledged if one or more devices respond.

Three properties follow, and the third is the interesting one.

Answering is optional per device. A device that has nothing to do with general call traffic simply does not acknowledge. That is not an error, and Table 2 marks general call support optional for every configuration.

The meaning is in the second byte. "The meaning of the general call address is always specified in the second byte." The address byte only says this is a broadcast; what kind of broadcast is the next byte's job.

The master cannot count the responders. This is the wired-AND again, exactly as in Chapter 6.2 §2 — several devices pulling SDA low is indistinguishable from one. The specification spells out the consequence for the failure direction too: "if one or more slaves acknowledge, the not-acknowledge will not be seen by the master." So a general call in which most devices refused looks identical to one in which all of them accepted.

The defined second bytes, for the case where its least significant bit is zero:

second bytemeaning
00000110 (06h)reset, and write the programmable part of the slave address by hardware
00000100 (04h)write the programmable part of the slave address by hardware, without resetting
00000000 (00h)"This code is not allowed to be used as the second byte."

The 06h case is the software reset of §3.1.14, and the specification is careful about its status:

Following a General Call, (00000000), sending 00000110 (06h) as the second byte causes a software reset. This feature is optional and not all devices respond to this command.

It also attaches a warning that belongs to Chapter 2.3's territory:

Precautions must be taken to ensure that a device is not pulling down the SDA or SCL line after applying the supply voltage, since these low levels would block the bus.

A device emerging from a reset while holding either line low jams the segment for everyone — the same rule every reset path in this curriculum has obeyed since Chapter 4.1.

7. Mandatory Versus Optional — The Table That Predicts Reality

UM10204 Table 2 lists which protocol features are mandatory and which are optional, per configuration. The addressing-related rows:

featuresingle mastermulti-masterslave
7-bit slave addressMMM
10-bit slave addressOOO
General Call addressOOO
Software ResetOOO
START byten/aOn/a
Device IDn/an/aO

One row is mandatory and the rest are optional, and that single asymmetry explains a great deal about what you actually meet in silicon. A designer can rely on seven-bit addressing working with any compliant part. Everything else has to be checked per device, in the datasheet, and a device that does not implement an optional feature is not faulty — it is exercising an option the specification granted it.

This is the practical reading skill the table teaches: when a device does not answer a general call, the first question is not "what is broken" but "does this part implement general call at all".

8. Decoding the Map in Hardware

The decode is purely combinational — eight bits in, a classification out — and the implementation choice worth making deliberately is how it is written.

A chain of bit tests works and is nearly unreviewable against the specification. A casez over the whole eight-bit byte, with don't-care positions in exactly the places the table has X columns, is a transcription: a reviewer can put the table beside the code and check it line by line, which is the property that matters for a block whose only job is to be faithful to a table.

Azvya Education Pvt. Ltd.VLSI Mentor
i2c_address_classifier.sv — SYNTHESIZABLE RTL. A casez written as a direct transcription of the reserved-address table.
   // Purely combinational decode of the reserved-address map. Encodes UM10204
   // Table 3 and the two footnotes that FORBID a device from responding.
   module i2c_address_classifier (
       input  logic [6:0] addr,          // the seven address bits
       input  logic       rw,            // the eighth bit on the wire
       output logic       is_reserved,   // the ADDRESS lies in a reserved group
       output logic [3:0] addr_class,    // the specific purpose, see localparams
       output logic       must_not_ack   // the specification forbids responding
   );
       // Class codes. CLS_USABLE is everything the map does not claim.
       localparam logic [3:0] CLS_USABLE       = 4'd0;
       localparam logic [3:0] CLS_GENERAL_CALL = 4'd1;   // 0000000 + W
       localparam logic [3:0] CLS_START_BYTE   = 4'd2;   // 0000000 + R
       localparam logic [3:0] CLS_CBUS         = 4'd3;   // 0000001 + X
       localparam logic [3:0] CLS_OTHER_BUS    = 4'd4;   // 0000010 + X
       localparam logic [3:0] CLS_FUTURE       = 4'd5;   // 0000011 + X
       localparam logic [3:0] CLS_HS_MASTER    = 4'd6;   // 00001XX + X
       localparam logic [3:0] CLS_DEVICE_ID    = 4'd7;   // 11111XX + R
       localparam logic [3:0] CLS_TENBIT       = 4'd8;   // 11110XX + X
       localparam logic [3:0] CLS_RSVD_UPPER   = 4'd9;   // 11111XX + W -- reserved group,
                                                         // no purpose assigned by Table 3

       // Reservation is a property of the ADDRESS GROUP, not of the direction bit:
       // "Two groups of eight addresses (0000XXX and 1111XXX) are reserved."
       // The R/W bit then selects among purposes WITHIN an entry -- which is why
       // general call and START byte share one address and differ only in direction.
       assign is_reserved = (addr[6:3] == 4'b0000) || (addr[6:3] == 4'b1111);

       // The decode is written as a casez over the whole eight-bit byte so that it
       // reads as a transcription of Table 3 rather than as a chain of bit tests.
       // The don't-care positions are exactly the table's X columns.
       always_comb begin
           casez ({addr, rw})
               8'b0000000_0: addr_class = CLS_GENERAL_CALL;   // general call address
               8'b0000000_1: addr_class = CLS_START_BYTE;     // START byte
               8'b0000001_?: addr_class = CLS_CBUS;           // CBUS address
               8'b0000010_?: addr_class = CLS_OTHER_BUS;      // different bus format
               8'b0000011_?: addr_class = CLS_FUTURE;         // reserved for future use
               8'b00001??_?: addr_class = CLS_HS_MASTER;      // Hs-mode master code
               8'b11110??_?: addr_class = CLS_TENBIT;         // 10-bit slave addressing
               8'b11111??_1: addr_class = CLS_DEVICE_ID;      // device ID
               8'b11111??_0: addr_class = CLS_RSVD_UPPER;     // reserved group, no purpose
               default:      addr_class = CLS_USABLE;         // the other 112 addresses
           endcase
       end

       // Two footnotes in Table 3 are prohibitions rather than descriptions, and a
       // compliant device has to obey them in hardware:
       //   START byte  -- "No device is allowed to acknowledge at the reception of
       //                   the START byte."
       //   CBUS address -- "I2C-bus compatible devices are not allowed to respond on
       //                   reception of this address."
       assign must_not_ack = (addr_class == CLS_START_BYTE) || (addr_class == CLS_CBUS);
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_address_classifier_tb.sv — SELF-CHECKING TESTBENCH, SIMULATION ONLY. Exhaustive: all 256 combinations against an independently-written model.
   module i2c_address_classifier_tb;
       localparam logic [3:0] CLS_USABLE       = 4'd0;
       localparam logic [3:0] CLS_GENERAL_CALL = 4'd1;
       localparam logic [3:0] CLS_START_BYTE   = 4'd2;
       localparam logic [3:0] CLS_CBUS         = 4'd3;
       localparam logic [3:0] CLS_OTHER_BUS    = 4'd4;
       localparam logic [3:0] CLS_FUTURE       = 4'd5;
       localparam logic [3:0] CLS_HS_MASTER    = 4'd6;
       localparam logic [3:0] CLS_DEVICE_ID    = 4'd7;
       localparam logic [3:0] CLS_TENBIT       = 4'd8;
       localparam logic [3:0] CLS_RSVD_UPPER   = 4'd9;

       logic [6:0] addr;
       logic       rw;
       logic       is_reserved;
       logic [3:0] addr_class;
       logic       must_not_ack;

       i2c_address_classifier dut (.*);

       int errors = 0;
       int n_reserved_addr = 0;
       int n_usable_addr   = 0;
       int class_hist [0:9];
       // Module scope: an initialised declaration inside a loop block is static in
       // SystemVerilog, and overriding the lifetime is not portable across tools.
       int usable_both;

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

       // INDEPENDENT reference model. Deliberately written as arithmetic range tests
       // rather than as a bit-pattern case, so that a shared misreading of the table
       // cannot make model and design agree. Two implementations of the same table.
       function automatic logic [3:0] ref_class(input int a, input int d);
           if (a == 0)                    return (d == 1) ? CLS_START_BYTE : CLS_GENERAL_CALL;
           else if (a == 1)               return CLS_CBUS;
           else if (a == 2)               return CLS_OTHER_BUS;
           else if (a == 3)               return CLS_FUTURE;
           else if (a >= 4  && a <= 7)    return CLS_HS_MASTER;      // 00001XX
           else if (a >= 120 && a <= 123) return CLS_TENBIT;         // 11110XX = 0x78..0x7B
           else if (a >= 124 && a <= 127) return (d == 1) ? CLS_DEVICE_ID : CLS_RSVD_UPPER;
           else                           return CLS_USABLE;
       endfunction

       function automatic logic ref_reserved(input int a);
           // Reservation is by address group, independent of direction.
           return (a <= 7) || (a >= 120);
       endfunction

       initial begin
           for (int i = 0; i <= 9; i++) class_hist[i] = 0;

           // Exhaustive: every one of the 128 addresses, in both directions.
           for (int a = 0; a < 128; a++) begin
               usable_both = 1;
               for (int d = 0; d < 2; d++) begin
                   addr = a[6:0];
                   rw   = d[0];
                   #1;
                   if (addr_class !== ref_class(a, d)) begin
                       $display("FAIL: addr=0x%02h rw=%0b -- class %0d, reference says %0d",
                                a, d, addr_class, ref_class(a, d));
                       errors++;
                   end
                   if (is_reserved !== ref_reserved(a)) begin
                       $display("FAIL: addr=0x%02h -- is_reserved %0b, reference says %0b",
                                a, is_reserved, ref_reserved(a));
                       errors++;
                   end
                   // must_not_ack is normative: exactly the START byte and CBUS.
                   if (must_not_ack !== ((ref_class(a,d) == CLS_START_BYTE) ||
                                         (ref_class(a,d) == CLS_CBUS))) begin
                       $display("FAIL: addr=0x%02h rw=%0b -- must_not_ack wrong", a, d);
                       errors++;
                   end
                   class_hist[addr_class]++;
                   if (addr_class != CLS_USABLE) usable_both = 0;
               end
               if (ref_reserved(a)) n_reserved_addr++;
               if (usable_both)     n_usable_addr++;
           end

           // The address-space arithmetic, verified by counting rather than asserted.
           if (n_reserved_addr != 16) begin
               $display("FAIL: %0d reserved addresses, expected 16 (two groups of eight)", n_reserved_addr);
               errors++;
           end
           if (n_usable_addr != 112) begin
               $display("FAIL: %0d usable addresses, expected 112 (128 - 16)", n_usable_addr);
               errors++;
           end
           // Every reserved entry must be claimed by some purpose -- no reserved
           // address may fall through to CLS_USABLE.
           if (class_hist[CLS_USABLE] != 112 * 2) begin
               $display("FAIL: %0d usable classifications, expected %0d", class_hist[CLS_USABLE], 112*2);
               errors++;
           end
           // The two single-address, direction-selected entries occur exactly once each.
           if (class_hist[CLS_GENERAL_CALL] != 1 || class_hist[CLS_START_BYTE] != 1) begin
               $display("FAIL: general call / START byte must be one combination each (%0d / %0d)",
                        class_hist[CLS_GENERAL_CALL], class_hist[CLS_START_BYTE]);
               errors++;
           end
           // 11110XX spans four addresses, both directions.
           if (class_hist[CLS_TENBIT] != 8) begin
               $display("FAIL: 10-bit prefix should cover 8 combinations, got %0d", class_hist[CLS_TENBIT]);
               errors++;
           end

           if (errors == 0)
               $display("PASS: all 256 combinations match an independent model; %0d reserved, %0d usable addresses",
                        n_reserved_addr, n_usable_addr);
           else $display("FAIL: %0d error(s)", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_address_classifier.v — SYNTHESIZABLE RTL. The same decode in Verilog-2005.
   // Purely combinational decode of the reserved-address map. Encodes UM10204
   // Table 3 and the two footnotes that FORBID a device from responding.
   module i2c_address_classifier (
       input  wire [6:0] addr,          // the seven address bits
       input  wire       rw,            // the eighth bit on the wire
       output wire       is_reserved,   // the ADDRESS lies in a reserved group
       output reg  [3:0] addr_class,    // the specific purpose, see localparams
       output wire       must_not_ack   // the specification forbids responding
   );
       localparam [3:0] CLS_USABLE       = 4'd0;
       localparam [3:0] CLS_GENERAL_CALL = 4'd1;   // 0000000 + W
       localparam [3:0] CLS_START_BYTE   = 4'd2;   // 0000000 + R
       localparam [3:0] CLS_CBUS         = 4'd3;   // 0000001 + X
       localparam [3:0] CLS_OTHER_BUS    = 4'd4;   // 0000010 + X
       localparam [3:0] CLS_FUTURE       = 4'd5;   // 0000011 + X
       localparam [3:0] CLS_HS_MASTER    = 4'd6;   // 00001XX + X
       localparam [3:0] CLS_DEVICE_ID    = 4'd7;   // 11111XX + R
       localparam [3:0] CLS_TENBIT       = 4'd8;   // 11110XX + X
       localparam [3:0] CLS_RSVD_UPPER   = 4'd9;   // 11111XX + W

       // Reservation is a property of the ADDRESS GROUP, not of the direction bit.
       assign is_reserved = (addr[6:3] == 4'b0000) || (addr[6:3] == 4'b1111);

       // Written as a casez over the whole byte so it reads as a transcription of
       // Table 3; the don't-care positions are exactly the table's X columns.
       always @* begin
           casez ({addr, rw})
               8'b0000000_0: addr_class = CLS_GENERAL_CALL;   // general call address
               8'b0000000_1: addr_class = CLS_START_BYTE;     // START byte
               8'b0000001_?: addr_class = CLS_CBUS;           // CBUS address
               8'b0000010_?: addr_class = CLS_OTHER_BUS;      // different bus format
               8'b0000011_?: addr_class = CLS_FUTURE;         // reserved for future use
               8'b00001??_?: addr_class = CLS_HS_MASTER;      // Hs-mode master code
               8'b11110??_?: addr_class = CLS_TENBIT;         // 10-bit slave addressing
               8'b11111??_1: addr_class = CLS_DEVICE_ID;      // device ID
               8'b11111??_0: addr_class = CLS_RSVD_UPPER;     // reserved group, no purpose
               default:      addr_class = CLS_USABLE;         // the other 112 addresses
           endcase
       end

       // Two footnotes are prohibitions rather than descriptions:
       //   START byte   -- no device is allowed to acknowledge it
       //   CBUS address -- I2C-bus devices are not allowed to respond to it
       assign must_not_ack = (addr_class == CLS_START_BYTE) || (addr_class == CLS_CBUS);
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_address_classifier_tb.v — SELF-CHECKING TESTBENCH, SIMULATION ONLY. The same exhaustive sweep in Verilog idiom.
   module i2c_address_classifier_tb;
       localparam [3:0] CLS_USABLE       = 4'd0;
       localparam [3:0] CLS_GENERAL_CALL = 4'd1;
       localparam [3:0] CLS_START_BYTE   = 4'd2;
       localparam [3:0] CLS_CBUS         = 4'd3;
       localparam [3:0] CLS_OTHER_BUS    = 4'd4;
       localparam [3:0] CLS_FUTURE       = 4'd5;
       localparam [3:0] CLS_HS_MASTER    = 4'd6;
       localparam [3:0] CLS_DEVICE_ID    = 4'd7;
       localparam [3:0] CLS_TENBIT       = 4'd8;
       localparam [3:0] CLS_RSVD_UPPER   = 4'd9;

       reg  [6:0] addr;
       reg        rw;
       wire       is_reserved;
       wire [3:0] addr_class;
       wire       must_not_ack;

       i2c_address_classifier dut (.addr(addr), .rw(rw), .is_reserved(is_reserved),
           .addr_class(addr_class), .must_not_ack(must_not_ack));

       integer errors, n_reserved_addr, n_usable_addr, usable_both, a, d, i;
       integer class_hist [0:9];

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

       // INDEPENDENT reference model: arithmetic range tests rather than a bit-pattern
       // case, so a shared misreading cannot make model and design agree.
       function [3:0] ref_class; input integer a; input integer d; begin
           if (a == 0)                         ref_class = (d == 1) ? CLS_START_BYTE : CLS_GENERAL_CALL;
           else if (a == 1)                    ref_class = CLS_CBUS;
           else if (a == 2)                    ref_class = CLS_OTHER_BUS;
           else if (a == 3)                    ref_class = CLS_FUTURE;
           else if (a >= 4   && a <= 7)        ref_class = CLS_HS_MASTER;
           else if (a >= 120 && a <= 123)      ref_class = CLS_TENBIT;
           else if (a >= 124 && a <= 127)      ref_class = (d == 1) ? CLS_DEVICE_ID : CLS_RSVD_UPPER;
           else                                ref_class = CLS_USABLE;
       end endfunction

       function ref_reserved; input integer a; begin
           ref_reserved = (a <= 7) || (a >= 120);
       end endfunction

       initial begin
           errors = 0; n_reserved_addr = 0; n_usable_addr = 0;
           for (i = 0; i <= 9; i = i + 1) class_hist[i] = 0;

           for (a = 0; a < 128; a = a + 1) begin
               usable_both = 1;
               for (d = 0; d < 2; d = d + 1) begin
                   addr = a[6:0];
                   rw   = d[0];
                   #1;
                   if (addr_class !== ref_class(a, d)) begin
                       $display("FAIL: addr=0x%02h rw=%0b -- class %0d, reference says %0d",
                                a, d, addr_class, ref_class(a, d));
                       errors = errors + 1;
                   end
                   if (is_reserved !== ref_reserved(a)) begin
                       $display("FAIL: addr=0x%02h -- is_reserved %0b, reference says %0b",
                                a, is_reserved, ref_reserved(a));
                       errors = errors + 1;
                   end
                   if (must_not_ack !== ((ref_class(a,d) == CLS_START_BYTE) ||
                                         (ref_class(a,d) == CLS_CBUS))) begin
                       $display("FAIL: addr=0x%02h rw=%0b -- must_not_ack wrong", a, d);
                       errors = errors + 1;
                   end
                   class_hist[addr_class] = class_hist[addr_class] + 1;
                   if (addr_class != CLS_USABLE) usable_both = 0;
               end
               if (ref_reserved(a)) n_reserved_addr = n_reserved_addr + 1;
               if (usable_both)     n_usable_addr   = n_usable_addr + 1;
           end

           if (n_reserved_addr != 16) begin
               $display("FAIL: %0d reserved addresses, expected 16", n_reserved_addr); errors = errors + 1; end
           if (n_usable_addr != 112) begin
               $display("FAIL: %0d usable addresses, expected 112", n_usable_addr); errors = errors + 1; end
           if (class_hist[CLS_USABLE] != 112 * 2) begin
               $display("FAIL: %0d usable classifications, expected %0d", class_hist[CLS_USABLE], 112*2);
               errors = errors + 1; end
           if (class_hist[CLS_GENERAL_CALL] != 1 || class_hist[CLS_START_BYTE] != 1) begin
               $display("FAIL: general call / START byte must be one combination each");
               errors = errors + 1; end
           if (class_hist[CLS_TENBIT] != 8) begin
               $display("FAIL: 10-bit prefix should cover 8 combinations, got %0d", class_hist[CLS_TENBIT]);
               errors = errors + 1; end

           if (errors == 0)
               $display("PASS: all 256 combinations match an independent model; %0d reserved, %0d usable addresses",
                        n_reserved_addr, n_usable_addr);
           else $display("FAIL: %0d error(s)", errors);
           $finish;
       end
   endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_address_classifier.vhd — SYNTHESIZABLE RTL. The same decode using a VHDL-2008 matching case.
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;

   -- Purely combinational decode of the reserved-address map. Encodes UM10204
   -- Table 3 and the two footnotes that FORBID a device from responding.
   entity i2c_address_classifier is
       port (
           addr         : in  std_logic_vector(6 downto 0);  -- the seven address bits
           rw           : in  std_logic;                     -- the eighth bit on the wire
           is_reserved  : out std_logic;                     -- ADDRESS in a reserved group
           addr_class   : out std_logic_vector(3 downto 0);  -- the specific purpose
           must_not_ack : out std_logic                      -- spec forbids responding
       );
   end entity;

   architecture rtl of i2c_address_classifier is
       constant CLS_USABLE       : std_logic_vector(3 downto 0) := x"0";
       constant CLS_GENERAL_CALL : std_logic_vector(3 downto 0) := x"1";  -- 0000000 + W
       constant CLS_START_BYTE   : std_logic_vector(3 downto 0) := x"2";  -- 0000000 + R
       constant CLS_CBUS         : std_logic_vector(3 downto 0) := x"3";  -- 0000001 + X
       constant CLS_OTHER_BUS    : std_logic_vector(3 downto 0) := x"4";  -- 0000010 + X
       constant CLS_FUTURE       : std_logic_vector(3 downto 0) := x"5";  -- 0000011 + X
       constant CLS_HS_MASTER    : std_logic_vector(3 downto 0) := x"6";  -- 00001XX + X
       constant CLS_DEVICE_ID    : std_logic_vector(3 downto 0) := x"7";  -- 11111XX + R
       constant CLS_TENBIT       : std_logic_vector(3 downto 0) := x"8";  -- 11110XX + X
       constant CLS_RSVD_UPPER   : std_logic_vector(3 downto 0) := x"9";  -- 11111XX + W

       signal byte_on_wire : std_logic_vector(7 downto 0);
       signal cls          : std_logic_vector(3 downto 0);
   begin
       byte_on_wire <= addr & rw;

       -- Reservation is a property of the ADDRESS GROUP, not of the direction bit.
       is_reserved <= '1' when (addr(6 downto 3) = "0000" or addr(6 downto 3) = "1111")
                      else '0';

       -- VHDL-2008 matching case: '-' is a don't-care, so this reads as a direct
       -- transcription of Table 3, exactly as the casez versions do.
       process (byte_on_wire)
       begin
           case? byte_on_wire is
               when "0000000" & "0" => cls <= CLS_GENERAL_CALL;   -- general call address
               when "0000000" & "1" => cls <= CLS_START_BYTE;     -- START byte
               when "0000001-"      => cls <= CLS_CBUS;           -- CBUS address
               when "0000010-"      => cls <= CLS_OTHER_BUS;      -- different bus format
               when "0000011-"      => cls <= CLS_FUTURE;         -- reserved for future use
               when "00001---"      => cls <= CLS_HS_MASTER;      -- Hs-mode master code
               when "11110---"      => cls <= CLS_TENBIT;         -- 10-bit slave addressing
               when "11111--1"      => cls <= CLS_DEVICE_ID;      -- device ID
               when "11111--0"      => cls <= CLS_RSVD_UPPER;     -- reserved, no purpose
               when others          => cls <= CLS_USABLE;         -- the other 112 addresses
           end case?;
       end process;

       addr_class <= cls;

       -- Two footnotes are prohibitions rather than descriptions:
       --   START byte   -- no device is allowed to acknowledge it
       --   CBUS address -- I2C-bus devices are not allowed to respond to it
       must_not_ack <= '1' when (cls = CLS_START_BYTE or cls = CLS_CBUS) else '0';
   end architecture;
Azvya Education Pvt. Ltd.VLSI Mentor
i2c_address_classifier_tb.vhd — SELF-CHECKING TESTBENCH, SIMULATION ONLY. The same exhaustive sweep with assert report severity.
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;

   entity i2c_address_classifier_tb is
   end entity;

   architecture sim of i2c_address_classifier_tb is
       constant CLS_USABLE       : std_logic_vector(3 downto 0) := x"0";
       constant CLS_GENERAL_CALL : std_logic_vector(3 downto 0) := x"1";
       constant CLS_START_BYTE   : std_logic_vector(3 downto 0) := x"2";
       constant CLS_CBUS         : std_logic_vector(3 downto 0) := x"3";
       constant CLS_OTHER_BUS    : std_logic_vector(3 downto 0) := x"4";
       constant CLS_FUTURE       : std_logic_vector(3 downto 0) := x"5";
       constant CLS_HS_MASTER    : std_logic_vector(3 downto 0) := x"6";
       constant CLS_DEVICE_ID    : std_logic_vector(3 downto 0) := x"7";
       constant CLS_TENBIT       : std_logic_vector(3 downto 0) := x"8";
       constant CLS_RSVD_UPPER   : std_logic_vector(3 downto 0) := x"9";

       signal addr         : std_logic_vector(6 downto 0) := (others => '0');
       signal rw           : std_logic := '0';
       signal is_reserved  : std_logic;
       signal addr_class   : std_logic_vector(3 downto 0);
       signal must_not_ack : std_logic;
       signal test_done    : std_logic := '0';
   begin
       dut : entity work.i2c_address_classifier
           port map (addr => addr, rw => rw, is_reserved => is_reserved,
                     addr_class => addr_class, must_not_ack => must_not_ack);

       watchdog : process
       begin
           wait for 20 us;
           if test_done = '0' then
               report "watchdog expired -- the sweep never completed" severity failure;
           end if;
           wait;
       end process;

       stim : process
           variable errs            : natural := 0;
           variable n_reserved_addr : natural := 0;
           variable n_usable_addr   : natural := 0;
           variable usable_both     : boolean;
           type hist_t is array (0 to 9) of natural;
           variable class_hist      : hist_t := (others => 0);

           -- INDEPENDENT reference model: arithmetic range tests rather than a
           -- bit-pattern case, so a shared misreading cannot make the two agree.
           function ref_class (a : natural; d : natural) return std_logic_vector is
           begin
               if a = 0 then
                   if d = 1 then return CLS_START_BYTE; else return CLS_GENERAL_CALL; end if;
               elsif a = 1                   then return CLS_CBUS;
               elsif a = 2                   then return CLS_OTHER_BUS;
               elsif a = 3                   then return CLS_FUTURE;
               elsif a >= 4   and a <= 7     then return CLS_HS_MASTER;
               elsif a >= 120 and a <= 123   then return CLS_TENBIT;
               elsif a >= 124 and a <= 127   then
                   if d = 1 then return CLS_DEVICE_ID; else return CLS_RSVD_UPPER; end if;
               else                               return CLS_USABLE;
               end if;
           end function;

           function ref_reserved (a : natural) return std_logic is
           begin
               -- Reservation is by address group, independent of direction.
               if a <= 7 or a >= 120 then return '1'; else return '0'; end if;
           end function;
       begin
           for a in 0 to 127 loop
               usable_both := true;
               for d in 0 to 1 loop
                   addr <= std_logic_vector(to_unsigned(a, 7));
                   if d = 1 then rw <= '1'; else rw <= '0'; end if;
                   wait for 1 ns;

                   if addr_class /= ref_class(a, d) then
                       report "addr=" & integer'image(a) & " rw=" & integer'image(d)
                            & ": class disagrees with the reference model" severity error;
                       errs := errs + 1;
                   end if;
                   if is_reserved /= ref_reserved(a) then
                       report "addr=" & integer'image(a) & ": is_reserved disagrees" severity error;
                       errs := errs + 1;
                   end if;
                   if (must_not_ack = '1') /= (ref_class(a,d) = CLS_START_BYTE
                                            or ref_class(a,d) = CLS_CBUS) then
                       report "addr=" & integer'image(a) & " rw=" & integer'image(d)
                            & ": must_not_ack wrong" severity error;
                       errs := errs + 1;
                   end if;

                   class_hist(to_integer(unsigned(addr_class)))
                       := class_hist(to_integer(unsigned(addr_class))) + 1;
                   if addr_class /= CLS_USABLE then usable_both := false; end if;
               end loop;
               if ref_reserved(a) = '1' then n_reserved_addr := n_reserved_addr + 1; end if;
               if usable_both then n_usable_addr := n_usable_addr + 1; end if;
           end loop;

           if n_reserved_addr /= 16 then
               report "reserved addresses = " & integer'image(n_reserved_addr) & ", expected 16"
                   severity error; errs := errs + 1; end if;
           if n_usable_addr /= 112 then
               report "usable addresses = " & integer'image(n_usable_addr) & ", expected 112"
                   severity error; errs := errs + 1; end if;
           if class_hist(0) /= 224 then
               report "usable classifications = " & integer'image(class_hist(0)) & ", expected 224"
                   severity error; errs := errs + 1; end if;
           if class_hist(1) /= 1 or class_hist(2) /= 1 then
               report "general call / START byte must be one combination each" severity error;
               errs := errs + 1; end if;
           if class_hist(8) /= 8 then
               report "10-bit prefix should cover 8 combinations" severity error;
               errs := errs + 1; end if;

           if errs = 0 then
               report "i2c_address_classifier self-check complete: all 256 combinations match an "
                    & "independent model; " & integer'image(n_reserved_addr) & " reserved, "
                    & integer'image(n_usable_addr) & " usable addresses" severity note;
           else
               report "i2c_address_classifier self-check FAILED" severity error;
           end if;
           test_done <= '1';
           wait;
       end process;
   end architecture;

8a. Cross-Language Parity

SystemVerilogVerilog-2005VHDL
decode constructcasez with ?casez with ?VHDL-2008 case? with -
don't-care marker??-
group testassign on a part-selectassign on a part-selectconditional signal assignment
class codeslocalparam logic [3:0]localparam [3:0]constant std_logic_vector

The VHDL version uses the matching case of VHDL-2008 (case? … when "0000001-" =>), which is the language's direct equivalent of casez and keeps the transcription property intact. Without it the decode would have to be an if-chain, which would be correct and considerably harder to review against the table — a real example of a language feature earning its place for a reason other than brevity.

Verified execution. All three complete at the same simulated time, having swept every combination:

languagesimulatorresultcompletes at
SystemVerilogIcarus Verilog, -g2012PASS256 ns
Verilog-2005Icarus Verilog, -g2005PASS256 ns
VHDLnvc 1.23.0PASS256 ns

9. Verifying a Table Exhaustively

An eight-bit input space has 256 members. That is small enough to test all of it, which changes what verification can claim: not "the cases we thought of are right" but "the function is right".

Two decisions make the sweep worth more than its size suggests.

The reference model is written differently from the design. The RTL is a casez over bit patterns; the model is a chain of arithmetic range tests on the address as an integer. Both encode Table 3, from the same source, through two different mental routes. A shared misreading is the failure mode an exhaustive sweep cannot catch on its own — if model and design were written the same way from the same wrong understanding, they would agree perfectly and both be wrong. Structuring them differently does not eliminate that risk, but it makes a shared error much less likely to survive, because the two forms fail differently under a misreading.

The counts are checked, not just the individual classifications. The sweep tallies its results and then asserts properties of the whole map:

checkvaluewhat it establishes
reserved addresses16two groups of eight, and not a bit more
addresses usable in both directions112the arithmetic of §1, by counting
usable classifications224112 addresses × 2 directions, so no reserved address leaks into "usable"
general call combinations1it is one address and one direction, not an address
START byte combinations1likewise — the pair that §3 is about
10-bit prefix combinations8four addresses × 2 directions

The 112 in that table is the same number derived arithmetically in §1, arrived at by a completely different route — counting simulation results rather than subtracting. That is the "two independent calculations" discipline applied to a number the whole chapter rests on.

10. Mutation Testing

Five faults injected into the verified RTL. Four caught; one is a provably equivalent mutant.

mutationwhat it breaksresult
reservation depends on the direction bitthe group test stops being about the groupFAIL — address 0x00
general call and START byte swappeda prohibited byte becomes a broadcastFAIL — address 0x00
must_not_ack omits the CBUS addressa device may answer CBUS trafficFAIL — address 0x01
11111XX decoded as the 10-bit prefixdevice ID misclassifiedFAIL — address 0x7C
Hs-mode range widened to 0000???see belowsurvived — provably equivalent

The survivor is a lesson about priority-ordered case statements, not a coverage gap.

Widening the Hs-mode branch from 00001?? to 0000??? looks like it should match far more: 0000??? covers addresses 0x00 through 0x07, the entire lower reserved group. But casez is priority-ordered, and the four branches above it already claim 0000000, 0000001, 0000010 and 0000011. So the widened branch newly matches only 0000100 through 0000111 — which is exactly 00001XX, the range it had before.

The mutation is a no-op. No stimulus can distinguish the two designs, because the earlier branches shadow everything the widening added.

That is worth knowing for two reasons. It means an exhaustive sweep — the strongest verification in this module — still cannot detect a redundantly widened case item, so case-item precision is a review property rather than a testable one. And it is a caution about the transcription style this chapter recommends: priority ordering makes the decode readable and also makes later items quietly tolerant of imprecision. A reviewer checking the code against the table line by line catches it; a testbench never will.

11. Verification Connection — Reserved-Address Behaviour Is Negative Testing

Most of what this chapter specifies is behaviour a device must not exhibit, and negative requirements need deliberate stimulus because nothing in normal operation produces them.

Azvya Education Pvt. Ltd.VLSI Mentor
UVM CONCEPT — VERIFICATION ONLY. Driving the reserved map on purpose.
   // Normal traffic never sends a reserved address, so a constrained-random
   // sequence weighted towards realism will never test any of this chapter.
   // The reserved cases have to be a DELIBERATE sequence.
   class i2c_reserved_addr_seq extends uvm_sequence #(i2c_addr_phase);
       `uvm_object_utils(i2c_reserved_addr_seq)
       function new(string name = "i2c_reserved_addr_seq"); super.new(name); endfunction

       task body();
           i2c_addr_phase t;
           // Every reserved combination, not a sample of them: the space is 16
           // addresses by 2 directions, which is 32 transfers. Cheap, and complete.
           for (int a = 0; a < 128; a++) begin
               if (!(a <= 7 || a >= 120)) continue;       // only the reserved groups
               for (int d = 0; d < 2; d++) begin
                   t = i2c_addr_phase::type_id::create("t");
                   start_item(t);
                   t.addr = a[6:0];
                   t.read = d[0];
                   finish_item(t);
               end
           end
       endtask
   endclass

   // The checks these transfers feed are all NEGATIVE, and the assertion is the
   // natural form for a "must never" requirement.
   property no_ack_on_start_byte;
       @(posedge scl_rising) disable iff (!rst_n)
       (addr_phase_done && addr_seen == 7'b0000000 && rw_seen == 1'b1)
           |-> !any_device_acked;
   endproperty
   assert property (no_ack_on_start_byte)
       else `uvm_error("I2C_RSVD", "a device acknowledged the START byte")

   property no_ack_on_cbus;
       @(posedge scl_rising) disable iff (!rst_n)
       (addr_phase_done && addr_seen == 7'b0000001) |-> !any_device_acked;
   endproperty

Three points, and the first is the one that generalises furthest.

Realistic random stimulus is the wrong tool here. A sequence weighted to resemble real traffic sends real addresses, and real traffic never addresses 0000001. The reserved map is reached only by a sequence written specifically to reach it — which means the coverage hole is invisible to any metric based on how much stimulus was run.

The space is small enough to enumerate. Thirty-two transfers cover every reserved address in both directions. When a requirement space is that small, sampling it randomly is strictly worse than walking it.

"Must never acknowledge" is an assertion, not a test. A test can confirm that no device answered this START byte. An assertion confirms it for every START byte in every test for the life of the project, including the ones written later by somebody who has not read this chapter.

12. FPGA and ASIC Implications

The decode is free, and the review is not. Ten casez items and a four-bit output is a handful of LUTs. The engineering cost of this block is entirely in checking it against the table, which is the argument for writing it as a transcription rather than as optimised logic.

The classifier belongs in front of the address comparator, not beside it. §4's prohibition-beats-match rule means the classification has to be available when the match decision is acted on. Structurally that makes the classifier a combinational stage feeding the decision logic, which is exactly how Chapter 6.5 wires it.

Reclaiming reserved addresses is a configuration decision that should be visible in silicon. If a system opts into a reserved address per §5, that decision wants to be a parameter or a strap with a name that says what it is — not an absence of checking. A device that silently answers a reserved address is indistinguishable, at bring-up, from a device with a broken comparator.

Hs-mode and device ID are decoded here and handled elsewhere. Recognising the 00001XX master code is this block's job; doing anything about High-speed mode is Module 14's. Keeping the recognition and the response in different blocks is what lets a device that does not support Hs-mode still correctly not answer its master code.

13. Debugging — The Device That Answered a Broadcast It Should Have Ignored

A bus that locked up whenever one particular master initialised

Pitfall — comparing the seven address bits and deciding about direction afterwards
Buggy Code
// A slave decodes its address the obvious way: compare the seven bits, then look
// at the direction to decide what to do next.
//
//   if (addr_bits == OWN_ADDR) begin
//       addressed <= 1'b1;
//       direction <= rw;
//       ack       <= 1'b1;
//   end else if (addr_bits == 7'b0000000) begin
//       // general call support
//       addressed <= 1'b1;
//       gen_call  <= 1'b1;
//       ack       <= 1'b1;             // <-- acknowledges 0000000 in BOTH directions
//   end
//
// The general call branch tests the seven ADDRESS BITS only. It has the direction
// bit available -- it is right there in the rw signal -- and does not consult it,
// the engineer's mental model is "0000000 is the general call address", which is
// true and incomplete.
//
// It passes every general call test, because a general call really is 0000000 with
// R/W = 0, and that is what a general call test sends.
Symptom

The board works with three of the four masters it has to interoperate with.

With the fourth, the bus locks up during that master's initialisation -- before any application traffic. Sometimes it recovers, sometimes it needs a power cycle. The failing master is the only one that is a software bit-banging implementation rather than a hardware peripheral, which immediately makes everyone suspect its timing, and its timing is measurably fine.

A capture of the initialisation shows the master sending 0x01 on the wire -- seven zero address bits and a one -- and a device pulling SDA low in the acknowledge slot. Then the master, which was not expecting an acknowledge, continues its wake-up sequence, and the slave, which thinks it has been addressed as a general call receiver, waits for a second byte that means something. The two proceed on incompatible assumptions until something times out.

The confusing part: 0x01 is not any device's address, so "which device answered 0x01" has no obvious answer, and the device that did answer looks from its own logs like it handled a general call correctly.

Root Cause

0x01 on the wire is the START BYTE: address 0000000 with R/W = 1. The specification's footnote is unambiguous -- "No device is allowed to acknowledge at the reception of the START byte" -- and a bit-banging master sends it deliberately, as a wake-up pattern, because it needs a long recognisable low period to give software-sampled slaves time to notice bus activity. Section 4 is exactly this.

The slave acknowledged it because its general call branch compared only the seven address bits. Those bits ARE 0000000 for both the general call and the START byte; the ONLY thing distinguishing a broadcast every device may answer from a byte no device may answer is the direction bit -- section 3, and Figures 1 and 2 are the same waveform apart from one interval.

Three masters never triggered it because three masters are hardware peripherals that have no reason to send a START byte. Table 2 marks the START byte optional and applicable only to multi-master configurations, so a hardware master omitting it is entirely compliant -- which means the bug was latent until a compliant master exercised a compliant optional feature.

And the reason the slave's own view looked correct is that it really did execute a correct general call reception. Its logic was right about everything except which byte it had received.

Fix
// Classify the whole EIGHT-BIT byte, and let the prohibition win before any match
// is acted on. Section 8's classifier takes {addr, rw} as one input for precisely
// this reason, and section 4's ordering rule is the other half:
//
//   if (must_not_ack) begin             // START byte, CBUS -- checked FIRST
//       addressed <= 1'b0;
//   end else if (own_match) begin
//       ...
//   end else if (gen_call_match) begin  // now genuinely only 0000000 + W
//       ...
//   end
//
// Chapter 6.5 builds that ordering and injects a fault that reverses it.
//
// The verification lesson is that this entire class of bug lives in stimulus
// NOBODY SENDS ON PURPOSE:
//
//   1. A general call test sends a general call. It cannot find this bug, because
//      the bug is in what happens to a DIFFERENT byte that shares seven bits with
//      it. The reserved map has to be walked deliberately -- section 11's sequence
//      enumerates all 32 reserved combinations, which is cheap and complete.
//
//   2. The requirement is NEGATIVE, so the natural check is an assertion rather
//      than a test: "no device acknowledges the START byte" holds for every
//      transfer in every test forever, including tests written by people who have
//      never read Table 3.
//
// The reading habit: in Table 3 the R/W column is part of the KEY, not a note. Two
// rows share an address and differ only in that column, and they mean opposite
// things. Any decoder that reduces the key to seven bits has merged two rows of
// the table into one.
//
// The interoperability habit: "works with the masters we tested" is weak evidence
// when the specification marks features optional. The failing master here was more
// compliant than the ones that passed -- it used an optional feature the others
// simply never exercise.

14. Common Misconceptions

"Sixteen addresses are reserved, so 112 are free for my board." 112 is the ceiling on what the specification leaves available. A real board's usable set is smaller, because fixed-address parts occupy what they occupy. Chapter 6.4 is about the gap.

"Whether an address is reserved depends on the R/W bit." It does not. The two groups are seven-bit patterns. The direction bit selects among purposes within an entry — and §10's first mutation is what conflating the two produces.

"0000000 is the general call address." 0000000 with R/W = 0 is. With R/W = 1 it is the START byte, which no device may acknowledge. §13 is one bit of difference costing an interoperability failure.

"A reserved address is simply unavailable." The specification permits reclaiming one when its intended purpose provably will never be needed. That is a system-architecture commitment for the life of the system, and it should be an explicit, named opt-in rather than an absence of checking.

"If my device's address matches, it should respond." Not for the START byte or the CBUS address. Those footnotes are prohibitions with no exception for a device that happens to have been given the address, and the prohibition has to be evaluated before the match is acted on.

"A device that ignores a general call is broken." General call support is optional in every configuration. A device that does not answer is exercising an option, and the specification even notes that a device may ignore the call by simply not acknowledging.

"The master can tell how many devices answered a general call." It cannot. The wired-AND makes one responder indistinguishable from many, and a NACK from most devices is invisible if even one acknowledges.

"An exhaustive test proves the decode is right." It proves the decode matches the model. If both were written from the same misreading they agree and are both wrong — which is why the model here is structured differently from the RTL — and §10 shows an exhaustive sweep still cannot detect a redundantly widened case item.

15. Reason It Through

Why must a classifier take eight bits rather than seven?

Because two rows of Table 3 share an address and are distinguished only by the direction bit, and they mean opposite things: 0000000+W is a broadcast every device may answer, 0000000+R is a byte no device may answer. A seven-bit classifier has merged those two rows, and §13 is the interoperability failure that follows.

A device is strapped to 0000001 by a board error. Its comparator matches. What must it do?

Not respond. The CBUS footnote forbids I²C-compatible devices from responding to that address, with no exception for a device that has been given it. That is why a decoder must evaluate the prohibition before acting on a match — the ordering is implicit in the specification and reversing it produces a device that is compliant except in exactly the case the rule exists for.

Your board has no CBUS devices and never uses Hs-mode. How much address space can you reclaim, and what are you committing to?

Potentially the 0000001 CBUS address and the four 00001XX Hs-mode master codes, among others — but the commitment is for the life of the system, including variants and field upgrades nobody has designed yet, and it forfeits interoperation with any future compliant master that uses them. Reclaiming the general call or START byte addresses is a stronger step again, because those carry prohibitions rather than merely purposes.

A master issues a general call and sees an acknowledge. What does it know?

That at least one device answered. Not which, and not how many — the wired-AND makes one responder indistinguishable from several. And it cannot detect refusals: if any device acknowledges, the NACKs of every other device are invisible. So a general call is a broadcast with essentially no feedback, which is why its meaning lives in a second byte rather than in a response.

Why can an exhaustive 256-combination sweep not catch a redundantly widened case item?

Because casez is priority-ordered, so a widened later item is shadowed by the earlier items that already claim those patterns. The two designs are functionally identical over the entire input space, so no stimulus distinguishes them. Case-item precision is a review property, and §10's surviving mutation is the demonstration.

Which single row of Table 2 explains most of what you actually meet in silicon?

The seven-bit slave address row, because it is the only mandatory one. Every other addressing feature — 10-bit, general call, software reset, START byte, device ID — is optional, so a designer can rely on seven-bit addressing with any compliant part and must check the datasheet for everything else. A device that omits an optional feature is not faulty.

16. Understanding Check

17. Summary

Two groups of eight are reserved — 0000XXX and 1111XXX — leaving 112 of 128 seven-bit addresses allocatable, verified here by counting simulation results as well as by arithmetic.

Reservation is a property of the address group, not of the direction bit. The R/W bit selects among purposes within an entry.

One address means two opposite things. 0000000+W is the general call; 0000000+R is the START byte, which no device may acknowledge. A classifier must therefore take all eight bits.

Two footnotes are prohibitions rather than descriptions, and the prohibition beats an address match — a rule whose priority the specification never states explicitly and which §13 shows costs an interoperability failure to get wrong.

The reserved space can be reclaimed when its purpose provably will never be needed, which is a commitment for the life of the system and should be a named opt-in rather than a missing check.

The general call gives essentially no feedback. Answering is optional, the meaning is in the second byte, and the wired-AND means the master can neither count responders nor see refusals.

One addressing feature is mandatory and the rest are optional, which is the best single predictor of what a designer can rely on across parts.

Write the decode as a transcription of the table. A casez, or VHDL-2008's case?, puts the code beside the table for line-by-line review — and the exhaustive sweep in §9 still cannot check case-item precision, so that review is not optional.

18. What Comes Next

The map is now established: what is reserved, what is prohibited, and how many addresses a board may allocate in principle. What it does not explain is why 112 available addresses still produce collisions on real boards every day, or what to do when two parts you need both ship at 0x48.

Chapter 6.4 is that problem: how real parts let you move their address, what strap pins actually do in silicon, how a strapped address can land in the reserved space this chapter just mapped, and how multiplexers and switches let the same address appear twice on one board.

Browse the full path on the I²C tutorials index. For the prefix this chapter placed in context, see 10-Bit Addressing; for the byte the map classifies, The Address Byte.

Continue learning