| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 | //// Simple I2C master devic, controlled by programmed I/O.//// Registers:// 0 - write data/command//     [15:8] - data bits (must be 1 for read)//     [7]    - ACK bit (must be 1 for write)//     [2:1]  - 00 = normal byte (S if needed, no following Sr/P)//              01 = follow with Sr (S if needed)//              10 = follow with P (S if needed)//              11 = dummy clocks (no S, for synchronization)//// 1 - read data/status//     [15:8] - data bits//     [7]    - ack bit//     [6]    - SDA//     [5]    - SCL//     [4]    - "started" (no S will be issued before next byte)//     [2:1]  - bits [2:1] from last command//     [0]    - busy//// 2 - baud rate divisor (f = clk/(4*(divisor+1)))//// 3 - bit [0] - send dummy clocks on SCL when idle//// This unit handles S(r) and P conditions by considering two classes of// symbols: "normal", when SCL is asserted at the end of themodule i2c (	    input	      rst_n,	    input	      clk,	    input	      valid,	    input [1:0]       addr,	    input [31:0]      wdata,	    input [3:0]       wstrb,	    output reg [31:0] rdata,	    output	      irq,	    inout	      i2c_scl,	    inout	      i2c_sda	    );   reg [7:0]		  divisor;   reg [7:0]		  baudctr;   reg [3:0]		  bitctr;   reg [1:0]		  phase;   reg [8:0]		  wreg;	// Output shift register   reg [8:0]		  rreg;	// Input shift register   reg			  do_read; // Shift in a data bit next cycle   reg			  busy;		// Data received, running   reg			  end_s, end_p; // Trailing S(r) or P   reg			  started;	// S sent, but not P   reg [1:0]		  outsymb; // Output symbol [abnormal, data]   reg			  scl_out = 1'b1;   reg			  sda_out = 1'b1;   assign i2c_scl = scl_out ? 1'bz : 1'b0;   assign i2c_sda = sda_out ? 1'bz : 1'b0;   always @(negedge rst_n or posedge clk)     if (~rst_n)       begin	  bitctr  <= 4'd14;	// Idle line - wait for start condition	  busy    <= 1'b0;	  outsymb <= 2'b11;	// A1	  baudctr <= 8'd0;	  divisor <= 8'd209;	// 84 MHz -> 100 kHz	  scl_out <= 1'b1;	  sda_out <= 1'b1;	  phase   <= 2'b00;	  do_read <= 1'b0;	  end_s   <= 1'bx;	  end_p   <= 1'bx;	  started <= 1'b0;       end     else       begin	  //	  // I2C state machine	  //	  if (|baudctr)	    begin	       baudctr <= baudctr - 1'b1;	    end	  else	    begin	       // I2C clock event	       baudctr <= divisor;	       phase <= phase + 1'b1;	       if ((phase == 2'b10) & ~i2c_scl)		 phase <= 2'b10; // Clock stretch	       // Phase 0: data is shifted out	       // Phase 1: SCL goes high	       // Phase 2: if SCL is low, hold	       // Phase 3: SCL does low if symbol is normal,	       //          sample SDA on read	       if (phase[0])		 scl_out <= outsymb[1] | ~phase[1];	       sda_out <= outsymb[0];	       if (phase == 2'b11)		 begin		    // Sample input and set up for the next cycle		    if (do_read)		      rreg <= { rreg[7:0], i2c_sda };		    do_read <= 1'b0;		    // Unit idle; send A0 or A1 depending on if we are		    // started or not.		    if (~busy)		      begin			 outsymb <= { 1'b1, ~started };		      end		    else		      begin			 bitctr  <= bitctr + 1'b1;			 started <= 1'b1;			 case (bitctr)			   4'd0, 4'd1, 4'd2, 4'd3, 4'd4,			   4'd5, 4'd6, 4'd7, 4'd8:			     begin				outsymb <= { 1'b0, wreg[8] }; // Nx				wreg   <= { wreg[7:0], 1'b1 };				do_read <= 1'b1;				if (bitctr[3])				  begin				     bitctr  <= end_s ? 4'd14 :						end_p ? 4'd12 : 4'b0;				     busy    <= end_p & ~end_s;				     // If we are to be followed by				     // an S(r) condition, we are not				     // really "started".				     started <= ~(end_s | end_p);				  end			     end // case: 4'd0, 4'd1, 4'd2, 4'd3, 4'd4,...			   // Stop condition			   4'd12: begin			      started <= 1'b0;			      outsymb <= 2'b10; // A0			   end			   4'd13: begin			      started <= 1'b0;			      outsymb <= 2'b11; // A1			      busy <= 1'b0;			   end			   // Start condition			   4'd14: begin			      started <= ~(end_s & end_p);			      outsymb <= 2'b11; // A1			   end			   4'd15: begin			      // N0, unless dummy in which case N1			      outsymb <= { 1'b0, ~started };			   end			   default: begin			      outsymb <= 2'bxx;			   end			 endcase // case (bitctr)		      end // else: !if(~busy)		 end // if (phase == 2'b11)	    end // else: !if(|baudctr)	  //	  // CPU write interface	  //	  if (valid)	    case (addr)	      2'b00:		 if (~busy)		   begin		      if (wstrb[1])			wreg[8:1] <= wdata[15:8];		      if (wstrb[0])			begin			   wreg[0] <= wdata[7];			   end_p   <= wdata[2];			   end_s   <= wdata[1];			   busy    <= 1'b1;			end		   end // if (~busy)	      2'b10: begin		if (wstrb[0])		  divisor <= wdata[7:0];	      end	      default: begin		 // Do nothing	      end	    endcase // case (addr)       end // else: !if(~rst_n)   //   // CPU read interface   //   always_comb     case (addr)       2'b00: rdata = { 16'b0, wreg, i2c_sda, i2c_scl, started, 1'b0,			end_p, end_s, busy | do_read };       2'b01: rdata = { 16'b0, rreg, i2c_sda, i2c_scl, started, 1'b0,			end_p, end_s, busy | do_read };       2'b10: rdata = { 24'b0, divisor };       default: rdata = 32'bx;     endcase // casez (addr)   //   // IRQ (level) when unit idle   //   assign irq = ~(busy | do_read);endmodule // i2c
 |