@@ -34,6 +34,9 @@ module bus_tx_flow import i3c_pkg::*; (
3434 // Open Drain / Push Pull
3535 output logic sel_od_pp_o,
3636
37+ // Output enable for SDA pad
38+ output logic sda_oe_o,
39+
3740 // Output I3C SDA bus line
3841 output logic sda_o
3942);
@@ -42,14 +45,16 @@ module bus_tx_flow import i3c_pkg::*; (
4245 logic bit_counter_en;
4346 logic [3 : 0 ] bit_counter_q, bit_counter_d;
4447
48+ // Registers for all critical signals directly connected to the SDA pad
4549 i3c_byte_t req_value_q, req_value_d;
4650 i3c_drive_e drive_mode_q, drive_mode_d;
51+ logic sda_oe_q, sda_oe_d;
4752
4853 logic tx_done; // Indicates finished bit write
4954 logic bus_tx_done; // Feedback to requester that transfer is done
5055 logic req_error;
5156
52- // TODO
57+ // TODO Can probably be removed
5358 assign req_error = 1'b0 ;
5459
5560 typedef enum logic [2 : 0 ] {
@@ -63,6 +68,24 @@ module bus_tx_flow import i3c_pkg::*; (
6368
6469 tx_state_e state_d, state_q;
6570
71+ // SDA is simply the MSB of the data shift register. No further logic or muxing.
72+ // Similar for pad drive mode and output enable.
73+ assign sda_o = req_value_q[7 ];
74+ assign sel_od_pp_o = drive_mode_q;
75+ assign sda_oe_o = sda_oe_q;
76+
77+ /*
78+ Truth table for sda_oe.
79+
80+ sel_od_pp_o | sda_o || sda_oe_o | IO state
81+ ------------+--------++----------+-----------
82+ 0 | 0 || 1 | 0
83+ 0 | 1 || 0 | hi-z
84+ 1 | 0 || 1 | 0
85+ 1 | 1 || 1 | 1
86+ */
87+ assign sda_oe_d = drive_mode_d || ! req_value_d[7 ];
88+
6689 // Common logic whenever a transfer gets started, including back-to-back transfers
6790 function automatic tx_state_e start_transfer (
6891 input bus_tx_req_t bus_tx_req,
@@ -122,7 +145,6 @@ module bus_tx_flow import i3c_pkg::*; (
122145
123146 endfunction : start_transfer
124147
125-
126148 // Bit counter used for byte transfers
127149 always_comb begin
128150 bit_counter_d = bit_counter_q;
@@ -136,10 +158,7 @@ module bus_tx_flow import i3c_pkg::*; (
136158 end
137159 end
138160
139- // SDA is simply the MSB of the data shift register. No further logic or muxing.
140- assign sda_o = req_value_q[7 ];
141- assign sel_od_pp_o = drive_mode_q;
142-
161+ // Main FSM which handles all low-level bus details in terms of transmitting
143162 always_comb begin : tx_fsm
144163 bit_counter_en = 1'b0 ;
145164
@@ -289,11 +308,13 @@ module bus_tx_flow import i3c_pkg::*; (
289308 bit_counter_q <= '0 ;
290309 req_value_q <= '1 ;
291310 drive_mode_q <= OpenDrain;
311+ sda_oe_q <= 1'b0 ;
292312 state_q <= Idle;
293313 end else begin
294314 bit_counter_q <= bit_counter_d;
295315 req_value_q <= req_value_d;
296316 drive_mode_q <= drive_mode_d;
317+ sda_oe_q <= sda_oe_d;
297318 state_q <= state_d;
298319 end
299320 end
0 commit comments