URL
https://opencores.org/ocsvn/i2c/i2c/trunk
Subversion Repositories i2c
[/] [i2c/] [trunk/] [bench/] [verilog/] [i2c_slave_model.v] - Rev 19
Go to most recent revision | Compare with Previous | Blame | View Log
///////////////////////////////////////////////////////////////////// //// //// //// 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.2 2002-03-17 10:26:38 rherveille Exp $ // // $Date: 2002-03-17 10:26:38 $ // $Revision: 1.2 $ // $Author: rherveille $ // $Locker: $ // $State: Exp $ // // Change History: // $Log: not supported by cvs2svn $ `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 // 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; 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); //detect start condition always@(negedge sda) if (scl) begin sta <= #1 1'b1; 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 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]; 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; if (rw) begin #3 mem_do <= mem[mem_adr]; 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 sda_o <= #1 (rw && (mem_adr <= 15) ); // send ack on write, receive ack on read end end data_ack: begin ld <= #1 1'b1; if (rw) if (sda) // 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; endmodule
Go to most recent revision | Compare with Previous | Blame | View Log