*.vcd | |||||
sim/*.vcd | |||||
sim/*.wlf | |||||
sim/testHarness |
# 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 |
// ---------------------------- 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 | |||||
// ------------------ 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 | |||||
// ---------------------------------- 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 | |||||
// -------------------------- 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 |
///////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 |
///////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 |
///////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 |
///////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 |
////////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 | |||||
////////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 | |||||
// ----------------------- 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 | |||||
////////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 | |||||
////////////////////////////////////////////////////////////////////// | |||||
//// //// | |||||
//// 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 |
////////////////////////////////////////////////////////////////////// | |||||
// timescale.v | |||||
////////////////////////////////////////////////////////////////////// | |||||
`timescale 1ns / 1ps | |||||
#!/bin/sh | |||||
iverilog -o testHarness -c filelist.icarus |
../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 | |||||
# | |||||
# 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 | |||||
*-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] |
vvp testHarness | |||||
#!/bin/sh | |||||
iverilog -o testHarness -cfilelist.icarus && vvp testHarness |
gtkwave wave.vcd myWave.sav |