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

Subversion Repositories i2c

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

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

powered by: WebSVN 2.1.0

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