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