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