OpenCores
URL https://opencores.org/ocsvn/i2c/i2c/trunk

Subversion Repositories i2c

[/] [i2c/] [trunk/] [bench/] [verilog/] [i2c_slave_model.v] - Blame information for rev 25

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 19 rherveille
/////////////////////////////////////////////////////////////////////
2
////                                                             ////
3
////  WISHBONE rev.B2 compliant synthesizable I2C Slave model    ////
4
////                                                             ////
5
////                                                             ////
6
////  Authors: Richard Herveille (richard@asics.ws) www.asics.ws ////
7
////           John Sheahan (jrsheahan@optushome.com.au)         ////
8
////                                                             ////
9
////  Downloaded from: http://www.opencores.org/projects/i2c/    ////
10
////                                                             ////
11
/////////////////////////////////////////////////////////////////////
12
////                                                             ////
13
//// Copyright (C) 2001,2002 Richard Herveille                   ////
14
////                         richard@asics.ws                    ////
15
////                                                             ////
16
//// This source file may be used and distributed without        ////
17
//// restriction provided that this copyright statement is not   ////
18
//// removed from the file and that any derivative work contains ////
19
//// the original copyright notice and the associated disclaimer.////
20
////                                                             ////
21
////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
22
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
23
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
24
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
25
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
26
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
27
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
28
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
29
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
30
//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
31
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
32
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
33
//// POSSIBILITY OF SUCH DAMAGE.                                 ////
34
////                                                             ////
35
/////////////////////////////////////////////////////////////////////
36
 
37
//  CVS Log
38 10 rherveille
//
39 25 rherveille
//  $Id: i2c_slave_model.v,v 1.3 2002-10-30 18:11:06 rherveille Exp $
40 10 rherveille
//
41 25 rherveille
//  $Date: 2002-10-30 18:11:06 $
42
//  $Revision: 1.3 $
43 19 rherveille
//  $Author: rherveille $
44
//  $Locker:  $
45
//  $State: Exp $
46
//
47
// Change History:
48
//               $Log: not supported by cvs2svn $
49 25 rherveille
//               Revision 1.2  2002/03/17 10:26:38  rherveille
50
//               Fixed some race conditions in the i2c-slave model.
51
//               Added debug information.
52
//               Added headers.
53
//
54 10 rherveille
 
55
`include "timescale.v"
56
 
57
module i2c_slave_model (scl, sda);
58
 
59
        //
60
        // parameters
61
        //
62
        parameter I2C_ADR = 7'b001_0000;
63
 
64
        //
65
        // input && outpus
66
        //
67
        input scl;
68
        inout sda;
69
 
70
        //
71
        // Variable declaration
72
        //
73 19 rherveille
        wire debug = 1'b1;
74
 
75 10 rherveille
        reg [7:0] mem [3:0]; // initiate memory
76
        reg [7:0] mem_adr;   // memory address
77
        reg [7:0] mem_do;    // memory data output
78
 
79
        reg sta, d_sta;
80
        reg sto, d_sto;
81
 
82
        reg [7:0] sr;        // 8bit shift register
83
        reg       rw;        // read/write direction
84
 
85
        wire      my_adr;    // my address called ??
86
        wire      i2c_reset; // i2c-statemachine reset
87
        reg [2:0] bit_cnt;   // 3bit downcounter
88
        wire      acc_done;  // 8bits transfered
89
        reg       ld;        // load downcounter
90
 
91
        reg       sda_o;     // sda-drive level
92 25 rherveille
        wire      sda_dly;   // delayed version of sda
93 10 rherveille
 
94
        // statemachine declaration
95
        parameter idle        = 3'b000;
96
        parameter slave_ack   = 3'b001;
97
        parameter get_mem_adr = 3'b010;
98
        parameter gma_ack     = 3'b011;
99
        parameter data        = 3'b100;
100
        parameter data_ack    = 3'b101;
101
 
102
        reg [2:0] state; // synopsys enum_state
103
 
104
        //
105
        // module body
106
        //
107
 
108
        initial
109 25 rherveille
        begin
110
           sda_o = 1'b1;
111
           state = idle;
112
        end
113 10 rherveille
 
114
        // generate shift register
115 25 rherveille
        always @(posedge scl)
116
          sr <= #1 {sr[6:0],sda};
117 10 rherveille
 
118
        //detect my_address
119
        assign my_adr = (sr[7:1] == I2C_ADR);
120 25 rherveille
        // FIXME: This should not be a generic assign, but rather
121 19 rherveille
        // qualified on address transfer phase and probably reset by stop
122 10 rherveille
 
123
        //generate bit-counter
124 25 rherveille
        always @(posedge scl)
125
          if(ld)
126
            bit_cnt <= #1 3'b111;
127
          else
128
            bit_cnt <= #1 bit_cnt - 3'h1;
129
 
130 10 rherveille
        //generate access done signal
131
        assign acc_done = !(|bit_cnt);
132
 
133 25 rherveille
        // generate delayed version of sda
134
        // this model assumes a hold time for sda after the falling edge of scl.
135
        // According to the Phillips i2c spec, there s/b a 0 ns hold time for sda
136
        // with regards to scl. If the data changes coincident with the clock, the
137
        // acknowledge is missed
138
        // Fix by Michael Sosnoski
139
        assign #1 sda_dly = sda;
140
 
141
 
142 10 rherveille
        //detect start condition
143 25 rherveille
        always @(negedge sda)
144
          if(scl)
145
            begin
146
                sta <= #1 1'b1;
147 19 rherveille
 
148 25 rherveille
                if(debug)
149
                  $display("DEBUG i2c_slave; start condition detected at %t", $time);
150
            end
151
          else
152
            sta <= #1 1'b0;
153 10 rherveille
 
154 25 rherveille
        always @(posedge scl)
155
          d_sta <= #1 sta;
156 10 rherveille
 
157
        // detect stop condition
158 25 rherveille
        always @(posedge sda)
159
          if(scl)
160
            begin
161
               sto <= #1 1'b1;
162 19 rherveille
 
163 25 rherveille
               if(debug)
164
                 $display("DEBUG i2c_slave; stop condition detected at %t", $time);
165
            end
166
          else
167
            sto <= #1 1'b0;
168 10 rherveille
 
169
        //generate i2c_reset signal
170
        assign i2c_reset = sta || sto;
171
 
172
        // generate statemachine
173 25 rherveille
        always @(negedge scl or posedge sto)
174
          if (sto || (sta && !d_sta) )
175
            begin
176
                state <= #1 idle; // reset statemachine
177 10 rherveille
 
178 25 rherveille
                sda_o <= #1 1'b1;
179
                ld    <= #1 1'b1;
180
            end
181
          else
182
            begin
183
                // initial settings
184
                sda_o <= #1 1'b1;
185
                ld    <= #1 1'b0;
186 19 rherveille
 
187 25 rherveille
                case(state) // synopsys full_case parallel_case
188
                    idle: // idle state
189
                      if (acc_done && my_adr)
190
                        begin
191
                            state <= #1 slave_ack;
192
                            rw <= #1 sr[0];
193
                            sda_o <= #1 1'b0; // generate i2c_ack
194 19 rherveille
 
195 25 rherveille
                            #2;
196
                            if(debug && rw)
197
                              $display("DEBUG i2c_slave; command byte received (read) at %t", $time);
198
                            if(debug && !rw)
199
                              $display("DEBUG i2c_slave; command byte received (write) at %t", $time);
200 19 rherveille
 
201 25 rherveille
                            if(rw)
202
                              begin
203
                                  mem_do <= #1 mem[mem_adr];
204 19 rherveille
 
205 25 rherveille
                                  if(debug)
206
                                    begin
207
                                        #2 $display("DEBUG i2c_slave; data block read %x from address %x (1)", mem_do, mem_adr);
208
                                        #2 $display("DEBUG i2c_slave; memcheck [0]=%x, [1]=%x, [2]=%x", mem[4'h0], mem[4'h1], mem[4'h2]);
209
                                    end
210
                              end
211
                        end
212 10 rherveille
 
213 25 rherveille
                    slave_ack:
214
                      begin
215
                          if(rw)
216
                            begin
217
                                state <= #1 data;
218
                                sda_o <= #1 mem_do[7];
219
                            end
220
                          else
221
                            state <= #1 get_mem_adr;
222 10 rherveille
 
223 25 rherveille
                          ld    <= #1 1'b1;
224
                      end
225 10 rherveille
 
226 25 rherveille
                    get_mem_adr: // wait for memory address
227
                      if(acc_done)
228
                        begin
229
                            state <= #1 gma_ack;
230
                            mem_adr <= #1 sr; // store memory address
231
                            sda_o <= #1 !(sr <= 15); // generate i2c_ack, for valid address
232 10 rherveille
 
233 25 rherveille
                            if(debug)
234
                              #1 $display("DEBUG i2c_slave; address received. adr=%x, ack=%b", sr, sda_o);
235
                        end
236 10 rherveille
 
237 25 rherveille
                    gma_ack:
238
                      begin
239
                          state <= #1 data;
240
                          ld    <= #1 1'b1;
241
                      end
242 19 rherveille
 
243 25 rherveille
                    data: // receive or drive data
244
                      begin
245
                          if(rw)
246
                            sda_o <= #1 mem_do[7];
247 10 rherveille
 
248 25 rherveille
                          if(acc_done)
249
                            begin
250
                                state <= #1 data_ack;
251
                                mem_adr <= #2 mem_adr + 8'h1;
252
                                sda_o <= #1 (rw && (mem_adr <= 15) ); // send ack on write, receive ack on read
253 10 rherveille
 
254 25 rherveille
                                if(rw)
255
                                  begin
256
                                      #3 mem_do <= mem[mem_adr];
257 19 rherveille
 
258 25 rherveille
                                      if(debug)
259
                                        #5 $display("DEBUG i2c_slave; data block read %x from address %x (2)", mem_do, mem_adr);
260
                                  end
261 19 rherveille
 
262 25 rherveille
                                if(!rw)
263
                                  begin
264
                                      mem[ mem_adr[3:0] ] <= #1 sr; // store data in memory
265 10 rherveille
 
266 25 rherveille
                                      if(debug)
267
                                        #2 $display("DEBUG i2c_slave; data block write %x to address %x", sr, mem_adr);
268
                                  end
269
                            end
270
                      end
271 10 rherveille
 
272 25 rherveille
                    data_ack:
273
                      begin
274
                          ld <= #1 1'b1;
275 19 rherveille
 
276 25 rherveille
                          if(rw)
277
                            if(sda) // read operation && master send NACK
278
                              begin
279
                                  state <= #1 idle;
280
                                  sda_o <= #1 1'b1;
281
                              end
282
                            else
283
                              begin
284
                                  state <= #1 data;
285
                                  sda_o <= #1 mem_do[7];
286
                              end
287
                          else
288
                            begin
289
                                state <= #1 data;
290
                                sda_o <= #1 1'b1;
291
                            end
292
                      end
293 19 rherveille
 
294 25 rherveille
                endcase
295
            end
296 10 rherveille
 
297 25 rherveille
        // read data from memory
298
        always @(posedge scl)
299
          if(!acc_done && rw)
300
            mem_do <= #1 {mem_do[6:0], 1'b1}; // insert 1'b1 for host ack generation
301 10 rherveille
 
302 25 rherveille
        // generate tri-states
303
        assign sda = sda_o ? 1'bz : 1'b0;
304 10 rherveille
 
305
 
306 25 rherveille
        //
307
        // Timing checks
308
        //
309 10 rherveille
 
310 25 rherveille
        wire tst_sto = sto;
311
        wire tst_sta = sta;
312
 
313
        specify
314
          specparam normal_scl_low  = 4700,
315
                    normal_scl_high = 4000,
316
                    normal_tsu_sta  = 4700,
317
                    normal_tsu_sto  = 4000,
318
                    normal_sta_sto  = 4700,
319
 
320
                    fast_scl_low  = 1300,
321
                    fast_scl_high =  600,
322
                    fast_tsu_sta  = 1300,
323
                    fast_tsu_sto  =  600,
324
                    fast_sta_sto  = 1300;
325
 
326
          $width(negedge scl, normal_scl_low);  // scl high time
327
          $width(posedge scl, normal_scl_high); // scl low time
328
 
329
          $setup(negedge sda &&& scl, negedge scl, normal_tsu_sta); // start condition
330
          $setup(posedge scl, posedge sda &&& scl, normal_tsu_sto); // stop condition
331
 
332
          $setup(posedge tst_sta, posedge tst_scl, normal_sta_sto); // stop to start time
333
        endspecify
334
 
335 10 rherveille
endmodule
336
 
337
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.