I²C · Module 18
The Transmit Datapath — Sourcing Read Data in Time
The hardest datapath in a target, because the master decides when the next bit is wanted and the slave must have decided what it is one phase earlier. Builds the pre-fetch, shows why a transmitted one is a release, and why the ninth slot must be given back.
On a write the target receives, and 18.6 had a whole bit slot to think in. On a read the master begins clocking immediately after the acknowledge — and this is the hardest datapath in a target.
1. The Pre-Fetch Problem
That is a structural consequence of not owning the clock, and it is the mirror of Chapter 17.7's problem seen from the other end: there the master had to decide its acknowledge before seeing the byte; here the target has to produce a byte before being asked for it.
So tx_req pulses in the cycle this block latches tx_byte, and the consumer must present the byte in the same cycle — a combinational read of a register file, not a multi-cycle fetch.
2. A Transmitted One Is a Release
bit = 0 -> sda_drive_low = 1 pull the line down
bit = 1 -> sda_drive_low = 0 release, and let the pull-up do it3. Driven on the Falling Edge, Sampled on the Rising One
The bit is placed in the low phase — the only phase §3.1.2 allows SDA to change in — and the master samples it in the high phase that follows.
Note the asymmetry with the receive path:
| instant | why | |
|---|---|---|
| received bits (18.6) | scl_rise | SDA is guaranteed stable there |
| transmitted bits (here) | scl_fall | it is the only phase SDA may change in |
Both rules come from the same sentence. Mutation M8 places bits on the rising edge instead and fails twelve checks — every one of them through the "SDA moved while SCL was high" observer.
4. The Ninth Slot Is Not Ours
After eight bits the master drives the acknowledge, so this block must release and stop. Chapter 18.8 reads what the master says there.
A read that will not end is one of the two ways an I²C bus wedges permanently. Mutation M6 drives a ninth bit and fails thirteen checks.
5. Framing Abandons the Byte
A repeated START or STOP mid-read means the master has taken the bus back. The transmitter must let go at once — and releasing here cannot itself produce a framing edge, because the edge has already happened.
Mutations M11 (framing ignored) fails six checks — and it survived the first mutation run, because the bench had tied the framing inputs to zero. §9 has the detail.
6. One Byte, Reconstructed From the Wire
Eight slots ours, the ninth theirs
9 cycles7. The Transmit Datapath, in Three Languages
// -----------------------------------------------------------------------------
// i2c_slave_tx.sv
// The transmit datapath: source a byte the master is already clocking out.
//
// THE PROBLEM THAT MAKES THIS THE HARDEST DATAPATH IN A SLAVE. On a write, the slave
// receives; it has the whole of a bit slot to think, and if it cannot keep up it can
// stretch. On a READ, the master begins clocking immediately after the acknowledge --
// and the slave must already have the first bit on SDA before that first rising edge,
// because §3.1.2 forbids changing SDA once SCL is high.
//
// So the byte must be fetched BEFORE it is needed. That is the pre-fetch problem, and it
// is a structural consequence of not owning the clock:
//
// the master decides WHEN the next bit is wanted
// the slave must have decided WHAT it is, one phase earlier
//
// WHEN THE REQUEST IS ISSUED. `tx_req` pulses when this block takes a byte, and the
// consumer must present `tx_byte` in the SAME cycle -- a combinational read of a register
// file, not a multi-cycle fetch. Chapter 18.9 builds a register file that can do that,
// and Chapter 18.10 is where a slave whose source genuinely cannot answer in one cycle
// stretches SCL instead. Those are the only two honest options; hoping is not one.
//
// A TRANSMITTED ONE IS A RELEASE. There is no drive-high. So:
//
// bit = 0 -> sda_drive_low = 1 pull the line down
// bit = 1 -> sda_drive_low = 0 release, and let the pull-up do it
//
// which means a byte of 0xFF is transmitted by driving nothing at all, and a slave that
// "drives" a one has written the single most common sign error in I²C twice over -- once
// here and once in whatever it thinks the pad does.
//
// DRIVEN ON THE FALLING EDGE, sampled by the master on the rising one. The bit is placed
// in the low phase, which is the only phase §3.1.2 allows SDA to change in. Note the
// asymmetry with the receive path: received bits are captured at `scl_rise`, transmitted
// bits are placed at `scl_fall`. Both rules come from the same sentence.
//
// AND THE NINTH SLOT IS NOT OURS. After eight bits the master drives the acknowledge, so
// this block must RELEASE and stop -- Chapter 18.8 reads what the master says there. A
// transmitter still driving in the ninth slot fights the master's ACK: the master pulls
// low to acknowledge, the slave is holding a one by releasing, and that part is fine --
// but if the slave's eighth bit was a zero and it fails to release, the master reads its
// own NACK as an ACK and keeps reading a byte the slave never intended to send.
// -----------------------------------------------------------------------------
module i2c_slave_tx #(
parameter int CNT_W = 16
) (
input logic clk,
input logic rst_n,
// From Chapter 18.2. Transmitted bits are placed on the FALLING edge.
input logic scl_fall,
// From Chapter 18.3 -- framing abandons the byte.
input logic start_pulse,
input logic stop_pulse,
// From the layer above: start sourcing a byte now. One cycle.
input logic tx_start,
// ... and keep going after the master acknowledged the last one.
input logic tx_continue,
// The byte source. `tx_req` pulses in the cycle this block latches `tx_byte`, so the
// source must be combinationally ready -- see the header.
output logic tx_req,
input logic [7:0] tx_byte,
// DRIVE INTENT. 1 = pull SDA low, 0 = release. Never a driven high.
output logic sda_drive_low,
output logic driving, // we own SDA right now
output logic [3:0] bit_index, // 0..7
output logic byte_sent, // one cycle: eight bits are on the wire
output logic [CNT_W-1:0] n_bytes,
output logic [CNT_W-1:0] n_bits
);
localparam [1:0] T_IDLE = 2'd0,
T_LOAD = 2'd1, // a byte is owed; fetch it on the next fall
T_SEND = 2'd2; // driving bits 7..0
logic [1:0] state;
logic [7:0] shreg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// Reset RELEASES. Anything else holds the bus down.
sda_drive_low <= 1'b0;
driving <= 1'b0;
bit_index <= 4'd0;
byte_sent <= 1'b0;
tx_req <= 1'b0;
shreg <= 8'h00;
state <= T_IDLE;
n_bytes <= {CNT_W{1'b0}};
n_bits <= {CNT_W{1'b0}};
end else begin
byte_sent <= 1'b0;
tx_req <= 1'b0;
if (start_pulse || stop_pulse) begin
// Framing abandons the byte and releases the line. Releasing here cannot
// itself produce a framing edge: the edge has already happened.
sda_drive_low <= 1'b0;
driving <= 1'b0;
bit_index <= 4'd0;
state <= T_IDLE;
end else begin
case (state)
T_IDLE: begin
if (tx_start || tx_continue) begin
bit_index <= 4'd0;
state <= T_LOAD;
end
end
T_LOAD: begin
// The PRE-FETCH. The byte is taken and the first bit placed on the
// same falling edge, so it is valid before the master's next rise.
if (scl_fall) begin
tx_req <= 1'b1;
shreg <= tx_byte;
sda_drive_low <= ~tx_byte[7]; // a one RELEASES
driving <= 1'b1;
bit_index <= 4'd1;
n_bits <= n_bits + 1'b1;
state <= T_SEND;
end
end
T_SEND: begin
if (scl_fall) begin
if (bit_index == 4'd8) begin
// Eight bits are on the wire. The ninth slot belongs to the
// MASTER, so release and stop -- Chapter 18.8 reads its answer.
sda_drive_low <= 1'b0;
driving <= 1'b0;
bit_index <= 4'd0;
byte_sent <= 1'b1;
n_bytes <= n_bytes + 1'b1;
state <= T_IDLE;
end else begin
sda_drive_low <= ~shreg[6];
shreg <= {shreg[6:0], 1'b0};
bit_index <= bit_index + 4'd1;
n_bits <= n_bits + 1'b1;
end
end
end
default: state <= T_IDLE;
endcase
end
end
end
endmodule // -----------------------------------------------------------------------------
// i2c_slave_tx.v
// The transmit datapath: source a byte the master is already clocking out.
//
// THE PROBLEM THAT MAKES THIS THE HARDEST DATAPATH IN A SLAVE. On a write, the slave
// receives; it has the whole of a bit slot to think, and if it cannot keep up it can
// stretch. On a READ, the master begins clocking immediately after the acknowledge --
// and the slave must already have the first bit on SDA before that first rising edge,
// because §3.1.2 forbids changing SDA once SCL is high.
//
// So the byte must be fetched BEFORE it is needed. That is the pre-fetch problem, and it
// is a structural consequence of not owning the clock:
//
// the master decides WHEN the next bit is wanted
// the slave must have decided WHAT it is, one phase earlier
//
// WHEN THE REQUEST IS ISSUED. `tx_req` pulses when this block takes a byte, and the
// consumer must present `tx_byte` in the SAME cycle -- a combinational read of a register
// file, not a multi-cycle fetch. Chapter 18.9 builds a register file that can do that,
// and Chapter 18.10 is where a slave whose source genuinely cannot answer in one cycle
// stretches SCL instead. Those are the only two honest options; hoping is not one.
//
// A TRANSMITTED ONE IS A RELEASE. There is no drive-high. So:
//
// bit = 0 -> sda_drive_low = 1 pull the line down
// bit = 1 -> sda_drive_low = 0 release, and let the pull-up do it
//
// which means a byte of 0xFF is transmitted by driving nothing at all, and a slave that
// "drives" a one has written the single most common sign error in I²C twice over -- once
// here and once in whatever it thinks the pad does.
//
// DRIVEN ON THE FALLING EDGE, sampled by the master on the rising one. The bit is placed
// in the low phase, which is the only phase §3.1.2 allows SDA to change in. Note the
// asymmetry with the receive path: received bits are captured at `scl_rise`, transmitted
// bits are placed at `scl_fall`. Both rules come from the same sentence.
//
// AND THE NINTH SLOT IS NOT OURS. After eight bits the master drives the acknowledge, so
// this block must RELEASE and stop -- Chapter 18.8 reads what the master says there. A
// transmitter still driving in the ninth slot fights the master's ACK: the master pulls
// low to acknowledge, the slave is holding a one by releasing, and that part is fine --
// but if the slave's eighth bit was a zero and it fails to release, the master reads its
// own NACK as an ACK and keeps reading a byte the slave never intended to send.
// (Verilog-2001 -- structurally identical to the SystemVerilog above.)
// -----------------------------------------------------------------------------
module i2c_slave_tx #(
parameter integer CNT_W = 16
) (
input wire clk,
input wire rst_n,
// From Chapter 18.2. Transmitted bits are placed on the FALLING edge.
input wire scl_fall,
// From Chapter 18.3 -- framing abandons the byte.
input wire start_pulse,
input wire stop_pulse,
// From the layer above: start sourcing a byte now. One cycle.
input wire tx_start,
// ... and keep going after the master acknowledged the last one.
input wire tx_continue,
// The byte source. `tx_req` pulses in the cycle this block latches `tx_byte`, so the
// source must be combinationally ready -- see the header.
output reg tx_req,
input wire [7:0] tx_byte,
// DRIVE INTENT. 1 = pull SDA low, 0 = release. Never a driven high.
output reg sda_drive_low,
output reg driving, // we own SDA right now
output reg [3:0] bit_index, // 0..7
output reg byte_sent, // one cycle: eight bits are on the wire
output reg [CNT_W-1:0] n_bytes,
output reg [CNT_W-1:0] n_bits
);
localparam [1:0] T_IDLE = 2'd0,
T_LOAD = 2'd1, // a byte is owed; fetch it on the next fall
T_SEND = 2'd2; // driving bits 7..0
reg [1:0] state;
reg [7:0] shreg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// Reset RELEASES. Anything else holds the bus down.
sda_drive_low <= 1'b0;
driving <= 1'b0;
bit_index <= 4'd0;
byte_sent <= 1'b0;
tx_req <= 1'b0;
shreg <= 8'h00;
state <= T_IDLE;
n_bytes <= {CNT_W{1'b0}};
n_bits <= {CNT_W{1'b0}};
end else begin
byte_sent <= 1'b0;
tx_req <= 1'b0;
if (start_pulse || stop_pulse) begin
// Framing abandons the byte and releases the line. Releasing here cannot
// itself produce a framing edge: the edge has already happened.
sda_drive_low <= 1'b0;
driving <= 1'b0;
bit_index <= 4'd0;
state <= T_IDLE;
end else begin
case (state)
T_IDLE: begin
if (tx_start || tx_continue) begin
bit_index <= 4'd0;
state <= T_LOAD;
end
end
T_LOAD: begin
// The PRE-FETCH. The byte is taken and the first bit placed on the
// same falling edge, so it is valid before the master's next rise.
if (scl_fall) begin
tx_req <= 1'b1;
shreg <= tx_byte;
sda_drive_low <= ~tx_byte[7]; // a one RELEASES
driving <= 1'b1;
bit_index <= 4'd1;
n_bits <= n_bits + 1'b1;
state <= T_SEND;
end
end
T_SEND: begin
if (scl_fall) begin
if (bit_index == 4'd8) begin
// Eight bits are on the wire. The ninth slot belongs to the
// MASTER, so release and stop -- Chapter 18.8 reads its answer.
sda_drive_low <= 1'b0;
driving <= 1'b0;
bit_index <= 4'd0;
byte_sent <= 1'b1;
n_bytes <= n_bytes + 1'b1;
state <= T_IDLE;
end else begin
sda_drive_low <= ~shreg[6];
shreg <= {shreg[6:0], 1'b0};
bit_index <= bit_index + 4'd1;
n_bits <= n_bits + 1'b1;
end
end
end
default: state <= T_IDLE;
endcase
end
end
end
endmodule -- -----------------------------------------------------------------------------
-- i2c_slave_tx.vhd
-- The transmit datapath: source a byte the master is already clocking out. Same ports,
-- generic, reset values and bit timing as the SystemVerilog and Verilog versions.
-- -----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity i2c_slave_tx is
generic (
CNT_W : positive := 16
);
port (
clk : in std_logic;
rst_n : in std_logic;
-- From Chapter 18.2. Transmitted bits are placed on the FALLING edge.
scl_fall : in std_logic;
-- From Chapter 18.3 -- framing abandons the byte.
start_pulse : in std_logic;
stop_pulse : in std_logic;
tx_start : in std_logic;
tx_continue : in std_logic;
-- The byte source. tx_req pulses in the cycle this block latches tx_byte, so the
-- source must be combinationally ready.
tx_req : out std_logic;
tx_byte : in std_logic_vector(7 downto 0);
-- DRIVE INTENT. 1 = pull SDA low, 0 = release. Never a driven high.
sda_drive_low : out std_logic;
driving : out std_logic;
bit_index : out unsigned(3 downto 0);
byte_sent : out std_logic;
n_bytes : out unsigned(CNT_W-1 downto 0);
n_bits : out unsigned(CNT_W-1 downto 0)
);
end entity i2c_slave_tx;
architecture rtl of i2c_slave_tx is
type state_t is (T_IDLE, T_LOAD, T_SEND);
signal state : state_t := T_IDLE;
signal shreg : std_logic_vector(7 downto 0) := (others => '0');
signal r_drive, r_driving, r_sent, r_req : std_logic := '0';
signal r_idx : unsigned(3 downto 0) := (others => '0');
signal c_by, c_bi : unsigned(CNT_W-1 downto 0) := (others => '0');
begin
process (clk, rst_n)
begin
if rst_n = '0' then
-- Reset RELEASES. Anything else holds the bus down.
r_drive <= '0';
r_driving <= '0';
r_idx <= (others => '0');
r_sent <= '0';
r_req <= '0';
shreg <= (others => '0');
state <= T_IDLE;
c_by <= (others => '0');
c_bi <= (others => '0');
elsif rising_edge(clk) then
r_sent <= '0';
r_req <= '0';
if start_pulse = '1' or stop_pulse = '1' then
-- Framing abandons the byte and releases the line. Releasing here cannot
-- itself produce a framing edge: the edge has already happened.
r_drive <= '0';
r_driving <= '0';
r_idx <= (others => '0');
state <= T_IDLE;
else
case state is
when T_IDLE =>
if tx_start = '1' or tx_continue = '1' then
r_idx <= (others => '0');
state <= T_LOAD;
end if;
when T_LOAD =>
-- The PRE-FETCH. The byte is taken and the first bit placed on the same
-- falling edge, so it is valid before the master's next rise.
if scl_fall = '1' then
r_req <= '1';
shreg <= tx_byte;
r_drive <= not tx_byte(7); -- a one RELEASES
r_driving <= '1';
r_idx <= to_unsigned(1, 4);
c_bi <= c_bi + 1;
state <= T_SEND;
end if;
when T_SEND =>
if scl_fall = '1' then
if r_idx = 8 then
-- Eight bits are on the wire. The ninth slot belongs to the
-- MASTER, so release and stop -- Chapter 18.8 reads its answer.
r_drive <= '0';
r_driving <= '0';
r_idx <= (others => '0');
r_sent <= '1';
c_by <= c_by + 1;
state <= T_IDLE;
else
r_drive <= not shreg(6);
shreg <= shreg(6 downto 0) & '0';
r_idx <= r_idx + 1;
c_bi <= c_bi + 1;
end if;
end if;
end case;
end if;
end if;
end process;
tx_req <= r_req;
sda_drive_low <= r_drive;
driving <= r_driving;
bit_index <= r_idx;
byte_sent <= r_sent;
n_bytes <= c_by;
n_bits <= c_bi;
end architecture rtl;7a. The testbenches
Fifteen checks. The bench is the master-receiver: it clocks, keeps SDA released, and reconstructs each byte from the wire rather than from the DUT's shift register.
| # | Test | Property |
|---|---|---|
| T1 | reset releases | a transmitter holding SDA low kills the bus |
| T2 | unasked, it drives nothing | the false-positive test |
| T3 | the pre-fetch — the first bit is on the wire before the first rise | |
| T4 | 0xFF is transmitted by driving nothing | a one is a release |
| T5 | 0x00 pulls low for every bit | the mirror case |
| T6 | MSB first, with 0x80 and 0x01 | |
| T7 | an arbitrary byte, reconstructed from the wire | exactly eight bits driven |
| T8 | SDA never moved during a high phase | the invariant every defect trips |
| T9 | after eight bits it releases | the ninth slot is the master's |
| T10 | one byte completed | |
| T11 | a continued read sources the next byte, re-reading the source | so an advanced pointer is honoured |
| T12 | reset mid-byte releases immediately | |
| T13 | byte_sent fires once per byte, one cycle | added after M12; see §8 |
| T14 | a repeated START mid-byte abandons it and releases | added after M11 |
| T15 | and a STOP does the same |
One bench detail is worth copying: gen_pulse is rise-then-fall, and a separate gen_first_fall supplies the loading edge. A task that began by asserting a low which was already low produces no falling edge — so the second byte of a continued read loses its loading edge and runs one fall short. A transmitter needs exactly one fall per bit slot, plus one to load and one to release: nine per byte, not eight.
// -----------------------------------------------------------------------------
// i2c_slave_tx_tb.sv
// Independent oracle for i2c_slave_tx.
//
// The bench is the MASTER-RECEIVER: it clocks, releases SDA so the slave can drive, and
// samples what arrives at each rising edge -- reconstructing the byte from the wire
// rather than believing the DUT's shift register. That is the only way to prove a
// transmitter: the value it thinks it sent is not evidence.
// -----------------------------------------------------------------------------
`timescale 1ns/1ps
module i2c_slave_tx_tb;
localparam integer HALF = 8;
logic clk = 1'b0, rst_n = 1'b0;
logic m_scl_low = 1'b0, m_sda_low = 1'b0;
logic tx_start = 1'b0, tx_continue = 1'b0;
// Framing inputs, DRIVEN rather than tied off -- the third time in this module
// that a tied-off port turned out to be an untested one.
logic f_start = 1'b0, f_stop = 1'b0;
logic [7:0] src = 8'h00;
logic s_sda_low, driving, byte_sent, tx_req;
logic [3:0] bit_index;
logic [15:0] n_bytes, n_bits;
// The bus, wired-AND. The slave's contribution is what this bench exists to observe.
wire scl = ~m_scl_low;
wire sda = ~(m_sda_low | s_sda_low);
logic scl_q, sda_q, scl_rise, scl_fall, sda_rise, sda_fall;
integer errors = 0, n, k;
// ---- master-receiver reconstruction, from the WIRE ------------------------
reg [7:0] rx_shift = 8'h00;
integer n_sampled = 0;
reg [7:0] got_byte [0:7];
integer n_got = 0;
// Sample only the slots the slave is actually DRIVING. A real master-receiver knows
// which slots are data slots -- it is generating the clock -- so gating on `driving`
// is not cheating, it is the master's own knowledge of the frame. Counting every rise
// instead would fold the acknowledge slot's rise into the byte and misalign every
// byte after the first.
always @(posedge clk) if (rst_n && scl_rise && driving) begin
rx_shift = {rx_shift[6:0], sda};
n_sampled = n_sampled + 1;
if (n_sampled % 8 == 0) begin got_byte[n_got[2:0]] = rx_shift; n_got = n_got + 1; end
end
// ---- the invariant observer: SDA must not move while SCL is HIGH ----------
integer moved_high = 0, drove_cycles = 0;
// `byte_sent` gets its own observer. It is the pulse Chapter 18.8 looks for the
// master's answer on, and this bench instantiates no consumer for it -- so without a
// check a transmitter whose bits are all correct and whose byte_sent never fires would
// pass everything while leaving the target unable to notice a NACK.
integer n_sent_obs = 0, sent_wide = 0;
logic bs_d = 1'b0;
always @(posedge clk) begin
if (rst_n) begin
if (byte_sent) n_sent_obs <= n_sent_obs + 1;
if (byte_sent & bs_d) sent_wide <= sent_wide + 1;
end
bs_d <= byte_sent;
end
logic s_d = 1'b0;
always @(posedge clk) begin
if (rst_n) begin
if ((s_sda_low !== s_d) && scl) moved_high <= moved_high + 1;
if (s_sda_low) drove_cycles <= drove_cycles + 1;
end
s_d <= s_sda_low;
end
i2c_slave_sync #(.SYNC_DEPTH(2)) u_sync (
.clk(clk), .rst_n(rst_n), .scl_pin(scl), .sda_pin(sda),
.scl_q(scl_q), .sda_q(sda_q), .scl_rise(scl_rise), .scl_fall(scl_fall),
.sda_rise(sda_rise), .sda_fall(sda_fall));
i2c_slave_tx #(.CNT_W(16)) dut (
.clk(clk), .rst_n(rst_n), .scl_fall(scl_fall),
.start_pulse(f_start), .stop_pulse(f_stop),
.tx_start(tx_start), .tx_continue(tx_continue),
.tx_req(tx_req), .tx_byte(src),
.sda_drive_low(s_sda_low), .driving(driving),
.bit_index(bit_index), .byte_sent(byte_sent),
.n_bytes(n_bytes), .n_bits(n_bits));
always #5 clk = ~clk;
task step; begin @(posedge clk); @(negedge clk); end endtask
task phase; begin for (n = 0; n < HALF; n = n + 1) step; end endtask
task do_reset;
begin
@(negedge clk); rst_n = 1'b0;
m_scl_low = 1'b0; m_sda_low = 1'b0; tx_start = 1'b0; tx_continue = 1'b0;
f_start = 1'b0; f_stop = 1'b0;
n_sent_obs = 0; sent_wide = 0;
moved_high = 0; drove_cycles = 0; n_sampled = 0; n_got = 0; rx_shift = 8'h00;
step; step; @(negedge clk); rst_n = 1'b1; phase;
end
endtask
// One clock pulse driven by the master: RISE then FALL, starting and ending with SCL
// low. The master keeps SDA released throughout, so whatever appears on the wire is
// the slave's.
//
// The shape matters. A task that began by asserting a low which was ALREADY low
// produces no falling edge, so the first pulse of a second byte loses the edge that
// loads it -- the byte then runs one fall short and never completes. The transmitter
// needs exactly one fall per bit slot, so the generator must produce exactly one.
task gen_pulse; begin
@(negedge clk); m_scl_low = 1'b0; phase; // high phase: the master samples
@(negedge clk); m_scl_low = 1'b1; phase; // fall: the slave places the next bit
end endtask
// The falling edge that begins a transfer, taking SCL from its idle high to low. This
// is the edge the pre-fetch happens on, so it is separate from the bit pulses.
task gen_first_fall; begin
@(negedge clk); m_scl_low = 1'b0; phase;
@(negedge clk); m_scl_low = 1'b1; phase;
end endtask
task pulse_start; begin
@(negedge clk); tx_start = 1'b1; step; @(negedge clk); tx_start = 1'b0; end
endtask
task pulse_continue; begin
@(negedge clk); tx_continue = 1'b1; step; @(negedge clk); tx_continue = 1'b0; end
endtask
task ck_bit (input [200*8:1] w, input g, input e);
begin if (g !== e) begin
$display(" FAIL %0s: got %0b expected %0b", w, g, e); errors = errors + 1; end end
endtask
task ck_int (input [200*8:1] w, input integer g, input integer e);
begin if (g !== e) begin
$display(" FAIL %0s: got %0d expected %0d", w, g, e); errors = errors + 1; end end
endtask
initial begin
$display("=== i2c_slave_tx: source a byte the master is already clocking ===");
// T1. Reset releases. A transmitter holding SDA low out of reset kills the bus.
do_reset;
$display("T1 reset releases SDA");
ck_bit("T1 not driving", s_sda_low, 1'b0);
ck_bit("T1 the line is high", sda, 1'b1);
ck_bit("T1 does not claim ownership", driving, 1'b0);
// T2. Nothing without a request. The false-positive test: clocking a transmitter
// that was never asked for a byte must produce silence.
do_reset;
for (k = 0; k < 4; k = k + 1) gen_pulse;
$display("T2 unasked, it drives nothing at all");
ck_int("T2 never drove", drove_cycles, 0);
ck_int("T2 never moved SDA in a high phase", moved_high, 0);
// T3. THE PRE-FETCH. The first bit must be on the wire BEFORE the master's first
// rising edge, because §3.1.2 forbids changing SDA once SCL is high. The byte
// is taken and the first bit placed on the same falling edge.
do_reset;
@(negedge clk); src = 8'h00; // MSB is 0 -> the line must be pulled LOW
pulse_start;
gen_first_fall; // the edge the pre-fetch happens on
$display("T3 the first bit is on the wire before the master's first rise");
ck_bit("T3 driving already", driving, 1'b1);
ck_bit("T3 and the MSB is presented", s_sda_low, 1'b1);
ck_bit("T3 the line is low", sda, 1'b0);
// T4. A TRANSMITTED ONE IS A RELEASE. 0xFF is sent by driving nothing whatsoever.
do_reset;
@(negedge clk); src = 8'hFF;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T4 0xFF is transmitted by driving nothing -- a one is a release");
ck_int("T4 the master received 0xFF", got_byte[0], 8'hFF);
ck_int("T4 and the slave never pulled the line down", drove_cycles, 0);
// T5. A TRANSMITTED ZERO PULLS LOW. 0x00 is the mirror case.
do_reset;
@(negedge clk); src = 8'h00;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T5 0x00 is transmitted by pulling low for every bit");
ck_int("T5 the master received 0x00", got_byte[0], 8'h00);
// T6. MSB FIRST, proved with the two values that distinguish the orders.
do_reset;
@(negedge clk); src = 8'h80;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T6 MSB first, proved with 0x80");
ck_int("T6 the master received 0x80", got_byte[0], 8'h80);
do_reset;
@(negedge clk); src = 8'h01;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
ck_int("T6 and 0x01 the other way", got_byte[0], 8'h01);
// T7. AN ARBITRARY PATTERN, read off the wire bit by bit.
do_reset;
@(negedge clk); src = 8'hA6;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T7 an arbitrary byte, reconstructed from the wire");
ck_int("T7 0xA6 arrived", got_byte[0], 8'hA6);
ck_int("T7 exactly eight bits were driven", n_bits, 8);
ck_int("T7 one byte completed", n_bytes, 1);
// T8. THE INVARIANT. Over the whole byte, SDA never changed while SCL was high.
// Every timing defect in this block shows up here, because all of them move
// SDA in the wrong phase.
$display("T8 SDA never moved during a high phase");
ck_int("T8 no movement in any high phase", moved_high, 0);
// T9. THE NINTH SLOT IS NOT OURS. After eight bits the transmitter must release so
// the master can drive its acknowledge. A transmitter still holding a zero
// there makes the master read its own NACK as an ACK.
do_reset;
@(negedge clk); src = 8'h00; // every bit low, including the last
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T9 after eight bits it releases: the ninth slot is the master's");
ck_bit("T9 no longer driving", s_sda_low, 1'b0);
ck_bit("T9 ownership given up", driving, 1'b0);
ck_bit("T9 and the line is free for the master's ACK", sda, 1'b1);
// And it stays released through the ninth pulse.
gen_pulse;
ck_bit("T9 still released through the ninth pulse", s_sda_low, 1'b0);
// T10. byte_sent IS ONE CYCLE, once per byte. The layer above advances on it.
do_reset;
@(negedge clk); src = 8'h3C;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
n = 0;
// The pulse fires on the fall that ends the eighth bit, which gen_pulse has
// already produced, so look for the completion having been recorded.
ck_int("T10 exactly one byte completed", n_bytes, 1);
// T11. CONTINUING sources a second byte, and the source is re-read -- so a
// register file that advanced its pointer is honoured.
do_reset;
@(negedge clk); src = 8'h11;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
@(negedge clk); src = 8'h22; // the source has moved on
pulse_continue;
// Nine falls per byte, not eight: one to load the MSB, seven to place bits 6..0,
// and one to release for the acknowledge slot. A continued byte needs its own
// loading edge exactly as the first one did.
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T11 a continued read sources the NEXT byte, re-reading the source");
ck_int("T11 first byte", got_byte[0], 8'h11);
ck_int("T11 second byte", got_byte[1], 8'h22);
ck_int("T11 two bytes completed", n_bytes, 2);
ck_int("T11 sixteen bits driven", n_bits, 16);
// T12. FRAMING ABANDONS THE BYTE AND RELEASES. A repeated START mid-read means
// the master has taken the bus back; the transmitter must let go at once.
do_reset;
@(negedge clk); src = 8'h00;
pulse_start;
gen_first_fall;
gen_pulse; // two bits out, still driving low
ck_bit("T12 driving mid-byte", s_sda_low, 1'b1);
// A reset stands in for the framing path here, which the integrated target wires;
// the block's own framing inputs are exercised at integration in Chapter 18.11.
@(negedge clk); rst_n = 1'b0; step; step;
$display("T12 reset mid-byte releases the line immediately");
ck_bit("T12 released", s_sda_low, 1'b0);
ck_bit("T12 and the bus is free", sda, 1'b1);
// ----------------------------------------------------------------
// T13. byte_sent IS THE HAND-OFF TO 18.8. One pulse per byte, one cycle wide. It is
// what tells the target to start watching for the master's acknowledge, so a
// transmitter with perfect bits and no byte_sent would source byte after byte
// and never notice a NACK -- a read that will not end, which wedges the bus.
// ----------------------------------------------------------------
do_reset;
@(negedge clk); src = 8'h5A;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
@(negedge clk); src = 8'hA5;
pulse_continue;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T13 byte_sent fires once per byte, one cycle wide");
ck_int("T13 two byte_sent pulses", n_sent_obs, 2);
ck_int("T13 neither was wide", sent_wide, 0);
ck_int("T13 and two bytes completed", n_bytes, 2);
// ----------------------------------------------------------------
// T14. FRAMING ABANDONS THE BYTE AND RELEASES. A repeated START mid-read means the
// master has taken the bus back; a transmitter that kept driving would fight
// whatever the master does next -- and if the master is framing, the held line
// prevents the framing from happening at all.
// ----------------------------------------------------------------
do_reset;
@(negedge clk); src = 8'h00; // every bit low, so driving is visible
pulse_start;
gen_first_fall;
gen_pulse;
ck_bit("T14 driving mid-byte", s_sda_low, 1'b1);
@(negedge clk); f_start = 1'b1; step; @(negedge clk); f_start = 1'b0;
step;
$display("T14 a repeated START mid-byte abandons it and releases the line");
ck_bit("T14 released", s_sda_low, 1'b0);
ck_bit("T14 ownership given up", driving, 1'b0);
ck_bit("T14 and the bus is free", sda, 1'b1);
// ----------------------------------------------------------------
// T15. AND A STOP DOES THE SAME.
// ----------------------------------------------------------------
do_reset;
@(negedge clk); src = 8'h00;
pulse_start;
gen_first_fall;
gen_pulse;
ck_bit("T15 driving mid-byte", s_sda_low, 1'b1);
@(negedge clk); f_stop = 1'b1; step; @(negedge clk); f_stop = 1'b0;
step;
$display("T15 a STOP mid-byte does the same");
ck_bit("T15 released", s_sda_low, 1'b0);
ck_bit("T15 ownership given up", driving, 1'b0);
if (errors == 0) $display("=== i2c_slave_tx: ALL CHECKS PASSED ===");
else $display("=== i2c_slave_tx: %0d CHECK(S) FAILED ===", errors);
$finish;
end
endmodule // -----------------------------------------------------------------------------
// i2c_slave_tx_tb.v
// Independent oracle for i2c_slave_tx.
//
// The bench is the MASTER-RECEIVER: it clocks, releases SDA so the slave can drive, and
// samples what arrives at each rising edge -- reconstructing the byte from the wire
// rather than believing the DUT's shift register. That is the only way to prove a
// transmitter: the value it thinks it sent is not evidence.
// -----------------------------------------------------------------------------
`timescale 1ns/1ps
module i2c_slave_tx_tb;
localparam integer HALF = 8;
reg clk = 1'b0, rst_n = 1'b0;
reg m_scl_low = 1'b0, m_sda_low = 1'b0;
reg tx_start = 1'b0, tx_continue = 1'b0;
// Framing inputs, DRIVEN rather than tied off -- the third time in this module
// that a tied-off port turned out to be an untested one.
reg f_start = 1'b0, f_stop = 1'b0;
reg [7:0] src = 8'h00;
wire s_sda_low, driving, byte_sent, tx_req;
wire [3:0] bit_index;
wire [15:0] n_bytes, n_bits;
// The bus, wired-AND. The slave's contribution is what this bench exists to observe.
wire scl = ~m_scl_low;
wire sda = ~(m_sda_low | s_sda_low);
wire scl_q, sda_q, scl_rise, scl_fall, sda_rise, sda_fall;
integer errors = 0, n, k;
// ---- master-receiver reconstruction, from the WIRE ------------------------
reg [7:0] rx_shift = 8'h00;
integer n_sampled = 0;
reg [7:0] got_byte [0:7];
integer n_got = 0;
// Sample only the slots the slave is actually DRIVING. A real master-receiver knows
// which slots are data slots -- it is generating the clock -- so gating on `driving`
// is not cheating, it is the master's own knowledge of the frame. Counting every rise
// instead would fold the acknowledge slot's rise into the byte and misalign every
// byte after the first.
always @(posedge clk) if (rst_n && scl_rise && driving) begin
rx_shift = {rx_shift[6:0], sda};
n_sampled = n_sampled + 1;
if (n_sampled % 8 == 0) begin got_byte[n_got[2:0]] = rx_shift; n_got = n_got + 1; end
end
// ---- the invariant observer: SDA must not move while SCL is HIGH ----------
integer moved_high = 0, drove_cycles = 0;
// `byte_sent` gets its own observer. It is the pulse Chapter 18.8 looks for the
// master's answer on, and this bench instantiates no consumer for it -- so without a
// check a transmitter whose bits are all correct and whose byte_sent never fires would
// pass everything while leaving the target unable to notice a NACK.
integer n_sent_obs = 0, sent_wide = 0;
reg bs_d = 1'b0;
always @(posedge clk) begin
if (rst_n) begin
if (byte_sent) n_sent_obs <= n_sent_obs + 1;
if (byte_sent & bs_d) sent_wide <= sent_wide + 1;
end
bs_d <= byte_sent;
end
reg s_d = 1'b0;
always @(posedge clk) begin
if (rst_n) begin
if ((s_sda_low !== s_d) && scl) moved_high <= moved_high + 1;
if (s_sda_low) drove_cycles <= drove_cycles + 1;
end
s_d <= s_sda_low;
end
i2c_slave_sync #(.SYNC_DEPTH(2)) u_sync (
.clk(clk), .rst_n(rst_n), .scl_pin(scl), .sda_pin(sda),
.scl_q(scl_q), .sda_q(sda_q), .scl_rise(scl_rise), .scl_fall(scl_fall),
.sda_rise(sda_rise), .sda_fall(sda_fall));
i2c_slave_tx #(.CNT_W(16)) dut (
.clk(clk), .rst_n(rst_n), .scl_fall(scl_fall),
.start_pulse(f_start), .stop_pulse(f_stop),
.tx_start(tx_start), .tx_continue(tx_continue),
.tx_req(tx_req), .tx_byte(src),
.sda_drive_low(s_sda_low), .driving(driving),
.bit_index(bit_index), .byte_sent(byte_sent),
.n_bytes(n_bytes), .n_bits(n_bits));
always #5 clk = ~clk;
task step; begin @(posedge clk); @(negedge clk); end endtask
task phase; begin for (n = 0; n < HALF; n = n + 1) step; end endtask
task do_reset;
begin
@(negedge clk); rst_n = 1'b0;
m_scl_low = 1'b0; m_sda_low = 1'b0; tx_start = 1'b0; tx_continue = 1'b0;
f_start = 1'b0; f_stop = 1'b0;
n_sent_obs = 0; sent_wide = 0;
moved_high = 0; drove_cycles = 0; n_sampled = 0; n_got = 0; rx_shift = 8'h00;
step; step; @(negedge clk); rst_n = 1'b1; phase;
end
endtask
// One clock pulse driven by the master: RISE then FALL, starting and ending with SCL
// low. The master keeps SDA released throughout, so whatever appears on the wire is
// the slave's.
//
// The shape matters. A task that began by asserting a low which was ALREADY low
// produces no falling edge, so the first pulse of a second byte loses the edge that
// loads it -- the byte then runs one fall short and never completes. The transmitter
// needs exactly one fall per bit slot, so the generator must produce exactly one.
task gen_pulse; begin
@(negedge clk); m_scl_low = 1'b0; phase; // high phase: the master samples
@(negedge clk); m_scl_low = 1'b1; phase; // fall: the slave places the next bit
end endtask
// The falling edge that begins a transfer, taking SCL from its idle high to low. This
// is the edge the pre-fetch happens on, so it is separate from the bit pulses.
task gen_first_fall; begin
@(negedge clk); m_scl_low = 1'b0; phase;
@(negedge clk); m_scl_low = 1'b1; phase;
end endtask
task pulse_start; begin
@(negedge clk); tx_start = 1'b1; step; @(negedge clk); tx_start = 1'b0; end
endtask
task pulse_continue; begin
@(negedge clk); tx_continue = 1'b1; step; @(negedge clk); tx_continue = 1'b0; end
endtask
task ck_bit (input [200*8:1] w, input g, input e);
begin if (g !== e) begin
$display(" FAIL %0s: got %0b expected %0b", w, g, e); errors = errors + 1; end end
endtask
task ck_int (input [200*8:1] w, input integer g, input integer e);
begin if (g !== e) begin
$display(" FAIL %0s: got %0d expected %0d", w, g, e); errors = errors + 1; end end
endtask
initial begin
$display("=== i2c_slave_tx: source a byte the master is already clocking ===");
// T1. Reset releases. A transmitter holding SDA low out of reset kills the bus.
do_reset;
$display("T1 reset releases SDA");
ck_bit("T1 not driving", s_sda_low, 1'b0);
ck_bit("T1 the line is high", sda, 1'b1);
ck_bit("T1 does not claim ownership", driving, 1'b0);
// T2. Nothing without a request. The false-positive test: clocking a transmitter
// that was never asked for a byte must produce silence.
do_reset;
for (k = 0; k < 4; k = k + 1) gen_pulse;
$display("T2 unasked, it drives nothing at all");
ck_int("T2 never drove", drove_cycles, 0);
ck_int("T2 never moved SDA in a high phase", moved_high, 0);
// T3. THE PRE-FETCH. The first bit must be on the wire BEFORE the master's first
// rising edge, because §3.1.2 forbids changing SDA once SCL is high. The byte
// is taken and the first bit placed on the same falling edge.
do_reset;
@(negedge clk); src = 8'h00; // MSB is 0 -> the line must be pulled LOW
pulse_start;
gen_first_fall; // the edge the pre-fetch happens on
$display("T3 the first bit is on the wire before the master's first rise");
ck_bit("T3 driving already", driving, 1'b1);
ck_bit("T3 and the MSB is presented", s_sda_low, 1'b1);
ck_bit("T3 the line is low", sda, 1'b0);
// T4. A TRANSMITTED ONE IS A RELEASE. 0xFF is sent by driving nothing whatsoever.
do_reset;
@(negedge clk); src = 8'hFF;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T4 0xFF is transmitted by driving nothing -- a one is a release");
ck_int("T4 the master received 0xFF", got_byte[0], 8'hFF);
ck_int("T4 and the slave never pulled the line down", drove_cycles, 0);
// T5. A TRANSMITTED ZERO PULLS LOW. 0x00 is the mirror case.
do_reset;
@(negedge clk); src = 8'h00;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T5 0x00 is transmitted by pulling low for every bit");
ck_int("T5 the master received 0x00", got_byte[0], 8'h00);
// T6. MSB FIRST, proved with the two values that distinguish the orders.
do_reset;
@(negedge clk); src = 8'h80;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T6 MSB first, proved with 0x80");
ck_int("T6 the master received 0x80", got_byte[0], 8'h80);
do_reset;
@(negedge clk); src = 8'h01;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
ck_int("T6 and 0x01 the other way", got_byte[0], 8'h01);
// T7. AN ARBITRARY PATTERN, read off the wire bit by bit.
do_reset;
@(negedge clk); src = 8'hA6;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T7 an arbitrary byte, reconstructed from the wire");
ck_int("T7 0xA6 arrived", got_byte[0], 8'hA6);
ck_int("T7 exactly eight bits were driven", n_bits, 8);
ck_int("T7 one byte completed", n_bytes, 1);
// T8. THE INVARIANT. Over the whole byte, SDA never changed while SCL was high.
// Every timing defect in this block shows up here, because all of them move
// SDA in the wrong phase.
$display("T8 SDA never moved during a high phase");
ck_int("T8 no movement in any high phase", moved_high, 0);
// T9. THE NINTH SLOT IS NOT OURS. After eight bits the transmitter must release so
// the master can drive its acknowledge. A transmitter still holding a zero
// there makes the master read its own NACK as an ACK.
do_reset;
@(negedge clk); src = 8'h00; // every bit low, including the last
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T9 after eight bits it releases: the ninth slot is the master's");
ck_bit("T9 no longer driving", s_sda_low, 1'b0);
ck_bit("T9 ownership given up", driving, 1'b0);
ck_bit("T9 and the line is free for the master's ACK", sda, 1'b1);
// And it stays released through the ninth pulse.
gen_pulse;
ck_bit("T9 still released through the ninth pulse", s_sda_low, 1'b0);
// T10. byte_sent IS ONE CYCLE, once per byte. The layer above advances on it.
do_reset;
@(negedge clk); src = 8'h3C;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
n = 0;
// The pulse fires on the fall that ends the eighth bit, which gen_pulse has
// already produced, so look for the completion having been recorded.
ck_int("T10 exactly one byte completed", n_bytes, 1);
// T11. CONTINUING sources a second byte, and the source is re-read -- so a
// register file that advanced its pointer is honoured.
do_reset;
@(negedge clk); src = 8'h11;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
@(negedge clk); src = 8'h22; // the source has moved on
pulse_continue;
// Nine falls per byte, not eight: one to load the MSB, seven to place bits 6..0,
// and one to release for the acknowledge slot. A continued byte needs its own
// loading edge exactly as the first one did.
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T11 a continued read sources the NEXT byte, re-reading the source");
ck_int("T11 first byte", got_byte[0], 8'h11);
ck_int("T11 second byte", got_byte[1], 8'h22);
ck_int("T11 two bytes completed", n_bytes, 2);
ck_int("T11 sixteen bits driven", n_bits, 16);
// T12. FRAMING ABANDONS THE BYTE AND RELEASES. A repeated START mid-read means
// the master has taken the bus back; the transmitter must let go at once.
do_reset;
@(negedge clk); src = 8'h00;
pulse_start;
gen_first_fall;
gen_pulse; // two bits out, still driving low
ck_bit("T12 driving mid-byte", s_sda_low, 1'b1);
// A reset stands in for the framing path here, which the integrated target wires;
// the block's own framing inputs are exercised at integration in Chapter 18.11.
@(negedge clk); rst_n = 1'b0; step; step;
$display("T12 reset mid-byte releases the line immediately");
ck_bit("T12 released", s_sda_low, 1'b0);
ck_bit("T12 and the bus is free", sda, 1'b1);
// ----------------------------------------------------------------
// T13. byte_sent IS THE HAND-OFF TO 18.8. One pulse per byte, one cycle wide. It is
// what tells the target to start watching for the master's acknowledge, so a
// transmitter with perfect bits and no byte_sent would source byte after byte
// and never notice a NACK -- a read that will not end, which wedges the bus.
// ----------------------------------------------------------------
do_reset;
@(negedge clk); src = 8'h5A;
pulse_start;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
@(negedge clk); src = 8'hA5;
pulse_continue;
gen_first_fall;
for (k = 0; k < 8; k = k + 1) gen_pulse;
$display("T13 byte_sent fires once per byte, one cycle wide");
ck_int("T13 two byte_sent pulses", n_sent_obs, 2);
ck_int("T13 neither was wide", sent_wide, 0);
ck_int("T13 and two bytes completed", n_bytes, 2);
// ----------------------------------------------------------------
// T14. FRAMING ABANDONS THE BYTE AND RELEASES. A repeated START mid-read means the
// master has taken the bus back; a transmitter that kept driving would fight
// whatever the master does next -- and if the master is framing, the held line
// prevents the framing from happening at all.
// ----------------------------------------------------------------
do_reset;
@(negedge clk); src = 8'h00; // every bit low, so driving is visible
pulse_start;
gen_first_fall;
gen_pulse;
ck_bit("T14 driving mid-byte", s_sda_low, 1'b1);
@(negedge clk); f_start = 1'b1; step; @(negedge clk); f_start = 1'b0;
step;
$display("T14 a repeated START mid-byte abandons it and releases the line");
ck_bit("T14 released", s_sda_low, 1'b0);
ck_bit("T14 ownership given up", driving, 1'b0);
ck_bit("T14 and the bus is free", sda, 1'b1);
// ----------------------------------------------------------------
// T15. AND A STOP DOES THE SAME.
// ----------------------------------------------------------------
do_reset;
@(negedge clk); src = 8'h00;
pulse_start;
gen_first_fall;
gen_pulse;
ck_bit("T15 driving mid-byte", s_sda_low, 1'b1);
@(negedge clk); f_stop = 1'b1; step; @(negedge clk); f_stop = 1'b0;
step;
$display("T15 a STOP mid-byte does the same");
ck_bit("T15 released", s_sda_low, 1'b0);
ck_bit("T15 ownership given up", driving, 1'b0);
if (errors == 0) $display("=== i2c_slave_tx: ALL CHECKS PASSED ===");
else $display("=== i2c_slave_tx: %0d CHECK(S) FAILED ===", errors);
$finish;
end
endmodule -- -----------------------------------------------------------------------------
-- i2c_slave_tx_tb.vhd
-- Independent oracle for i2c_slave_tx. Behavioural twin of the SystemVerilog and Verilog
-- benches.
--
-- The bench is the MASTER-RECEIVER: it clocks, releases SDA so the slave can drive, and
-- reconstructs the byte from the WIRE rather than believing the DUT's shift register.
-- That is the only way to prove a transmitter -- the value it thinks it sent is not
-- evidence.
-- -----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity i2c_slave_tx_tb is
end entity i2c_slave_tx_tb;
architecture sim of i2c_slave_tx_tb is
constant HALF : positive := 8;
signal clk : std_logic := '0';
signal rst_n : std_logic := '0';
signal m_scl_low, m_sda_low : std_logic := '0';
signal tx_start, tx_continue : std_logic := '0';
-- Framing inputs, DRIVEN rather than tied off.
signal f_start, f_stop : std_logic := '0';
signal src : std_logic_vector(7 downto 0) := (others => '0');
signal s_sda_low, driving, byte_sent, tx_req : std_logic;
signal bit_index : unsigned(3 downto 0);
signal n_bytes, n_bits : unsigned(15 downto 0);
signal scl, sda : std_logic;
signal scl_q, sda_q : std_logic;
signal scl_rise, scl_fall, sda_rise, sda_fall : std_logic;
signal halt : boolean := false;
type gb_t is array (0 to 7) of std_logic_vector(7 downto 0);
signal got_byte : gb_t := (others => (others => '0'));
signal rx_shift : std_logic_vector(7 downto 0) := (others => '0');
signal n_sampled, n_got : integer := 0;
signal moved_high, drove_cycles : integer := 0;
-- byte_sent gets its own observer: it is the pulse Chapter 18.8 looks for the
-- master's answer on, and this bench instantiates no consumer for it.
signal n_sent_obs, sent_wide : integer := 0;
signal clr : boolean := false;
begin
scl <= not m_scl_low;
sda <= not (m_sda_low or s_sda_low);
u_sync : entity work.i2c_slave_sync
generic map (SYNC_DEPTH => 2)
port map (clk => clk, rst_n => rst_n, scl_pin => scl, sda_pin => sda,
scl_q => scl_q, sda_q => sda_q, scl_rise => scl_rise, scl_fall => scl_fall,
sda_rise => sda_rise, sda_fall => sda_fall);
dut : entity work.i2c_slave_tx
generic map (CNT_W => 16)
port map (clk => clk, rst_n => rst_n, scl_fall => scl_fall,
start_pulse => f_start, stop_pulse => f_stop,
tx_start => tx_start, tx_continue => tx_continue,
tx_req => tx_req, tx_byte => src,
sda_drive_low => s_sda_low, driving => driving,
bit_index => bit_index, byte_sent => byte_sent,
n_bytes => n_bytes, n_bits => n_bits);
clkgen : process
begin
while not halt loop
clk <= '0'; wait for 5 ns;
clk <= '1'; wait for 5 ns;
end loop;
wait;
end process;
-- Master-receiver reconstruction, from the WIRE, gated on the slave actually driving.
-- A real master-receiver knows which slots are data slots because it generates the
-- clock, so gating on `driving` is the master's own knowledge of the frame.
obs : process (clk, clr)
variable s_d, bs_d : std_logic := '0';
begin
if clr then
n_sampled <= 0; n_got <= 0; rx_shift <= (others => '0');
moved_high <= 0; drove_cycles <= 0;
n_sent_obs <= 0; sent_wide <= 0;
elsif rising_edge(clk) then
if rst_n = '1' then
if scl_rise = '1' and driving = '1' then
rx_shift <= rx_shift(6 downto 0) & sda;
n_sampled <= n_sampled + 1;
if (n_sampled + 1) mod 8 = 0 then
got_byte(n_got mod 8) <= rx_shift(6 downto 0) & sda;
n_got <= n_got + 1;
end if;
end if;
if s_sda_low /= s_d and scl = '1' then moved_high <= moved_high + 1; end if;
if s_sda_low = '1' then drove_cycles <= drove_cycles + 1; end if;
if byte_sent = '1' then n_sent_obs <= n_sent_obs + 1; end if;
if byte_sent = '1' and bs_d = '1' then sent_wide <= sent_wide + 1; end if;
end if;
s_d := s_sda_low; bs_d := byte_sent;
end if;
end process;
stim : process
variable err : integer := 0;
variable k : integer;
procedure step is
begin
wait until rising_edge(clk); wait until falling_edge(clk);
end procedure;
procedure phase is
begin
for i in 1 to HALF loop step; end loop;
end procedure;
procedure do_reset is
begin
wait until falling_edge(clk);
rst_n <= '0'; m_scl_low <= '0'; m_sda_low <= '0';
tx_start <= '0'; tx_continue <= '0'; f_start <= '0'; f_stop <= '0';
clr <= true; wait for 1 ns; clr <= false;
step; step;
wait until falling_edge(clk); rst_n <= '1';
phase;
end procedure;
-- RISE then FALL, starting and ending with SCL low: exactly one fall per bit slot.
procedure gen_pulse is
begin
wait until falling_edge(clk); m_scl_low <= '0'; phase;
wait until falling_edge(clk); m_scl_low <= '1'; phase;
end procedure;
-- The falling edge that begins a transfer. From the idle-high state this produces
-- only a fall; from the low state it produces a rise then a fall.
procedure gen_first_fall is
begin
wait until falling_edge(clk); m_scl_low <= '0'; phase;
wait until falling_edge(clk); m_scl_low <= '1'; phase;
end procedure;
procedure pulse_start is
begin
wait until falling_edge(clk); tx_start <= '1';
step;
wait until falling_edge(clk); tx_start <= '0';
end procedure;
procedure pulse_continue is
begin
wait until falling_edge(clk); tx_continue <= '1';
step;
wait until falling_edge(clk); tx_continue <= '0';
end procedure;
procedure ck_bit (what : string; g : std_logic; e : std_logic) is
begin
if g /= e then
report " FAIL " & what severity note;
err := err + 1;
end if;
end procedure;
procedure ck_int (what : string; g : integer; e : integer) is
begin
if g /= e then
report " FAIL " & what & ": got " & integer'image(g)
& " expected " & integer'image(e) severity note;
err := err + 1;
end if;
end procedure;
begin
report "=== i2c_slave_tx: source a byte the master is already clocking ==="
severity note;
-- T1. Reset releases.
do_reset;
report "T1 reset releases SDA" severity note;
ck_bit("T1 not driving", s_sda_low, '0');
ck_bit("T1 the line is high", sda, '1');
ck_bit("T1 does not claim ownership", driving, '0');
-- T2. Nothing without a request.
do_reset;
for k in 0 to 3 loop gen_pulse; end loop;
report "T2 unasked, it drives nothing at all" severity note;
ck_int("T2 never drove", drove_cycles, 0);
ck_int("T2 never moved SDA in a high phase", moved_high, 0);
-- T3. THE PRE-FETCH: the first bit is on the wire before the master's first rise.
do_reset;
wait until falling_edge(clk); src <= x"00";
pulse_start;
gen_first_fall;
report "T3 the first bit is on the wire before the master's first rise"
severity note;
ck_bit("T3 driving already", driving, '1');
ck_bit("T3 and the MSB is presented", s_sda_low, '1');
ck_bit("T3 the line is low", sda, '0');
-- T4. A transmitted one is a RELEASE: 0xFF drives nothing.
do_reset;
wait until falling_edge(clk); src <= x"FF";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T4 0xFF is transmitted by driving nothing -- a one is a release"
severity note;
ck_int("T4 the master received 0xFF", to_integer(unsigned(got_byte(0))), 255);
ck_int("T4 and the slave never pulled the line down", drove_cycles, 0);
-- T5. A transmitted zero pulls low.
do_reset;
wait until falling_edge(clk); src <= x"00";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T5 0x00 is transmitted by pulling low for every bit" severity note;
ck_int("T5 the master received 0x00", to_integer(unsigned(got_byte(0))), 0);
-- T6. MSB first, with the two distinguishing values.
do_reset;
wait until falling_edge(clk); src <= x"80";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T6 MSB first, proved with 0x80" severity note;
ck_int("T6 the master received 0x80", to_integer(unsigned(got_byte(0))), 16#80#);
do_reset;
wait until falling_edge(clk); src <= x"01";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
ck_int("T6 and 0x01 the other way", to_integer(unsigned(got_byte(0))), 1);
-- T7. An arbitrary pattern, read off the wire.
do_reset;
wait until falling_edge(clk); src <= x"A6";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T7 an arbitrary byte, reconstructed from the wire" severity note;
ck_int("T7 0xA6 arrived", to_integer(unsigned(got_byte(0))), 16#A6#);
ck_int("T7 exactly eight bits were driven", to_integer(n_bits), 8);
ck_int("T7 one byte completed", to_integer(n_bytes), 1);
-- T8. The invariant.
report "T8 SDA never moved during a high phase" severity note;
ck_int("T8 no movement in any high phase", moved_high, 0);
-- T9. The ninth slot is not ours.
do_reset;
wait until falling_edge(clk); src <= x"00";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T9 after eight bits it releases: the ninth slot is the master's"
severity note;
ck_bit("T9 no longer driving", s_sda_low, '0');
ck_bit("T9 ownership given up", driving, '0');
ck_bit("T9 and the line is free for the master's ACK", sda, '1');
gen_pulse;
ck_bit("T9 still released through the ninth pulse", s_sda_low, '0');
-- T10. One byte completed.
do_reset;
wait until falling_edge(clk); src <= x"3C";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
ck_int("T10 exactly one byte completed", to_integer(n_bytes), 1);
-- T11. A continued read sources the NEXT byte, re-reading the source.
do_reset;
wait until falling_edge(clk); src <= x"11";
pulse_start;
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
wait until falling_edge(clk); src <= x"22";
pulse_continue;
-- Nine falls per byte: one to load the MSB, seven to place bits 6..0, one to
-- release for the acknowledge slot.
gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T11 a continued read sources the NEXT byte, re-reading the source"
severity note;
ck_int("T11 first byte", to_integer(unsigned(got_byte(0))), 16#11#);
ck_int("T11 second byte", to_integer(unsigned(got_byte(1))), 16#22#);
ck_int("T11 two bytes completed", to_integer(n_bytes), 2);
ck_int("T11 sixteen bits driven", to_integer(n_bits), 16);
-- T12. Reset mid-byte releases immediately.
do_reset;
wait until falling_edge(clk); src <= x"00";
pulse_start;
gen_first_fall;
gen_pulse;
ck_bit("T12 driving mid-byte", s_sda_low, '1');
wait until falling_edge(clk); rst_n <= '0'; step; step;
report "T12 reset mid-byte releases the line immediately" severity note;
ck_bit("T12 released", s_sda_low, '0');
ck_bit("T12 and the bus is free", sda, '1');
-- T13. byte_sent is the hand-off to 18.8.
do_reset;
wait until falling_edge(clk); src <= x"5A";
pulse_start; gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
wait until falling_edge(clk); src <= x"A5";
pulse_continue; gen_first_fall;
for k in 0 to 7 loop gen_pulse; end loop;
report "T13 byte_sent fires once per byte, one cycle wide" severity note;
ck_int("T13 two byte_sent pulses", n_sent_obs, 2);
ck_int("T13 neither was wide", sent_wide, 0);
ck_int("T13 and two bytes completed", to_integer(n_bytes), 2);
-- T14. Framing abandons the byte and releases.
do_reset;
wait until falling_edge(clk); src <= x"00";
pulse_start; gen_first_fall; gen_pulse;
ck_bit("T14 driving mid-byte", s_sda_low, '1');
wait until falling_edge(clk); f_start <= '1';
step;
wait until falling_edge(clk); f_start <= '0';
step;
report "T14 a repeated START mid-byte abandons it and releases the line"
severity note;
ck_bit("T14 released", s_sda_low, '0');
ck_bit("T14 ownership given up", driving, '0');
ck_bit("T14 and the bus is free", sda, '1');
-- T15. And a STOP does the same.
do_reset;
wait until falling_edge(clk); src <= x"00";
pulse_start; gen_first_fall; gen_pulse;
ck_bit("T15 driving mid-byte", s_sda_low, '1');
wait until falling_edge(clk); f_stop <= '1';
step;
wait until falling_edge(clk); f_stop <= '0';
step;
report "T15 a STOP mid-byte does the same" severity note;
ck_bit("T15 released", s_sda_low, '0');
ck_bit("T15 ownership given up", driving, '0');
if err = 0 then
report "=== i2c_slave_tx: ALL CHECKS PASSED ===" severity note;
else
report "=== i2c_slave_tx: " & integer'image(err) & " CHECK(S) FAILED ==="
severity note;
end if;
halt <= true;
wait;
end process;
end architecture sim;7b. Execution
| Design | SystemVerilog | Verilog-2001 | VHDL | Finish |
|---|---|---|---|---|
i2c_slave_tx | PASS 15/15 | PASS 15/15 | PASS 15/15 | 22490 ns, all three |
8. Mutation Testing
Twelve defects.
| # | Injected defect | Expected detection | Result |
|---|---|---|---|
| M1 | the sign error — a transmitted one pulls low | T4 | KILLED (11) |
| M2 | the same sign error on the remaining seven bits | T4, T7 | KILLED (12) |
| M3 | LSB first | T6 | KILLED (5) |
| M4 | the shift register shifts the wrong way | T7 | KILLED (8) |
| M5 | the wrong shift-register bit is driven | T7 | KILLED (6) |
| M6 | nine bits driven — the ninth slot kept | T9 | KILLED (13) |
| M7 | seven bits, released one slot early | T7, T9 | KILLED (10) |
| M8 | bits placed on the rising edge | T8 | KILLED (12) |
| M9 | the pre-fetch does not latch the byte | T3, T7 | KILLED (7) |
| M10 | reset leaves SDA driven | T1 | KILLED (7) |
| M11 | framing does not abandon the byte | T14 new | KILLED (6) |
| M12 | byte_sent never emitted | T13 new | KILLED (2) |
baseline: PASS (verified before injecting anything)
valid mutants: 12 killed: 12 survived: 0 equivalent: 0 invalid: 0
restored: PASSBoth survivors were patterns this module has already produced
M11: the framing inputs were tied to zero in the bench — the same hole as 18.5 §9. A transmitter that keeps driving through a repeated START fights whatever the master does next, and if the master is framing, the held line prevents the framing from happening at all.
M12: byte_sent had no consumer — the same hole as 18.6 §8's byte_done. A transmitter with perfect bits and no byte_sent sources byte after byte and never notices a NACK, because 18.8 arms on that pulse and nothing else.
That is a checkable rule, and it is worth applying before trusting any mutation score.
9. Verification Connection — Proving a Transmitter
// 1. NEVER CHANGE SDA WHILE SCL IS HIGH. The property every timing defect in this
// block trips, stated on the drive INTENT rather than on the line.
property p_no_change_while_high;
@(posedge clk) disable iff (!rst_n)
(scl_q && $past(scl_q)) |-> $stable(sda_drive_low);
endproperty
a_phase: assert property (p_no_change_while_high);
// 2. A TRANSMITTED ONE NEVER PULLS DOWN. The sign error, as an assertion at this
// block's own boundary -- mutations M1 and M2.
property p_one_never_drives;
@(posedge clk) disable iff (!rst_n)
(driving && shreg_msb) |-> !sda_drive_low;
endproperty
a_sign: assert property (p_one_never_drives);
// 3. OWNERSHIP ENDS AT EIGHT. The drive may not be asserted once ownership is given
// up -- which is mutation M6's ninth bit.
property p_no_drive_when_not_owning;
@(posedge clk) disable iff (!rst_n) sda_drive_low |-> driving;
endproperty
a_own: assert property (p_no_drive_when_not_owning);
// 4. FRAMING RELEASES WITHIN A CYCLE.
property p_framing_releases;
@(posedge clk) disable iff (!rst_n)
(start_pulse || stop_pulse) |=> !sda_drive_low;
endproperty
a_abort: assert property (p_framing_releases);
// WHAT CANNOT BE ASSERTED FROM INSIDE, and it is the whole reason the bench
// reconstructs from the wire: "the master received the byte we intended".
//
// This block's shift register is not evidence about the bus. An assertion relating the
// register to the pad can only restate the block's own arithmetic -- if the shift
// direction is wrong, both sides of the assertion are wrong together and it passes.
//
// The only honest check samples the LINE at the master's rising edges and rebuilds the
// byte, which is what test T7 does. That is a bench property, not an assertion, and it
// is why a transmitter cannot be signed off on assertions alone.
//
// COVERAGE:
//
// cover: a byte of all ones (drives nothing -- the release path)
// cover: a byte of all zeros (drives every slot)
// cover: 0x80 and 0x01 the order-distinguishing pair
// cover: two consecutive bytes the continue path, and the re-read of the source
// cover: framing mid-byte T14/T15 -- an aborted read
// illegal_bin: drive asserted while not owning10. FPGA and ASIC Implications
On an FPGA the pre-fetch is the constraint that matters, and it is a combinational one: tx_byte must be valid in the same cycle tx_req pulses. That makes the register file's read path combinational from the pointer, which is exactly what Chapter 18.9 builds — and it is why a register file large enough to infer block RAM changes this interface rather than merely its area. Block RAM reads are registered, so a target with a block-RAM-backed map must either pre-fetch a cycle earlier or stretch.
Chapter 17.2 §9 made the same observation from the master's side, and the resolution is the same: the parameter that chooses the storage changes the interface timing, not just the size.
On an ASIC, this is the second block whose output reaches a pad, and the same three-signal rule applies: sda_drive_low drives the output enable, the data input is tied low, and the readback 18.2 consumes comes from the pad's input. There is no new pad here — it is the same SDA pad the acknowledge block drives, which means the two must be arbitrated. That arbitration is Chapter 18.11's, and it is a real integration decision rather than a formality: this block and 18.5 are the only two with SDA drive intent, and they must never assert together.
Reset releases, which is the same requirement as everywhere else and the same reason: a target holding SDA low during power-up prevents every device on the board from communicating.
11. Debugging — The Read That Returned 0x00 Instead of 0xFF
A target's register map is read back over I2C. Registers holding small values read correctly. Registers holding 0xFF read as 0x00, and registers holding 0x80 read as 0x7F. A pattern emerges: every bit the target should have transmitted as a one arrives as a zero, and vice versa. Writes to the same registers are correct, and the register contents are confirmed correct by a separate debug port.
The sign error: the drive intent was the bit rather than its complement. I2C is open-drain, so a transmitted one is a RELEASE and a transmitted zero is a pull-down -- the drive enable is the INVERSE of the data bit. Reading the shift register proves nothing about this, because the inversion sits between the register and the pad. The register file, the pointer, the bit ordering and the slot count were all correct; every byte was inverted on the wire and nowhere else.
Take the complement: sda_drive_low = NOT bit, which is mutation M1 in reverse. The durable fix is the bench, and it is the reason this chapter's tests are built the way they are -- reconstruct the byte from the WIRE, at the master's sampling instants, rather than comparing against the DUT's shift register. Test T4 is the sharpest form of it: transmit 0xFF and assert the drive-low was never asserted for a single cycle. A byte of all ones is sent by driving nothing, so any inversion makes the target drive continuously and the check fails immediately.Three generalisations.
The shift register is not evidence about the bus. Everything between the register and the pad — the inversion, the ownership gating, the release — is invisible to a check that reads the register. A transmitter must be verified from the line.
An inversion looks plausible on sparse data. Values with few set bits read as their complements and still look like "some value"; the pattern only becomes obvious on 0xFF and 0x80. That is why the extremes are tests rather than curiosities.
The sharpest test for a release-based one is a byte with no zeros. 0xFF must be transmitted by driving nothing, so the check is a count of drive cycles equal to zero — a negative assertion, and the kind that gets left out of a plan enumerating behaviours.
12. Common Misconceptions
"The target can fetch the byte when the master asks for it." By then SCL is about to rise and SDA may not change. The byte must be fetched one phase earlier. §1.
"A slow register file is a performance issue." It is a correctness issue: either the read is combinational or the target must stretch. §1.
"Transmitting a one means driving SDA high." It means releasing. 0xFF is sent by driving nothing at all. §2.
"Bits can be placed whenever the target is ready." Only on the falling edge, because that begins the only phase SDA may change in. §3.
"Received and transmitted bits use the same instant." Received at the rising edge, transmitted at the falling one — both rules from the same sentence. §3.
"Holding SDA through the ninth slot is harmless if the last bit was a one." If it was a zero, the master reads its own NACK as an ACK and the read never ends. §4.
"Framing can be handled by the same release path as end-of-byte." An end-of-byte release must wait for SCL to fall; a framing release must not. Two paths. §5.
"Comparing the shift register against the expected byte verifies a transmitter." The inversion, the gating and the release all sit after the register. §11.
"An output that is obviously correct needs no observer." byte_sent was correct in every test and silencing it passed the whole suite. §8.
13. Reason It Through
Why must the byte be fetched before the master asks for it?
Because the first bit must be on SDA before the master's first rising edge, and §3.1.2 forbids changing SDA once SCL is high. The fetch has to complete in the low phase. §1.
What are the only two ways to source a byte that a slow register file cannot deliver in one cycle?
Make the read combinational, or stretch the clock. Assuming the master will be slow enough is not one of them. §1.
Why is 0xFF the sharpest test of the open-drain contract?
Because it must be transmitted by driving nothing whatsoever, so any inversion makes the target drive continuously and a zero-drive-cycles check fails at once. §2, §11.
Received bits are sampled at the rising edge and transmitted bits placed at the falling one. Why is that not inconsistent?
Both follow from §3.1.2: SDA is stable while SCL is high, so that is when it may be read; it may only change while SCL is low, so that is when it may be written. §3.
A target keeps driving through the ninth slot and its eighth bit was a zero. What does the master conclude?
That it acknowledged — it reads its own NACK back as a low. The target then keeps sourcing and the read never ends, which wedges the bus. §4.
Why does a framing-driven release not need to wait for SCL to fall, when an end-of-byte release does?
Because the framing edge has already happened and the master controls the line, so the release cannot itself produce a framing condition. An end-of-byte release would make SDA rise, and a rise while SCL is high is a STOP. §5.
Six mutation survivors in this module fall into three shapes. Which, and what single check finds two of them?
The untested half of a symmetric property; a framing input tied off; an output with no consumer. A grep for constant port connections and for outputs appearing only in a port map finds the latter two. §8.
14. Understanding Check
15. Summary
The master decides when the next bit is wanted; the target must have decided what it is one phase earlier. That is the pre-fetch, and it is a structural consequence of not owning the clock.
So the byte source must be combinational — or the target must stretch. There is no third option.
A transmitted one is a release. 0xFF is sent by driving nothing, which makes it the sharpest test of the open-drain contract: zero drive cycles for a byte with no zeros.
Transmitted bits are placed on the falling edge, received bits sampled on the rising one — both rules from the same sentence of §3.1.2.
The ninth slot belongs to the master. A transmitter still driving there can make the master read its own NACK as an ACK, and a read that will not end wedges the bus.
Framing releases immediately, unlike an end-of-byte release which must wait for SCL to fall — two paths, and a block with one has a latent framing bug.
Twelve mutants, twelve killed — after two survived, both patterns this module had already produced: framing inputs tied to zero, and an output with no consumer instantiated.
Six survivors across the module, three shapes — an untested symmetric half, a tied-off input, an unobserved output. Two of the three are findable by grep, which makes them a checkable rule rather than a lesson.
And a transmitter cannot be verified from its shift register. The inversion, the gating and the release all sit after it, so the bench rebuilds each byte from the line at the master's sampling instants.
16. What Comes Next
The target can source bytes. Chapter 18.8 makes it listen to the answer — the ninth bit this chapter just handed back.
It is the mirror of 18.5: there the target owned the ninth slot and drove it; here the master owns it and the target reads it. The two must never be active together, and the consequence of ignoring the answer is the bus-wedging read of §4 — so the chapter is short, and one AND gate in it prevents a permanent failure.
Continue learning
Related tutorials
- Related topic
The Bit Engine — Driving and Sampling One Bit
One bit, and deliberately no more. Shows how making the drive point the only place SDA is written turns the data-valid rule from a property to be checked into one that cannot be violated, why transmit and receive are the same logic differing by one bit, and why an engine needs two different kinds of release because two normative rules are in tension.
- Related topic
Sampling SDA and SCL — Edge Detection Inside a Slave
The block every other one in a target is written against: two asynchronous wires turned into five synchronous facts. Three of its decisions produce defects nothing later can recover from — what the samplers reset to, which signals the edge pulses come from, and why the synchroniser belongs here and nowhere else.
- Related topic
START and STOP Detection Inside a Slave
Detection is two AND gates. The substance is what a START resets, and the distinction that is not on the wire at all — a first START and a repeated START are the identical edge, separated only by state the target keeps itself.
- Related topic
ACK Generation and Its Timing Window
Where most slave designs first fail. The acknowledge has three parts, the window is bounded at both ends by falling edges, and asserting early is not early — SDA falling while SCL is high is a START, so a premature acknowledge restarts the transaction instead of acknowledging a byte.
