Skip to content

Commit

Permalink
[i2c] Add StretchAcqSetup state to preserve ACK setup time
Browse files Browse the repository at this point in the history
Add StretchAcqSetup state to follow the release of the hold from
StretchAcqFull after the ACQ FIFO gains the necessary space. Continue to
stretch SCL so the change to SDA doesn't violate setup time, then
proceed to the normal ACK setup state.

Remove the immediate write to the ACQ FIFO in the StretchAcqFull state
when we're proceeding to a normal ACK. This created extra ACQ FIFO
writes when it transitioned to the AcquireAckWait state, and the FSM
gets simpler and less error-prone if only error cases operate on FIFOs
outside of the non-stretch states.

Signed-off-by: Alexander Williams <[email protected]>
  • Loading branch information
a-will committed Apr 9, 2024
1 parent cfc063a commit 4062019
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 12 deletions.
8 changes: 6 additions & 2 deletions hw/ip/i2c/dv/env/seq_lib/i2c_glitch_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,24 @@ class i2c_glitch_vseq extends i2c_target_smoke_vseq;
// Target function clock stretch handling.
StretchAddr,
StretchTx, StretchTxSetup,
StretchAcqFull
StretchAcqFull, StretchAcqSetup
} state_e;

// initialize the states in which glitch is to be introduced
// Ignore state transitions covered in other testcases
// WaitForStop -> Idle and WaitForStop -> AcquireStart
// TransmitAckPulse -> Idle and TransmitAckPulse -> AcquireStart
// AcquireByte -> Idle and AcquireByte -> AcquireStart
// StretchAcqSetup is also an invalid start, as a control symbol is impossible
// in this state.
state_e read_states[] = '{TransmitWait, TransmitSetup, TransmitPulse, TransmitHold, TransmitAck,
TransmitAckPulse, StretchTx, StretchTxSetup};
state_e write_states[] = '{AcquireAckWait, AcquireAckSetup, AcquireAckPulse, AcquireAckHold,
StretchAcqFull};
state_e addr_states[] = '{StretchAddr, AddrAckWait, AddrAckSetup, AddrAckPulse, AddrAckHold};
state_e scl_high_states[] = '{TransmitPulse, AcquireAckPulse, AddrAckPulse};
// AddrAckSetup is here because SCL and SDA can change simultaneously,
// leading to failures after the modeled CDC random insertion delay.
state_e scl_high_states[] = '{TransmitPulse, AcquireAckPulse, AddrAckSetup, AddrAckPulse};

// Common steps for DUT initialization
virtual task setup();
Expand Down
31 changes: 21 additions & 10 deletions hw/ip/i2c/rtl/i2c_target_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ module i2c_target_fsm import i2c_pkg::*;
// Target function clock stretch handling.
StretchAddr,
StretchTx, StretchTxSetup,
StretchAcqFull
StretchAcqFull, StretchAcqSetup
} state_e;

state_e state_q, state_d;
Expand Down Expand Up @@ -585,12 +585,15 @@ module i2c_target_fsm import i2c_pkg::*;
nack_transaction_d = 1'b1;
acq_fifo_wvalid_o = !acq_fifo_full_or_last_space;
acq_fifo_wdata_o = {AcqNack, input_byte};
end else if (!stretch_rx) begin
// When space becomes available, deposit entry
acq_fifo_wvalid_o = 1'b1; // assert that acq_fifo has space
acq_fifo_wdata_o = {AcqData, input_byte}; // transfer data to acq_fifo
end
end
// StretchAcqSetup: Drive the ACK and wait for tSetupData before
// releasing SCL
StretchAcqSetup : begin
target_idle_o = 1'b0;
scl_d = 1'b0;
sda_d = 1'b0;
end
// default
default : begin
target_idle_o = 1'b1;
Expand Down Expand Up @@ -882,15 +885,23 @@ module i2c_target_fsm import i2c_pkg::*;
end
end
// StretchAcqFull: target stretches the clock when acq_fifo is full
// When space becomes available, deposit the entry into the acqusition fifo
// and move on to receive the next byte.
// If we hit our NACK timeout we must continue and unconditionally NACK
// the next one.
// When space becomes available, move on to prepare to ACK. If we hit
// our NACK timeout we must continue and unconditionally NACK the next
// one.
StretchAcqFull : begin
if (nack_timeout) begin
state_d = WaitForStop;
end else if (~stretch_rx) begin
state_d = AcquireByte;
state_d = StretchAcqSetup;
load_tcount = 1'b1;
tcount_sel = tSetupData;
end
end
// StretchAcqSetup: Drive the ACK and wait for tSetupData before
// releasing SCL
StretchAcqSetup : begin
if (tcount_q == 20'd1) begin
state_d = AcquireAckSetup;
end
end
// default
Expand Down

0 comments on commit 4062019

Please sign in to comment.