diff options
author | Clifford Wolf <clifford@clifford.at> | 2013-01-05 11:13:26 +0100 |
---|---|---|
committer | Clifford Wolf <clifford@clifford.at> | 2013-01-05 11:13:26 +0100 |
commit | 7764d0ba1dcf064ae487ee985c43083a0909e7f4 (patch) | |
tree | 18c05b8729df381af71b707748ce1d605e0df764 /tests/i2c_bench | |
download | yosys-7764d0ba1dcf064ae487ee985c43083a0909e7f4.tar.gz yosys-7764d0ba1dcf064ae487ee985c43083a0909e7f4.tar.bz2 yosys-7764d0ba1dcf064ae487ee985c43083a0909e7f4.zip |
initial import
Diffstat (limited to 'tests/i2c_bench')
-rw-r--r-- | tests/i2c_bench/i2c_master_bit_ctrl.v | 576 | ||||
-rw-r--r-- | tests/i2c_bench/i2c_master_byte_ctrl.v | 344 | ||||
-rw-r--r-- | tests/i2c_bench/i2c_master_defines.v | 59 | ||||
-rw-r--r-- | tests/i2c_bench/i2c_master_top.v | 301 | ||||
-rw-r--r-- | tests/i2c_bench/i2c_slave_model.v | 361 | ||||
-rwxr-xr-x | tests/i2c_bench/run-test.sh | 50 | ||||
-rw-r--r-- | tests/i2c_bench/spi_slave_model.v | 125 | ||||
-rw-r--r-- | tests/i2c_bench/timescale.v | 2 | ||||
-rw-r--r-- | tests/i2c_bench/tst_bench_top.v | 468 | ||||
-rw-r--r-- | tests/i2c_bench/wb_master_model.v | 205 |
10 files changed, 2491 insertions, 0 deletions
diff --git a/tests/i2c_bench/i2c_master_bit_ctrl.v b/tests/i2c_bench/i2c_master_bit_ctrl.v new file mode 100644 index 000000000..6594fd60c --- /dev/null +++ b/tests/i2c_bench/i2c_master_bit_ctrl.v @@ -0,0 +1,576 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// 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.14 2009-01-20 10:25:29 rherveille Exp $ +// +// $Date: 2009-01-20 10:25:29 $ +// $Revision: 1.14 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: $ +// Revision 1.14 2009/01/20 10:25:29 rherveille +// Added clock synchronization logic +// Fixed slave_wait signal +// +// Revision 1.13 2009/01/19 20:29:26 rherveille +// Fixed synopsys miss spell (synopsis) +// Fixed cr[0] register width +// Fixed ! usage instead of ~ +// Fixed bit controller parameter width to 18bits +// +// 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 ( + input clk, // system clock + input rst, // synchronous active high reset + input nReset, // asynchronous active low reset + input ena, // core enable signal + + input [15:0] clk_cnt, // clock prescale value + + input [ 3:0] cmd, // command (from byte controller) + output reg cmd_ack, // command complete acknowledge + output reg busy, // i2c bus busy + output reg al, // i2c bus arbitration lost + + input din, + output reg dout, + + input scl_i, // i2c clock line input + output scl_o, // i2c clock line output + output reg scl_oen, // i2c clock line output enable (active low) + input sda_i, // i2c data line input + output sda_o, // i2c data line output + output reg sda_oen // i2c data line output enable (active low) +); + + + // + // variable declarations + // + + reg [ 1:0] cSCL, cSDA; // capture SCL and SDA + reg [ 2:0] fSCL, fSDA; // SCL and SDA filter inputs + reg sSCL, sSDA; // filtered and synchronized SCL and SDA inputs + reg dSCL, dSDA; // delayed versions of sSCL and sSDA + reg dscl_oen; // delayed scl_oen + reg sda_chk; // check SDA output (Multi-master arbitration) + reg clk_en; // clock generation signals + reg slave_wait; // slave inserts wait states + reg [15:0] cnt; // clock divider counter (synthesis) + reg [13:0] filter_cnt; // clock divider for filter + + + // state machine variable + reg [17: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 <= scl_oen; + + // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low + // slave_wait remains asserted until the slave releases SCL + always @(posedge clk or negedge nReset) + if (!nReset) slave_wait <= 1'b0; + else slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL); + + // master drives SCL high, but another master pulls it low + // master start counting down its low cycle now (clock synchronization) + wire scl_sync = dSCL & ~sSCL & scl_oen; + + + // generate clk enable signal + always @(posedge clk or negedge nReset) + if (~nReset) + begin + cnt <= 16'h0; + clk_en <= 1'b1; + end + else if (rst || ~|cnt || !ena || scl_sync) + begin + cnt <= clk_cnt; + clk_en <= 1'b1; + end + else if (slave_wait) + begin + cnt <= cnt; + clk_en <= 1'b0; + end + else + begin + cnt <= cnt - 16'h1; + clk_en <= 1'b0; + end + + + // generate bus status controller + + // capture SDA and SCL + // reduce metastability risk + always @(posedge clk or negedge nReset) + if (!nReset) + begin + cSCL <= 2'b00; + cSDA <= 2'b00; + end + else if (rst) + begin + cSCL <= 2'b00; + cSDA <= 2'b00; + end + else + begin + cSCL <= {cSCL[0],scl_i}; + cSDA <= {cSDA[0],sda_i}; + end + + + // filter SCL and SDA signals; (attempt to) remove glitches + always @(posedge clk or negedge nReset) + if (!nReset ) filter_cnt <= 14'h0; + else if (rst || !ena ) filter_cnt <= 14'h0; + else if (~|filter_cnt) filter_cnt <= clk_cnt[15:2]; //16x I2C bus frequency + else filter_cnt <= filter_cnt -1; + + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + fSCL <= 3'b111; + fSDA <= 3'b111; + end + else if (rst) + begin + fSCL <= 3'b111; + fSDA <= 3'b111; + end + else if (~|filter_cnt) + begin + fSCL <= {fSCL[1:0],cSCL[1]}; + fSDA <= {fSDA[1:0],cSDA[1]}; + end + + + // generate filtered SCL and SDA signals + always @(posedge clk or negedge nReset) + if (~nReset) + begin + sSCL <= 1'b1; + sSDA <= 1'b1; + + dSCL <= 1'b1; + dSDA <= 1'b1; + end + else if (rst) + begin + sSCL <= 1'b1; + sSDA <= 1'b1; + + dSCL <= 1'b1; + dSDA <= 1'b1; + end + else + begin + sSCL <= &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]); + sSDA <= &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]); + + dSCL <= sSCL; + dSDA <= 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 + reg sta_condition; + reg sto_condition; + always @(posedge clk or negedge nReset) + if (~nReset) + begin + sta_condition <= 1'b0; + sto_condition <= 1'b0; + end + else if (rst) + begin + sta_condition <= 1'b0; + sto_condition <= 1'b0; + end + else + begin + sta_condition <= ~sSDA & dSDA & sSCL; + sto_condition <= sSDA & ~dSDA & sSCL; + end + + + // generate i2c bus busy signal + always @(posedge clk or negedge nReset) + if (!nReset) busy <= 1'b0; + else if (rst ) busy <= 1'b0; + else busy <= (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'b0; + else if (rst) + cmd_stop <= 1'b0; + else if (clk_en) + cmd_stop <= cmd == `I2C_CMD_STOP; + + always @(posedge clk or negedge nReset) + if (~nReset) + al <= 1'b0; + else if (rst) + al <= 1'b0; + else + al <= (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 <= sSDA; + + + // generate statemachine + + // nxt_state decoder + parameter [17:0] idle = 18'b0_0000_0000_0000_0000; + parameter [17:0] start_a = 18'b0_0000_0000_0000_0001; + parameter [17:0] start_b = 18'b0_0000_0000_0000_0010; + parameter [17:0] start_c = 18'b0_0000_0000_0000_0100; + parameter [17:0] start_d = 18'b0_0000_0000_0000_1000; + parameter [17:0] start_e = 18'b0_0000_0000_0001_0000; + parameter [17:0] stop_a = 18'b0_0000_0000_0010_0000; + parameter [17:0] stop_b = 18'b0_0000_0000_0100_0000; + parameter [17:0] stop_c = 18'b0_0000_0000_1000_0000; + parameter [17:0] stop_d = 18'b0_0000_0001_0000_0000; + parameter [17:0] rd_a = 18'b0_0000_0010_0000_0000; + parameter [17:0] rd_b = 18'b0_0000_0100_0000_0000; + parameter [17:0] rd_c = 18'b0_0000_1000_0000_0000; + parameter [17:0] rd_d = 18'b0_0001_0000_0000_0000; + parameter [17:0] wr_a = 18'b0_0010_0000_0000_0000; + parameter [17:0] wr_b = 18'b0_0100_0000_0000_0000; + parameter [17:0] wr_c = 18'b0_1000_0000_0000_0000; + parameter [17:0] wr_d = 18'b1_0000_0000_0000_0000; + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + c_state <= idle; + cmd_ack <= 1'b0; + scl_oen <= 1'b1; + sda_oen <= 1'b1; + sda_chk <= 1'b0; + end + else if (rst | al) + begin + c_state <= idle; + cmd_ack <= 1'b0; + scl_oen <= 1'b1; + sda_oen <= 1'b1; + sda_chk <= 1'b0; + end + else + begin + cmd_ack <= 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 <= start_a; + `I2C_CMD_STOP: c_state <= stop_a; + `I2C_CMD_WRITE: c_state <= wr_a; + `I2C_CMD_READ: c_state <= rd_a; + default: c_state <= idle; + endcase + + scl_oen <= scl_oen; // keep SCL in same state + sda_oen <= sda_oen; // keep SDA in same state + sda_chk <= 1'b0; // don't check SDA output + end + + // start + start_a: + begin + c_state <= start_b; + scl_oen <= scl_oen; // keep SCL in same state + sda_oen <= 1'b1; // set SDA high + sda_chk <= 1'b0; // don't check SDA output + end + + start_b: + begin + c_state <= start_c; + scl_oen <= 1'b1; // set SCL high + sda_oen <= 1'b1; // keep SDA high + sda_chk <= 1'b0; // don't check SDA output + end + + start_c: + begin + c_state <= start_d; + scl_oen <= 1'b1; // keep SCL high + sda_oen <= 1'b0; // set SDA low + sda_chk <= 1'b0; // don't check SDA output + end + + start_d: + begin + c_state <= start_e; + scl_oen <= 1'b1; // keep SCL high + sda_oen <= 1'b0; // keep SDA low + sda_chk <= 1'b0; // don't check SDA output + end + + start_e: + begin + c_state <= idle; + cmd_ack <= 1'b1; + scl_oen <= 1'b0; // set SCL low + sda_oen <= 1'b0; // keep SDA low + sda_chk <= 1'b0; // don't check SDA output + end + + // stop + stop_a: + begin + c_state <= stop_b; + scl_oen <= 1'b0; // keep SCL low + sda_oen <= 1'b0; // set SDA low + sda_chk <= 1'b0; // don't check SDA output + end + + stop_b: + begin + c_state <= stop_c; + scl_oen <= 1'b1; // set SCL high + sda_oen <= 1'b0; // keep SDA low + sda_chk <= 1'b0; // don't check SDA output + end + + stop_c: + begin + c_state <= stop_d; + scl_oen <= 1'b1; // keep SCL high + sda_oen <= 1'b0; // keep SDA low + sda_chk <= 1'b0; // don't check SDA output + end + + stop_d: + begin + c_state <= idle; + cmd_ack <= 1'b1; + scl_oen <= 1'b1; // keep SCL high + sda_oen <= 1'b1; // set SDA high + sda_chk <= 1'b0; // don't check SDA output + end + + // read + rd_a: + begin + c_state <= rd_b; + scl_oen <= 1'b0; // keep SCL low + sda_oen <= 1'b1; // tri-state SDA + sda_chk <= 1'b0; // don't check SDA output + end + + rd_b: + begin + c_state <= rd_c; + scl_oen <= 1'b1; // set SCL high + sda_oen <= 1'b1; // keep SDA tri-stated + sda_chk <= 1'b0; // don't check SDA output + end + + rd_c: + begin + c_state <= rd_d; + scl_oen <= 1'b1; // keep SCL high + sda_oen <= 1'b1; // keep SDA tri-stated + sda_chk <= 1'b0; // don't check SDA output + end + + rd_d: + begin + c_state <= idle; + cmd_ack <= 1'b1; + scl_oen <= 1'b0; // set SCL low + sda_oen <= 1'b1; // keep SDA tri-stated + sda_chk <= 1'b0; // don't check SDA output + end + + // write + wr_a: + begin + c_state <= wr_b; + scl_oen <= 1'b0; // keep SCL low + sda_oen <= din; // set SDA + sda_chk <= 1'b0; // don't check SDA output (SCL low) + end + + wr_b: + begin + c_state <= wr_c; + scl_oen <= 1'b1; // set SCL high + sda_oen <= din; // keep SDA + sda_chk <= 1'b0; // don't check SDA output yet + // allow some time for SDA and SCL to settle + end + + wr_c: + begin + c_state <= wr_d; + scl_oen <= 1'b1; // keep SCL high + sda_oen <= din; + sda_chk <= 1'b1; // check SDA output + end + + wr_d: + begin + c_state <= idle; + cmd_ack <= 1'b1; + scl_oen <= 1'b0; // set SCL low + sda_oen <= din; + sda_chk <= 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 diff --git a/tests/i2c_bench/i2c_master_byte_ctrl.v b/tests/i2c_bench/i2c_master_byte_ctrl.v new file mode 100644 index 000000000..513953a82 --- /dev/null +++ b/tests/i2c_bench/i2c_master_byte_ctrl.v @@ -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.8 2009-01-19 20:29:26 rherveille Exp $ +// +// $Date: 2009-01-19 20:29:26 $ +// $Revision: 1.8 $ +// $Author: rherveille $ +// $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 <= 8'h0; + else if (rst) + sr <= 8'h0; + else if (ld) + sr <= din; + else if (shift) + sr <= {sr[6:0], core_rxd}; + + // generate counter + always @(posedge clk or negedge nReset) + if (!nReset) + dcnt <= 3'h0; + else if (rst) + dcnt <= 3'h0; + else if (ld) + dcnt <= 3'h7; + else if (shift) + dcnt <= dcnt - 3'h1; + + assign cnt_done = ~(|dcnt); + + // + // state machine + // + reg [4:0] c_state; // synopsys enum_state + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + core_cmd <= `I2C_CMD_NOP; + core_txd <= 1'b0; + shift <= 1'b0; + ld <= 1'b0; + cmd_ack <= 1'b0; + c_state <= ST_IDLE; + ack_out <= 1'b0; + end + else if (rst | i2c_al) + begin + core_cmd <= `I2C_CMD_NOP; + core_txd <= 1'b0; + shift <= 1'b0; + ld <= 1'b0; + cmd_ack <= 1'b0; + c_state <= ST_IDLE; + ack_out <= 1'b0; + end + else + begin + // initially reset all signals + core_txd <= sr[7]; + shift <= 1'b0; + ld <= 1'b0; + cmd_ack <= 1'b0; + + case (c_state) // synopsys full_case parallel_case + ST_IDLE: + if (go) + begin + if (start) + begin + c_state <= ST_START; + core_cmd <= `I2C_CMD_START; + end + else if (read) + begin + c_state <= ST_READ; + core_cmd <= `I2C_CMD_READ; + end + else if (write) + begin + c_state <= ST_WRITE; + core_cmd <= `I2C_CMD_WRITE; + end + else // stop + begin + c_state <= ST_STOP; + core_cmd <= `I2C_CMD_STOP; + end + + ld <= 1'b1; + end + + ST_START: + if (core_ack) + begin + if (read) + begin + c_state <= ST_READ; + core_cmd <= `I2C_CMD_READ; + end + else + begin + c_state <= ST_WRITE; + core_cmd <= `I2C_CMD_WRITE; + end + + ld <= 1'b1; + end + + ST_WRITE: + if (core_ack) + if (cnt_done) + begin + c_state <= ST_ACK; + core_cmd <= `I2C_CMD_READ; + end + else + begin + c_state <= ST_WRITE; // stay in same state + core_cmd <= `I2C_CMD_WRITE; // write next bit + shift <= 1'b1; + end + + ST_READ: + if (core_ack) + begin + if (cnt_done) + begin + c_state <= ST_ACK; + core_cmd <= `I2C_CMD_WRITE; + end + else + begin + c_state <= ST_READ; // stay in same state + core_cmd <= `I2C_CMD_READ; // read next bit + end + + shift <= 1'b1; + core_txd <= ack_in; + end + + ST_ACK: + if (core_ack) + begin + if (stop) + begin + c_state <= ST_STOP; + core_cmd <= `I2C_CMD_STOP; + end + else + begin + c_state <= ST_IDLE; + core_cmd <= `I2C_CMD_NOP; + + // generate command acknowledge signal + cmd_ack <= 1'b1; + end + + // assign ack_out output to bit_controller_rxd (contains last received bit) + ack_out <= core_rxd; + + core_txd <= 1'b1; + end + else + core_txd <= ack_in; + + ST_STOP: + if (core_ack) + begin + c_state <= ST_IDLE; + core_cmd <= `I2C_CMD_NOP; + + // generate command acknowledge signal + cmd_ack <= 1'b1; + end + + endcase + end +endmodule diff --git a/tests/i2c_bench/i2c_master_defines.v b/tests/i2c_bench/i2c_master_defines.v new file mode 100644 index 000000000..e81c546a6 --- /dev/null +++ b/tests/i2c_bench/i2c_master_defines.v @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// 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.3 2001-11-05 11:59:25 rherveille Exp $ +// +// $Date: 2001-11-05 11:59:25 $ +// $Revision: 1.3 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: not supported by cvs2svn $ + + +// 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 diff --git a/tests/i2c_bench/i2c_master_top.v b/tests/i2c_bench/i2c_master_top.v new file mode 100644 index 000000000..5e9cde7e0 --- /dev/null +++ b/tests/i2c_bench/i2c_master_top.v @@ -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.12 2009-01-19 20:29:26 rherveille Exp $ +// +// $Date: 2009-01-19 20:29:26 $ +// $Revision: 1.12 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// 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_we_i & wb_ack_o; + + // generate acknowledge output signal + always @(posedge wb_clk_i) + wb_ack_o <= 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) // synopsys parallel_case + 3'b000: wb_dat_o <= prer[ 7:0]; + 3'b001: wb_dat_o <= prer[15:8]; + 3'b010: wb_dat_o <= ctr; + 3'b011: wb_dat_o <= rxr; // write is transmit register (txr) + 3'b100: wb_dat_o <= sr; // write is command register (cr) + 3'b101: wb_dat_o <= txr; + 3'b110: wb_dat_o <= cr; + 3'b111: wb_dat_o <= 0; // reserved + default: wb_dat_o <= 16'bx; + endcase + end + + // generate registers + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + begin + prer <= 16'hffff; + ctr <= 8'h0; + txr <= 8'h0; + end + else if (wb_rst_i) + begin + prer <= 16'hffff; + ctr <= 8'h0; + txr <= 8'h0; + end + else + if (wb_wacc) + case (wb_adr_i) // synopsys parallel_case + 3'b000 : prer [ 7:0] <= wb_dat_i; + 3'b001 : prer [15:8] <= wb_dat_i; + 3'b010 : ctr <= wb_dat_i; + 3'b011 : txr <= wb_dat_i; + default: ; + endcase + + // generate command register (special case) + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + cr <= 8'h0; + else if (wb_rst_i) + cr <= 8'h0; + else if (wb_wacc) + begin + if (core_en & (wb_adr_i == 3'b100) ) + cr <= wb_dat_i; + end + else + begin + if (done | i2c_al) + cr[7:4] <= 4'h0; // clear command bits when done + // or when aribitration lost + cr[2:1] <= 2'b0; // reserved bits + cr[0] <= 1'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'b0; + rxack <= 1'b0; + tip <= 1'b0; + irq_flag <= 1'b0; + end + else if (wb_rst_i) + begin + al <= 1'b0; + rxack <= 1'b0; + tip <= 1'b0; + irq_flag <= 1'b0; + end + else + begin + al <= i2c_al | (al & ~sta); + rxack <= irxack; + tip <= (rd | wr); + irq_flag <= (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'b0; + else if (wb_rst_i) + wb_inta_o <= 1'b0; + else + wb_inta_o <= 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 diff --git a/tests/i2c_bench/i2c_slave_model.v b/tests/i2c_bench/i2c_slave_model.v new file mode 100644 index 000000000..02b7572cf --- /dev/null +++ b/tests/i2c_bench/i2c_slave_model.v @@ -0,0 +1,361 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant synthesizable I2C Slave model //// +//// //// +//// //// +//// Authors: Richard Herveille (richard@asics.ws) www.asics.ws //// +//// John Sheahan (jrsheahan@optushome.com.au) //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001,2002 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_slave_model.v,v 1.7 2006-09-04 09:08:51 rherveille Exp $ +// +// $Date: 2006-09-04 09:08:51 $ +// $Revision: 1.7 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: not supported by cvs2svn $ +// Revision 1.6 2005/02/28 11:33:48 rherveille +// Fixed Tsu:sta timing check. +// Added Thd:sta timing check. +// +// Revision 1.5 2003/12/05 11:05:19 rherveille +// Fixed slave address MSB='1' bug +// +// Revision 1.4 2003/09/11 08:25:37 rherveille +// Fixed a bug in the timing section. Changed 'tst_scl' into 'tst_sto'. +// +// Revision 1.3 2002/10/30 18:11:06 rherveille +// Added timing tests to i2c_model. +// Updated testbench. +// +// Revision 1.2 2002/03/17 10:26:38 rherveille +// Fixed some race conditions in the i2c-slave model. +// Added debug information. +// Added headers. +// + +`include "timescale.v" + +module i2c_slave_model (scl, sda); + + // + // parameters + // + parameter I2C_ADR = 7'b001_0000; + + // + // input && outpus + // + input scl; + inout sda; + + // + // Variable declaration + // + wire debug = 1'b1; + + reg [7:0] mem [3:0]; // initiate memory + reg [7:0] mem_adr; // memory address + reg [7:0] mem_do; // memory data output + + reg sta, d_sta; + reg sto, d_sto; + + reg [7:0] sr; // 8bit shift register + reg rw; // read/write direction + + wire my_adr; // my address called ?? + wire i2c_reset; // i2c-statemachine reset + reg [2:0] bit_cnt; // 3bit downcounter + wire acc_done; // 8bits transfered + reg ld; // load downcounter + + reg sda_o; // sda-drive level + wire sda_dly; // delayed version of sda + + // statemachine declaration + parameter idle = 3'b000; + parameter slave_ack = 3'b001; + parameter get_mem_adr = 3'b010; + parameter gma_ack = 3'b011; + parameter data = 3'b100; + parameter data_ack = 3'b101; + + reg [2:0] state; // synopsys enum_state + + // + // module body + // + + initial + begin + sda_o = 1'b1; + state = idle; + mem[0] = 0; + mem[1] = 0; + mem[2] = 0; + mem[3] = 0; + end + + // generate shift register + always @(posedge scl) + sr <= #1 {sr[6:0],sda}; + + //detect my_address + assign my_adr = (sr[7:1] == I2C_ADR); + // FIXME: This should not be a generic assign, but rather + // qualified on address transfer phase and probably reset by stop + + //generate bit-counter + always @(posedge scl) + if(ld) + bit_cnt <= #1 3'b111; + else + bit_cnt <= #1 bit_cnt - 3'h1; + + //generate access done signal + assign acc_done = !(|bit_cnt); + + // generate delayed version of sda + // this model assumes a hold time for sda after the falling edge of scl. + // According to the Phillips i2c spec, there s/b a 0 ns hold time for sda + // with regards to scl. If the data changes coincident with the clock, the + // acknowledge is missed + // Fix by Michael Sosnoski + assign #1 sda_dly = sda; + + + //detect start condition + always @(negedge sda) + if(scl) + begin + sta <= #1 1'b1; + d_sta <= #1 1'b0; + sto <= #1 1'b0; + + if(debug) + $display("DEBUG i2c_slave; start condition detected at %t", $time); + end + else + sta <= #1 1'b0; + + always @(posedge scl) + d_sta <= #1 sta; + + // detect stop condition + always @(posedge sda) + if(scl) + begin + sta <= #1 1'b0; + sto <= #1 1'b1; + + if(debug) + $display("DEBUG i2c_slave; stop condition detected at %t", $time); + end + else + sto <= #1 1'b0; + + //generate i2c_reset signal + assign i2c_reset = sta || sto; + + // generate statemachine + always @(negedge scl or posedge sto) + if (sto || (sta && !d_sta) ) + begin + state <= #1 idle; // reset statemachine + + sda_o <= #1 1'b1; + ld <= #1 1'b1; + end + else + begin + // initial settings + sda_o <= #1 1'b1; + ld <= #1 1'b0; + + case(state) // synopsys full_case parallel_case + idle: // idle state + if (acc_done && my_adr) + begin + state <= #1 slave_ack; + rw <= #1 sr[0]; + sda_o <= #1 1'b0; // generate i2c_ack + + #2; + if(debug && rw) + $display("DEBUG i2c_slave; command byte received (read) at %t", $time); + if(debug && !rw) + $display("DEBUG i2c_slave; command byte received (write) at %t", $time); + + if(rw) + begin + mem_do <= #1 mem[mem_adr % 4]; + + if(debug) + begin + #2 $display("DEBUG i2c_slave; data block read %x from address %x (1)", mem_do, mem_adr); + #2 $display("DEBUG i2c_slave; memcheck [0]=%x, [1]=%x, [2]=%x", mem[4'h0], mem[4'h1], mem[4'h2]); + end + end + end + + slave_ack: + begin + if(rw) + begin + state <= #1 data; + sda_o <= #1 mem_do[7]; + end + else + state <= #1 get_mem_adr; + + ld <= #1 1'b1; + end + + get_mem_adr: // wait for memory address + if(acc_done) + begin + state <= #1 gma_ack; + mem_adr <= #1 sr; // store memory address + sda_o <= #1 !(sr <= 15); // generate i2c_ack, for valid address + + if(debug) + #1 $display("DEBUG i2c_slave; address received. adr=%x, ack=%b", sr, sda_o); + end + + gma_ack: + begin + state <= #1 data; + ld <= #1 1'b1; + end + + data: // receive or drive data + begin + if(rw) + sda_o <= #1 mem_do[7]; + + if(acc_done) + begin + state <= #1 data_ack; + mem_adr <= #2 mem_adr + 8'h1; + sda_o <= #1 (rw && (mem_adr <= 15) ); // send ack on write, receive ack on read + + if(rw) + begin + #3 mem_do <= mem[mem_adr % 4]; + + if(debug) + #5 $display("DEBUG i2c_slave; data block read %x from address %x (2)", mem_do, mem_adr); + end + + if(!rw) + begin + mem[ mem_adr[3:0] ] <= #1 sr; // store data in memory + + if(debug) + #2 $display("DEBUG i2c_slave; data block write %x to address %x", sr, mem_adr); + end + end + end + + data_ack: + begin + ld <= #1 1'b1; + + if(rw) + if(sr[0]) // read operation && master send NACK + begin + state <= #1 idle; + sda_o <= #1 1'b1; + end + else + begin + state <= #1 data; + sda_o <= #1 mem_do[7]; + end + else + begin + state <= #1 data; + sda_o <= #1 1'b1; + end + end + + endcase + end + + // read data from memory + always @(posedge scl) + if(!acc_done && rw) + mem_do <= #1 {mem_do[6:0], 1'b1}; // insert 1'b1 for host ack generation + + // generate tri-states + assign sda = sda_o ? 1'bz : 1'b0; + + + // + // Timing checks + // + + wire tst_sto = sto; + wire tst_sta = sta; + + specify + specparam normal_scl_low = 4700, + normal_scl_high = 4000, + normal_tsu_sta = 4700, + normal_thd_sta = 4000, + normal_tsu_sto = 4000, + normal_tbuf = 4700, + + fast_scl_low = 1300, + fast_scl_high = 600, + fast_tsu_sta = 1300, + fast_thd_sta = 600, + fast_tsu_sto = 600, + fast_tbuf = 1300; + + $width(negedge scl, normal_scl_low); // scl low time + $width(posedge scl, normal_scl_high); // scl high time + + $setup(posedge scl, negedge sda &&& scl, normal_tsu_sta); // setup start + $setup(negedge sda &&& scl, negedge scl, normal_thd_sta); // hold start + $setup(posedge scl, posedge sda &&& scl, normal_tsu_sto); // setup stop + + $setup(posedge tst_sta, posedge tst_sto, normal_tbuf); // stop to start time + endspecify + +endmodule + + diff --git a/tests/i2c_bench/run-test.sh b/tests/i2c_bench/run-test.sh new file mode 100755 index 000000000..5fdbb0594 --- /dev/null +++ b/tests/i2c_bench/run-test.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +set -e +make -C ../.. +../../yosys -l i2c_master_syn.log -o i2c_master_syn.v \ + -p hierarchy -p proc -p memory -p techmap -p opt -p abc -p opt \ + i2c_master_top.v i2c_master_bit_ctrl.v i2c_master_byte_ctrl.v +. /opt/Xilinx/13.4/ISE_DS/settings64.sh + +vlogcomp --work ref i2c_master_bit_ctrl.v +vlogcomp --work ref i2c_master_byte_ctrl.v +vlogcomp --work ref i2c_master_top.v +vlogcomp --work ref i2c_slave_model.v +vlogcomp --work ref spi_slave_model.v +vlogcomp --work ref tst_bench_top.v +vlogcomp --work ref wb_master_model.v +fuse --work ref -o testbench_ref --top tst_bench_top + +cat > testbench_ref.tcl << EOT +vcd dumpfile testbench_ref.vcd +vcd dumpvars -m tst_bench_top -l 0 +vcd dumpon +run 2 ms +exit +EOT + +./testbench_ref -tclbatch testbench_ref.tcl + +vlogcomp --work syn i2c_master_syn.v +vlogcomp --work syn ../../techlibs/simlib.v +vlogcomp --work syn ../../techlibs/stdcells_sim.v +vlogcomp --work syn i2c_slave_model.v +vlogcomp --work syn spi_slave_model.v +vlogcomp --work syn tst_bench_top.v +vlogcomp --work syn wb_master_model.v +fuse --work syn -o testbench_syn --top tst_bench_top + +cat > testbench_syn.tcl << EOT +vcd dumpfile testbench_syn.vcd +vcd dumpvars -m tst_bench_top -l 0 +vcd dumpon +run 2 ms +exit +EOT + +./testbench_syn -tclbatch testbench_syn.tcl + +perl ../tools/vcdcd.pl testbench_ref.vcd testbench_syn.vcd | tee testbench_diff.txt +echo READY. + diff --git a/tests/i2c_bench/spi_slave_model.v b/tests/i2c_bench/spi_slave_model.v new file mode 100644 index 000000000..d49347b0c --- /dev/null +++ b/tests/i2c_bench/spi_slave_model.v @@ -0,0 +1,125 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// SPI Slave Model //// +//// //// +//// //// +//// Authors: Richard Herveille (richard@asics.ws) www.asics.ws //// +//// //// +//// http://www.opencores.org/projects/simple_spi/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2004 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: spi_slave_model.v,v 1.1 2004-02-28 15:32:54 rherveille Exp $ +// +// $Date: 2004-02-28 15:32:54 $ +// $Revision: 1.1 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: not supported by cvs2svn $ +// +// + + +// Requires: Verilog2001 + +`include "timescale.v" + +module spi_slave_model ( + input wire csn, + input wire sc, + input wire di, + output wire do +); + + // + // Variable declaration + // + wire debug = 1'b1; + + wire cpol = 1'b0; + wire cpha = 1'b0; + + reg [7:0] mem [7:0]; // initiate memory + reg [2:0] mem_adr; // memory address + reg [7:0] mem_do; // memory data output + + reg [7:0] sri, sro; // 8bit shift register + + reg [2:0] bit_cnt; + reg ld; + + wire clk; + + // + // module body + // + + assign clk = cpol ^ cpha ^ sc; + + // generate shift registers + always @(posedge clk) + sri <= #1 {sri[6:0],di}; + + always @(posedge clk) + if (&bit_cnt) + sro <= #1 mem[mem_adr]; + else + sro <= #1 {sro[6:0],1'bx}; + + assign do = sro[7]; + + //generate bit-counter + always @(posedge clk, posedge csn) + if(csn) + bit_cnt <= #1 3'b111; + else + bit_cnt <= #1 bit_cnt - 3'h1; + + //generate access done signal + always @(posedge clk) + ld <= #1 ~(|bit_cnt); + + always @(negedge clk) + if (ld) begin + mem[mem_adr] <= #1 sri; + mem_adr <= #1 mem_adr + 1'b1; + end + + initial + begin + bit_cnt=3'b111; + mem_adr = 0; + sro = mem[mem_adr]; + end +endmodule + + diff --git a/tests/i2c_bench/timescale.v b/tests/i2c_bench/timescale.v new file mode 100644 index 000000000..60d4ecbd1 --- /dev/null +++ b/tests/i2c_bench/timescale.v @@ -0,0 +1,2 @@ +`timescale 1ns / 10ps + diff --git a/tests/i2c_bench/tst_bench_top.v b/tests/i2c_bench/tst_bench_top.v new file mode 100644 index 000000000..9458de054 --- /dev/null +++ b/tests/i2c_bench/tst_bench_top.v @@ -0,0 +1,468 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master controller Testbench //// +//// //// +//// //// +//// 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: tst_bench_top.v,v 1.8 2006-09-04 09:08:51 rherveille Exp $ +// +// $Date: 2006-09-04 09:08:51 $ +// $Revision: 1.8 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: not supported by cvs2svn $ +// Revision 1.7 2005/02/27 09:24:18 rherveille +// Fixed scl, sda delay. +// +// Revision 1.6 2004/02/28 15:40:42 rherveille +// *** empty log message *** +// +// Revision 1.4 2003/12/05 11:04:38 rherveille +// Added slave address configurability +// +// Revision 1.3 2002/10/30 18:11:06 rherveille +// Added timing tests to i2c_model. +// Updated testbench. +// +// Revision 1.2 2002/03/17 10:26:38 rherveille +// Fixed some race conditions in the i2c-slave model. +// Added debug information. +// Added headers. +// + +`include "timescale.v" + +module tst_bench_top(); + + // + // wires && regs + // + reg clk; + reg rstn; + + wire [31:0] adr; + wire [ 7:0] dat_i, dat_o, dat0_i, dat1_i; + wire we; + wire stb; + wire cyc; + wire ack0, ack1; + wire inta; + + reg [7:0] q, qq; + + wire scl, scl0_o, scl0_oen, scl1_o, scl1_oen; + wire sda, sda0_o, sda0_oen, sda1_o, sda1_oen; + + parameter PRER_LO = 3'b000; + parameter PRER_HI = 3'b001; + parameter CTR = 3'b010; + parameter RXR = 3'b011; + parameter TXR = 3'b011; + parameter CR = 3'b100; + parameter SR = 3'b100; + + parameter TXR_R = 3'b101; // undocumented / reserved output + parameter CR_R = 3'b110; // undocumented / reserved output + + parameter RD = 1'b1; + parameter WR = 1'b0; + parameter SADR = 7'b0010_000; + + // + // Module body + // + + // generate clock + always #5 clk = ~clk; + + // hookup wishbone master model + wb_master_model #(8, 32) u0 ( + .clk(clk), + .rst(rstn), + .adr(adr), + .din(dat_i), + .dout(dat_o), + .cyc(cyc), + .stb(stb), + .we(we), + .sel(), + .ack(ack0 || ack1), + .err(1'b0), + .rty(1'b0) + ); + + wire stb0 = stb & ~adr[3]; + wire stb1 = stb & adr[3]; + + assign dat_i = ({{8'd8}{stb0}} & dat0_i) | ({{8'd8}{stb1}} & dat1_i); + + // hookup wishbone_i2c_master core + i2c_master_top i2c_top ( + + // wishbone interface + .wb_clk_i(clk), + .wb_rst_i(1'b0), + .arst_i(rstn), + .wb_adr_i(adr[2:0]), + .wb_dat_i(dat_o), + .wb_dat_o(dat0_i), + .wb_we_i(we), + .wb_stb_i(stb0), + .wb_cyc_i(cyc), + .wb_ack_o(ack0), + .wb_inta_o(inta), + + // i2c signals + .scl_pad_i(scl), + .scl_pad_o(scl0_o), + .scl_padoen_o(scl0_oen), + .sda_pad_i(sda), + .sda_pad_o(sda0_o), + .sda_padoen_o(sda0_oen) + ), + i2c_top2 ( + + // wishbone interface + .wb_clk_i(clk), + .wb_rst_i(1'b0), + .arst_i(rstn), + .wb_adr_i(adr[2:0]), + .wb_dat_i(dat_o), + .wb_dat_o(dat1_i), + .wb_we_i(we), + .wb_stb_i(stb1), + .wb_cyc_i(cyc), + .wb_ack_o(ack1), + .wb_inta_o(inta), + + // i2c signals + .scl_pad_i(scl), + .scl_pad_o(scl1_o), + .scl_padoen_o(scl1_oen), + .sda_pad_i(sda), + .sda_pad_o(sda1_o), + .sda_padoen_o(sda1_oen) + ); + + + // hookup i2c slave model + i2c_slave_model #(SADR) i2c_slave ( + .scl(scl), + .sda(sda) + ); + + //assign scl = ~((!scl0_oen && !scl0_o) || (!scl1_oen && !scl1_o)); + //assign sda = ~((!sda0_oen && !sda0_o) || (!sda1_oen && !sda1_o)); + + // create i2c lines + delay m0_scl (scl0_oen ? 1'bz : scl0_o, scl), + m1_scl (scl1_oen ? 1'bz : scl1_o, scl), + m0_sda (sda0_oen ? 1'bz : sda0_o, sda), + m1_sda (sda1_oen ? 1'bz : sda1_o, sda); + + pullup p1(scl); // pullup scl line + pullup p2(sda); // pullup sda line + + initial + begin + `ifdef WAVES + $shm_open("waves"); + $shm_probe("AS",tst_bench_top,"AS"); + $display("INFO: Signal dump enabled ...\n\n"); + `endif + +// force i2c_slave.debug = 1'b1; // enable i2c_slave debug information + force i2c_slave.debug = 1'b0; // disable i2c_slave debug information + + $display("\nstatus: %t Testbench started\n\n", $time); + +// $dumpfile("bench.vcd"); +// $dumpvars(1, tst_bench_top); +// $dumpvars(1, tst_bench_top.i2c_slave); + + // initially values + clk = 0; + + // reset system + rstn = 1'b1; // negate reset + #2; + rstn = 1'b0; // assert reset + #1000; + repeat(1) @(posedge clk); + rstn = 1'b1; // negate reset + + $display("status: %t done reset", $time); + + @(posedge clk); + + // + // program core + // + + // program internal registers + u0.wb_write(1, PRER_LO, 8'hfa); // load prescaler lo-byte + u0.wb_write(1, PRER_LO, 8'hc8); // load prescaler lo-byte + u0.wb_write(1, PRER_HI, 8'h00); // load prescaler hi-byte + $display("status: %t programmed registers", $time); + + u0.wb_cmp(0, PRER_LO, 8'hc8); // verify prescaler lo-byte + u0.wb_cmp(0, PRER_HI, 8'h00); // verify prescaler hi-byte + $display("status: %t verified registers", $time); + + u0.wb_write(1, CTR, 8'h80); // enable core + $display("status: %t core enabled", $time); + + // + // access slave (write) + // + + // drive slave address + u0.wb_write(1, TXR, {SADR,WR} ); // present slave address, set write-bit + u0.wb_write(0, CR, 8'h90 ); // set command (start, write) + $display("status: %t generate 'start', write cmd %0h (slave address+write)", $time, {SADR,WR} ); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(0, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // send memory address + u0.wb_write(1, TXR, 8'h01); // present slave's memory address + u0.wb_write(0, CR, 8'h10); // set command (write) + $display("status: %t write slave memory address 01", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(0, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // send memory contents + u0.wb_write(1, TXR, 8'ha5); // present data + u0.wb_write(0, CR, 8'h10); // set command (write) + $display("status: %t write data a5", $time); + +while (scl) #1; +force scl= 1'b0; +#100000; +release scl; + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // send memory contents for next memory address (auto_inc) + u0.wb_write(1, TXR, 8'h5a); // present data + u0.wb_write(0, CR, 8'h50); // set command (stop, write) + $display("status: %t write next data 5a, generate 'stop'", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // + // delay + // +// #100000; // wait for 100us. +// $display("status: %t wait 100us", $time); + + // + // access slave (read) + // + + // drive slave address + u0.wb_write(1, TXR,{SADR,WR} ); // present slave address, set write-bit + u0.wb_write(0, CR, 8'h90 ); // set command (start, write) + $display("status: %t generate 'start', write cmd %0h (slave address+write)", $time, {SADR,WR} ); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // send memory address + u0.wb_write(1, TXR, 8'h01); // present slave's memory address + u0.wb_write(0, CR, 8'h10); // set command (write) + $display("status: %t write slave address 01", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // drive slave address + u0.wb_write(1, TXR, {SADR,RD} ); // present slave's address, set read-bit + u0.wb_write(0, CR, 8'h90 ); // set command (start, write) + $display("status: %t generate 'repeated start', write cmd %0h (slave address+read)", $time, {SADR,RD} ); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // read data from slave + u0.wb_write(1, CR, 8'h20); // set command (read, ack_read) + $display("status: %t read + ack", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // check data just received + u0.wb_read(1, RXR, qq); + if(qq !== 8'ha5) + $display("\nERROR: Expected a5, received %x at time %t", qq, $time); + else + $display("status: %t received %x", $time, qq); + + // read data from slave + u0.wb_write(1, CR, 8'h20); // set command (read, ack_read) + $display("status: %t read + ack", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // check data just received + u0.wb_read(1, RXR, qq); + if(qq !== 8'h5a) + $display("\nERROR: Expected 5a, received %x at time %t", qq, $time); + else + $display("status: %t received %x", $time, qq); + + // read data from slave + u0.wb_write(1, CR, 8'h20); // set command (read, ack_read) + $display("status: %t read + ack", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // check data just received + u0.wb_read(1, RXR, qq); + $display("status: %t received %x from 3rd read address", $time, qq); + + // read data from slave + u0.wb_write(1, CR, 8'h28); // set command (read, nack_read) + $display("status: %t read + nack", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // check data just received + u0.wb_read(1, RXR, qq); + $display("status: %t received %x from 4th read address", $time, qq); + + // + // check invalid slave memory address + // + + // drive slave address + u0.wb_write(1, TXR, {SADR,WR} ); // present slave address, set write-bit + u0.wb_write(0, CR, 8'h90 ); // set command (start, write) + $display("status: %t generate 'start', write cmd %0h (slave address+write). Check invalid address", $time, {SADR,WR} ); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // send memory address + u0.wb_write(1, TXR, 8'h10); // present slave's memory address + u0.wb_write(0, CR, 8'h10); // set command (write) + $display("status: %t write slave memory address 10", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + // slave should have send NACK + $display("status: %t Check for nack", $time); + if(!q[7]) + $display("\nERROR: Expected NACK, received ACK\n"); + + // read data from slave + u0.wb_write(1, CR, 8'h40); // set command (stop) + $display("status: %t generate 'stop'", $time); + + // check tip bit + u0.wb_read(1, SR, q); + while(q[1]) + u0.wb_read(1, SR, q); // poll it until it is zero + $display("status: %t tip==0", $time); + + #250000; // wait 250us + $display("\n\nstatus: %t Testbench done", $time); + $finish; + end + +endmodule + +module delay (in, out); + input in; + output out; + + assign out = in; + + specify + (in => out) = (599,599); + endspecify +endmodule + + diff --git a/tests/i2c_bench/wb_master_model.v b/tests/i2c_bench/wb_master_model.v new file mode 100644 index 000000000..65a9b7988 --- /dev/null +++ b/tests/i2c_bench/wb_master_model.v @@ -0,0 +1,205 @@ +/////////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 Wishbone Master model //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/mem_ctrl //// +//// //// +/////////////////////////////////////////////////////////////////////// +//// //// +//// 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: wb_master_model.v,v 1.4 2004-02-28 15:40:42 rherveille Exp $ +// +// $Date: 2004-02-28 15:40:42 $ +// $Revision: 1.4 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// +`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; + +//////////////////////////////////////////////////////////////////// +// +// Local Wires +// + +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 = 32'hxxxx_xxxx; + //adr = 0; + adr = {awidth{1'bx}}; + dout = {dwidth{1'bx}}; + cyc = 1'b0; + stb = 1'bx; + we = 1'hx; + sel = {dwidth/8{1'bx}}; + #1; + $display("\nINFO: WISHBONE MASTER MODEL INSTANTIATED (%m)\n"); + 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 + + |