2 Copyright (c) 2017, IIT Madras
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
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.
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 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
14 Author Names : Vinod.G, Ayush Mittal
15 Email ID : g.vinod1993@gmail.com, 29ayush@gmail.com
17 I2C Controller top module which is compliant with UM10204 I2C Specification provided by NXP Semiconductors. This is a single master, multiple slave controller.
19 // ================================================
24 // ================================================
25 // Project Imports and Includes
26 import AXI4_Lite_Types ::*;
27 import AXI4_Lite_Fabric ::*;
29 import defined_types ::*;
32 import Semi_FIFOF ::*;
33 `include "instance_defines.bsv"
34 `include "I2C_Defs.bsv"
36 // ================================================
37 // Interface Declarations
38 /*(* always_enabled, always_ready *)
41 interface Inout#(Bit#(1)) sda;
43 interface Inout#(Bit#(1)) scl;
46 (*always_enabled, always_ready*)
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;
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 );
83 interface I2C_out_tri;
85 interface Inout#(Bit#(1)) sda;
87 interface Inout#(Bit#(1)) scl;
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();
100 // ==============================================
101 // Function Definitions
102 function Reg#(t) readOnlyReg(t r); //~ Useless :: Processor needs to be given access to mstatus
103 return (interface Reg;
105 method Action _write(t x) = noAction;
109 function Reg#(t) writeOnlyReg(Reg#(t) r)
113 return (interface Reg;
115 method Action _write(t x);
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);
129 // ==============================================
131 (* doc = "This Module implements the I2C Master/Slave Controller based on NXP PCF8584" *)
133 module mkI2CController(I2C_IFC) //For the sake of ease of compiling - having a non-polymorphic type TODO Change
136 //////////////////////////////////////////////////////////////////////////////
137 ///////////Register Declarations/////////////////////////////////////////////
138 ////////////////////////////////////////////////////////////////////////////
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
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
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
173 Reg#(I2C_RegWidth) s3 <- mkReg(9); //Interrupt Vector Register
175 //~/Discuss : If there are only 4-5 interupts why use a 8 bit register And decide upon final values for interupts
177 Reg#(I2C_RegWidth) s0 <- mkRegU(); //Data Shift Register
178 //~ Maybe better to have preset Values rather than random
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
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
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
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
209 ////########## COnfigurable Registers Over.....
210 /// Unused Pins : zero
211 /// : s3 4 MSB s2 5,6 bit
212 ////########################################
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
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));
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;
231 //Maintenance variables
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);
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
256 //Module Instantiations
257 AXI4_Lite_Slave_Xactor_IFC #(`PADDR, `Reg_width, `USERSPACE) s_xactor <- mkAXI4_Lite_Slave_Xactor;
262 //Function to access Registers
263 function I2C_RegWidth get_i2c(I2C i2c);
264 Reg#(I2C_RegWidth) regi2c = (
266 Control : mcontrolReg; //~ Are we creating new reg each time
277 PRG_SLEW: prg_slew_rg;
279 PWRUPZHL: pwrupzhl_rg;
280 PWRUP_PULL_EN : pwrup_pull_en_rg;
281 default : readOnlyReg(8'b0);
287 //Function to write into the registers
288 function Action set_i2c(I2C i2c,Bit#(32) value );
292 zero <= 0; //Indicates to the Driver that the control register has been written in the beginning
294 $display("Control Written");
295 if(!intCond && mTransFSM != NAck)
297 if(value[2:1] == 2 && (intCond || mTransFSM == NAck) && bb == 0 ) //RT START CONDITIONS
304 $display("Repeated Start Instruction received");
305 controlReg <= 8'hc5 | truncate(value); //TODO 45h Check this out
309 else if(value[2:1] == 2 && bb == 0)
311 $display("Invalid Rt Start");
316 ber <=1; //~ add bus error functionality
319 mcontrolReg._write(truncate(value));
321 S01 : begin s01._write(truncate(value)); $display("S01 written"); end
322 S0 : begin s0._write(truncate(value)); $display("S0 written"); pin <=1; end
330 s2._write(truncate(value));
332 $display("S2 written");
334 S3 : s3._write(truncate(value)); //~ default
341 c_scl._write(truncate(value));
344 $display("Received scl but eso was %d",eso);
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];
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" *)
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" *)
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");
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
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");
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
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;
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;
406 // $display("tick i2c sent");
407 // $display("cprescaler : %d rprescaler : %d",cprescaler,rprescaler,$time);
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
413 // $display("coSCL: %d", coSCL - 1);
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);
420 // $display("tick sent");
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
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
435 // $display("From toggle rule :",~val_SCL);
436 //$display("TriState SCL Value : %b", line_SCL._read,$time);
441 //////////////State Machine Implementation ////////////////////////////////
443 Initially, Module Is Off Eso = 0.
444 Only Check Config Register And write into register rules should fire.
446 ESO = 0 => Go to reset state.
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
464 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
466 ///////////////////////////////////////////////////////////////////////////
468 rule idler(mTransFSM == Idle);
469 if(cycwaste == 0) begin
474 cycwaste <= cycwaste + 1;
476 else if(cycwaste == 'd600)
478 mTransFSM <= Idleready;
483 // Should it leave control of SCL And SDA Line
489 cycwaste <= cycwaste + 1;
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");
499 else if(controlReg[2:1] == 2)
504 $display("Start Received");
509 else if(controlReg[2:1] == 1 ) begin // Stop
510 $display("Invalid Stop",mTransFSM);
515 ber <=1; //~ add bus error functionality
519 (* doc = "Reset the I2C State Machine and wait for another transaction request" *)
520 rule reset_state(mTransFSM == ResetI2C && pwI2C && ber == 0);
525 // Should it leave control of SCL And SDA Line
532 //~/ should we have a reset interupt
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
542 $display("Came Here",sendInd);
545 mTransFSM <= SendAddr; //~Once Cycle Delay whats 0-1 ?
546 $display("start sent");
553 val_SDA <= startSig[sendInd];
554 sendInd <= sendInd-1;
555 end //TODO check what happens when multiple start has to be send!!!!
561 rule send_rtstart_trans(val_SCL_in == 1 && mTransFSM == RTSTA && pwesoCond ); //~ pwi2c & i2c on & both transrec - sta
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
565 mTransFSM <= Intrpt; //~Once Cycle Delay whats 0-1 ?
566 $display("RT start sent");
575 val_SDA <= startSig[sendInd];
576 sendInd <= sendInd-1;
577 end //TODO check what happens when multiple start has to be send!!!!
580 (* doc = "Send Slave Address for Transaction" *)
581 rule send_addr(sendAddr && sclSync); // Fires On Falling Edge
583 if(dataBit == 0) begin
591 $display("Address Sent");
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]);
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 );
611 if(val_SDA_in != 0 && val_SCL == 0 ) //Line SCL is actually high
619 else if(mTransFSM == ReadData)
623 $display("Acknowledgement Not Received Bus Error");
625 else if(val_SCL == 1) begin // Acknowledgement is done // Here line scl is actually low
627 $display("eni : %d",eni);
628 if(mTransFSM == SendAddr || mTransFSM == SendData )
636 $display("Acknowledgement Received. Waiting For Interupt Serve ",$time);
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
651 // $display("Waiting For Interrupt %h",controlReg,$time); //Pitfall if eso was turned off in wait interupt
654 i2ctimeout <= i2ctimeout + 1; //~ Have to add timer interupt also reset timer count
656 if(i2ctimeout <= i2ctime[13:0] ) //14 as enable int 15 as int
658 mTransFSM <= End; i2ctime[15] <=1;
666 $display("Interupt Is Served. Along with pin & control reg - %d & operation - %d ",controlReg,operation);
669 if(controlReg[2:1] == 2)
671 $display("Invalid Start");
673 mTransFSM <= ResetI2C;
675 else if(controlReg[2:1] == 1)
676 begin //Signalling the end of transaction
679 $display("Received Stop Condition ",val_SDA);
681 else if(s3 == 'h0A) begin
682 mTransFSM <= SendAddr;
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];
689 else if(operation == Write) begin
690 mTransFSM <= SendData;
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];
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
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
714 $display("Leaving Bus For Acknowledge");
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];
725 (* doc = "Send a NoAck to Slave signifying the end of read transaction" *)
726 rule send_Nack(mTransFSM == NAck && pwsclCond); //~
728 if(line_SCL._read == 0) begin //~ why scl
731 //Makes sense after interrupt support is added
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;
745 resetcount <= resetcount + 1;
746 if(resetcount == 'd59)
749 mTransFSM <= ResetI2C;
750 $display("Resetting");
758 rule receive_data1((mTransFSM == ReadData || mTransFSM == NAck_1) && sclSync && ( dataBit == 0 || dataBit == 8) ); //~ Falling Edge
761 if(!last_byte_read) begin
762 $display("Going to Ack, Taking controll of the bus btw");
768 $display("Going to NAck, Taking controll of the bus btw");
775 last_byte_read <= False;
782 rule wait_interrupt_receive_end ( dataBit == 8 && mTransFSM == NAck && val_SCL_in == 0);
783 if(controlReg[2:1] == 1)
790 st_toggle<=False; //Stop Signal goes from 0 to 1
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);
798 if(val_SDA == 1) begin
800 // statusReg <= 'b0000001;
803 //Interrupt needs to be sent and final course of action is determined
807 val_SDA <= stopSig[sendInd];
808 sendInd <= sendInd - 1; end
811 //Rules for Communicating with AXI-4
812 //TODO - Code different conditions such as only certain registers can be accessed at certain times
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);
818 if(truncate(req.araddr) == pack(i2c)) begin
820 $display("Setting pin to 1 in read phase");
822 else $display("Not equal %h, %h",req.araddr,pack(i2c));
824 if(truncate(req.araddr) == pack(i2c1)) begin
825 $display("Clearing Status Bits");
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);
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);
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};
852 resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_SLVERR, buser: wr_addr.awuser};
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);
861 //Interface Definitions
862 /* interface I2C_out out;
863 interface sda = line_SDA.io;
864 interface scl = line_SCL.io;
867 interface I2C_out out;
868 method Bit#(1) scl_out;
871 method Bit#(1) i2c_DRV0;
874 method Bit#(1) i2c_DRV1;
877 method Bit#(1) i2c_DRV2;
880 method Bit#(1) i2c_PD;
883 method Bit#(1) i2c_PPEN;
886 method Bit#(1) i2c_PRG_SLEW;
887 return prg_slew_rg[0];
889 method Bit#(1) i2c_PUQ;
892 method Bit#(1) i2c_PWRUPZHL;
893 return pwrupzhl_rg[0];
895 method Bit#(1) i2c_PWRUP_PULL_EN;
896 return pwrup_pull_en_rg[0];
898 method Action scl_in(Bit#(1) in);
901 method Bool scl_out_en;
902 return (cOutEn && eso == 1'b1);
904 method Bit#(1) sda_out;
907 method Action sda_in(Bit#(1) in);
910 method Bool sda_out_en;
911 return (dOutEn && eso == 1'b1);
916 interface slave_i2c_axi = s_xactor.axi_side;
918 method Bit#(1) isint=~pin & eni;
921 $display($time,"I2C: Interrupt is high");
925 method Bit#(1) isber = ber;
927 method Bit#(1) timerint();
931 method Action resetc( Bit#(1) rst );
935 /* method Action set_eso(Bit#(1) temp_eso);
939 method Action set_s2(Bit#(8) temp_s2);
943 method Action set_s1(Bit#(8) temp_s1);
944 mcontrolReg <= temp_s1;
953 $display("temp_s1: %b",temp_s1);
956 method Action set_s0(Bit#(8) temp_s0);
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);
970 // rule send_input_sda;
971 // dut.out.sda_in(line_SDA._read);
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;
983 // ===============================================
985 // ===============================================
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();
996 counter <= counter + 1;
997 //$display("counter : %d",counter);
1002 rule send_values(counter == 1);
1003 //test.set_eso(1'b1);
1010 // ===============================================