//////////////////////////////////////////////////////////////////////
//// ////
//// serialInterface.v ////
//// ////
//// This file is part of the i2cSlave opencores effort.
//// ////
//// ////
//// Module Description: ////
//// Perform all serial to parallel, and parallel
//// to serial conversions. Perform device address matching
//// Handle arbitrary length I2C reads terminated by NAK
//// from host, and arbitrary length I2C writes terminated
//// by STOP from host
//// The second byte of a I2C write is always interpreted
//// as a register address, and becomes the base register address
//// for all read and write transactions.
//// I2C WRITE: devAddr, regAddr, data[regAddr], data[regAddr+1], ..... data[regAddr+N]
//// I2C READ: data[regAddr], data[regAddr+1], ..... data[regAddr+N]
//// Note that when regAddR reaches 255 it will automatically wrap round to 0
//// ////
//// To Do: ////
////
//// ////
//// Author(s): ////
//// - Steve Fielding, sfielding@base2designs.com ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2008 Steve Fielding and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from ////
//// ////
//////////////////////////////////////////////////////////////////////
//
`include "timescale.v"
`include "i2cSlave_define.v"
module serialInterface (clearStartStopDet, clk, dataIn, dataOut, regAddr, rst, scl, sdaIn, sdaOut, startStopDetState, writeEn);
input clk;
input [7:0]dataIn;
input rst;
input scl;
input sdaIn;
input [1:0]startStopDetState;
output clearStartStopDet;
output [7:0]dataOut;
output [15:0]regAddr;
output sdaOut;
output writeEn;
reg clearStartStopDet, next_clearStartStopDet;
wire clk;
wire [7:0]dataIn;
reg [7:0]dataOut, next_dataOut;
reg [15:0]regAddr, next_regAddr;
reg regAddr_hiByte = 1'b0; //high and low byte of regAddr
wire rst;
wire scl;
wire sdaIn;
reg sdaOut, next_sdaOut;
wire [1:0]startStopDetState;
reg writeEn, next_writeEn;
// diagram signals declarations
reg [2:0]bitCnt, next_bitCnt;
reg [7:0]rxData, next_rxData;
reg [1:0]streamSt, next_streamSt;
reg [7:0]txData, next_txData;
// BINARY ENCODED state machine: SISt
// State codes definitions:
`define START 4'b0000
`define CHK_RD_WR 4'b0001
`define READ_RD_LOOP 4'b0010
`define READ_WT_HI 4'b0011
`define READ_CHK_LOOP_FIN 4'b0100
`define READ_WT_LO 4'b0101
`define READ_WT_ACK 4'b0110
`define WRITE_WT_LO 4'b0111
`define WRITE_WT_HI 4'b1000
`define WRITE_CHK_LOOP_FIN 4'b1001
`define WRITE_LOOP_WT_LO 4'b1010
`define WRITE_ST_LOOP 4'b1011
`define WRITE_WT_LO2 4'b1100
`define WRITE_WT_HI2 4'b1101
`define WRITE_CLR_WR 4'b1110
`define WRITE_CLR_ST_STOP 4'b1111
reg [3:0]CurrState_SISt, NextState_SISt;
// Diagram actions (continuous assignments allowed only: assign ...)
// diagram ACTION
// Machine: SISt
// NextState logic (combinatorial)
always @ (startStopDetState or streamSt or scl or txData or bitCnt or rxData or sdaIn or regAddr or dataIn or sdaOut or writeEn or dataOut or clearStartStopDet or CurrState_SISt)
begin
NextState_SISt <= CurrState_SISt;
// Set default values for outputs and signals
next_streamSt <= streamSt;
next_txData <= txData;
next_rxData <= rxData;
next_sdaOut <= sdaOut;
next_writeEn <= writeEn;
next_dataOut <= dataOut;
next_bitCnt <= bitCnt;
next_clearStartStopDet <= clearStartStopDet;
next_regAddr <= regAddr;
case (CurrState_SISt) // synopsys parallel_case full_case
`START:
begin
next_streamSt <= `STREAM_IDLE;
next_txData <= 8'h00;
next_rxData <= 8'h00;
next_sdaOut <= 1'b1;
next_writeEn <= 1'b0;
next_dataOut <= 8'h00;
next_bitCnt <= 3'b000;
next_clearStartStopDet <= 1'b0;
NextState_SISt <= `CHK_RD_WR;
end
`CHK_RD_WR:
begin
if (streamSt == `STREAM_READ)
begin
NextState_SISt <= `READ_RD_LOOP;
next_txData <= dataIn;
next_regAddr <= regAddr + 1'b1;
next_bitCnt <= 3'b001;
end
else
begin
NextState_SISt <= `WRITE_WT_HI;
next_rxData <= 8'h00;
end
end
`READ_RD_LOOP:
begin
if (scl == 1'b0)
begin
NextState_SISt <= `READ_WT_HI;
next_sdaOut <= txData [7];
next_txData <= {txData [6:0], 1'b0};
end
end
`READ_WT_HI:
begin
if (scl == 1'b1)
begin
NextState_SISt <= `READ_CHK_LOOP_FIN;
end
end
`READ_CHK_LOOP_FIN:
begin
if (bitCnt == 3'b000)
begin
NextState_SISt <= `READ_WT_LO;
end
else
begin
NextState_SISt <= `READ_RD_LOOP;
next_bitCnt <= bitCnt + 1'b1;
end
end
`READ_WT_LO:
begin
if (scl == 1'b0)
begin
NextState_SISt <= `READ_WT_ACK;
next_sdaOut <= 1'b1;
end
end
`READ_WT_ACK:
begin
if (scl == 1'b1)
begin
NextState_SISt <= `CHK_RD_WR;
if (sdaIn == `I2C_NAK)
next_streamSt <= `STREAM_IDLE;
end
end
`WRITE_WT_LO:
begin
if ((scl == 1'b0) && (startStopDetState == `STOP_DET ||
(streamSt == `STREAM_IDLE && startStopDetState == `NULL_DET)))
begin
NextState_SISt <= `WRITE_CLR_ST_STOP;
case (startStopDetState)
`NULL_DET:
next_bitCnt <= bitCnt + 1'b1;
`START_DET: begin
next_streamSt <= `STREAM_IDLE;
next_rxData <= 8'h00;
end
default: ;
endcase
next_streamSt <= `STREAM_IDLE;
next_clearStartStopDet <= 1'b1;
end
else if (scl == 1'b0)
begin
NextState_SISt <= `WRITE_ST_LOOP;
case (startStopDetState)
`NULL_DET:
next_bitCnt <= bitCnt + 1'b1;
`START_DET: begin
next_streamSt <= `STREAM_IDLE;
next_rxData <= 8'h00;
end
default: ;
endcase
end
end
`WRITE_WT_HI:
begin
if (scl == 1'b1)
begin
NextState_SISt <= `WRITE_WT_LO;
next_rxData <= {rxData [6:0], sdaIn};
next_bitCnt <= 3'b000;
end
end
`WRITE_CHK_LOOP_FIN:
begin
if (bitCnt == 3'b111)
begin
NextState_SISt <= `WRITE_CLR_WR;
next_sdaOut <= `I2C_ACK;
case (streamSt)
`STREAM_IDLE: begin
if (rxData[7:1] == `I2C_ADDRESS && startStopDetState == `START_DET) begin
if (rxData[0] == 1'b1)
next_streamSt <= `STREAM_READ;
else
next_streamSt <= `STREAM_WRITE_ADDR;
end
else
next_sdaOut <= `I2C_NAK;
end
`STREAM_WRITE_ADDR: begin
if(regAddr_hiByte == 0) begin
next_regAddr[15:8] <= rxData;
regAddr_hiByte <= 1;
end
else begin
next_streamSt <= `STREAM_WRITE_DATA;
next_regAddr[7:0] <= rxData;
regAddr_hiByte <= 0;
end
end
`STREAM_WRITE_DATA: begin
next_dataOut <= rxData;
next_writeEn <= 1'b1;
end
default:
next_streamSt <= streamSt;
endcase
end
else
begin
NextState_SISt <= `WRITE_ST_LOOP;
next_bitCnt <= bitCnt + 1'b1;
end
end
`WRITE_LOOP_WT_LO:
begin
if (scl == 1'b0)
begin
NextState_SISt <= `WRITE_CHK_LOOP_FIN;
end
end
`WRITE_ST_LOOP:
begin
if (scl == 1'b1)
begin
NextState_SISt <= `WRITE_LOOP_WT_LO;
next_rxData <= {rxData [6:0], sdaIn};
end
end
`WRITE_WT_LO2:
begin
if (scl == 1'b0)
begin
NextState_SISt <= `CHK_RD_WR;
next_sdaOut <= 1'b1;
end
end
`WRITE_WT_HI2:
begin
next_clearStartStopDet <= 1'b0;
if (scl == 1'b1)
begin
NextState_SISt <= `WRITE_WT_LO2;
end
end
`WRITE_CLR_WR:
begin
if (writeEn == 1'b1)
next_regAddr <= regAddr + 1'b1;
next_writeEn <= 1'b0;
next_clearStartStopDet <= 1'b1;
NextState_SISt <= `WRITE_WT_HI2;
end
`WRITE_CLR_ST_STOP:
begin
next_clearStartStopDet <= 1'b0;
NextState_SISt <= `CHK_RD_WR;
end
endcase
end
// Current State Logic (sequential)
always @ (posedge clk)
begin
if (rst == 1'b1)
CurrState_SISt <= `START;
else
CurrState_SISt <= NextState_SISt;
end
// Registered outputs logic
always @ (posedge clk)
begin
if (rst == 1'b1)
begin
sdaOut <= 1'b1;
writeEn <= 1'b0;
dataOut <= 8'h00;
clearStartStopDet <= 1'b0;
// regAddr <= // Initialization in the reset state or default value required!!
streamSt <= `STREAM_IDLE;
txData <= 8'h00;
rxData <= 8'h00;
bitCnt <= 3'b000;
end
else
begin
sdaOut <= next_sdaOut;
writeEn <= next_writeEn;
dataOut <= next_dataOut;
clearStartStopDet <= next_clearStartStopDet;
regAddr <= next_regAddr;
streamSt <= next_streamSt;
txData <= next_txData;
rxData <= next_rxData;
bitCnt <= next_bitCnt;
end
end
endmodule