[Cryptech-Commits] [core/i2c] 01/01: initial commit of I2C code for coretest

git at cryptech.is git at cryptech.is
Thu Aug 28 14:39:16 UTC 2014


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch master
in repository core/i2c.

commit d846f5ebdec82b4ae21e75e1da02db92f9bcd715
Author: Paul Selkirk <pselkirk at isc.org>
Date:   Thu Aug 28 10:28:06 2014 -0400

    initial commit of I2C code for coretest
---
 LICENSE            |  24 +++
 README.md          |   7 +
 README.md.gpg      | Bin 0 -> 508 bytes
 src/rtl/i2c.v      | 219 ++++++++++++++++++++
 src/rtl/i2c_core.v | 586 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 836 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0fb159c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Author: Joachim Strömbergson
+Copyright (c) 2014, SUNET
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..24edcbb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+i2c
+===
+
+An I2C slave implemented in Verilog.
+
+The core i2c functionality is based on Bunnie Huang's i2c_slave.v from the
+novena-ws2312b-fpga project (https://github.com/xobs/novena-ws2812b-fpga).
diff --git a/README.md.gpg b/README.md.gpg
new file mode 100644
index 0000000..12790ea
Binary files /dev/null and b/README.md.gpg differ
diff --git a/src/rtl/i2c.v b/src/rtl/i2c.v
new file mode 100644
index 0000000..112ad70
--- /dev/null
+++ b/src/rtl/i2c.v
@@ -0,0 +1,219 @@
+//======================================================================
+//
+// i2c.v
+// ------
+// Top level wrapper for the i2c core.
+//
+// A simple I2C interface.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014, SUNET
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module i2c(
+            input wire 		 clk,
+            input wire 		 reset_n,
+
+            // External interface.
+	    input wire 		 SCL,
+	    input wire 		 SDA,
+	    output wire 	 SDA_pd,
+	    input wire [7:0] 	 i2c_device_addr,
+
+            // Internal receive interface.
+            output wire 	 rxd_syn,
+            output [7 : 0] 	 rxd_data,
+            input wire 		 rxd_ack,
+
+            // Internal transmit interface.
+            input wire 		 txd_syn,
+            input wire [7 : 0] 	 txd_data,
+            output wire 	 txd_ack,
+            
+            // API interface.
+            input wire 		 cs,
+            input wire 		 we,
+            input wire [7 : 0] 	 address,
+            input wire [31 : 0]  write_data,
+            output wire [31 : 0] read_data,
+            output wire 	 error,
+
+            // Debug output.
+            output wire [7 : 0]  debug
+           );
+
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  // API addresses.
+  parameter ADDR_CORE_NAME0   = 8'h00;
+  parameter ADDR_CORE_NAME1   = 8'h01;
+  parameter ADDR_CORE_TYPE    = 8'h02;
+  parameter ADDR_CORE_VERSION = 8'h03;
+
+  // Core ID constants.
+  parameter CORE_NAME0   = 32'h69326320;  // "i2c "
+  parameter CORE_NAME1   = 32'h20202020;  // "    "
+  parameter CORE_TYPE    = 32'h20202031;  // "   1"
+  parameter CORE_VERSION = 32'h302e3031;  // "0.01"
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+
+  wire 	        core_SCL;
+  wire 	        core_SDA;
+  wire 		core_SDA_pd;
+  wire [7:0] 	core_i2c_device_addr;
+
+  wire          core_rxd_syn;
+  wire [7 : 0]  core_rxd_data;
+  wire          core_rxd_ack;
+
+  wire          core_txd_syn;
+  wire [7 : 0]  core_txd_data;
+  wire          core_txd_ack;
+
+  reg [31 : 0]  tmp_read_data;
+  reg           tmp_error;
+
+  
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign core_SCL      = SCL;
+  assign core_SDA      = SDA;
+  assign SDA_pd        = core_SDA_pd;
+  assign core_i2c_device_addr = i2c_device_addr;
+
+  assign rxd_syn       = core_rxd_syn;
+  assign rxd_data      = core_rxd_data;
+  assign core_rxd_ack  = rxd_ack;
+  
+  assign core_txd_syn  = txd_syn;
+  assign core_txd_data = txd_data;
+  assign txd_ack       = core_txd_ack;
+  
+  assign read_data     = tmp_read_data;
+  assign error         = tmp_error;
+
+  assign debug         = core_rxd_data;
+  
+
+  //----------------------------------------------------------------
+  // core
+  //
+  // Instantiation of the i2c core.
+  //----------------------------------------------------------------
+  i2c_core core(
+                 .clk(clk),
+                 .reset(reset_n),
+
+                 // External data interface
+		.SCL(core_SCL),
+		.SDA(core_SDA),
+		.SDA_pd(core_SDA_pd),
+		.i2c_device_addr(core_i2c_device_addr),
+
+                 // Internal receive interface.
+                 .rxd_syn(core_rxd_syn),
+                 .rxd_data(core_rxd_data),
+                 .rxd_ack(core_rxd_ack),
+                 
+                 // Internal transmit interface.
+                 .txd_syn(core_txd_syn),
+                 .txd_data(core_txd_data),
+                 .txd_ack(core_txd_ack)
+                );
+
+  
+  //----------------------------------------------------------------
+  // api
+  //
+  // The core API that allows an internal host to control the
+  // core functionality.
+  //----------------------------------------------------------------
+  always @*
+    begin: api
+      // Default assignments.
+      tmp_read_data = 32'h00000000;
+      tmp_error     = 0;
+      
+      if (cs)
+        begin
+          if (we)
+            begin
+              // Write operations.
+              case (address)
+                default:
+                  begin
+                    tmp_error = 1;
+                  end
+              endcase // case (address)
+            end
+          else
+            begin
+              // Read operations.
+              case (address)
+                ADDR_CORE_NAME0:
+                  begin
+                    tmp_read_data = CORE_NAME0;
+                  end
+
+                ADDR_CORE_NAME1:
+                  begin
+                    tmp_read_data = CORE_NAME1;
+                  end
+
+                ADDR_CORE_TYPE:
+                  begin
+                    tmp_read_data = CORE_TYPE;
+                  end
+
+                ADDR_CORE_VERSION:
+                  begin
+                    tmp_read_data = CORE_VERSION;
+                  end
+                
+                default:
+                  begin
+                    tmp_error = 1;
+                  end
+              endcase // case (address)
+            end
+        end
+    end
+  
+endmodule // i2c
+
+//======================================================================
+// EOF i2c.v
+//======================================================================
diff --git a/src/rtl/i2c_core.v b/src/rtl/i2c_core.v
new file mode 100644
index 0000000..3e2772a
--- /dev/null
+++ b/src/rtl/i2c_core.v
@@ -0,0 +1,586 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011, Andrew "bunnie" Huang
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, 
+// are permitted provided that the following conditions are met:
+//
+//  * Redistributions of source code must retain the above copyright notice, 
+//    this list of conditions and the following disclaimer.
+//  * Redistributions in binary form must reproduce the above copyright notice, 
+//    this list of conditions and the following disclaimer in the documentation and/or 
+//    other materials provided with the distribution.
+//
+//    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
+//    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
+//    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+//    SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+//    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+//    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+//    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+//    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+//    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+//    POSSIBILITY OF SUCH DAMAGE.
+//
+//////////////////////////////////////////////////////////////////////////////
+// A simple I2C slave implementation. Oversampled for robustness.
+// The slave is extended into the snoop & surpress version for the DDC bus;
+// this is just a starting point for basic testing and also simple comms
+// with the CPU.
+//
+// i2c slave module requires the top level module to implement the IOBs
+// This is just to keep the tri-state easy to implemen across the hierarchy
+//
+// The code required on the top level is:
+//   IOBUF #(.DRIVE(12), .SLEW("SLOW")) IOBUF_sda (.IO(SDA), .I(1'b0), .T(!SDA_pd));
+//
+///////////
+`timescale 1 ns / 1 ps
+
+module i2c_core (
+                 input wire 	    clk,
+                 input wire 	    reset,
+
+                 // External data interface
+		 input wire 	    SCL,
+		 input wire 	    SDA,
+		 output reg 	    SDA_pd,
+		 input wire [7:0]   i2c_device_addr,
+
+                 // Internal receive interface.
+                 output wire 	    rxd_syn,
+                 output [7 : 0]     rxd_data,
+                 input wire 	    rxd_ack,
+
+                 // Internal transmit interface.
+                 input wire 	    txd_syn,
+                 input wire [7 : 0] txd_data,
+                 output wire 	    txd_ack
+		 );
+
+   /////// I2C physical layer components
+   /// SDA is stable when SCL is high.
+   /// If SDA moves while SCL is high, this is considered a start or stop condition.
+   ///
+   /// Otherwise, SDA can move around when SCL is low (this is where we suppress bits or 
+   /// overdrive as needed). SDA is a wired-AND bus, so you only "drive" zero.
+   ///
+   /// In an oversampled implementation, a rising and falling edge de-glitcher is needed
+   /// for SCL and SDA.
+   ///
+
+   // rise fall time cycles computation:
+   // At 400kHz operation, 2.5us is a cycle. "chatter" from transition should be about
+   // 5% of total cycle time max (just rule of thumb), so 0.125us should be the equiv
+   // number of cycles.
+   // For the demo board, a 25 MHz clock is provided, and 0.125us ~ 4 cycles
+   // At 100kHz operation, 10us is a cycle, so 0.5us ~ 12 cycles
+   parameter TRF_CYCLES = 5'd4;  // number of cycles for rise/fall time
+   
+   ////////////////
+   ///// protocol-level state machine
+   ////////////////
+   parameter I2C_START     = 14'b1 << 0; // should only pass through this state for one cycle
+   parameter I2C_RESTART   = 14'b1 << 1;
+   parameter I2C_DADDR     = 14'b1 << 2;
+   parameter I2C_ACK_DADDR = 14'b1 << 3;
+   parameter I2C_WR_DATA   = 14'b1 << 4;
+   parameter I2C_RXD_SYN   = 14'b1 << 5;
+   parameter I2C_RXD_ACK   = 14'b1 << 6;
+   parameter I2C_ACK_WR    = 14'b1 << 7;
+   parameter I2C_END_WR    = 14'b1 << 8;
+   parameter I2C_TXD_SYN   = 14'b1 << 9;
+   parameter I2C_TXD_ACK   = 14'b1 << 10;
+   parameter I2C_RD_DATA   = 14'b1 << 11;
+   parameter I2C_ACK_RD    = 14'b1 << 12;
+   parameter I2C_END_RD    = 14'b1 << 13;
+   parameter I2C_END_RD2   = 14'b1 << 14;
+   parameter I2C_WAITSTOP  = 14'b1 << 15;
+
+   parameter I2C_nSTATES = 16;
+
+   reg [(I2C_nSTATES-1):0]     I2C_cstate = {{(I2C_nSTATES-1){1'b0}}, 1'b1};  //current and next states
+   reg [(I2C_nSTATES-1):0]     I2C_nstate;
+
+//`define SIMULATION  
+`ifdef SIMULATION
+   // synthesis translate_off
+   reg [8*20:1] 	                    I2C_state_ascii = "I2C_START          ";
+   always @(I2C_cstate) begin
+      if      (I2C_cstate == I2C_START)     I2C_state_ascii <= "I2C_START          ";
+      else if (I2C_cstate == I2C_RESTART)   I2C_state_ascii <= "I2C_RESTART        ";
+      else if (I2C_cstate == I2C_DADDR)     I2C_state_ascii <= "I2C_DADDR          ";
+      else if (I2C_cstate == I2C_ACK_DADDR) I2C_state_ascii <= "I2C_ACK_DADDR      ";
+      else if (I2C_cstate == I2C_WR_DATA)   I2C_state_ascii <= "I2C_WR_DATA        ";
+      else if (I2C_cstate == I2C_ACK_WR)    I2C_state_ascii <= "I2C_ACK_WR         ";
+      else if (I2C_cstate == I2C_END_WR)    I2C_state_ascii <= "I2C_END_WR         ";
+      else if (I2C_cstate == I2C_RD_DATA)   I2C_state_ascii <= "I2C_RD_DATA        ";
+      else if (I2C_cstate == I2C_ACK_RD)    I2C_state_ascii <= "I2C_ACK_RD         ";
+      else if (I2C_cstate == I2C_END_RD)    I2C_state_ascii <= "I2C_END_RD         ";
+      else if (I2C_cstate == I2C_END_RD2)   I2C_state_ascii <= "I2C_END_RD2        ";
+      else if (I2C_cstate == I2C_WAITSTOP)  I2C_state_ascii <= "I2C_WAITSTOP       ";
+      else if (I2C_cstate == I2C_RXD_SYN)   I2C_state_ascii <= "I2C_RXD_SYN        ";
+      else if (I2C_cstate == I2C_RXD_ACK)   I2C_state_ascii <= "I2C_RXD_ACK        ";
+      else if (I2C_cstate == I2C_TXD_SYN)   I2C_state_ascii <= "I2C_TXD_SYN        ";
+      else if (I2C_cstate == I2C_TXD_ACK)   I2C_state_ascii <= "I2C_TXD_ACK        ";
+      else                                  I2C_state_ascii <= "WTF                ";
+   end
+   // synthesis translate_on
+`endif
+   
+   reg [3:0] 		       I2C_bitcnt;
+   reg [7:0] 		       I2C_daddr;
+   reg [7:0] 		       I2C_wdata;
+   reg [7:0] 		       I2C_rdata;
+
+   reg 			       rxd_syn_reg;
+   reg 			       txd_ack_reg;
+
+   assign rxd_data = I2C_wdata;
+   assign rxd_syn  = rxd_syn_reg;
+   assign txd_ack  = txd_ack_reg;
+
+
+   ////////// code begins here
+   always @ (posedge clk) begin
+      if (reset || ((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_RISE))) // stop condition always resets
+	I2C_cstate <= I2C_START; 
+      else
+	I2C_cstate <= I2C_nstate;
+   end
+
+   always @ (*) begin
+      case (I2C_cstate) //synthesis parallel_case full_case
+	I2C_START: begin // wait for the start condition
+	   I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_DADDR : I2C_START;
+	end
+	I2C_RESTART: begin // repeated start moves immediately to DADDR
+	   I2C_nstate = I2C_DADDR;
+	end
+
+	// device address branch
+	I2C_DADDR: begin // 8 bits to get the address
+	   I2C_nstate = ((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_ACK_DADDR : I2C_DADDR;
+	end
+	I2C_ACK_DADDR: begin // depending upon W/R bit state, go to one of two branches
+	   I2C_nstate = (SCL_cstate == SCL_FALL) ?
+			(I2C_daddr[7:1] == i2c_device_addr[7:1]) ?
+			(I2C_daddr[0] == 1'b0 ? I2C_WR_DATA : I2C_TXD_SYN) :
+			I2C_WAITSTOP : // !I2C_daddr match
+			I2C_ACK_DADDR; // !SCL_FALL
+	end
+
+	// write branch
+	I2C_WR_DATA: begin // 8 bits to get the write data
+	   I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_RESTART : // repeated start
+			((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_RXD_SYN : I2C_WR_DATA;
+	end
+	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+	I2C_RXD_SYN: begin // put data on the coretest bus
+	   I2C_nstate = I2C_RXD_ACK;
+	end
+	I2C_RXD_ACK: begin // wait for coretest ack
+           I2C_nstate = rxd_ack ? I2C_ACK_WR : I2C_RXD_ACK;
+	end
+	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+	I2C_ACK_WR: begin // trigger the ack response (pull SDA low until next falling edge)
+	   // and stay in this state until the next falling edge of SCL
+	   I2C_nstate = (SCL_cstate == SCL_FALL) ? I2C_END_WR : I2C_ACK_WR;
+	end
+	I2C_END_WR: begin // one-cycle state to update address+1, reset SDA pulldown
+	   I2C_nstate = I2C_WR_DATA; // SCL is now low
+	end
+
+	// read branch
+	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+	I2C_TXD_SYN: begin // get data from the coretest bus
+           I2C_nstate = txd_syn ? I2C_TXD_ACK : I2C_TXD_SYN;
+	end
+	I2C_TXD_ACK: begin // send coretest ack
+	   I2C_nstate = txd_syn ? I2C_TXD_ACK : I2C_RD_DATA;
+	end
+	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+	I2C_RD_DATA: begin // 8 bits to get the read data
+	   I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_RESTART : // repeated start
+			((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_ACK_RD : I2C_RD_DATA;
+	end
+	I2C_ACK_RD: begin // wait for an (n)ack response
+	   // need to sample (n)ack on a rising edge
+	   I2C_nstate = (SCL_cstate == SCL_RISE) ? I2C_END_RD : I2C_ACK_RD;
+	end
+	I2C_END_RD: begin // if nack, just go to start state (don't explicitly check stop event)
+	   // single cycle state for adr+1 update
+	   I2C_nstate = (SDA_cstate == SDA_LOW) ? I2C_END_RD2 : I2C_START;
+	end
+	I2C_END_RD2: begin // before entering I2C_RD_DATA, we need to have seen a falling edge.
+	   I2C_nstate = (SCL_cstate == SCL_FALL) ? I2C_RD_DATA : I2C_END_RD2;
+	end
+
+	// we're not the addressed device, so we just idle until we see a stop
+	I2C_WAITSTOP: begin
+	   I2C_nstate = (((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_RISE))) ? // stop
+			I2C_START : 
+			(((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_FALL))) ? // or start
+			I2C_RESTART :
+			I2C_WAITSTOP;
+	end
+      endcase // case (cstate)
+   end
+
+   always @ (posedge clk) begin
+      if( reset ) begin
+	 I2C_bitcnt <= 4'b0;
+	 I2C_daddr <= 8'b0;
+	 I2C_wdata <= 8'b0;
+	 SDA_pd <= 1'b0;
+	 I2C_rdata <= 8'b0;
+      end else begin
+	 case (I2C_cstate) // synthesis parallel_case full_case
+	   I2C_START: begin // everything in reset
+	      I2C_bitcnt <= 4'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	      SDA_pd <= 1'b0;
+	   end
+
+	   I2C_RESTART: begin
+	      I2C_bitcnt <= 4'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	      SDA_pd <= 1'b0;
+	   end
+
+	   // get my i2c device address (am I being talked to?)
+	   I2C_DADDR: begin // shift in the address on rising edges of clock
+	      if( SCL_cstate == SCL_RISE ) begin
+		 I2C_bitcnt <= I2C_bitcnt + 4'b1;
+		 I2C_daddr[7] <= I2C_daddr[6];
+		 I2C_daddr[6] <= I2C_daddr[5];
+		 I2C_daddr[5] <= I2C_daddr[4];
+		 I2C_daddr[4] <= I2C_daddr[3];
+		 I2C_daddr[3] <= I2C_daddr[2];
+		 I2C_daddr[2] <= I2C_daddr[1];
+		 I2C_daddr[1] <= I2C_daddr[0];
+		 I2C_daddr[0] <= (SDA_cstate == SDA_HIGH) ? 1'b1 : 1'b0;
+	      end else begin // we're oversampled so we need a hold-state gutter
+		 I2C_bitcnt <= I2C_bitcnt;
+		 I2C_daddr <= I2C_daddr;
+	      end // else: !if( SCL_cstate == SCL_RISE )
+	      SDA_pd <= 1'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	   end // case: I2C_DADDR
+	   I2C_ACK_DADDR: begin
+	      SDA_pd <= 1'b1;  // active pull down ACK
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	   end
+
+	   // write branch
+	   I2C_WR_DATA: begin // shift in data on rising edges of clock
+	      if( SCL_cstate == SCL_RISE ) begin
+		 I2C_bitcnt <= I2C_bitcnt + 4'b1;
+		 I2C_wdata[7] <= I2C_wdata[6];
+		 I2C_wdata[6] <= I2C_wdata[5];
+		 I2C_wdata[5] <= I2C_wdata[4];
+		 I2C_wdata[4] <= I2C_wdata[3];
+		 I2C_wdata[3] <= I2C_wdata[2];
+		 I2C_wdata[2] <= I2C_wdata[1];
+		 I2C_wdata[1] <= I2C_wdata[0];
+		 I2C_wdata[0] <= (SDA_cstate == SDA_HIGH) ? 1'b1 : 1'b0;
+	      end else begin
+		 I2C_bitcnt <= I2C_bitcnt; // hold state gutter
+		 I2C_wdata <= I2C_wdata;
+	      end // else: !if( SCL_cstate == SCL_RISE )
+	      SDA_pd <= 1'b0;
+	      I2C_daddr <= I2C_daddr;
+	      I2C_rdata <= I2C_rdata;
+	   end // case: I2C_WR_DATA
+	   // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+	   I2C_RXD_SYN: begin // put data on the coretest bus
+              rxd_syn_reg <= 1;
+	   end
+	   I2C_RXD_ACK: begin // wait for coretest ack
+              if (rxd_ack)
+		begin
+		   rxd_syn_reg <= 0;
+		end
+	   end
+	   // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+	   I2C_ACK_WR: begin
+	      SDA_pd <= 1'b1;  // active pull down ACK
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_wdata <= I2C_wdata;
+	      I2C_rdata <= I2C_rdata;
+	   end
+	   I2C_END_WR: begin
+	      SDA_pd <= 1'b0; // let SDA rise (host may look for this to know ack is done
+	      I2C_bitcnt <= 4'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_daddr <= I2C_daddr;
+	   end
+
+	   // read branch
+	   // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+	   I2C_TXD_SYN: begin // get data from the coretest bus
+              if (txd_syn)
+		begin
+		   I2C_rdata <= txd_data;
+                   txd_ack_reg <= 1;
+		end
+	   end
+	   I2C_TXD_ACK: begin // send coretest ack
+              if (!txd_syn)
+		begin
+                   txd_ack_reg <= 0;
+		end
+	   end
+	   // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+	   I2C_RD_DATA: begin // shift out data on falling edges of clock
+	      SDA_pd <= I2C_rdata[7] ? 1'b0 : 1'b1;
+	      if( SCL_cstate == SCL_RISE ) begin
+		 I2C_bitcnt <= I2C_bitcnt + 4'b1;
+	      end else begin
+		 I2C_bitcnt <= I2C_bitcnt; // hold state gutter
+	      end
+	      
+	      if( SCL_cstate == SCL_FALL ) begin
+		 I2C_rdata[7] <= I2C_rdata[6];
+		 I2C_rdata[6] <= I2C_rdata[5];
+		 I2C_rdata[5] <= I2C_rdata[4];
+		 I2C_rdata[4] <= I2C_rdata[3];
+		 I2C_rdata[3] <= I2C_rdata[2];
+		 I2C_rdata[2] <= I2C_rdata[1];
+		 I2C_rdata[1] <= I2C_rdata[0];
+		 I2C_rdata[0] <= 1'b0;
+	      end else begin
+		 I2C_rdata <= I2C_rdata;
+	      end // else: !if( SCL_cstate == SCL_RISE )
+	      I2C_daddr <= I2C_daddr;
+	      I2C_wdata <= I2C_wdata;
+	   end // case: I2C_RD_DATA
+	   I2C_ACK_RD: begin
+	      SDA_pd <= 1'b0;  // in ack state don't pull down, we are listening to host
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+	   I2C_END_RD: begin
+	      SDA_pd <= 1'b0; // let SDA rise (host may look for this to know ack is done
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+	   I2C_END_RD2: begin
+	      SDA_pd <= 1'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+
+	   I2C_WAITSTOP: begin
+	      SDA_pd <= 1'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+	 endcase // case (cstate)
+      end // else: !if( reset )
+   end // always @ (posedge clk or posedge reset)
+
+
+   ///////////////////////////////////////////////////////////////
+   /////////// low level state machines //////////////////////////
+   ///////////////////////////////////////////////////////////////
+   
+   
+   ////////////////
+   ///// SCL low-level sampling state machine
+   ////////////////
+   parameter SCL_HIGH = 4'b1 << 0; // should only pass through this state for one cycle
+   parameter SCL_FALL = 4'b1 << 1;
+   parameter SCL_LOW  = 4'b1 << 2;
+   parameter SCL_RISE = 4'b1 << 3;
+   parameter SCL_nSTATES = 4;
+
+   reg [(SCL_nSTATES-1):0]     SCL_cstate = {{(SCL_nSTATES-1){1'b0}}, 1'b1};  //current and next states
+   reg [(SCL_nSTATES-1):0]     SCL_nstate;
+
+//`define SIMULATION  
+`ifdef SIMULATION
+   // synthesis translate_off
+   reg [8*20:1] 	                 SCL_state_ascii = "SCL_HIGH           ";
+
+   always @(SCL_cstate) begin
+      if      (SCL_cstate == SCL_HIGH)     SCL_state_ascii <= "SCL_HIGH           ";
+      else if (SCL_cstate == SCL_FALL)     SCL_state_ascii <= "SCL_FALL           ";
+      else if (SCL_cstate == SCL_LOW )     SCL_state_ascii <= "SCL_LOW            ";
+      else if (SCL_cstate == SCL_RISE)     SCL_state_ascii <= "SCL_RISE           ";
+      else SCL_state_ascii                                 <= "WTF                ";
+   end
+   // synthesis translate_on
+`endif
+
+   reg [4:0] 		       SCL_rfcnt;
+   reg 			       SCL_s, SCL_sync;
+   reg 			       SDA_s, SDA_sync;
+
+   always @ (posedge clk) begin
+      if (reset)
+	SCL_cstate <= SCL_HIGH; // always start here even if it's wrong -- easier to test
+      else
+	SCL_cstate <= SCL_nstate;
+   end
+
+   always @ (*) begin
+      case (SCL_cstate) //synthesis parallel_case full_case
+	SCL_HIGH: begin
+	   SCL_nstate = ((SCL_rfcnt > TRF_CYCLES) && (SCL_sync == 1'b0)) ? SCL_FALL : SCL_HIGH;
+	end
+	SCL_FALL: begin
+	   SCL_nstate = SCL_LOW;
+	end
+	SCL_LOW: begin
+	   SCL_nstate = ((SCL_rfcnt > TRF_CYCLES) && (SCL_sync == 1'b1)) ? SCL_RISE : SCL_LOW;
+	end
+	SCL_RISE: begin
+	   SCL_nstate = SCL_HIGH;
+	end
+      endcase // case (cstate)
+   end // always @ (*)
+
+   always @ (posedge clk) begin
+      if( reset ) begin
+	 SCL_rfcnt <= 5'b0;
+      end else begin
+	 case (SCL_cstate) // synthesis parallel_case full_case
+	   SCL_HIGH: begin
+	      if( SCL_sync == 1'b1 ) begin
+		 SCL_rfcnt <= 5'b0;
+	      end else begin
+		 SCL_rfcnt <= SCL_rfcnt + 5'b1;
+	      end
+	   end
+	   SCL_FALL: begin
+	      SCL_rfcnt <= 5'b0;
+	   end
+	   SCL_LOW: begin
+	      if( SCL_sync == 1'b0 ) begin
+		 SCL_rfcnt <= 5'b0;
+	      end else begin
+		 SCL_rfcnt <= SCL_rfcnt + 5'b1;
+	      end
+	   end
+	   SCL_RISE: begin
+	      SCL_rfcnt <= 5'b0;
+	   end
+	 endcase // case (cstate)
+      end // else: !if( reset )
+   end // always @ (posedge clk or posedge reset)
+
+
+   ////////////////
+   ///// SDA low-level sampling state machine
+   ////////////////
+   parameter SDA_HIGH = 4'b1 << 0; // should only pass through this state for one cycle
+   parameter SDA_FALL = 4'b1 << 1;
+   parameter SDA_LOW  = 4'b1 << 2;
+   parameter SDA_RISE = 4'b1 << 3;
+   parameter SDA_nSTATES = 4;
+
+   reg [(SDA_nSTATES-1):0]     SDA_cstate = {{(SDA_nSTATES-1){1'b0}}, 1'b1};  //current and next states
+   reg [(SDA_nSTATES-1):0]     SDA_nstate;
+
+//`define SIMULATION  
+`ifdef SIMULATION
+   // synthesis translate_off
+   reg [8*20:1] 	                 SDA_state_ascii = "SDA_HIGH           ";
+
+   always @(SDA_cstate) begin
+      if      (SDA_cstate == SDA_HIGH)     SDA_state_ascii <= "SDA_HIGH           ";
+      else if (SDA_cstate == SDA_FALL)     SDA_state_ascii <= "SDA_FALL           ";
+      else if (SDA_cstate == SDA_LOW )     SDA_state_ascii <= "SDA_LOW            ";
+      else if (SDA_cstate == SDA_RISE)     SDA_state_ascii <= "SDA_RISE           ";
+      else SDA_state_ascii                                 <= "WTF                ";
+   end
+   // synthesis translate_on
+`endif
+
+   reg [4:0] 		       SDA_rfcnt;
+
+   always @ (posedge clk) begin
+      if (reset)
+	SDA_cstate <= SDA_HIGH; // always start here even if it's wrong -- easier to test
+      else
+	SDA_cstate <= SDA_nstate;
+   end
+
+   always @ (*) begin
+      case (SDA_cstate) //synthesis parallel_case full_case
+	SDA_HIGH: begin
+	   SDA_nstate = ((SDA_rfcnt > TRF_CYCLES) && (SDA_sync == 1'b0)) ? SDA_FALL : SDA_HIGH;
+	end
+	SDA_FALL: begin
+	   SDA_nstate = SDA_LOW;
+	end
+	SDA_LOW: begin
+	   SDA_nstate = ((SDA_rfcnt > TRF_CYCLES) && (SDA_sync == 1'b1)) ? SDA_RISE : SDA_LOW;
+	end
+	SDA_RISE: begin
+	   SDA_nstate = SDA_HIGH;
+	end
+      endcase // case (cstate)
+   end // always @ (*)
+
+   always @ (posedge clk) begin
+      if( reset ) begin
+	 SDA_rfcnt <= 5'b0;
+      end else begin
+	 case (SDA_cstate) // synthesis parallel_case full_case
+	   SDA_HIGH: begin
+	      if( SDA_sync == 1'b1 ) begin
+		 SDA_rfcnt <= 5'b0;
+	      end else begin
+		 SDA_rfcnt <= SDA_rfcnt + 5'b1;
+	      end
+	   end
+	   SDA_FALL: begin
+	      SDA_rfcnt <= 5'b0;
+	   end
+	   SDA_LOW: begin
+	      if( SDA_sync == 1'b0 ) begin
+		 SDA_rfcnt <= 5'b0;
+	      end else begin
+		 SDA_rfcnt <= SDA_rfcnt + 5'b1;
+	      end
+	   end
+	   SDA_RISE: begin
+	      SDA_rfcnt <= 5'b0;
+	   end
+	 endcase // case (cstate)
+      end // else: !if( reset )
+   end // always @ (posedge clk or posedge reset)
+
+   
+   
+   /////////////////////
+   /////// synchronizers
+   /////////////////////
+   always @ (posedge clk) begin
+      SCL_s <= SCL;
+      SCL_sync <= SCL_s;
+      SDA_s <= SDA;
+      SDA_sync <= SDA_s;
+   end // always @ (posedge clk or posedge reset)
+   
+endmodule // i2c_slave



More information about the Commits mailing list