`timescale 1ps/1ps `default_nettype none module i2c_receiver (input wire clock, input wire reset, input wire i_scl, input wire i_sdi, output wire o_sdo, output wire [7:0] o_data, output wire o_strobe, output wire o_start, output wire o_stop, input wire i_ack); // Active ONE logic sdi_prev; logic scl_prev; logic start_condition; logic stop_condition; logic scl_rise; logic scl_fall; always_ff @(posedge clock) if (reset) begin sdi_prev <= 1'b1; scl_prev <= 1'b1; end else begin sdi_prev <= i_sdi; scl_prev <= i_scl; end assign start_condition = (sdi_prev == 1'b1) && (i_sdi == 1'b0) && (scl_prev == 1'b1) && (i_scl == 1'b1); assign stop_condition = (sdi_prev == 1'b0) && (i_sdi == 1'b1) && (scl_prev == 1'b1) && (i_scl == 1'b1); assign scl_rise = (scl_prev == 1'b0) && (i_scl == 1'b1); assign scl_fall = (scl_prev == 1'b1) && (i_scl == 1'b0); enum int unsigned { ST_WAIT_FOR_START = 0, ST_RECEIVE_BITS, ST_WAIT_FOR_SCL_LOW, ST_SEND_ACK } state; logic [2:0] bit_cntr; logic [7:0] data_sr; logic byte_strobe; logic sdo; always_ff @(posedge clock) if (reset) begin state <= ST_WAIT_FOR_START; bit_cntr <= '0; byte_strobe <= 1'b0; sdo <= 1'b1; end else begin byte_strobe <= 1'b0; if (stop_condition) state <= ST_WAIT_FOR_START; else case (state) ST_WAIT_FOR_START: begin sdo <= 1'b1; if (start_condition) begin bit_cntr <= '0; state <= ST_RECEIVE_BITS; end end ST_RECEIVE_BITS: if (scl_rise) begin data_sr <= {data_sr[6:0], i_sdi}; bit_cntr <= bit_cntr + 1'b1; if (bit_cntr == 3'd7) begin state <= ST_WAIT_FOR_SCL_LOW; byte_strobe <= 1'b1; end end ST_WAIT_FOR_SCL_LOW: if (scl_fall) begin sdo <= i_ack ? 1'b0 : 1'b1; state <= ST_SEND_ACK; end ST_SEND_ACK: if (scl_fall) begin sdo <= 1'b1; state <= ST_RECEIVE_BITS; end endcase end assign o_data = data_sr; assign o_strobe = byte_strobe; assign o_start = start_condition; assign o_stop = stop_condition; assign o_sdo = sdo; endmodule // i2c_receiver