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.
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 address | R/W | purpose | notes |
|---|---|---|---|
0000000 | 0 | general call address | §4; also carries software reset |
0000000 | 1 | START byte | no device may acknowledge |
0000001 | X | CBUS address | I²C devices may not respond |
0000010 | X | reserved for a different bus format | only devices that implement that format may respond |
0000011 | X | reserved for future purposes | |
00001XX | X | Hs-mode master code | four addresses; High-speed mode, Module 14 |
11110XX | X | 10-bit slave addressing | four addresses; Chapter 6.2 |
11111XX | 1 | device ID | four 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 cyclesSTART byte — the same seven zeros and R/W = 1
8 cyclesThe 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 byte | meaning |
|---|---|
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:
| feature | single master | multi-master | slave |
|---|---|---|---|
| 7-bit slave address | M | M | M |
| 10-bit slave address | O | O | O |
| General Call address | O | O | O |
| Software Reset | O | O | O |
| START byte | n/a | O | n/a |
| Device ID | n/a | n/a | O |
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.
// 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 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 // 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 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 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; 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
| SystemVerilog | Verilog-2005 | VHDL | |
|---|---|---|---|
| decode construct | casez with ? | casez with ? | VHDL-2008 case? with - |
| don't-care marker | ? | ? | - |
| group test | assign on a part-select | assign on a part-select | conditional signal assignment |
| class codes | localparam 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:
| language | simulator | result | completes at |
|---|---|---|---|
| SystemVerilog | Icarus Verilog, -g2012 | PASS | 256 ns |
| Verilog-2005 | Icarus Verilog, -g2005 | PASS | 256 ns |
| VHDL | nvc 1.23.0 | PASS | 256 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:
| check | value | what it establishes |
|---|---|---|
| reserved addresses | 16 | two groups of eight, and not a bit more |
| addresses usable in both directions | 112 | the arithmetic of §1, by counting |
| usable classifications | 224 | 112 addresses × 2 directions, so no reserved address leaks into "usable" |
| general call combinations | 1 | it is one address and one direction, not an address |
| START byte combinations | 1 | likewise — the pair that §3 is about |
| 10-bit prefix combinations | 8 | four 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.
| mutation | what it breaks | result |
|---|---|---|
| reservation depends on the direction bit | the group test stops being about the group | FAIL — address 0x00 |
| general call and START byte swapped | a prohibited byte becomes a broadcast | FAIL — address 0x00 |
must_not_ack omits the CBUS address | a device may answer CBUS traffic | FAIL — address 0x01 |
11111XX decoded as the 10-bit prefix | device ID misclassified | FAIL — address 0x7C |
Hs-mode range widened to 0000??? | see below | survived — 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.
// 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;
endpropertyThree 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
// 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.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.
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.
// 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
Related tutorials
- Related topic
Who Acknowledges When — Slave ACK and Master ACK
The acknowledge belongs to the receiver of a byte, so the direction of that byte decides who answers — not whether a device is the master or the slave. One sentence, four table rows, and the confusion it resolves is the most common one on this bus.
- Related topic
General Call and Broadcast Addressing
Address 0x00 reaches every device at once, participation is optional, and declining is done by staying silent. Explains why one acknowledge hides every refusal, why the meaning lives in the second byte, and why bit 0 of that byte turns a command into a master announcing itself.
- Related topic
Software Reset and Device ID
Two optional reserved-address services and what optional costs a design that wants to rely on them. Works through the seven-step Device ID read, its 12/9/3 bit packing across three bytes, and the two Remarks that name exactly which events destroy it.
- Related topic
The START Condition
START is SDA falling while SCL is high, it is generated only by the controller, and it makes the bus busy. Derive what every device must do in response, then build a detector in three languages and find out why its two guard terms and its reset value are all load-bearing.
