Browse Source

added i2c example from VL

master
Simon Schmidt 2 years ago
parent
commit
b3637d6d76

+ 4
- 0
i2c_slave_opencores/.gitignore View File

@@ -0,0 +1,4 @@
*.vcd
sim/*.vcd
sim/*.wlf
sim/testHarness

+ 7
- 0
i2c_slave_opencores/README.md View File

@@ -0,0 +1,7 @@
# i2c_slave_opencores
I2C Verilog Testbench für einen CO2 Sensor
Beispiel ist von OpenCores
https://git.efi.th-nuernberg.de/gitea/schmidtsi76327/i2c_slave_opencores

+ 17
- 0
i2c_slave_opencores/bench/i2cSlaveTB_defines.v View File

@@ -0,0 +1,17 @@
// ---------------------------- i2cSlaveTB_defines.v -----------------
`define SEND_START 1'b1
`define SEND_STOP 1'b1
`define NULL 1'b0
`define ACK 1'b0
`define NACK 1'b1

`define DEV_I2C_ADDR 8'hcc

`define PRER_LO_REG 3'b000
`define PRER_HI_REG 3'b001
`define CTR_REG 3'b010
`define RXR_REG 3'b011
`define TXR_REG 3'b011
`define CR_REG 3'b100
`define SR_REG 3'b100


+ 168
- 0
i2c_slave_opencores/bench/multiByteReadWrite.v View File

@@ -0,0 +1,168 @@
// ------------------ multiByteReadWrite.v ----------------------
`include "timescale.v"
`include "i2cSlaveTB_defines.v"


module multiByteReadWrite();
reg ack;
reg [31:0] readData;
reg [7:0] dataByteRead;
//reg [7:0] dataMSB;

// ------------------ write ----------------------
task write;
input [7:0] i2cAddr;
input [15:0] regAddr;
input [31:0] data;
input stop;

begin
$write("I2C Write: At [0x%0x] = 0x%0x\n", regAddr, data);

//i2c address
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, i2cAddr);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h90); //STA, WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("I2C device address sent, SR = 0x%x\n", dataByteRead );

//slave reg address high byte
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, regAddr[15:8]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h10); //WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Slave reg address sent, SR = 0x%x\n", dataByteRead );

//slave reg address low byte
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, regAddr[7:0]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h10); //WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Slave reg address sent, SR = 0x%x\n", dataByteRead );

//data[31:24]
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, data[31:24]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h10); //WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[31:24] sent, SR = 0x%x\n", dataByteRead );

//data[23:16]
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, data[23:16]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h10); //WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[23:16] sent, SR = 0x%x\n", dataByteRead );

//data[15:8]
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, data[15:8]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h10); //WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[15:8] sent, SR = 0x%x\n", dataByteRead );

//data[7:0]
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, data[7:0]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , {1'b0, stop, 6'b010000}); //STO?, WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[7:0] sent, SR = 0x%x\n", dataByteRead );

end
endtask

// ------------------ read ----------------------
task read;
input [7:0] i2cAddr;
input [15:0] regAddr;
input [31:0] expectedData;
output [31:0] data;
input stop;

begin

//i2c address
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, i2cAddr); //write
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h90); //STA, WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("I2C device address sent, SR = 0x%x\n", dataByteRead );
#5000;

//slave reg address high byte
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, regAddr[15:8]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , {1'b0, stop, 6'b010000}); //STO?, WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Slave reg address sent, SR = 0x%x\n", dataByteRead );
#5000;
//slave reg address low byte
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, regAddr[7:0]);
testHarness.u_wb_master_model.wb_write(1, `CR_REG , {1'b0, stop, 6'b010000}); //STO?, WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Slave reg address sent, SR = 0x%x\n", dataByteRead );
#5000;

//i2c address
testHarness.u_wb_master_model.wb_write(1, `TXR_REG, {i2cAddr[7:1], 1'b1}); //read
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h90); //STA, WR
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("I2C device address sent, SR = 0x%x\n", dataByteRead );

//data[31:24]
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h20); //RD, ACK
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[31:24] rxed, SR = 0x%x\n", dataByteRead );
testHarness.u_wb_master_model.wb_read(1, `RXR_REG, readData[31:24]);

//data[23:16]
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h20); //RD, ACK
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[23:16] rxed, SR = 0x%x\n", dataByteRead );
testHarness.u_wb_master_model.wb_read(1, `RXR_REG, readData[23:16]);

//data[15:8]
testHarness.u_wb_master_model.wb_write(1, `CR_REG , 8'h20); //RD, ACK
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[15:8] rxed, SR = 0x%x\n", dataByteRead );
testHarness.u_wb_master_model.wb_read(1, `RXR_REG, readData[15:8]);

//data[7:0]
testHarness.u_wb_master_model.wb_write(1, `CR_REG , {1'b0, 1'b0, 6'b101000}); //STO, RD, NAK
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
while (dataByteRead[1] == 1'b1) //while trans in progress
testHarness.u_wb_master_model.wb_read(1, `SR_REG , dataByteRead);
//$write("Data[7:0] rxed, SR = 0x%x\n", dataByteRead );
testHarness.u_wb_master_model.wb_read(1, `RXR_REG, readData[7:0]);

data = readData;
if (data != expectedData) begin
$write("***** I2C Read ERROR: At 0x%0x. Expected 0x%0x, got 0x%0x\n", regAddr, expectedData, data);
//$stop;
end
else
$write("[read] I2C Read: At [0x%x] = 0x%0x\n", regAddr, data);
end
endtask

endmodule


+ 57
- 0
i2c_slave_opencores/bench/testCase0.v View File

@@ -0,0 +1,57 @@
// ---------------------------------- testcase0.v ----------------------------
`include "timescale.v"
`include "i2cSlave_define.v"
`include "i2cSlaveTB_defines.v"

module testCase0();

reg ack;
reg [7:0] data;
reg [15:0] dataWord;
reg [7:0] dataRead;
reg [7:0] dataWrite;
integer i;
integer j;

initial
begin
$write("\n\n");
testHarness.reset;
testHarness.tb_readEn <= 1'b0;
testHarness.tb_writeEn <= 1'b0;

// set i2c master clock scale reg PRER = (48MHz / (5 * 400KHz) ) - 1
$write("Testing register read/write\n");
testHarness.u_wb_master_model.wb_write(1, `PRER_LO_REG , 8'h17);
testHarness.u_wb_master_model.wb_write(1, `PRER_HI_REG , 8'h00);
testHarness.u_wb_master_model.wb_cmp(1, `PRER_LO_REG , 8'h17);

// enable i2c master
testHarness.u_wb_master_model.wb_write(1, `CTR_REG , 8'h80);

multiByteReadWrite.write({`I2C_ADDRESS, 1'b0}, 16'h1234, 32'h89abcdef, `SEND_STOP);
multiByteReadWrite.read({`I2C_ADDRESS, 1'b0}, 16'h1234, 32'h89abcdef, dataWord, `NULL);
#100;

testHarness.tb_addr <= 16'h1234;
testHarness.tb_dataIn <= 16'h5555;

#10 testHarness.tb_writeEn <= 1'b1;
#10 testHarness.tb_readEn <= 1'b1;
#10 testHarness.tb_writeEn <= 1'b0;
#10 testHarness.tb_readEn <= 1'b0;

#100;
multiByteReadWrite.read({`I2C_ADDRESS, 1'b0}, 16'h1234, 32'h89abcdef, dataWord, `NULL);

#100;
multiByteReadWrite.write({`I2C_ADDRESS, 1'b0}, 16'h1234, 32'h89abcdef, `SEND_STOP);
multiByteReadWrite.read({`I2C_ADDRESS, 1'b0}, 16'h1234, 32'h89abcdef, dataWord, `NULL);

$write("Finished all tests\n");
$finish;

end
endmodule


+ 122
- 0
i2c_slave_opencores/bench/testHarness.v View File

@@ -0,0 +1,122 @@
// -------------------------- testHarness.v -----------------------
`include "timescale.v"
module testHarness ();
reg rst;
reg clk;
reg i2cHostClk;
wire sda;
wire scl;
wire sdaOutEn;
wire sdaOut;
wire sdaIn;
wire [2:0] adr;
wire [7:0] masterDout;
wire [7:0] masterDin;
wire we;
wire stb;
wire cyc;
wire ack;
wire scl_pad_i;
wire scl_pad_o;
wire scl_padoen_o;
wire sda_pad_i;
wire sda_pad_o;
wire sda_padoen_o;
// tb passthrough
reg tb_readEn;
reg tb_writeEn;
reg [15:0] tb_addr;
reg [15:0] tb_dataIn;
wire [15:0] tb_dataOut;
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testHarness);
end
i2cSlave u_i2cSlave(
.clk(clk),
.rst(rst),
.sda(sda),
.scl(scl),
.tb_readEn(tb_readEn),
.tb_writeEn(tb_writeEn),
.tb_addr(tb_addr),
.tb_dataIn(tb_dataIn),
.tb_dataOut(tb_dataOut)
);
i2c_master_top #(.ARST_LVL(1'b1)) u_i2c_master_top (
.wb_clk_i(clk),
.wb_rst_i(rst),
.arst_i(rst),
.wb_adr_i(adr),
.wb_dat_i(masterDout),
.wb_dat_o(masterDin),
.wb_we_i(we),
.wb_stb_i(stb),
.wb_cyc_i(cyc),
.wb_ack_o(ack),
.wb_inta_o(),
.scl_pad_i(scl_pad_i),
.scl_pad_o(scl_pad_o),
.scl_padoen_o(scl_padoen_o),
.sda_pad_i(sda_pad_i),
.sda_pad_o(sda_pad_o),
.sda_padoen_o(sda_padoen_o)
);
wb_master_model #(.dwidth(8), .awidth(3)) u_wb_master_model (
.clk(clk),
.rst(rst),
.adr(adr),
.din(masterDin),
.dout(masterDout),
.cyc(cyc),
.stb(stb),
.we(we),
.sel(),
.ack(ack),
.err(1'b0),
.rty(1'b0)
);
assign sda = (sda_padoen_o == 1'b0) ? sda_pad_o : 1'bz;
assign sda_pad_i = sda;
pullup(sda);
assign scl = (scl_padoen_o == 1'b0) ? scl_pad_o : 1'bz;
assign scl_pad_i = scl;
pullup(scl);
// ****************************** Clock section ******************************
//approx 48MHz clock
`define CLK_HALF_PERIOD 10
always begin
#`CLK_HALF_PERIOD clk <= 1'b0;
#`CLK_HALF_PERIOD clk <= 1'b1;
end
// ****************************** reset ******************************
task reset;
begin
rst <= 1'b1;
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
rst <= 1'b0;
@(posedge clk);
@(posedge clk);
@(posedge clk);
end
endtask
endmodule

BIN
i2c_slave_opencores/doc/Philips_I2C_spec.pdf View File


BIN
i2c_slave_opencores/doc/i2cSlave_FSM.pdf View File


BIN
i2c_slave_opencores/doc/i2cSlave_IPCore_Specification.pdf View File


BIN
i2c_slave_opencores/doc/i2c_master_specs.pdf View File


BIN
i2c_slave_opencores/doc/src/i2cSlave_IPCore_Specification.sxw View File


+ 538
- 0
i2c_slave_opencores/model/i2c_master_bit_ctrl.v View File

@@ -0,0 +1,538 @@
/////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE rev.B2 compliant I2C Master bit-controller ////
//// ////
//// ////
//// Author: Richard Herveille ////
//// richard@asics.ws ////
//// www.asics.ws ////
//// ////
//// Downloaded from: http://www.opencores.org/projects/i2c/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2001 Richard Herveille ////
//// richard@asics.ws ////
//// ////
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
//// 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. ////
//// ////
/////////////////////////////////////////////////////////////////////

// CVS Log
//
// $Id: i2c_master_bit_ctrl.v,v 1.1 2008-11-08 13:15:10 sfielding Exp $
//
// $Date: 2008-11-08 13:15:10 $
// $Revision: 1.1 $
// $Author: sfielding $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.12 2006/09/04 09:08:13 rherveille
// fixed short scl high pulse after clock stretch
// fixed slave model not returning correct '(n)ack' signal
//
// Revision 1.11 2004/05/07 11:02:26 rherveille
// Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
//
// Revision 1.10 2003/08/09 07:01:33 rherveille
// Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
// Fixed a potential bug in the byte controller's host-acknowledge generation.
//
// Revision 1.9 2003/03/10 14:26:37 rherveille
// Fixed cmd_ack generation item (no bug).
//
// Revision 1.8 2003/02/05 00:06:10 rherveille
// Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
//
// Revision 1.7 2002/12/26 16:05:12 rherveille
// Small code simplifications
//
// Revision 1.6 2002/12/26 15:02:32 rherveille
// Core is now a Multimaster I2C controller
//
// Revision 1.5 2002/11/30 22:24:40 rherveille
// Cleaned up code
//
// Revision 1.4 2002/10/30 18:10:07 rherveille
// Fixed some reported minor start/stop generation timing issuess.
//
// Revision 1.3 2002/06/15 07:37:03 rherveille
// Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
//
// Revision 1.2 2001/11/05 11:59:25 rherveille
// Fixed wb_ack_o generation bug.
// Fixed bug in the byte_controller statemachine.
// Added headers.
//

//
/////////////////////////////////////
// Bit controller section
/////////////////////////////////////
//
// Translate simple commands into SCL/SDA transitions
// Each command has 5 states, A/B/C/D/idle
//
// start: SCL ~~~~~~~~~~\____
// SDA ~~~~~~~~\______
// x | A | B | C | D | i
//
// repstart SCL ____/~~~~\___
// SDA __/~~~\______
// x | A | B | C | D | i
//
// stop SCL ____/~~~~~~~~
// SDA ==\____/~~~~~
// x | A | B | C | D | i
//
//- write SCL ____/~~~~\____
// SDA ==X=========X=
// x | A | B | C | D | i
//
//- read SCL ____/~~~~\____
// SDA XXXX=====XXXX
// x | A | B | C | D | i
//

// Timing: Normal mode Fast mode
///////////////////////////////////////////////////////////////////////
// Fscl 100KHz 400KHz
// Th_scl 4.0us 0.6us High period of SCL
// Tl_scl 4.7us 1.3us Low period of SCL
// Tsu:sta 4.7us 0.6us setup time for a repeated start condition
// Tsu:sto 4.0us 0.6us setup time for a stop conditon
// Tbuf 4.7us 1.3us Bus free time between a stop and start condition
//

// synopsys translate_off
`include "timescale.v"
// synopsys translate_on

`include "i2c_master_defines.v"

module i2c_master_bit_ctrl(
clk, rst, nReset,
clk_cnt, ena, cmd, cmd_ack, busy, al, din, dout,
scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen
);

//
// inputs & outputs
//
input clk;
input rst;
input nReset;
input ena; // core enable signal

input [15:0] clk_cnt; // clock prescale value

input [3:0] cmd;
output cmd_ack; // command complete acknowledge
reg cmd_ack;
output busy; // i2c bus busy
reg busy;
output al; // i2c bus arbitration lost
reg al;

input din;
output dout;
reg dout;

// I2C lines
input scl_i; // i2c clock line input
output scl_o; // i2c clock line output
output scl_oen; // i2c clock line output enable (active low)
reg scl_oen;
input sda_i; // i2c data line input
output sda_o; // i2c data line output
output sda_oen; // i2c data line output enable (active low)
reg sda_oen;


//
// variable declarations
//

reg sSCL, sSDA; // synchronized SCL and SDA inputs
reg dscl_oen; // delayed scl_oen
reg sda_chk; // check SDA output (Multi-master arbitration)
reg clk_en; // clock generation signals
wire slave_wait;
// reg [15:0] cnt = clk_cnt; // clock divider counter (simulation)
reg [15:0] cnt; // clock divider counter (synthesis)

// state machine variable
reg [16:0] c_state; // synopsys enum_state

//
// module body
//

// whenever the slave is not ready it can delay the cycle by pulling SCL low
// delay scl_oen
always @(posedge clk)
dscl_oen <= #1 scl_oen;

assign slave_wait = dscl_oen && !sSCL;


// generate clk enable signal
always @(posedge clk or negedge nReset)
if(~nReset)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if (rst)
begin
cnt <= #1 16'h0;
clk_en <= #1 1'b1;
end
else if ( ~|cnt || !ena)
begin
cnt <= #1 clk_cnt;
clk_en <= #1 1'b1;
end
else if (slave_wait)
begin
cnt <= #1 cnt;
clk_en <= #1 1'b0;
end
else
begin
cnt <= #1 cnt - 16'h1;
clk_en <= #1 1'b0;
end


// generate bus status controller
reg dSCL, dSDA;
reg sta_condition;
reg sto_condition;

// synchronize SCL and SDA inputs
// reduce metastability risc
always @(posedge clk or negedge nReset)
if (~nReset)
begin
sSCL <= #1 1'b1;
sSDA <= #1 1'b1;

dSCL <= #1 1'b1;
dSDA <= #1 1'b1;
end
else if (rst)
begin
sSCL <= #1 1'b1;
sSDA <= #1 1'b1;

dSCL <= #1 1'b1;
dSDA <= #1 1'b1;
end
else
begin
sSCL <= #1 scl_i;
sSDA <= #1 sda_i;

dSCL <= #1 sSCL;
dSDA <= #1 sSDA;
end

// detect start condition => detect falling edge on SDA while SCL is high
// detect stop condition => detect rising edge on SDA while SCL is high
always @(posedge clk or negedge nReset)
if (~nReset)
begin
sta_condition <= #1 1'b0;
sto_condition <= #1 1'b0;
end
else if (rst)
begin
sta_condition <= #1 1'b0;
sto_condition <= #1 1'b0;
end
else
begin
sta_condition <= #1 ~sSDA & dSDA & sSCL;
sto_condition <= #1 sSDA & ~dSDA & sSCL;
end

// generate i2c bus busy signal
always @(posedge clk or negedge nReset)
if(!nReset)
busy <= #1 1'b0;
else if (rst)
busy <= #1 1'b0;
else
busy <= #1 (sta_condition | busy) & ~sto_condition;

// generate arbitration lost signal
// aribitration lost when:
// 1) master drives SDA high, but the i2c bus is low
// 2) stop detected while not requested
reg cmd_stop;
always @(posedge clk or negedge nReset)
if (~nReset)
cmd_stop <= #1 1'b0;
else if (rst)
cmd_stop <= #1 1'b0;
else if (clk_en)
cmd_stop <= #1 cmd == `I2C_CMD_STOP;

always @(posedge clk or negedge nReset)
if (~nReset)
al <= #1 1'b0;
else if (rst)
al <= #1 1'b0;
else
al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);


// generate dout signal (store SDA on rising edge of SCL)
always @(posedge clk)
if(sSCL & ~dSCL)
dout <= #1 sSDA;

// generate statemachine

// nxt_state decoder
parameter [16:0] idle = 17'b0_0000_0000_0000_0000;
parameter [16:0] start_a = 17'b0_0000_0000_0000_0001;
parameter [16:0] start_b = 17'b0_0000_0000_0000_0010;
parameter [16:0] start_c = 17'b0_0000_0000_0000_0100;
parameter [16:0] start_d = 17'b0_0000_0000_0000_1000;
parameter [16:0] start_e = 17'b0_0000_0000_0001_0000;
parameter [16:0] stop_a = 17'b0_0000_0000_0010_0000;
parameter [16:0] stop_b = 17'b0_0000_0000_0100_0000;
parameter [16:0] stop_c = 17'b0_0000_0000_1000_0000;
parameter [16:0] stop_d = 17'b0_0000_0001_0000_0000;
parameter [16:0] rd_a = 17'b0_0000_0010_0000_0000;
parameter [16:0] rd_b = 17'b0_0000_0100_0000_0000;
parameter [16:0] rd_c = 17'b0_0000_1000_0000_0000;
parameter [16:0] rd_d = 17'b0_0001_0000_0000_0000;
parameter [16:0] wr_a = 17'b0_0010_0000_0000_0000;
parameter [16:0] wr_b = 17'b0_0100_0000_0000_0000;
parameter [16:0] wr_c = 17'b0_1000_0000_0000_0000;
parameter [16:0] wr_d = 17'b1_0000_0000_0000_0000;

always @(posedge clk or negedge nReset)
if (!nReset)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
sda_chk <= #1 1'b0;
end
else if (rst | al)
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b0;
scl_oen <= #1 1'b1;
sda_oen <= #1 1'b1;
sda_chk <= #1 1'b0;
end
else
begin
cmd_ack <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle

if (clk_en)
case (c_state) // synopsys full_case parallel_case
// idle state
idle:
begin
case (cmd) // synopsys full_case parallel_case
`I2C_CMD_START:
c_state <= #1 start_a;

`I2C_CMD_STOP:
c_state <= #1 stop_a;

`I2C_CMD_WRITE:
c_state <= #1 wr_a;

`I2C_CMD_READ:
c_state <= #1 rd_a;

default:
c_state <= #1 idle;
endcase

scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 sda_oen; // keep SDA in same state
sda_chk <= #1 1'b0; // don't check SDA output
end

// start
start_a:
begin
c_state <= #1 start_b;
scl_oen <= #1 scl_oen; // keep SCL in same state
sda_oen <= #1 1'b1; // set SDA high
sda_chk <= #1 1'b0; // don't check SDA output
end

start_b:
begin
c_state <= #1 start_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA high
sda_chk <= #1 1'b0; // don't check SDA output
end

start_c:
begin
c_state <= #1 start_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // set SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end

start_d:
begin
c_state <= #1 start_e;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end

start_e:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end

// stop
stop_a:
begin
c_state <= #1 stop_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b0; // set SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end

stop_b:
begin
c_state <= #1 stop_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end

stop_c:
begin
c_state <= #1 stop_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b0; // keep SDA low
sda_chk <= #1 1'b0; // don't check SDA output
end

stop_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // set SDA high
sda_chk <= #1 1'b0; // don't check SDA output
end

// read
rd_a:
begin
c_state <= #1 rd_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 1'b1; // tri-state SDA
sda_chk <= #1 1'b0; // don't check SDA output
end

rd_b:
begin
c_state <= #1 rd_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
sda_chk <= #1 1'b0; // don't check SDA output
end

rd_c:
begin
c_state <= #1 rd_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 1'b1; // keep SDA tri-stated
sda_chk <= #1 1'b0; // don't check SDA output
end

rd_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 1'b1; // keep SDA tri-stated
sda_chk <= #1 1'b0; // don't check SDA output
end

// write
wr_a:
begin
c_state <= #1 wr_b;
scl_oen <= #1 1'b0; // keep SCL low
sda_oen <= #1 din; // set SDA
sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
end

wr_b:
begin
c_state <= #1 wr_c;
scl_oen <= #1 1'b1; // set SCL high
sda_oen <= #1 din; // keep SDA
sda_chk <= #1 1'b1; // check SDA output
end

wr_c:
begin
c_state <= #1 wr_d;
scl_oen <= #1 1'b1; // keep SCL high
sda_oen <= #1 din;
sda_chk <= #1 1'b1; // check SDA output
end

wr_d:
begin
c_state <= #1 idle;
cmd_ack <= #1 1'b1;
scl_oen <= #1 1'b0; // set SCL low
sda_oen <= #1 din;
sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
end

endcase
end


// assign scl and sda output (always gnd)
assign scl_o = 1'b0;
assign sda_o = 1'b0;

endmodule

+ 344
- 0
i2c_slave_opencores/model/i2c_master_byte_ctrl.v View File

@@ -0,0 +1,344 @@
/////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE rev.B2 compliant I2C Master byte-controller ////
//// ////
//// ////
//// Author: Richard Herveille ////
//// richard@asics.ws ////
//// www.asics.ws ////
//// ////
//// Downloaded from: http://www.opencores.org/projects/i2c/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2001 Richard Herveille ////
//// richard@asics.ws ////
//// ////
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
//// 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. ////
//// ////
/////////////////////////////////////////////////////////////////////

// CVS Log
//
// $Id: i2c_master_byte_ctrl.v,v 1.1 2008-11-08 13:15:10 sfielding Exp $
//
// $Date: 2008-11-08 13:15:10 $
// $Revision: 1.1 $
// $Author: sfielding $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.7 2004/02/18 11:40:46 rherveille
// Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command.
//
// Revision 1.6 2003/08/09 07:01:33 rherveille
// Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
// Fixed a potential bug in the byte controller's host-acknowledge generation.
//
// Revision 1.5 2002/12/26 15:02:32 rherveille
// Core is now a Multimaster I2C controller
//
// Revision 1.4 2002/11/30 22:24:40 rherveille
// Cleaned up code
//
// Revision 1.3 2001/11/05 11:59:25 rherveille
// Fixed wb_ack_o generation bug.
// Fixed bug in the byte_controller statemachine.
// Added headers.
//

// synopsys translate_off
`include "timescale.v"
// synopsys translate_on

`include "i2c_master_defines.v"

module i2c_master_byte_ctrl (
clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din,
cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen );

//
// inputs & outputs
//
input clk; // master clock
input rst; // synchronous active high reset
input nReset; // asynchronous active low reset
input ena; // core enable signal

input [15:0] clk_cnt; // 4x SCL

// control inputs
input start;
input stop;
input read;
input write;
input ack_in;
input [7:0] din;

// status outputs
output cmd_ack;
reg cmd_ack;
output ack_out;
reg ack_out;
output i2c_busy;
output i2c_al;
output [7:0] dout;

// I2C signals
input scl_i;
output scl_o;
output scl_oen;
input sda_i;
output sda_o;
output sda_oen;


//
// Variable declarations
//

// statemachine
parameter [4:0] ST_IDLE = 5'b0_0000;
parameter [4:0] ST_START = 5'b0_0001;
parameter [4:0] ST_READ = 5'b0_0010;
parameter [4:0] ST_WRITE = 5'b0_0100;
parameter [4:0] ST_ACK = 5'b0_1000;
parameter [4:0] ST_STOP = 5'b1_0000;

// signals for bit_controller
reg [3:0] core_cmd;
reg core_txd;
wire core_ack, core_rxd;

// signals for shift register
reg [7:0] sr; //8bit shift register
reg shift, ld;

// signals for state machine
wire go;
reg [2:0] dcnt;
wire cnt_done;

//
// Module body
//

// hookup bit_controller
i2c_master_bit_ctrl bit_controller (
.clk ( clk ),
.rst ( rst ),
.nReset ( nReset ),
.ena ( ena ),
.clk_cnt ( clk_cnt ),
.cmd ( core_cmd ),
.cmd_ack ( core_ack ),
.busy ( i2c_busy ),
.al ( i2c_al ),
.din ( core_txd ),
.dout ( core_rxd ),
.scl_i ( scl_i ),
.scl_o ( scl_o ),
.scl_oen ( scl_oen ),
.sda_i ( sda_i ),
.sda_o ( sda_o ),
.sda_oen ( sda_oen )
);

// generate go-signal
assign go = (read | write | stop) & ~cmd_ack;

// assign dout output to shift-register
assign dout = sr;

// generate shift register
always @(posedge clk or negedge nReset)
if (!nReset)
sr <= #1 8'h0;
else if (rst)
sr <= #1 8'h0;
else if (ld)
sr <= #1 din;
else if (shift)
sr <= #1 {sr[6:0], core_rxd};

// generate counter
always @(posedge clk or negedge nReset)
if (!nReset)
dcnt <= #1 3'h0;
else if (rst)
dcnt <= #1 3'h0;
else if (ld)
dcnt <= #1 3'h7;
else if (shift)
dcnt <= #1 dcnt - 3'h1;

assign cnt_done = ~(|dcnt);

//
// state machine
//
reg [4:0] c_state; // synopsis enum_state

always @(posedge clk or negedge nReset)
if (!nReset)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
ack_out <= #1 1'b0;
end
else if (rst | i2c_al)
begin
core_cmd <= #1 `I2C_CMD_NOP;
core_txd <= #1 1'b0;
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;
c_state <= #1 ST_IDLE;
ack_out <= #1 1'b0;
end
else
begin
// initially reset all signals
core_txd <= #1 sr[7];
shift <= #1 1'b0;
ld <= #1 1'b0;
cmd_ack <= #1 1'b0;

case (c_state) // synopsys full_case parallel_case
ST_IDLE:
if (go)
begin
if (start)
begin
c_state <= #1 ST_START;
core_cmd <= #1 `I2C_CMD_START;
end
else if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else if (write)
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else // stop
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
end

ld <= #1 1'b1;
end

ST_START:
if (core_ack)
begin
if (read)
begin
c_state <= #1 ST_READ;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE;
core_cmd <= #1 `I2C_CMD_WRITE;
end

ld <= #1 1'b1;
end

ST_WRITE:
if (core_ack)
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_READ;
end
else
begin
c_state <= #1 ST_WRITE; // stay in same state
core_cmd <= #1 `I2C_CMD_WRITE; // write next bit
shift <= #1 1'b1;
end

ST_READ:
if (core_ack)
begin
if (cnt_done)
begin
c_state <= #1 ST_ACK;
core_cmd <= #1 `I2C_CMD_WRITE;
end
else
begin
c_state <= #1 ST_READ; // stay in same state
core_cmd <= #1 `I2C_CMD_READ; // read next bit
end

shift <= #1 1'b1;
core_txd <= #1 ack_in;
end

ST_ACK:
if (core_ack)
begin
if (stop)
begin
c_state <= #1 ST_STOP;
core_cmd <= #1 `I2C_CMD_STOP;
end
else
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;

// generate command acknowledge signal
cmd_ack <= #1 1'b1;
end

// assign ack_out output to bit_controller_rxd (contains last received bit)
ack_out <= #1 core_rxd;

core_txd <= #1 1'b1;
end
else
core_txd <= #1 ack_in;

ST_STOP:
if (core_ack)
begin
c_state <= #1 ST_IDLE;
core_cmd <= #1 `I2C_CMD_NOP;

// generate command acknowledge signal
cmd_ack <= #1 1'b1;
end

endcase
end
endmodule

+ 64
- 0
i2c_slave_opencores/model/i2c_master_defines.v View File

@@ -0,0 +1,64 @@
/////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE rev.B2 compliant I2C Master controller defines ////
//// ////
//// ////
//// Author: Richard Herveille ////
//// richard@asics.ws ////
//// www.asics.ws ////
//// ////
//// Downloaded from: http://www.opencores.org/projects/i2c/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2001 Richard Herveille ////
//// richard@asics.ws ////
//// ////
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
//// 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. ////
//// ////
/////////////////////////////////////////////////////////////////////

// CVS Log
//
// $Id: i2c_master_defines.v,v 1.1 2008-11-08 13:15:10 sfielding Exp $
//
// $Date: 2008-11-08 13:15:10 $
// $Revision: 1.1 $
// $Author: sfielding $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.3 2001/11/05 11:59:25 rherveille
// Fixed wb_ack_o generation bug.
// Fixed bug in the byte_controller statemachine.
// Added headers.
//


// I2C registers wishbone addresses

// bitcontroller states
`define I2C_CMD_NOP 4'b0000
`define I2C_CMD_START 4'b0001
`define I2C_CMD_STOP 4'b0010
`define I2C_CMD_WRITE 4'b0100
`define I2C_CMD_READ 4'b1000

+ 301
- 0
i2c_slave_opencores/model/i2c_master_top.v View File

@@ -0,0 +1,301 @@
/////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE revB.2 compliant I2C Master controller Top-level ////
//// ////
//// ////
//// Author: Richard Herveille ////
//// richard@asics.ws ////
//// www.asics.ws ////
//// ////
//// Downloaded from: http://www.opencores.org/projects/i2c/ ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2001 Richard Herveille ////
//// richard@asics.ws ////
//// ////
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
//// 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. ////
//// ////
/////////////////////////////////////////////////////////////////////

// CVS Log
//
// $Id: i2c_master_top.v,v 1.1 2008-11-08 13:15:10 sfielding Exp $
//
// $Date: 2008-11-08 13:15:10 $
// $Revision: 1.1 $
// $Author: sfielding $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.11 2005/02/27 09:26:24 rherveille
// Fixed register overwrite issue.
// Removed full_case pragma, replaced it by a default statement.
//
// Revision 1.10 2003/09/01 10:34:38 rherveille
// Fix a blocking vs. non-blocking error in the wb_dat output mux.
//
// Revision 1.9 2003/01/09 16:44:45 rherveille
// Fixed a bug in the Command Register declaration.
//
// Revision 1.8 2002/12/26 16:05:12 rherveille
// Small code simplifications
//
// Revision 1.7 2002/12/26 15:02:32 rherveille
// Core is now a Multimaster I2C controller
//
// Revision 1.6 2002/11/30 22:24:40 rherveille
// Cleaned up code
//
// Revision 1.5 2001/11/10 10:52:55 rherveille
// Changed PRER reset value from 0x0000 to 0xffff, conform specs.
//

// synopsys translate_off
`include "timescale.v"
// synopsys translate_on

`include "i2c_master_defines.v"

module i2c_master_top(
wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o,
wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o,
scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o );

// parameters
parameter ARST_LVL = 1'b0; // asynchronous reset level

//
// inputs & outputs
//

// wishbone signals
input wb_clk_i; // master clock input
input wb_rst_i; // synchronous active high reset
input arst_i; // asynchronous reset
input [2:0] wb_adr_i; // lower address bits
input [7:0] wb_dat_i; // databus input
output [7:0] wb_dat_o; // databus output
input wb_we_i; // write enable input
input wb_stb_i; // stobe/core select signal
input wb_cyc_i; // valid bus cycle input
output wb_ack_o; // bus cycle acknowledge output
output wb_inta_o; // interrupt request signal output

reg [7:0] wb_dat_o;
reg wb_ack_o;
reg wb_inta_o;

// I2C signals
// i2c clock line
input scl_pad_i; // SCL-line input
output scl_pad_o; // SCL-line output (always 1'b0)
output scl_padoen_o; // SCL-line output enable (active low)

// i2c data line
input sda_pad_i; // SDA-line input
output sda_pad_o; // SDA-line output (always 1'b0)
output sda_padoen_o; // SDA-line output enable (active low)


//
// variable declarations
//

// registers
reg [15:0] prer; // clock prescale register
reg [ 7:0] ctr; // control register
reg [ 7:0] txr; // transmit register
wire [ 7:0] rxr; // receive register
reg [ 7:0] cr; // command register
wire [ 7:0] sr; // status register

// done signal: command completed, clear command register
wire done;

// core enable signal
wire core_en;
wire ien;

// status register signals
wire irxack;
reg rxack; // received aknowledge from slave
reg tip; // transfer in progress
reg irq_flag; // interrupt pending flag
wire i2c_busy; // bus busy (start signal detected)
wire i2c_al; // i2c bus arbitration lost
reg al; // status register arbitration lost bit

//
// module body
//

// generate internal reset
wire rst_i = arst_i ^ ARST_LVL;

// generate wishbone signals
wire wb_wacc = wb_cyc_i & wb_stb_i & wb_we_i;

// generate acknowledge output signal
always @(posedge wb_clk_i)
wb_ack_o <= #1 wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored

// assign DAT_O
always @(posedge wb_clk_i)
begin
case (wb_adr_i) // synopsis parallel_case
3'b000: wb_dat_o <= #1 prer[ 7:0];
3'b001: wb_dat_o <= #1 prer[15:8];
3'b010: wb_dat_o <= #1 ctr;
3'b011: wb_dat_o <= #1 rxr; // write is transmit register (txr)
3'b100: wb_dat_o <= #1 sr; // write is command register (cr)
3'b101: wb_dat_o <= #1 txr;
3'b110: wb_dat_o <= #1 cr;
3'b111: wb_dat_o <= #1 0; // reserved
endcase
end

// generate registers
always @(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
begin
prer <= #1 16'hffff;
ctr <= #1 8'h0;
txr <= #1 8'h0;
end
else if (wb_rst_i)
begin
prer <= #1 16'hffff;
ctr <= #1 8'h0;
txr <= #1 8'h0;
end
else
if (wb_wacc)
case (wb_adr_i) // synopsis parallel_case
3'b000 : prer [ 7:0] <= #1 wb_dat_i;
3'b001 : prer [15:8] <= #1 wb_dat_i;
3'b010 : ctr <= #1 wb_dat_i;
3'b011 : txr <= #1 wb_dat_i;
default: ;
endcase

// generate command register (special case)
always @(posedge wb_clk_i or negedge rst_i)
if (~rst_i)
cr <= #1 8'h0;
else if (wb_rst_i)
cr <= #1 8'h0;
else if (wb_wacc)
begin
if (core_en & (wb_adr_i == 3'b100) )
cr <= #1 wb_dat_i;
end
else
begin
if (done | i2c_al)
cr[7:4] <= #1 4'h0; // clear command bits when done
// or when aribitration lost
cr[2:1] <= #1 2'b0; // reserved bits
cr[0] <= #1 2'b0; // clear IRQ_ACK bit
end


// decode command register
wire sta = cr[7];
wire sto = cr[6];
wire rd = cr[5];
wire wr = cr[4];
wire ack = cr[3];
wire iack = cr[0];

// decode control register
assign core_en = ctr[7];
assign ien = ctr[6];

// hookup byte controller block
i2c_master_byte_ctrl byte_controller (
.clk ( wb_clk_i ),
.rst ( wb_rst_i ),
.nReset ( rst_i ),
.ena ( core_en ),
.clk_cnt ( prer ),
.start ( sta ),
.stop ( sto ),
.read ( rd ),
.write ( wr ),
.ack_in ( ack ),
.din ( txr ),
.cmd_ack ( done ),
.ack_out ( irxack ),
.dout ( rxr ),
.i2c_busy ( i2c_busy ),
.i2c_al ( i2c_al ),
.scl_i ( scl_pad_i ),
.scl_o ( scl_pad_o ),
.scl_oen ( scl_padoen_o ),
.sda_i ( sda_pad_i ),
.sda_o ( sda_pad_o ),
.sda_oen ( sda_padoen_o )
);

// status register block + interrupt request signal
always @(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
begin
al <= #1 1'b0;
rxack <= #1 1'b0;
tip <= #1 1'b0;
irq_flag <= #1 1'b0;
end
else if (wb_rst_i)
begin
al <= #1 1'b0;
rxack <= #1 1'b0;
tip <= #1 1'b0;
irq_flag <= #1 1'b0;
end
else
begin
al <= #1 i2c_al | (al & ~sta);
rxack <= #1 irxack;
tip <= #1 (rd | wr);
irq_flag <= #1 (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated
end

// generate interrupt request signals
always @(posedge wb_clk_i or negedge rst_i)
if (!rst_i)
wb_inta_o <= #1 1'b0;
else if (wb_rst_i)
wb_inta_o <= #1 1'b0;
else
wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set)

// assign status register bits
assign sr[7] = rxack;
assign sr[6] = i2c_busy;
assign sr[5] = al;
assign sr[4:2] = 3'h0; // reserved
assign sr[1] = tip;
assign sr[0] = irq_flag;

endmodule

+ 176
- 0
i2c_slave_opencores/model/wb_master_model.v View File

@@ -0,0 +1,176 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// wb_master_model.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// Based on: ////
//// - i2c/bench/verilog/wb_master_model.v ////
//// Copyright (C) 2001 Richard Herveille ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// 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 http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "timescale.v"
module wb_master_model(clk, rst, adr, din, dout, cyc, stb, we, sel, ack, err, rty);
parameter dwidth = 32;
parameter awidth = 32;
input clk, rst;
output [awidth -1:0] adr;
input [dwidth -1:0] din;
output [dwidth -1:0] dout;
output cyc, stb;
output we;
output [dwidth/8 -1:0] sel;
input ack, err, rty;
// Internal signals
reg [awidth -1:0] adr;
reg [dwidth -1:0] dout;
reg cyc, stb;
reg we;
reg [dwidth/8 -1:0] sel;
reg [dwidth -1:0] q;
// Memory Logic
initial
begin
adr = {awidth{1'bx}};
dout = {dwidth{1'bx}};
cyc = 1'b0;
stb = 1'bx;
we = 1'hx;
sel = {dwidth/8{1'bx}};
#1;
end
// Wishbone write cycle
task wb_write;
input delay;
integer delay;
input [awidth -1:0] a;
input [dwidth -1:0] d;
begin
// wait initial delay
repeat(delay) @(posedge clk);
// assert wishbone signal
#1;
adr = a;
dout = d;
cyc = 1'b1;
stb = 1'b1;
we = 1'b1;
sel = {dwidth/8{1'b1}};
@(posedge clk);
// wait for acknowledge from slave
while(~ack) @(posedge clk);
// negate wishbone signals
#1;
cyc = 1'b0;
stb = 1'bx;
adr = {awidth{1'bx}};
dout = {dwidth{1'bx}};
we = 1'hx;
sel = {dwidth/8{1'bx}};
end
endtask
// Wishbone read cycle
task wb_read;
input delay;
integer delay;
input [awidth -1:0] a;
output [dwidth -1:0] d;
begin
// wait initial delay
repeat(delay) @(posedge clk);
// assert wishbone signals
#1;
adr = a;
dout = {dwidth{1'bx}};
cyc = 1'b1;
stb = 1'b1;
we = 1'b0;
sel = {dwidth/8{1'b1}};
@(posedge clk);
// wait for acknowledge from slave
while(~ack) @(posedge clk);
// negate wishbone signals
#1;
cyc = 1'b0;
stb = 1'bx;
adr = {awidth{1'bx}};
dout = {dwidth{1'bx}};
we = 1'hx;
sel = {dwidth/8{1'bx}};
d = din;
end
endtask
// Wishbone compare cycle (read data from location and compare with expected data)
task wb_cmp;
input delay;
integer delay;
input [awidth -1:0] a;
input [dwidth -1:0] d_exp;
begin
wb_read (delay, a, q);
if (d_exp !== q)
$display("Data compare error. Received %h, expected %h at time %t", q, d_exp, $time);
end
endtask
endmodule

+ 199
- 0
i2c_slave_opencores/rtl/i2cSlave.v View File

@@ -0,0 +1,199 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// i2cSlave.v ////
//// ////
//// This file is part of the i2cSlave opencores effort.
//// <http://www.opencores.org/cores//> ////
//// ////
//// Module Description: ////
//// You will need to modify this file to implement your
//// interface.
//// ////
//// 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 <http://www.opencores.org/lgpl.shtml> ////
//// ////
//////////////////////////////////////////////////////////////////////
//
`include "i2cSlave_define.v"
module i2cSlave (
clk,
rst,
sda,
scl,
tb_readEn,
tb_writeEn,
tb_addr,
tb_dataIn,
tb_dataOut
);
input clk;
input rst;
inout sda;
input scl;
// tb interface
input tb_readEn;
input tb_writeEn;
input [15:0] tb_addr;
input [15:0] tb_dataIn;
output [15:0] tb_dataOut;
// local wires and regs
reg sdaDeb;
reg sclDeb;
reg [`DEB_I2C_LEN-1:0] sdaPipe;
reg [`DEB_I2C_LEN-1:0] sclPipe;
reg [`SCL_DEL_LEN-1:0] sclDelayed;
reg [`SDA_DEL_LEN-1:0] sdaDelayed;
reg [1:0] startStopDetState;
wire clearStartStopDet;
wire sdaOut;
wire sdaIn;
wire [15:0] regAddr;
wire [7:0] dataToRegIF;
wire writeEn;
wire [7:0] dataFromRegIF;
reg [1:0] rstPipe;
wire rstSyncToClk;
reg startEdgeDet;
assign sda = (sdaOut == 1'b0) ? 1'b0 : 1'bz;
assign sdaIn = sda;
// sync rst rsing edge to clk
always @(posedge clk) begin
if (rst == 1'b1)
rstPipe <= 2'b11;
else
rstPipe <= {rstPipe[0], 1'b0};
end
assign rstSyncToClk = rstPipe[1];
// debounce sda and scl
always @(posedge clk) begin
if (rstSyncToClk == 1'b1) begin
sdaPipe <= {`DEB_I2C_LEN{1'b1}};
sdaDeb <= 1'b1;
sclPipe <= {`DEB_I2C_LEN{1'b1}};
sclDeb <= 1'b1;
end
else begin
sdaPipe <= {sdaPipe[`DEB_I2C_LEN-2:0], sdaIn};
sclPipe <= {sclPipe[`DEB_I2C_LEN-2:0], scl};
if (&sclPipe[`DEB_I2C_LEN-1:1] == 1'b1)
sclDeb <= 1'b1;
else if (|sclPipe[`DEB_I2C_LEN-1:1] == 1'b0)
sclDeb <= 1'b0;
if (&sdaPipe[`DEB_I2C_LEN-1:1] == 1'b1)
sdaDeb <= 1'b1;
else if (|sdaPipe[`DEB_I2C_LEN-1:1] == 1'b0)
sdaDeb <= 1'b0;
end
end
// delay scl and sda
// sclDelayed is used as a delayed sampling clock
// sdaDelayed is only used for start stop detection
// Because sda hold time from scl falling is 0nS
// sda must be delayed with respect to scl to avoid incorrect
// detection of start/stop at scl falling edge.
always @(posedge clk) begin
if (rstSyncToClk == 1'b1) begin
sclDelayed <= {`SCL_DEL_LEN{1'b1}};
sdaDelayed <= {`SDA_DEL_LEN{1'b1}};
end
else begin
sclDelayed <= {sclDelayed[`SCL_DEL_LEN-2:0], sclDeb};
sdaDelayed <= {sdaDelayed[`SDA_DEL_LEN-2:0], sdaDeb};
end
end
// start stop detection
always @(posedge clk) begin
if (rstSyncToClk == 1'b1) begin
startStopDetState <= `NULL_DET;
startEdgeDet <= 1'b0;
end
else begin
if (sclDeb == 1'b1 && sdaDelayed[`SDA_DEL_LEN-2] == 1'b0 && sdaDelayed[`SDA_DEL_LEN-1] == 1'b1)
startEdgeDet <= 1'b1;
else
startEdgeDet <= 1'b0;
if (clearStartStopDet == 1'b1)
startStopDetState <= `NULL_DET;
else if (sclDeb == 1'b1) begin
if (sdaDelayed[`SDA_DEL_LEN-2] == 1'b1 && sdaDelayed[`SDA_DEL_LEN-1] == 1'b0)
startStopDetState <= `STOP_DET;
else if (sdaDelayed[`SDA_DEL_LEN-2] == 1'b0 && sdaDelayed[`SDA_DEL_LEN-1] == 1'b1)
startStopDetState <= `START_DET;
end
end
end
registerInterface u_registerInterface(
.clk(clk),
.addr(regAddr),
.dataIn(dataToRegIF),
.writeEn(writeEn),
.dataOut(dataFromRegIF),
.tb_readEn(tb_readEn),
.tb_writeEn(tb_writeEn),
.tb_addr(tb_addr),
.tb_dataIn(tb_dataIn),
.tb_dataOut(tb_dataOut)
);
serialInterface u_serialInterface (
.clk(clk),
.rst(rstSyncToClk | startEdgeDet),
.dataIn(dataFromRegIF),
.dataOut(dataToRegIF),
.writeEn(writeEn),
.regAddr(regAddr),
.scl(sclDelayed[`SCL_DEL_LEN-1]),
.sdaIn(sdaDeb),
.sdaOut(sdaOut),
.startStopDetState(startStopDetState),
.clearStartStopDet(clearStartStopDet)
);
endmodule

+ 68
- 0
i2c_slave_opencores/rtl/i2cSlave_define.v View File

@@ -0,0 +1,68 @@
// ----------------------- i2cSlave_define.v --------------------

// stream states
`define STREAM_IDLE 2'b00
`define STREAM_READ 2'b01
`define STREAM_WRITE_ADDR 2'b10
`define STREAM_WRITE_DATA 2'b11

// start stop detection states
`define NULL_DET 2'b00
`define START_DET 2'b01
`define STOP_DET 2'b10

// i2c ack and nak
`define I2C_NAK 1'b1
`define I2C_ACK 1'b0

// ----------------------------------------------------------------
// ------------- modify constants below this line -----------------
// ----------------------------------------------------------------

// i2c device address
`define I2C_ADDRESS 7'h3c

// System clock frequency in MHz
// If you are using a clock frequency below 24MHz, then the macro
// for SDA_DEL_LEN will result in compile errors for i2cSlave.v
// you will need to hand tweak the SDA_DEL_LEN constant definition
`define CLK_FREQ 48

// Debounce SCL and SDA over this many clock ticks
// The rise time of SCL and SDA can be up to 1000nS (in standard mode)
// so it is essential to debounce the inputs.
// The spec requires 0.05V of hysteresis, but in practise
// simply debouncing the inputs is sufficient
// I2C spec requires suppresion of spikes of
// maximum duration 50nS, so this debounce time should be greater than 50nS
// Also increases data hold time and decreases data setup time
// during an I2C read operation
// 10 ticks = 208nS @ 48MHz
`define DEB_I2C_LEN (10*`CLK_FREQ)/48

// Delay SCL for use as internal sampling clock
// Using delayed version of SCL to ensure that
// SDA is stable when it is sampled.
// Not entirely citical, as according to I2C spec
// SDA should have a minimum of 100nS of set up time
// with respect to SCL rising edge. But with the very slow edge
// speeds used in I2C it is better to err on the side of caution.
// This delay also has the effect of adding extra hold time to the data
// with respect to SCL falling edge. I2C spec requires 0nS of data hold time.
// 10 ticks = 208nS @ 48MHz
`define SCL_DEL_LEN (10*`CLK_FREQ)/48

// Delay SDA for use in start/stop detection
// Use delayed SDA during start/stop detection to avoid
// incorrect detection at SCL falling edge.
// From I2C spec start/stop setup is 600nS with respect to SCL rising edge
// and start/stop hold is 600nS wrt SCL falling edge.
// So it is relatively easy to discriminate start/stop,
// but data setup time is a minimum of 100nS with respect to SCL rising edge
// and 0nS hold wrt to SCL falling edge.
// So the tricky part is providing robust start/stop detection
// in the presence of regular data transitions.
// This delay time should be less than 100nS
// 4 ticks = 83nS @ 48MHz
`define SDA_DEL_LEN (4*`CLK_FREQ)/48


+ 109
- 0
i2c_slave_opencores/rtl/registerInterface.v View File

@@ -0,0 +1,109 @@
//////////////////////////////////////////////////////////////////////
//// ////
//// registerInterface.v ////
//// ////
//// This file is part of the i2cSlave opencores effort.
//// <http://www.opencores.org/cores//> ////
//// ////
//// Module Description: ////
//// You will need to modify this file to implement your
//// interface.
//// Add your control and status bytes/bits to module inputs and outputs,
//// and also to the I2C read and write process blocks
//// ////
//// 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 <http://www.opencores.org/lgpl.shtml> ////
//// ////
//////////////////////////////////////////////////////////////////////
//
`include "i2cSlave_define.v"


module registerInterface (
clk,
addr,
dataIn,
writeEn,
dataOut,
tb_readEn,
tb_writeEn,
tb_addr,
tb_dataIn,
tb_dataOut
);

// i2c interface
input clk;
input [15:0] addr;
input [7:0] dataIn;
input writeEn;
output [7:0] dataOut;
reg [7:0] dataOut;

// speicher
reg [7:0] memory [16'hffff:0];

// tb interface
input tb_readEn;
input tb_writeEn;
input [15:0] tb_addr;
input [15:0] tb_dataIn;
output [15:0] tb_dataOut;
reg [15:0] tb_dataOut;

// --- TB Read
always @(posedge tb_readEn) begin
tb_dataOut[15:8] <= memory[tb_addr];
tb_dataOut[7:0] <= memory[tb_addr + 1'b1];
end

// --- TB Write
always @(posedge tb_writeEn) begin
memory[tb_addr] <= tb_dataIn[15:8];
memory[tb_addr + 1'b1] <= tb_dataIn[7:0];
end

// --- I2C Read
always @(posedge clk) begin
dataOut <= memory[addr];
end

// --- I2C Write
always @(posedge clk) begin
if (writeEn == 1'b1) begin
memory[addr] <= dataIn;
end
end

endmodule



+ 372
- 0
i2c_slave_opencores/rtl/serialInterface.v View File

@@ -0,0 +1,372 @@

//////////////////////////////////////////////////////////////////////
//// ////
//// serialInterface.v ////
//// ////
//// This file is part of the i2cSlave opencores effort.
//// <http://www.opencores.org/cores//> ////
//// ////
//// 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 <http://www.opencores.org/lgpl.shtml> ////
//// ////
//////////////////////////////////////////////////////////////////////
//
`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

+ 5
- 0
i2c_slave_opencores/rtl/timescale.v View File

@@ -0,0 +1,5 @@
//////////////////////////////////////////////////////////////////////
// timescale.v
//////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps


+ 2
- 0
i2c_slave_opencores/sim/build_icarus.bat View File

@@ -0,0 +1,2 @@
#!/bin/sh
iverilog -o testHarness -c filelist.icarus

+ 16
- 0
i2c_slave_opencores/sim/filelist.icarus View File

@@ -0,0 +1,16 @@
../rtl/serialInterface.v
../rtl/registerInterface.v
../rtl/i2cSlave.v
../model/i2c_master_bit_ctrl.v
../model/i2c_master_byte_ctrl.v
../model/i2c_master_top.v
../model/wb_master_model.v
../bench/multiByteReadWrite.v
../bench/testHarness.v
../bench/testCase0.v

+incdir+../rtl
+incdir+../bench
+incdir+../model
+define+SIM_COMPILE


+ 50
- 0
i2c_slave_opencores/sim/gtkwave.ini View File

@@ -0,0 +1,50 @@
#
# sample rc file
#
hier_max_level 1
force_toolbars 0

dynamic_resizing 1
hpane_pack 1
use_vcd 0
#initial_window_x 700
#initial_window_y 400
use_maxtime_display 0

enable_vcd_autosave 0
use_roundcaps 1

use_nonprop_fonts yes
enable_horiz_grid yes
use_big_fonts no
constant_marker_update yes
show_grid yes
show_base_symbols no
use_roundcaps yes

atomic_vectors yes
vcd_explicit_zero_subscripts no

#
# color additions
#
color_back 000000
color_grid 202070
color_high 00ff00
color_low 008000
color_trans 00c000
color_mid c0c000

color_value ffffff
color_vbox 00ff00
color_vtrans 00c000

color_x 00ff00
color_xfill 004000

color_umark ff8080
color_mark ffff80

color_time ffffff
color_timeb 000000


+ 10
- 0
i2c_slave_opencores/sim/myWave.sav View File

@@ -0,0 +1,10 @@
*-27.236394 43400000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
@28
testHarness.u_i2cSlave.scl
testHarness.u_i2cSlave.sda
@22
testHarness.u_i2cSlave.tb_readEn
testHarness.u_i2cSlave.tb_writeEn
testHarness.u_i2cSlave.tb_addr[15:0]
testHarness.u_i2cSlave.tb_dataIn[15:0]
testHarness.u_i2cSlave.tb_dataOut[15:0]

+ 2
- 0
i2c_slave_opencores/sim/run_icarus.bat View File

@@ -0,0 +1,2 @@
vvp testHarness

+ 2
- 0
i2c_slave_opencores/sim/simulate.sh View File

@@ -0,0 +1,2 @@
#!/bin/sh
iverilog -o testHarness -cfilelist.icarus && vvp testHarness

+ 1
- 0
i2c_slave_opencores/sim/viewWave.bat View File

@@ -0,0 +1 @@
gtkwave wave.vcd myWave.sav

Loading…
Cancel
Save