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