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

Subversion Repositories i2c

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

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 56 rherveille
//  $Id: i2c_slave_model.v,v 1.6 2005-02-28 11:33:48 rherveille Exp $
40 10 rherveille
//
41 56 rherveille
//  $Date: 2005-02-28 11:33:48 $
42
//  $Revision: 1.6 $
43 19 rherveille
//  $Author: rherveille $
44
//  $Locker:  $
45
//  $State: Exp $
46
//
47
// Change History:
48
//               $Log: not supported by cvs2svn $
49 56 rherveille
//               Revision 1.5  2003/12/05 11:05:19  rherveille
50
//               Fixed slave address MSB='1' bug
51
//
52 46 rherveille
//               Revision 1.4  2003/09/11 08:25:37  rherveille
53
//               Fixed a bug in the timing section. Changed 'tst_scl' into 'tst_sto'.
54
//
55 43 rherveille
//               Revision 1.3  2002/10/30 18:11:06  rherveille
56
//               Added timing tests to i2c_model.
57
//               Updated testbench.
58
//
59 25 rherveille
//               Revision 1.2  2002/03/17 10:26:38  rherveille
60
//               Fixed some race conditions in the i2c-slave model.
61
//               Added debug information.
62
//               Added headers.
63
//
64 10 rherveille
 
65
`include "timescale.v"
66
 
67
module i2c_slave_model (scl, sda);
68
 
69
        //
70
        // parameters
71
        //
72
        parameter I2C_ADR = 7'b001_0000;
73
 
74
        //
75
        // input && outpus
76
        //
77
        input scl;
78
        inout sda;
79
 
80
        //
81
        // Variable declaration
82
        //
83 19 rherveille
        wire debug = 1'b1;
84
 
85 10 rherveille
        reg [7:0] mem [3:0]; // initiate memory
86
        reg [7:0] mem_adr;   // memory address
87
        reg [7:0] mem_do;    // memory data output
88
 
89
        reg sta, d_sta;
90
        reg sto, d_sto;
91
 
92
        reg [7:0] sr;        // 8bit shift register
93
        reg       rw;        // read/write direction
94
 
95
        wire      my_adr;    // my address called ??
96
        wire      i2c_reset; // i2c-statemachine reset
97
        reg [2:0] bit_cnt;   // 3bit downcounter
98
        wire      acc_done;  // 8bits transfered
99
        reg       ld;        // load downcounter
100
 
101
        reg       sda_o;     // sda-drive level
102 25 rherveille
        wire      sda_dly;   // delayed version of sda
103 10 rherveille
 
104
        // statemachine declaration
105
        parameter idle        = 3'b000;
106
        parameter slave_ack   = 3'b001;
107
        parameter get_mem_adr = 3'b010;
108
        parameter gma_ack     = 3'b011;
109
        parameter data        = 3'b100;
110
        parameter data_ack    = 3'b101;
111
 
112
        reg [2:0] state; // synopsys enum_state
113
 
114
        //
115
        // module body
116
        //
117
 
118
        initial
119 25 rherveille
        begin
120
           sda_o = 1'b1;
121
           state = idle;
122
        end
123 10 rherveille
 
124
        // generate shift register
125 25 rherveille
        always @(posedge scl)
126
          sr <= #1 {sr[6:0],sda};
127 10 rherveille
 
128
        //detect my_address
129
        assign my_adr = (sr[7:1] == I2C_ADR);
130 25 rherveille
        // FIXME: This should not be a generic assign, but rather
131 19 rherveille
        // qualified on address transfer phase and probably reset by stop
132 10 rherveille
 
133
        //generate bit-counter
134 25 rherveille
        always @(posedge scl)
135
          if(ld)
136
            bit_cnt <= #1 3'b111;
137
          else
138
            bit_cnt <= #1 bit_cnt - 3'h1;
139
 
140 10 rherveille
        //generate access done signal
141
        assign acc_done = !(|bit_cnt);
142
 
143 25 rherveille
        // generate delayed version of sda
144
        // this model assumes a hold time for sda after the falling edge of scl.
145
        // According to the Phillips i2c spec, there s/b a 0 ns hold time for sda
146
        // with regards to scl. If the data changes coincident with the clock, the
147
        // acknowledge is missed
148
        // Fix by Michael Sosnoski
149
        assign #1 sda_dly = sda;
150
 
151
 
152 10 rherveille
        //detect start condition
153 25 rherveille
        always @(negedge sda)
154
          if(scl)
155
            begin
156 46 rherveille
                sta   <= #1 1'b1;
157
                d_sta <= #1 1'b0;
158
                sto   <= #1 1'b0;
159 19 rherveille
 
160 25 rherveille
                if(debug)
161
                  $display("DEBUG i2c_slave; start condition detected at %t", $time);
162
            end
163
          else
164
            sta <= #1 1'b0;
165 10 rherveille
 
166 25 rherveille
        always @(posedge scl)
167
          d_sta <= #1 sta;
168 10 rherveille
 
169
        // detect stop condition
170 25 rherveille
        always @(posedge sda)
171
          if(scl)
172
            begin
173 46 rherveille
               sta <= #1 1'b0;
174 25 rherveille
               sto <= #1 1'b1;
175 19 rherveille
 
176 25 rherveille
               if(debug)
177
                 $display("DEBUG i2c_slave; stop condition detected at %t", $time);
178
            end
179
          else
180
            sto <= #1 1'b0;
181 10 rherveille
 
182
        //generate i2c_reset signal
183
        assign i2c_reset = sta || sto;
184
 
185
        // generate statemachine
186 25 rherveille
        always @(negedge scl or posedge sto)
187
          if (sto || (sta && !d_sta) )
188
            begin
189
                state <= #1 idle; // reset statemachine
190 10 rherveille
 
191 25 rherveille
                sda_o <= #1 1'b1;
192
                ld    <= #1 1'b1;
193
            end
194
          else
195
            begin
196
                // initial settings
197
                sda_o <= #1 1'b1;
198
                ld    <= #1 1'b0;
199 19 rherveille
 
200 25 rherveille
                case(state) // synopsys full_case parallel_case
201
                    idle: // idle state
202
                      if (acc_done && my_adr)
203
                        begin
204
                            state <= #1 slave_ack;
205
                            rw <= #1 sr[0];
206
                            sda_o <= #1 1'b0; // generate i2c_ack
207 19 rherveille
 
208 25 rherveille
                            #2;
209
                            if(debug && rw)
210
                              $display("DEBUG i2c_slave; command byte received (read) at %t", $time);
211
                            if(debug && !rw)
212
                              $display("DEBUG i2c_slave; command byte received (write) at %t", $time);
213 19 rherveille
 
214 25 rherveille
                            if(rw)
215
                              begin
216
                                  mem_do <= #1 mem[mem_adr];
217 19 rherveille
 
218 25 rherveille
                                  if(debug)
219
                                    begin
220
                                        #2 $display("DEBUG i2c_slave; data block read %x from address %x (1)", mem_do, mem_adr);
221
                                        #2 $display("DEBUG i2c_slave; memcheck [0]=%x, [1]=%x, [2]=%x", mem[4'h0], mem[4'h1], mem[4'h2]);
222
                                    end
223
                              end
224
                        end
225 10 rherveille
 
226 25 rherveille
                    slave_ack:
227
                      begin
228
                          if(rw)
229
                            begin
230
                                state <= #1 data;
231
                                sda_o <= #1 mem_do[7];
232
                            end
233
                          else
234
                            state <= #1 get_mem_adr;
235 10 rherveille
 
236 25 rherveille
                          ld    <= #1 1'b1;
237
                      end
238 10 rherveille
 
239 25 rherveille
                    get_mem_adr: // wait for memory address
240
                      if(acc_done)
241
                        begin
242
                            state <= #1 gma_ack;
243
                            mem_adr <= #1 sr; // store memory address
244
                            sda_o <= #1 !(sr <= 15); // generate i2c_ack, for valid address
245 10 rherveille
 
246 25 rherveille
                            if(debug)
247
                              #1 $display("DEBUG i2c_slave; address received. adr=%x, ack=%b", sr, sda_o);
248
                        end
249 10 rherveille
 
250 25 rherveille
                    gma_ack:
251
                      begin
252
                          state <= #1 data;
253
                          ld    <= #1 1'b1;
254
                      end
255 19 rherveille
 
256 25 rherveille
                    data: // receive or drive data
257
                      begin
258
                          if(rw)
259
                            sda_o <= #1 mem_do[7];
260 10 rherveille
 
261 25 rherveille
                          if(acc_done)
262
                            begin
263
                                state <= #1 data_ack;
264
                                mem_adr <= #2 mem_adr + 8'h1;
265
                                sda_o <= #1 (rw && (mem_adr <= 15) ); // send ack on write, receive ack on read
266 10 rherveille
 
267 25 rherveille
                                if(rw)
268
                                  begin
269
                                      #3 mem_do <= mem[mem_adr];
270 19 rherveille
 
271 25 rherveille
                                      if(debug)
272
                                        #5 $display("DEBUG i2c_slave; data block read %x from address %x (2)", mem_do, mem_adr);
273
                                  end
274 19 rherveille
 
275 25 rherveille
                                if(!rw)
276
                                  begin
277
                                      mem[ mem_adr[3:0] ] <= #1 sr; // store data in memory
278 10 rherveille
 
279 25 rherveille
                                      if(debug)
280
                                        #2 $display("DEBUG i2c_slave; data block write %x to address %x", sr, mem_adr);
281
                                  end
282
                            end
283
                      end
284 10 rherveille
 
285 25 rherveille
                    data_ack:
286
                      begin
287
                          ld <= #1 1'b1;
288 19 rherveille
 
289 25 rherveille
                          if(rw)
290
                            if(sda) // read operation && master send NACK
291
                              begin
292
                                  state <= #1 idle;
293
                                  sda_o <= #1 1'b1;
294
                              end
295
                            else
296
                              begin
297
                                  state <= #1 data;
298
                                  sda_o <= #1 mem_do[7];
299
                              end
300
                          else
301
                            begin
302
                                state <= #1 data;
303
                                sda_o <= #1 1'b1;
304
                            end
305
                      end
306 19 rherveille
 
307 25 rherveille
                endcase
308
            end
309 10 rherveille
 
310 25 rherveille
        // read data from memory
311
        always @(posedge scl)
312
          if(!acc_done && rw)
313
            mem_do <= #1 {mem_do[6:0], 1'b1}; // insert 1'b1 for host ack generation
314 10 rherveille
 
315 25 rherveille
        // generate tri-states
316
        assign sda = sda_o ? 1'bz : 1'b0;
317 10 rherveille
 
318
 
319 25 rherveille
        //
320
        // Timing checks
321
        //
322 10 rherveille
 
323 25 rherveille
        wire tst_sto = sto;
324
        wire tst_sta = sta;
325
 
326
        specify
327
          specparam normal_scl_low  = 4700,
328
                    normal_scl_high = 4000,
329
                    normal_tsu_sta  = 4700,
330 56 rherveille
                    normal_thd_sta  = 4000,
331 25 rherveille
                    normal_tsu_sto  = 4000,
332 56 rherveille
                    normal_tbuf     = 4700,
333 25 rherveille
 
334
                    fast_scl_low  = 1300,
335
                    fast_scl_high =  600,
336
                    fast_tsu_sta  = 1300,
337 56 rherveille
                    fast_thd_sta  =  600,
338 25 rherveille
                    fast_tsu_sto  =  600,
339 56 rherveille
                    fast_tbuf     = 1300;
340 25 rherveille
 
341 56 rherveille
          $width(negedge scl, normal_scl_low);  // scl low time
342
          $width(posedge scl, normal_scl_high); // scl high time
343 25 rherveille
 
344 56 rherveille
          $setup(posedge scl, negedge sda &&& scl, normal_tsu_sta); // setup start
345
          $setup(negedge sda &&& scl, negedge scl, normal_thd_sta); // hold start
346
          $setup(posedge scl, posedge sda &&& scl, normal_tsu_sto); // setup stop
347 25 rherveille
 
348 56 rherveille
          $setup(posedge tst_sta, posedge tst_sto, normal_tbuf); // stop to start time
349 25 rherveille
        endspecify
350
 
351 10 rherveille
endmodule
352
 
353
 

powered by: WebSVN 2.1.0

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