4
4
--
5
5
-- Copyright 2025 Oxide Computer Company
6
6
7
+ -- I2C Control Link Layer
8
+ --
9
+ -- This block handles the bit-level details of an I2C transaction. It requires higher order logic
10
+ -- to actually orchestrate the transaction and is designed for use with i2c_ctrl_txn_layer.
11
+ --
12
+ -- Notes:
13
+ -- - This block currently does not support block stretching.
14
+ -- - This block currently does not do ackknowledge-polling after a write.
15
+
7
16
library ieee;
8
17
use ieee.std_logic_1164.all ;
9
18
use ieee.numeric_std_unsigned.all ;
@@ -101,6 +110,7 @@ architecture rtl of i2c_ctrl_link_layer is
101
110
transition_sda_cntr_en : std_logic ;
102
111
ack_sending : std_logic ;
103
112
sr_scl_fedge_seen : std_logic ;
113
+ stop_requested : std_logic ;
104
114
105
115
-- interfaces
106
116
rx_data : std_logic_vector (7 downto 0 );
@@ -125,6 +135,7 @@ architecture rtl of i2c_ctrl_link_layer is
125
135
'0' , -- transition_sda_cntr_en
126
136
'0' , -- ack_sending
127
137
'0' , -- sr_scl_fedge_seen
138
+ '0' , -- stop_requested
128
139
(others => '0' ),-- rx_data
129
140
'0' , -- rx_data_valid
130
141
(others => '0' ),-- tx_data
@@ -255,6 +266,12 @@ begin
255
266
v.transition_sda_cntr_en := '0' ;
256
267
end if ;
257
268
269
+ -- Latch if a stop is requested to handle the case when it may need to happen before the end
270
+ -- of the transaction.
271
+ if sm_reg.stop_requested = '0' then
272
+ v.stop_requested := '1' when tx_stop = '1' and txn_next_valid = '1' else '0' ;
273
+ end if ;
274
+
258
275
case sm_reg.state is
259
276
260
277
-- Ready and awaiting the next transaction
@@ -311,12 +328,14 @@ begin
311
328
end if ;
312
329
313
330
when HANDLE_NEXT =>
314
- if txn_next_valid then
331
+ if v.stop_requested then
332
+ v.state := STOP_SDA;
333
+ elsif txn_next_valid then
315
334
if tx_start then
316
335
-- A repeated start was issued mid-transaction
317
- v.state := WAIT_REPEAT_START;
318
- v.counter := START_SETUP_HOLD_TICKS;
319
- v.count_load := '1' ;
336
+ v.state := WAIT_REPEAT_START;
337
+ v.counter := START_SETUP_HOLD_TICKS;
338
+ v.count_load := '1' ;
320
339
elsif tx_stop then
321
340
v.state := STOP_SDA;
322
341
elsif tx_data_valid then
@@ -335,6 +354,8 @@ begin
335
354
if sm_reg.bits_shifted = 8 then
336
355
v.state := ACK_RX;
337
356
v.bits_shifted := 0 ;
357
+ elsif v.stop_requested then
358
+ v.state := STOP_SDA;
338
359
else
339
360
v.sda_oe := not sm_reg.tx_data(7 );
340
361
v.tx_data := sm_reg.tx_data(sm_reg.tx_data'high - 1 downto sm_reg.tx_data'low ) & '1' ;
@@ -347,7 +368,7 @@ begin
347
368
v.sda_oe := '0' ;
348
369
349
370
if scl_redge then
350
- v.state := HANDLE_NEXT;
371
+ v.state := STOP_SDA when v.stop_requested else HANDLE_NEXT;
351
372
v.rx_ack := not sda_in_syncd;
352
373
v.rx_ack_valid := '1' ;
353
374
end if ;
@@ -370,13 +391,14 @@ begin
370
391
-- at the first transition_sda pulse start sending the (N)ACK
371
392
if transition_sda = '1' then
372
393
if sm_reg.ack_sending = '0' then
373
- v.sda_oe := tx_ack;
394
+ v.sda_oe := '1' when (tx_ack = '1' and v.stop_requested = '0' )
395
+ else '0' ;
374
396
v.ack_sending := '1' ;
375
397
else
376
398
-- at the next transition point release the bus
377
399
v.sda_oe := '0' ;
378
400
v.ack_sending := '0' ;
379
- v.state := HANDLE_NEXT;
401
+ v.state := STOP_SDA when sm_reg.stop_requested else HANDLE_NEXT;
380
402
end if ;
381
403
end if ;
382
404
@@ -405,7 +427,9 @@ begin
405
427
end case ;
406
428
407
429
-- next state logic
408
- v.ready := '1' when v.state = IDLE or v.state = HANDLE_NEXT else '0' ;
430
+ v.ready := '1' when v.state = IDLE or
431
+ (v.state = HANDLE_NEXT and sm_reg.stop_requested = '0' )
432
+ else '0' ;
409
433
410
434
sm_reg_next <= v;
411
435
end process ;
0 commit comments