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

Subversion Repositories i2c

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

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

powered by: WebSVN 2.1.0

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