fix i2c syntax error
[shakti-peripherals.git] / src / peripherals / i2c / I2C_top.bsv
1 /*
2 Copyright (c) 2017, IIT Madras
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 * Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
13
14 Author Names : Vinod.G, Ayush Mittal
15 Email ID : g.vinod1993@gmail.com, 29ayush@gmail.com
16
17 I2C Controller top module which is compliant with UM10204 I2C Specification provided by NXP Semiconductors. This is a single master, multiple slave controller.
18 */
19 // ================================================
20 package I2C_top;
21 // Bluespec Libraries
22 import GetPut ::*;
23 import TriState ::*;
24 import Counter ::*;
25 // ================================================
26 // Project Imports and Includes
27 import AXI4_Lite_Types ::*;
28 import AXI4_Lite_Fabric ::*;
29 import ConcatReg ::*;
30 import defined_types ::*;
31 import BUtils ::*;
32 import I2C_Defs ::*;
33 import Semi_FIFOF ::*;
34 `include "instance_defines.bsv"
35 `include "I2C_Defs.bsv"
36
37 // ================================================
38 // Interface Declarations
39 /*(* always_enabled, always_ready *)
40 interface I2C_out;
41 (* prefix = "SDA" *)
42 interface Inout#(Bit#(1)) sda;
43 (* prefix = "SCL" *)
44 interface Inout#(Bit#(1)) scl;
45 endinterface*/
46
47 (*always_enabled, always_ready*)
48 interface I2C_out;
49 method Bit#(1) i2c_DRV0;
50 method Bit#(1) i2c_DRV1;
51 method Bit#(1) i2c_DRV2;
52 method Bit#(1) i2c_PD;
53 method Bit#(1) i2c_PPEN;
54 method Bit#(1) i2c_PRG_SLEW;
55 method Bit#(1) i2c_PUQ;
56 method Bit#(1) i2c_PWRUPZHL;
57 method Bit#(1) i2c_PWRUP_PULL_EN;
58 interface Get#(Bit#(1)) scl_out;
59 interface Put#(Bit#(1)) scl_in;
60 interface Get#(Bit#(1)) scl_out_en;
61 interface Get#(Bit#(1)) sda_out;
62 interface Put#(Bit#(1)) sda_in;
63 interface Get#(Bit#(1)) sda_out_en;
64 endinterface
65
66
67 interface I2C_IFC;
68 interface AXI4_Lite_Slave_IFC#(`PADDR, `Reg_width, `USERSPACE) slave_i2c_axi;
69 interface I2C_out out;
70 (* always_enabled, always_ready *)
71 method Bit#(1) isint();
72 method Action resetc (Bit#(1) rst);
73 method Bit#(1) timerint();
74 method Bit#(1) isber();
75 // (* always_enabled, always_ready *)
76 //method Bit#(5) interrupt_pins;
77 //Test interface to test this module without a driver. Will not be included as part of the final design
78 // method Action set_eso ( Bit#(1) temp_eso );
79 // method Action set_s2 ( Bit#(8) temp_s2 );
80 // method Action set_s1 ( Bit#(8) temp_s1 );
81 // method Action set_s0 ( Bit#(8) temp_s0 );
82 endinterface
83
84 interface I2C_out_tri;
85 (* prefix = "SDA" *)
86 interface Inout#(Bit#(1)) sda;
87 (* prefix = "SCL" *)
88 interface Inout#(Bit#(1)) scl;
89 endinterface
90
91 interface I2C_IFC_wrap;
92 interface I2C_out_tri out_tri;
93 interface AXI4_Lite_Slave_IFC#(`PADDR, `Reg_width, `USERSPACE) slave_i2c_axi_wrap;
94 (* always_enabled, always_ready *)
95 method Bit#(1) isint_wrap();
96 method Action resetc_wrap (Bit#(1) rst);
97 method Bit#(1) timerint_wrap();
98 method Bit#(1) isber_wrap();
99 endinterface
100
101 // ==============================================
102 // Function Definitions
103 function Reg#(t) readOnlyReg(t r); //~ Useless :: Processor needs to be given access to mstatus
104 return (interface Reg;
105 method t _read = r;
106 method Action _write(t x) = noAction;
107 endinterface);
108 endfunction
109
110 function Reg#(t) writeOnlyReg(Reg#(t) r)
111 provisos(
112 Literal#(t)
113 );
114 return (interface Reg;
115 method t _read = 0;
116 method Action _write(t x);
117 r._write(x);
118 endmethod
119 endinterface);
120 endfunction
121 function Reg#(t) conditionalWrite(Reg#(t) r, Bool a);
122 return (interface Reg;
123 method t _read = r._read;
124 method Action _write(t x);
125 if(a)
126 r._write(x);
127 endmethod
128 endinterface);
129 endfunction
130 // ==============================================
131 // Module Definition
132 (* doc = "This Module implements the I2C Master/Slave Controller based on NXP PCF8584" *)
133 (* synthesize *)
134 module mkI2CController(I2C_IFC) //For the sake of ease of compiling - having a non-polymorphic type TODO Change
135 provisos(
136 );
137 //////////////////////////////////////////////////////////////////////////////
138 ///////////Register Declarations/////////////////////////////////////////////
139 ////////////////////////////////////////////////////////////////////////////
140
141 //Timing Registers
142 Reg#(Bit#(1)) val_SCL <- mkReg(1); // SCL value that is sent through the inout pin using tristate
143 Reg#(Bit#(1)) val_SCL_in <- mkReg(1);
144 Reg#(Bit#(1)) val_SDA <- mkReg(1); // SDA value that is sent through the inout pin using tristate
145 Reg#(Bit#(1)) val_SDA_in <- mkReg(1);
146 Reg#(Bool) dOutEn <- mkReg(False); // Data out Enable for the SDA Tristate Buffer
147 Reg#(Bool) cOutEn <- mkReg(False); // Data out Enable for the SCL Tristate Buffer
148
149 Reg#(Bit#(8)) cprescaler <- mkReg(0); // Prescaler Counter for the Chip clock
150 Reg#(Bit#(8)) rprescaler <- mkReg(0); // Prescaler Counter Restorer for the chip clock
151 Reg#(Bit#(32)) coSCL <- mkReg(0); // SCL Counter for the SCL clock
152 Reg#(Bit#(32)) reSCL <- mkReg(0); // SCL Counter Restorer for the SCL clock
153 Reg#(Bit#(10)) cycwaste <- mkReg(0); // Waste Cycle count
154 Reg#(Bit#(32)) c_scl <- mkReg(0); // Waste Cycle count
155
156 //Programmable Registers (Will be used by the Device Drivers to Initialize - Based On PCF8584)
157 Reg#(I2C_RegWidth) s01 <- mkReg(0); //I2C Own Address Slave Register
158 Reg#(I2C_RegWidth) s2 <- mkReg('b11000000); //Clock Register - Use to set the module and SCL clock
159 Reg#(I2C_RegWidth) drv0_rg <- mkReg(1);
160 Reg#(I2C_RegWidth) drv1_rg <- mkReg(1);
161 Reg#(I2C_RegWidth) drv2_rg <- mkReg(0);
162 Reg#(I2C_RegWidth) pd_rg <- mkReg(0);
163 Reg#(I2C_RegWidth) ppen_rg <- mkReg(0);
164 Reg#(I2C_RegWidth) prg_slew_rg <- mkReg(1);
165 Reg#(I2C_RegWidth) puq_rg <- mkReg(0);
166 Reg#(I2C_RegWidth) pwrupzhl_rg <- mkReg(0);
167 Reg#(I2C_RegWidth) pwrup_pull_en_rg <- mkReg(0);
168 // Clock Reg Syntax difference from PCF5854 (maybe internally it does so but who knows)
169 // MSB = 1 By default
170 // Intialization Of clock register will be accepted only if MSB = 0 ;
171 // Once the initial initialization has been done and I2C Controller has started we dont care about that bit
172 // Maybe the ultimate reset can be synced using it /~/Discuss
173
174 Reg#(I2C_RegWidth) s3 <- mkReg(9); //Interrupt Vector Register
175
176 //~/Discuss : If there are only 4-5 interupts why use a 8 bit register And decide upon final values for interupts
177
178 Reg#(I2C_RegWidth) s0 <- mkRegU(); //Data Shift Register
179 //~ Maybe better to have preset Values rather than random
180
181
182 // Control Registers
183 Reg#(Bit#(1)) pin <- mkReg(1); // Used as a software reset. If pin is 1 all status bits are reset.Used as transmission complete status in polled applications
184 Reg#(Bit#(1)) eso <- mkReg(0); // Enable Serial Output. ESO = 0 - Registers can be initialized. ESO = 1 - I2C Serial Transmission
185 Reg#(Bit#(1)) es1 <- mkReg(0); // Selection of registers. Not used currently
186 Reg#(Bit#(1)) es2 <- mkReg(0); // Selection of registers. Not used currently.
187 Reg#(Bit#(1)) eni <- mkReg(0); // Enables the external interrupt output, which is generated when the PIN is active (active low - 0)
188 Reg#(Bit#(1)) sta <- mkReg(0); // STA and STO generates the START and STOP bit for the processor
189 Reg#(Bit#(1)) sto <- mkReg(0);
190 Reg#(Bit#(1)) ack <- mkReg(1); // This is normally set to 1. I2C automatically sends an acknowledge after a read/write transaction
191
192 // Status Registers - Many of the status bits are unused for now since only single master support is present
193 Reg#(Bit#(1)) configchange <- mkReg(0); // Should be set to 0 by the driver. No purpose -- Maybe can be checked if driver is initializing properly
194
195 Reg#(Bit#(1)) zero <- mkReg(1); // Should be set to 0 by the driver. No purpose -- Maybe can be checked if driver is initializing properly
196 Reg#(Bit#(1)) sts <- mkReg(0); // Used only Slave receiver mode to detect STOP. Not used
197 Reg#(Bit#(1)) ber <- mkReg(0); // Bus Error - Set to 1 when there is a misplaced START, STOP bit
198 Reg#(Bit#(1)) ad0_lrb <- mkReg(0); // LRB - holds the last received bit through I2C bus. AD0 - Generall Call bit used for broadcast. Valid only while PIN=0
199 Reg#(Bit#(1)) aas <- mkReg(0); // Addressed as slave - Used in Slave Receiver mode
200 Reg#(Bit#(1)) lab <- mkReg(0); // Lost Arbitration bit - Used in Multiple Master systems only to denote that the master lost the arbitration
201 Reg#(Bit#(1)) bb <- mkReg(1); // ~Bus Busy bit - Indicates that the bus is busy(0 = busy). Also used in multi master systems only // 0 = busy
202 Reg#(Bit#(16)) i2ctime <- mkReg(0); //~/Discuss :- Should We have it configurable PCA9654 does
203
204
205 //TriState#(Bit#(1)) line_SCL <- mkTriState(cOutEn && eso == 1'b1, val_SCL); // TODO - See how other slaves control SCL
206 //TriState#(Bit#(1)) line_SDA <- mkTriState(dOutEn && eso == 1'b1, val_SDA); // SDA Tristate Buffer
207
208
209
210 ////########## COnfigurable Registers Over.....
211 /// Unused Pins : zero
212 /// : s3 4 MSB s2 5,6 bit
213 ////########################################
214
215 //Custom added MM registers be read or written by the processor master in buffered mode. Support not added yet
216 Reg#(Bit#(14)) i2ctimeout <- mkReg(1); //~/Discuss :- Should We have it configurable PCA9654 does
217
218
219
220 // Concatenated CSRs TODO
221 Reg#(I2C_RegWidth) mcontrolReg = concatReg8(pin,writeOnlyReg(eso),writeOnlyReg(es1),writeOnlyReg(es2),writeOnlyReg(eni),writeOnlyReg(sta),writeOnlyReg(sto),writeOnlyReg(ack));
222 Reg#(I2C_RegWidth) mstatusReg = concatReg8(pin,readOnlyReg(zero),readOnlyReg(sts),readOnlyReg(ber),readOnlyReg(ad0_lrb),readOnlyReg(aas),readOnlyReg(lab),readOnlyReg(bb));
223
224 //FSM Registers
225 Reg#(MTrans_State) mTransFSM <- mkReg(Idle);
226 Reg#(Bool) mod_start <- mkReg(False); //Redundant actually
227 Reg#(Bool) scl_start <- mkReg(False);
228 Reg#(Bool) st_toggle <- mkReg(False);
229 PulseWire pwI2C <- mkPulseWire;
230 PulseWire pwSCL <- mkPulseWire;
231
232 //Maintenance variables
233
234 Reg#(Bit#(4)) dataBit <- mkReg(8);
235 Reg#(Bool) last_byte_read <- mkReg(False);
236 Reg#(I2C_RegWidth) controlReg = concatReg8(pin,eso,es1,es2,eni,sta,sto,ack);
237 Reg#(Bit#(7)) statusReg = concatReg7(zero,sts,ber,ad0_lrb,aas,lab,bb);
238 Reg#(Transaction) operation <- mkReg(Write);
239 Bool pwesoCond = (pwI2C && eso == 1'b1);
240 Bool pwsclCond = (pwSCL && eso == 1'b1);
241 Bool sclSync = (pwsclCond && val_SCL==1); // Sends a tick on falling edge
242 Bool sclnSync = (pwsclCond && val_SCL==0); // Sends a tick on risisng edge
243 Bool startBit = mTransFSM == STA;
244 Bool stopBit = mTransFSM == End;
245 Bool sendAddr = mTransFSM == SendAddr;
246 Bool ackCond = mTransFSM == Ack;
247 Bool intCond = mTransFSM == Intrpt;
248 Bit#(3) startSig = 3'b110; //To prevent quick transitions which might result in a spike
249 Bit#(3) stopSig = 3'b001;
250 Reg#(Bit#(2)) sendInd <- mkReg(2);
251
252
253 //Intrupt Register
254 Reg#(Bit#(1)) rstsig <- mkReg(0); //~/ Use wire Creg is costly
255 Reg#(Bit#(6)) resetcount <- mkReg(0); // To count no. of cycles reset pin has been high
256
257 //Module Instantiations
258 AXI4_Lite_Slave_Xactor_IFC #(`PADDR, `Reg_width, `USERSPACE) s_xactor <- mkAXI4_Lite_Slave_Xactor;
259
260
261
262
263 //Function to access Registers
264 function I2C_RegWidth get_i2c(I2C i2c);
265 Reg#(I2C_RegWidth) regi2c = (
266 case (i2c)
267 Control : mcontrolReg; //~ Are we creating new reg each time
268 Status : mstatusReg;
269 S01 : s01;
270 S0 : s0;
271 S2 : s2;
272 S3 : s3;
273 DRV0 : drv0_rg;
274 DRV1 : drv1_rg;
275 DRV2 : drv2_rg;
276 PD : pd_rg;
277 PPEN : ppen_rg;
278 PRG_SLEW: prg_slew_rg;
279 PUQ : puq_rg;
280 PWRUPZHL: pwrupzhl_rg;
281 PWRUP_PULL_EN : pwrup_pull_en_rg;
282 default : readOnlyReg(8'b0);
283 endcase
284 );
285 return regi2c;
286 endfunction
287
288 //Function to write into the registers
289 function Action set_i2c(I2C i2c,Bit#(32) value );
290 action
291 case(i2c)
292 Control : begin
293 zero <= 0; //Indicates to the Driver that the control register has been written in the beginning
294
295 $display("Control Written");
296 if(!intCond && mTransFSM != NAck)
297 configchange <=1;
298 if(value[2:1] == 2 && (intCond || mTransFSM == NAck) && bb == 0 ) //RT START CONDITIONS
299 begin
300 dataBit <= 8;
301 st_toggle <= True;
302 mTransFSM <= RTSTA;
303 dOutEn<= True;
304 cOutEn<=True;
305 $display("Repeated Start Instruction received");
306 controlReg <= 8'hc5 | truncate(value); //TODO 45h Check this out
307 val_SDA <= 1;
308 sendInd <= 2;
309 end
310 else if(value[2:1] == 2 && bb == 0)
311 begin
312 $display("Invalid Rt Start");
313 mTransFSM <= End;
314 dOutEn <= True;
315 cOutEn <= True;
316 sendInd <= 2;
317 ber <=1; //~ add bus error functionality
318 end
319 else
320 mcontrolReg._write(truncate(value));
321 end
322 S01 : begin s01._write(truncate(value)); $display("S01 written"); end
323 S0 : begin s0._write(truncate(value)); $display("S0 written"); pin <=1; end
324 S2 : begin
325 if(eso == 0)
326 begin
327 mod_start <= True;
328 scl_start <= True;
329 rprescaler <= 0;
330 mTransFSM <= Idle;
331 s2._write(truncate(value));
332 end
333 $display("S2 written");
334 end
335 S3 : s3._write(truncate(value)); //~ default
336 SCL : begin
337 if(eso == 0)
338 begin
339 mod_start <= True;
340 scl_start <= True;
341 reSCL<=0;
342 c_scl._write(truncate(value));
343 mTransFSM <= Idle;
344 end
345 $display("Received scl but eso was %d",eso);
346 end
347 Time : i2ctime._write(truncate(value));
348 DRV0 : drv0_rg <= value[7:0];
349 DRV1 : drv1_rg <= value[7:0];
350 DRV2 : drv2_rg <= value[7:0];
351 PD : pd_rg <= value[7:0];
352 PPEN : ppen_rg <= value[7:0];
353 PRG_SLEW: prg_slew_rg <= value[7:0];
354 PUQ : puq_rg <= value[7:0];
355 PWRUPZHL: pwrupzhl_rg <= value[7:0];
356 PWRUP_PULL_EN : pwrup_pull_en_rg <= value[7:0];
357 default : noAction;
358 endcase
359 endaction
360 endfunction
361
362 (* doc = "This sets the module's operating frequency based on the values in s2 register",
363 doc = "Assuming Processor operates at 50MHz for now",
364 doc = "PreScaler is an approximation of the available values" *)
365
366 (* descending_urgency = "wait_interrupt,toggle_scl" *)
367 // (* descending_urgency = "receive_data1,wait_interrupt_receive_end" *)
368 (* descending_urgency = "send_stop_condition, toggle_scl" *)
369 (* descending_urgency = "reset_state,resetfilter" *)
370 (* descending_urgency = "rl_wr_req,reset_state" *)
371 (* descending_urgency = "rl_wr_req,wait_interrupt_receive_end" *)
372 (* descending_urgency = "rl_wr_req,idler" *)
373 (* descending_urgency = "reset_state, check_Ack" *)
374 (* mutually_exclusive = "rl_wr_req,send_data,check_Ack,send_addr,receive_data " *)
375 (* mutually_exclusive = "set_scl_clock,count_scl,restore_scl" *)
376 (* descending_urgency = "set_i2c_clock,count_prescale,restore_prescale" *)
377
378 rule set_i2c_clock (mod_start && eso==1'b0); //Sync problems might be there - check //~ eso is mkregU + shouldnt it be 0
379 $display("I2C is Setting");
380 mod_start <= False;
381 cprescaler <= s2;
382 rprescaler <= s2;
383 //TODO Currently I2C clock can be set only once when starting -- should see if it should dynamically changed
384 //~ It Can be changed whenever wished but changes reflect only if bus is restarted i.e not busy; no man ref
385 endrule
386
387 (* doc = "This rule is used to select one of the SCL clock frequencies among the ones based on the s2 register encoding" *)
388 rule set_scl_clock(scl_start && eso == 1'b0 ); //~ eso should be 0 + regU not
389 $display("SCL is Setting");
390 scl_start <= False;
391 coSCL <= c_scl;
392 reSCL <= c_scl;
393 //TODO Currently SCL Clock can be set only once when starting -- should see if it should be dynamically changed
394 //TODO Currently 50MHz processor running freq. and ~8MHz Module operating freq. is assumed. Should generalize
395 //TODO -8
396 endrule
397
398 (* doc = "Prescaler register counter which will trigger the rules making it operate in the stated freq. approx." *)
399 rule count_prescale(cprescaler > 0);
400 cprescaler <= cprescaler - 1;
401 endrule
402
403 (* doc = "A tick is sent which will fire the rules making it emulate a module clock, when counter becomes zero" *)
404 rule restore_prescale(cprescaler == 0 && rprescaler > 0);
405 cprescaler <= rprescaler;
406 pwI2C.send;
407 // $display("tick i2c sent");
408 // $display("cprescaler : %d rprescaler : %d",cprescaler,rprescaler,$time);
409 endrule
410
411 (* doc = "This rule is used to count down SCL clock which is a scaled down version of the Module clock derived from the system clock. SCL toggles only during transmission. For Multiple masters, different scenarios might arise" *)
412 rule count_scl(coSCL > 0 && pwesoCond && st_toggle); //~ st_toggle dec false
413 coSCL <= coSCL - 1;
414 // $display("coSCL: %d", coSCL - 1);
415 endrule
416
417 (* doc = "This rule is used to restore the SCL count value. Sending a tick, operating as scl clock" *)
418 rule restore_scl(coSCL == 0 && pwI2C && reSCL > 0);
419 coSCL <= reSCL;
420 pwSCL.send;
421 // $display("tick sent");
422 endrule
423
424
425 //Master Transmitter Mode - Transmission
426 //Test sending through SDA
427 //When integrated with AXI, this rule should fire whenever R/W bit of the slave address is 0
428 /*rule check_bus_busy(mTransFSM == Idle && pwI2C && eso==1'b1);
429 if(statusReg[0] != 1)
430 mTransFSM <= ContCheck; //If Bus is busy, the control does not move forward -- For Multiple Masters only
431 endrule*/
432
433 (* doc = "This rule is used to toggle the Serial Clock line based on coSCL input" *)
434 rule toggle_scl(st_toggle && pwSCL); //~ st_toggle is false
435 val_SCL <= ~val_SCL;
436 // $display("From toggle rule :",~val_SCL);
437 //$display("TriState SCL Value : %b", line_SCL._read,$time);
438 endrule
439
440
441
442 //////////////State Machine Implementation ////////////////////////////////
443 /*
444 Initially, Module Is Off Eso = 0.
445 Only Check Config Register And write into register rules should fire.
446
447 ESO = 0 => Go to reset state.
448
449 Interrupt Generation And Documentation
450 Interrupt Vector = S3 Default Value: 00000000
451 01.) 00H = Clock register Yet Not Initialized
452 02.) 01H = Address has been sent waiting for slave to acknowledge // Not generated
453 03.) 02H = Slave has acknowledged waitng for Data to be written
454 04.) 03H = Slave Sent A Nack in send address phase
455 05.) 04H = Slave Sent A Nack in Write Data Phase (data was being written to slave)
456 06.) 05H = Master Was unable to send a ack during receive data phase
457 07.) 06H = Master Received A data from slave please read
458 08.) 07H = I2C Reset By Reset Signal //Not generated
459 09.) 08H = Master Received Last Byte From Slave
460 10.) 09H = Idle i.e Not Busy // Have to modify in multi master .i2c might be idle yet busy
461 11.) 0AH = RT Strart sent // If int then it means enter address
462 12.) 0BH = Start Sent
463 13.) 0CH = timeout
464 14.)
465 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
466 */
467 ///////////////////////////////////////////////////////////////////////////
468
469 rule idler(mTransFSM == Idle);
470 if(cycwaste == 0) begin
471 /* dOutEn <= True;
472 cOutEn <= True;
473 val_SDA <= 1;
474 val_SCL <= 1;*/
475 cycwaste <= cycwaste + 1;
476 end
477 else if(cycwaste == 'd600)
478 begin
479 mTransFSM <= Idleready;
480 s3 <= 'h09;
481 cycwaste <= 0;
482 sendInd <= 2;
483 i2ctimeout <= 1;
484 // Should it leave control of SCL And SDA Line
485
486 statusReg <= 1;
487 resetcount <= 0 ;
488 end
489 else
490 cycwaste <= cycwaste + 1;
491 endrule
492 (* mutually_exclusive = "check_control_reg, send_start_trans" *)
493 (* doc = "Checks the control Reg (after Driver updates it) and based on byte loaded goes to Write/Read" *)
494 rule check_control_reg(configchange == 1 && pwesoCond && !intCond && mTransFSM != Idle && mTransFSM !=NAck); //~ mod edge and serial on
495 $display("Configchanged fire");
496 configchange <= 0 ; // Discuss For More than 1 enques
497 if(controlReg[2:1] == 2 && bb==0) begin // Start
498 $display("Invalid Start");
499 end
500 else if(controlReg[2:1] == 2)
501 begin
502 mTransFSM <= STA;
503 st_toggle <= True;
504 val_SDA <= 1;
505 $display("Start Received");
506 dOutEn <= True;
507 cOutEn <= True;
508
509 end
510 else if(controlReg[2:1] == 1 ) begin // Stop
511 $display("Invalid Stop",mTransFSM);
512 mTransFSM <= End;
513 dOutEn <= True;
514 cOutEn <= True;
515 sendInd <= 2;
516 ber <=1; //~ add bus error functionality
517 end
518 endrule
519
520 (* doc = "Reset the I2C State Machine and wait for another transaction request" *)
521 rule reset_state(mTransFSM == ResetI2C && pwI2C && ber == 0);
522 st_toggle <= False;
523 dOutEn <= False;
524 cOutEn <= False;
525 i2ctimeout <= 1;
526 // Should it leave control of SCL And SDA Line
527 controlReg <= 128;
528 statusReg <= 1;
529 resetcount <= 0 ;
530 sendInd <= 2;
531 mTransFSM <= Idle;
532
533 //~/ should we have a reset interupt
534 endrule
535
536
537
538
539
540 (* doc = "Send Start bit to the Slave" *)
541 rule send_start_trans(val_SCL_in == 1 && startBit && pwesoCond && bb == 1); //~ pwi2c & i2c on & both transrec - sta
542
543 $display("Came Here",sendInd);
544 if(val_SDA == 0)
545 begin
546 mTransFSM <= SendAddr; //~Once Cycle Delay whats 0-1 ?
547 $display("start sent");
548 bb <= 0;
549 sta <=0 ;
550 s3 <= 'h0B;
551 end
552 else
553 begin
554 val_SDA <= startSig[sendInd];
555 sendInd <= sendInd-1;
556 end //TODO check what happens when multiple start has to be send!!!!
557 endrule
558
559
560
561
562 rule send_rtstart_trans(val_SCL_in == 1 && mTransFSM == RTSTA && pwesoCond ); //~ pwi2c & i2c on & both transrec - sta
563 $display("Here");
564 if(val_SDA == 0) //If I read val_SDA - Next transaction is x or it is normal--- Why? //~ it was because of code bug send ind going to -1
565 begin
566 mTransFSM <= Intrpt; //~Once Cycle Delay whats 0-1 ?
567 $display("RT start sent");
568 pin<=0;
569 i2ctimeout <=1;
570 bb <= 0;
571 sta <=0 ;
572 s3 <= 'h0A;
573 end
574 else
575 begin
576 val_SDA <= startSig[sendInd];
577 sendInd <= sendInd-1;
578 end //TODO check what happens when multiple start has to be send!!!!
579 endrule
580
581 (* doc = "Send Slave Address for Transaction" *)
582 rule send_addr(sendAddr && sclSync); // Fires On Falling Edge
583 sendInd <= 2;
584 if(dataBit == 0) begin
585 dOutEn <= False;
586 mTransFSM <= Ack;
587 s3 <= 8'b1;
588 if(s0[0] == 0)
589 operation <= Write;
590 else
591 operation <= Read;
592 $display("Address Sent");
593 end
594 else
595 begin
596 dataBit <= dataBit - 1;
597 val_SDA <= s0[dataBit-1];
598 $display("Sending Bit %d In neg cycle Bit %d ", dataBit - 1,s0[dataBit-1]);
599 end
600
601 endrule
602
603
604
605
606
607
608 rule check_Ack(ackCond && pwsclCond); //Should Fire When SCL is high //~shouldn't it be pwsclcond or sclsync
609 //$display("Value : %d ,Condition : ",line_SDA,line_SDA!=0 );
610 dataBit <= 8;
611 i2ctimeout <= 1;
612 if(val_SDA_in != 0 && val_SCL == 0 ) //Line SCL is actually high
613 begin //Bus Error
614 ad0_lrb <= 1;
615 mTransFSM <= NAck;
616 dOutEn <= True;
617 ber <= 1;
618 if(sendAddr)
619 s3 <= 'h03;
620 else if(mTransFSM == ReadData)
621 s3 <= 'h04;
622 else
623 s3 <= 'h05;
624 $display("Acknowledgement Not Received Bus Error");
625 end
626 else if(val_SCL == 1) begin // Acknowledgement is done // Here line scl is actually low
627 pin <= 0;
628 $display("eni : %d",eni);
629 if(mTransFSM == SendAddr || mTransFSM == SendData )
630 s3 <= 'h02;
631 else
632 s3 <= 'h06;
633
634 ad0_lrb <= 0;
635 dOutEn<= True;
636 mTransFSM <= Intrpt;
637 $display("Acknowledgement Received. Waiting For Interupt Serve ",$time);
638 // $finish();
639 end
640 endrule
641
642
643
644
645
646
647
648 (* doc = "Wait for the generated interrupt to be serviced" *)
649 rule wait_interrupt(intCond && pwesoCond && val_SCL_in ==0 );
650 if(pin == 1'b0) begin
651
652 // $display("Waiting For Interrupt %h",controlReg,$time); //Pitfall if eso was turned off in wait interupt
653 val_SCL <= 0;
654 if(i2ctime[14] == 1)
655 i2ctimeout <= i2ctimeout + 1; //~ Have to add timer interupt also reset timer count
656
657 if(i2ctimeout <= i2ctime[13:0] ) //14 as enable int 15 as int
658 begin //Reset state
659 mTransFSM <= End; i2ctime[15] <=1;
660 s3 <= 'h0C;
661 end
662 else
663 st_toggle <= False;
664 end
665 else begin
666
667 $display("Interupt Is Served. Along with pin & control reg - %d & operation - %d ",controlReg,operation);
668 i2ctimeout <= 1;
669 st_toggle <= True;
670 if(controlReg[2:1] == 2)
671 begin
672 $display("Invalid Start");
673 ber <=1 ;
674 mTransFSM <= ResetI2C;
675 end
676 else if(controlReg[2:1] == 1)
677 begin //Signalling the end of transaction
678 mTransFSM <= End;
679 val_SDA <= 0;
680 $display("Received Stop Condition ",val_SDA);
681 end
682 else if(s3 == 'h0A) begin
683 mTransFSM <= SendAddr;
684 dOutEn <= True;
685 $display("Sending RT Address Bit %d In negative cycle Bit %d",dataBit - 1 , s0[dataBit - 1]);
686 dataBit <= dataBit - 1;
687 val_SDA <= s0[dataBit - 1];
688
689 end
690 else if(operation == Write) begin
691 mTransFSM <= SendData;
692 dOutEn <= True;
693 $display("Sending Bit %d In negative cycle Bit %d",dataBit - 1 , s0[dataBit - 1]);
694 dataBit <= dataBit - 1;
695 val_SDA <= s0[dataBit - 1];
696 end
697
698 else begin
699 if(ack == 0) //~ Value SCL what hc0 doesnt = nack?
700 last_byte_read <= True;
701 if(val_SCL == 0) begin //Hopefully this should ward off read sync error that might //~ discuss maybe
702 mTransFSM <= ReadData;
703 dOutEn <= False; //~ when we set true
704 end
705 end
706 end
707 endrule
708
709 (* doc = "Shift the 8-bit data through the SDA line at each low pulse of SCL" *)
710 rule send_data(mTransFSM == SendData && sclSync);
711 $display("WData: TriState SDA Value : %b", val_SDA._read,$time);
712 if(dataBit == 'd0) begin //~ smthhng
713 mTransFSM <= Ack;
714 dOutEn <= False;
715 $display("Leaving Bus For Acknowledge");
716 end
717 else
718 begin
719 $display("Sending Bit %d In negative cycle Bit %d",dataBit - 1 , s0[dataBit - 1]);
720 dataBit <= dataBit - 1;
721 val_SDA <= s0[dataBit - 1];
722 end
723 endrule
724
725 /*
726 (* doc = "Send a NoAck to Slave signifying the end of read transaction" *)
727 rule send_Nack(mTransFSM == NAck && pwsclCond); //~
728 val_SDA <= 1;
729 if(line_SCL._read == 0) begin //~ why scl
730 mTransFSM <= End;
731 end
732 //Makes sense after interrupt support is added
733 endrule
734 */
735
736 (* doc = "Receive the 8-bit data through the SDA line at each high pulse of SCL" *)
737 rule receive_data(mTransFSM == ReadData && sclnSync); //~ Rising Edge
738 $display("Receiving Bit %d In Positive Cycle And Bit %d",dataBit - 1,val_SDA_in);
739 dataBit <= dataBit - 1;
740 s0[dataBit - 1 ] <= val_SDA_in;
741 endrule
742
743 rule resetfilter;
744 if(rstsig == 1)
745 begin
746 resetcount <= resetcount + 1;
747 if(resetcount == 'd59)
748 begin
749 ber <= 0;
750 mTransFSM <= ResetI2C;
751 $display("Resetting");
752 s3 <= 'h07;
753 end
754 end
755 else
756 resetcount <= 0 ;
757 endrule
758
759 rule receive_data1((mTransFSM == ReadData || mTransFSM == NAck_1) && sclSync && ( dataBit == 0 || dataBit == 8) ); //~ Falling Edge
760 if(dataBit == 0)
761 begin
762 if(!last_byte_read) begin
763 $display("Going to Ack, Taking controll of the bus btw");
764 mTransFSM <= Ack;
765 val_SDA <= 0;
766 dOutEn <= True;
767 end
768 else begin
769 $display("Going to NAck, Taking controll of the bus btw");
770 mTransFSM <= NAck_1;
771 val_SDA <= 1;
772 dataBit <= 8 ;
773 dOutEn <= True;
774 pin <=0 ;
775 s3 <= 'h08;
776 last_byte_read <= False;
777 end
778 end
779 else
780 mTransFSM <= NAck;
781 endrule
782
783 rule wait_interrupt_receive_end ( dataBit == 8 && mTransFSM == NAck && val_SCL_in == 0);
784 if(controlReg[2:1] == 1)
785 begin
786 mTransFSM <= End;
787 val_SDA <= 0;
788 st_toggle <= True;
789 end
790 else
791 st_toggle<=False; //Stop Signal goes from 0 to 1
792 endrule
793
794
795 (* doc = "Send a STOP bit signifying no more transaction from this master" *)
796 rule send_stop_condition(stopBit && pwesoCond && val_SCL_in == 1); //~ it might be fal edge
797 $display("Sending Stop SDA Value : %b SCL Value : %b", val_SDA._read,val_SCL._read,$time);
798
799 if(val_SDA == 1) begin
800 mTransFSM <= Idle;
801 // statusReg <= 'b0000001;
802 sto <= 0;
803 st_toggle <= False;
804 //Interrupt needs to be sent and final course of action is determined
805 end
806 else
807 begin
808 val_SDA <= stopSig[sendInd];
809 sendInd <= sendInd - 1; end
810 endrule
811
812 //Rules for Communicating with AXI-4
813 //TODO - Code different conditions such as only certain registers can be accessed at certain times
814 rule rl_rd_req_rsp;
815 //TODO - What if a read request is issued to the data register
816 $display("AXI Read Request time %d pin %d",$time,pin);
817 let req <- pop_o (s_xactor.o_rd_addr);
818 I2C i2c = S0;
819 if(truncate(req.araddr) == pack(i2c)) begin
820 pin <=1;
821 $display("Setting pin to 1 in read phase");
822 end
823 else $display("Not equal %h, %h",req.araddr,pack(i2c));
824 I2C i2c1 = Status;
825 if(truncate(req.araddr) == pack(i2c1)) begin
826 $display("Clearing Status Bits");
827 ber <= 0;
828 end
829
830 I2C i2c2 = SCL;
831 I2C i2c3 = Time;
832 Bit#(`Reg_width) rdreg ;
833 if(truncate(req.araddr) == pack(i2c2))
834 rdreg = duplicate(c_scl);
835 else if(truncate(req.araddr) == pack(i2c3))
836 rdreg = duplicate(i2ctime);
837 else
838 rdreg = duplicate(get_i2c(unpack(truncate(req.araddr))));
839 $display("Register Read %h: Value: %d ",req.araddr,rdreg);
840 let resq = AXI4_Lite_Rd_Data {rresp : AXI4_LITE_OKAY, rdata : rdreg ,ruser: 0};
841 s_xactor.i_rd_data.enq(resq);
842
843 endrule
844
845 rule rl_wr_req;
846 $display("AXI Write Request ",$time);
847 let wr_addr <- pop_o (s_xactor.o_wr_addr);
848 let wr_data <- pop_o (s_xactor.o_wr_data);
849 $display("Wr_addr : %h Wr_data: %h", wr_addr.awaddr, wr_data.wdata);
850 set_i2c(unpack(truncate(wr_addr.awaddr)),truncate(wr_data.wdata));
851 let resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_SLVERR, buser: wr_addr.awuser};
852 if(ber==1)
853 resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_SLVERR, buser: wr_addr.awuser};
854 else
855 resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_OKAY, buser: wr_addr.awuser};
856 s_xactor.i_wr_resp.enq(resp);
857 $display("Received Value %d",wr_data.wdata);
858 endrule
859
860
861
862 //Interface Definitions
863 /* interface I2C_out out;
864 interface sda = line_SDA.io;
865 interface scl = line_SCL.io;
866 endinterface*/
867
868 interface I2C_out out;
869 method Bit#(1) i2c_DRV0;
870 return drv0_rg[0];
871 endmethod
872 method Bit#(1) i2c_DRV1;
873 return drv1_rg[0];
874 endmethod
875 method Bit#(1) i2c_DRV2;
876 return drv2_rg[0];
877 endmethod
878 method Bit#(1) i2c_PD;
879 return pd_rg[0];
880 endmethod
881 method Bit#(1) i2c_PPEN;
882 return ppen_rg[0];
883 endmethod
884 method Bit#(1) i2c_PRG_SLEW;
885 return prg_slew_rg[0];
886 endmethod
887 method Bit#(1) i2c_PUQ;
888 return puq_rg[0];
889 endmethod
890 method Bit#(1) i2c_PWRUPZHL;
891 return pwrupzhl_rg[0];
892 endmethod
893 method Bit#(1) i2c_PWRUP_PULL_EN;
894 return pwrup_pull_en_rg[0];
895 endmethod
896 interface scl_out = interface Get
897 method ActionValue#(Bit#(1)) get;
898 return val_SCL;
899 endmethod
900 endinterface;
901 interface scl_in = interface Put
902 method Action put(Bit#(1) in);
903 val_SCL_in <= in;
904 endmethod
905 endinterface;
906 interface scl_out_en = interface Get
907 method ActionValue#(Bit#(1)) get;
908 return pack(cOutEn && eso == 1'b1);
909 endmethod
910 endinterface;
911 interface sda_out = interface Get
912 method ActionValue#(Bit#(1)) get;
913 return val_SDA;
914 endmethod
915 endinterface;
916 interface sda_in = interface Put
917 method Action put(Bit#(1) in);
918 val_SDA_in <= in;
919 endmethod
920 endinterface;
921 interface sda_out_en = interface Get
922 method ActionValue#(Bit#(1)) get;
923 return pack(dOutEn && eso == 1'b1);
924 endmethod
925 endinterface;
926 endinterface
927
928 //AXI-4 Interface
929 interface slave_i2c_axi = s_xactor.axi_side;
930
931 method Bit#(1) isint=~pin & eni;
932 /*let lv_res=
933 if(lv_res==1)
934 $display($time,"I2C: Interrupt is high");
935 return lv_res;*/
936 // endmethod
937
938 method Bit#(1) isber = ber;
939
940 method Bit#(1) timerint();
941 return i2ctime[15];
942 endmethod
943
944 method Action resetc( Bit#(1) rst );
945 rstsig <= rst;
946 endmethod
947 //Test Interface
948 /* method Action set_eso(Bit#(1) temp_eso);
949 eso <= temp_eso;
950 endmethod*/
951 /*
952 method Action set_s2(Bit#(8) temp_s2);
953 s2 <= temp_s2;
954 endmethod
955
956 method Action set_s1(Bit#(8) temp_s1);
957 mcontrolReg <= temp_s1;
958 /*pin <= temp_s1[7];
959 eso <= temp_s1[6];
960 es1 <= temp_s1[5];
961 es2 <= temp_s1[4];
962 eni <= temp_s1[3];
963 sta <= temp_s1[2];
964 sto <= temp_s1[1];
965 ack <= temp_s1[0];
966 $display("temp_s1: %b",temp_s1);
967 endmethod
968
969 method Action set_s0(Bit#(8) temp_s0);
970 s0 <= temp_s0;
971 endmethod
972 */
973 endmodule
974 //
975 // (*synthesize*)
976 // module mkI2CController_wrap(I2C_IFC_wrap);
977 // I2C_IFC dut <- mkI2CController();
978 // TriState#(Bit#(1)) line_SCL <- mkTriState(dut.out.scl_out_en, dut.out.scl_out);
979 // TriState#(Bit#(1)) line_SDA <- mkTriState(dut.out.sda_out_en, dut.out.sda_out);
980 // rule send_input_scl;
981 // dut.out.scl_in(line_SCL._read);
982 // endrule
983 // rule send_input_sda;
984 // dut.out.sda_in(line_SDA._read);
985 // endrule
986 // interface slave_i2c_axi_wrap = dut.slave_i2c_axi;
987 // method isint_wrap = dut.isint;
988 // method resetc_wrap = dut.resetc;
989 // method timerint_wrap = dut.timerint;
990 // method isber_wrap = dut.isber;
991 // interface I2C_out_tri out_tri;
992 // interface sda = line_SDA.io;
993 // interface scl = line_SCL.io;
994 // endinterface
995 // endmodule
996 // ===============================================
997 /*
998 // ===============================================
999 // Test Bench
1000 module mkTb(Empty);
1001 Reg#(Bit#(32)) counter <- mkReg(0);
1002 //Reg#(Bit#(1)) scl_dr <- mkReg(0);
1003 //Reg#(Bit#(1)) sda_dr <- mkReg(0);
1004 TriState#(Bit#(1)) scl_dr <- mkTriState(False,0);
1005 TriState#(Bit#(1)) sda_dr <- mkTriState(False,0);
1006 I2C_IFC test <- mkI2CController();
1007
1008 rule count;
1009 counter <= counter + 1;
1010 //$display("counter : %d",counter);
1011 if(counter == 50000)
1012 $finish(0);
1013 endrule
1014
1015 rule send_values(counter == 1);
1016 //test.set_eso(1'b1);
1017 test.set_s2(8'd4);
1018 test.set_s1('hc5);
1019 test.set_s0('ha5);
1020 endrule
1021
1022 endmodule
1023 // ===============================================
1024 */endpackage