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 // ================================================
25 // ================================================
26 // Project Imports and Includes
27 import AXI4_Lite_Types ::*;
28 import AXI4_Lite_Fabric ::*;
30 import defined_types ::*;
33 import Semi_FIFOF ::*;
34 `include "instance_defines.bsv"
35 `include "I2C_Defs.bsv"
37 // ================================================
38 // Interface Declarations
39 /*(* always_enabled, always_ready *)
42 interface Inout#(Bit#(1)) sda;
44 interface Inout#(Bit#(1)) scl;
47 (*always_enabled, always_ready*)
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;
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 );
84 interface I2C_out_tri;
86 interface Inout#(Bit#(1)) sda;
88 interface Inout#(Bit#(1)) scl;
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();
101 // ==============================================
102 // Function Definitions
103 function Reg#(t) readOnlyReg(t r); //~ Useless :: Processor needs to be given access to mstatus
104 return (interface Reg;
106 method Action _write(t x) = noAction;
110 function Reg#(t) writeOnlyReg(Reg#(t) r)
114 return (interface Reg;
116 method Action _write(t x);
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);
130 // ==============================================
132 (* doc = "This Module implements the I2C Master/Slave Controller based on NXP PCF8584" *)
134 module mkI2CController(I2C_IFC) //For the sake of ease of compiling - having a non-polymorphic type TODO Change
137 //////////////////////////////////////////////////////////////////////////////
138 ///////////Register Declarations/////////////////////////////////////////////
139 ////////////////////////////////////////////////////////////////////////////
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
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
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
174 Reg#(I2C_RegWidth) s3 <- mkReg(9); //Interrupt Vector Register
176 //~/Discuss : If there are only 4-5 interupts why use a 8 bit register And decide upon final values for interupts
178 Reg#(I2C_RegWidth) s0 <- mkRegU(); //Data Shift Register
179 //~ Maybe better to have preset Values rather than random
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
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
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
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
210 ////########## COnfigurable Registers Over.....
211 /// Unused Pins : zero
212 /// : s3 4 MSB s2 5,6 bit
213 ////########################################
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
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));
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;
232 //Maintenance variables
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);
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
257 //Module Instantiations
258 AXI4_Lite_Slave_Xactor_IFC #(`PADDR, `Reg_width, `USERSPACE) s_xactor <- mkAXI4_Lite_Slave_Xactor;
263 //Function to access Registers
264 function I2C_RegWidth get_i2c(I2C i2c);
265 Reg#(I2C_RegWidth) regi2c = (
267 Control : mcontrolReg; //~ Are we creating new reg each time
278 PRG_SLEW: prg_slew_rg;
280 PWRUPZHL: pwrupzhl_rg;
281 PWRUP_PULL_EN : pwrup_pull_en_rg;
282 default : readOnlyReg(8'b0);
288 //Function to write into the registers
289 function Action set_i2c(I2C i2c,Bit#(32) value );
293 zero <= 0; //Indicates to the Driver that the control register has been written in the beginning
295 $display("Control Written");
296 if(!intCond && mTransFSM != NAck)
298 if(value[2:1] == 2 && (intCond || mTransFSM == NAck) && bb == 0 ) //RT START CONDITIONS
305 $display("Repeated Start Instruction received");
306 controlReg <= 8'hc5 | truncate(value); //TODO 45h Check this out
310 else if(value[2:1] == 2 && bb == 0)
312 $display("Invalid Rt Start");
317 ber <=1; //~ add bus error functionality
320 mcontrolReg._write(truncate(value));
322 S01 : begin s01._write(truncate(value)); $display("S01 written"); end
323 S0 : begin s0._write(truncate(value)); $display("S0 written"); pin <=1; end
331 s2._write(truncate(value));
333 $display("S2 written");
335 S3 : s3._write(truncate(value)); //~ default
342 c_scl._write(truncate(value));
345 $display("Received scl but eso was %d",eso);
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];
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" *)
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" *)
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");
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
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");
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
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;
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;
407 // $display("tick i2c sent");
408 // $display("cprescaler : %d rprescaler : %d",cprescaler,rprescaler,$time);
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
414 // $display("coSCL: %d", coSCL - 1);
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);
421 // $display("tick sent");
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
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
436 // $display("From toggle rule :",~val_SCL);
437 //$display("TriState SCL Value : %b", line_SCL._read,$time);
442 //////////////State Machine Implementation ////////////////////////////////
444 Initially, Module Is Off Eso = 0.
445 Only Check Config Register And write into register rules should fire.
447 ESO = 0 => Go to reset state.
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
465 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
467 ///////////////////////////////////////////////////////////////////////////
469 rule idler(mTransFSM == Idle);
470 if(cycwaste == 0) begin
475 cycwaste <= cycwaste + 1;
477 else if(cycwaste == 'd600)
479 mTransFSM <= Idleready;
484 // Should it leave control of SCL And SDA Line
490 cycwaste <= cycwaste + 1;
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");
500 else if(controlReg[2:1] == 2)
505 $display("Start Received");
510 else if(controlReg[2:1] == 1 ) begin // Stop
511 $display("Invalid Stop",mTransFSM);
516 ber <=1; //~ add bus error functionality
520 (* doc = "Reset the I2C State Machine and wait for another transaction request" *)
521 rule reset_state(mTransFSM == ResetI2C && pwI2C && ber == 0);
526 // Should it leave control of SCL And SDA Line
533 //~/ should we have a reset interupt
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
543 $display("Came Here",sendInd);
546 mTransFSM <= SendAddr; //~Once Cycle Delay whats 0-1 ?
547 $display("start sent");
554 val_SDA <= startSig[sendInd];
555 sendInd <= sendInd-1;
556 end //TODO check what happens when multiple start has to be send!!!!
562 rule send_rtstart_trans(val_SCL_in == 1 && mTransFSM == RTSTA && pwesoCond ); //~ pwi2c & i2c on & both transrec - sta
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
566 mTransFSM <= Intrpt; //~Once Cycle Delay whats 0-1 ?
567 $display("RT start sent");
576 val_SDA <= startSig[sendInd];
577 sendInd <= sendInd-1;
578 end //TODO check what happens when multiple start has to be send!!!!
581 (* doc = "Send Slave Address for Transaction" *)
582 rule send_addr(sendAddr && sclSync); // Fires On Falling Edge
584 if(dataBit == 0) begin
592 $display("Address Sent");
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]);
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 );
612 if(val_SDA_in != 0 && val_SCL == 0 ) //Line SCL is actually high
620 else if(mTransFSM == ReadData)
624 $display("Acknowledgement Not Received Bus Error");
626 else if(val_SCL == 1) begin // Acknowledgement is done // Here line scl is actually low
628 $display("eni : %d",eni);
629 if(mTransFSM == SendAddr || mTransFSM == SendData )
637 $display("Acknowledgement Received. Waiting For Interupt Serve ",$time);
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
652 // $display("Waiting For Interrupt %h",controlReg,$time); //Pitfall if eso was turned off in wait interupt
655 i2ctimeout <= i2ctimeout + 1; //~ Have to add timer interupt also reset timer count
657 if(i2ctimeout <= i2ctime[13:0] ) //14 as enable int 15 as int
659 mTransFSM <= End; i2ctime[15] <=1;
667 $display("Interupt Is Served. Along with pin & control reg - %d & operation - %d ",controlReg,operation);
670 if(controlReg[2:1] == 2)
672 $display("Invalid Start");
674 mTransFSM <= ResetI2C;
676 else if(controlReg[2:1] == 1)
677 begin //Signalling the end of transaction
680 $display("Received Stop Condition ",val_SDA);
682 else if(s3 == 'h0A) begin
683 mTransFSM <= SendAddr;
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];
690 else if(operation == Write) begin
691 mTransFSM <= SendData;
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];
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
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
715 $display("Leaving Bus For Acknowledge");
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];
726 (* doc = "Send a NoAck to Slave signifying the end of read transaction" *)
727 rule send_Nack(mTransFSM == NAck && pwsclCond); //~
729 if(line_SCL._read == 0) begin //~ why scl
732 //Makes sense after interrupt support is added
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;
746 resetcount <= resetcount + 1;
747 if(resetcount == 'd59)
750 mTransFSM <= ResetI2C;
751 $display("Resetting");
759 rule receive_data1((mTransFSM == ReadData || mTransFSM == NAck_1) && sclSync && ( dataBit == 0 || dataBit == 8) ); //~ Falling Edge
762 if(!last_byte_read) begin
763 $display("Going to Ack, Taking controll of the bus btw");
769 $display("Going to NAck, Taking controll of the bus btw");
776 last_byte_read <= False;
783 rule wait_interrupt_receive_end ( dataBit == 8 && mTransFSM == NAck && val_SCL_in == 0);
784 if(controlReg[2:1] == 1)
791 st_toggle<=False; //Stop Signal goes from 0 to 1
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);
799 if(val_SDA == 1) begin
801 // statusReg <= 'b0000001;
804 //Interrupt needs to be sent and final course of action is determined
808 val_SDA <= stopSig[sendInd];
809 sendInd <= sendInd - 1; end
812 //Rules for Communicating with AXI-4
813 //TODO - Code different conditions such as only certain registers can be accessed at certain times
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);
819 if(truncate(req.araddr) == pack(i2c)) begin
821 $display("Setting pin to 1 in read phase");
823 else $display("Not equal %h, %h",req.araddr,pack(i2c));
825 if(truncate(req.araddr) == pack(i2c1)) begin
826 $display("Clearing Status Bits");
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);
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);
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};
853 resp = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_SLVERR, buser: wr_addr.awuser};
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);
862 //Interface Definitions
863 /* interface I2C_out out;
864 interface sda = line_SDA.io;
865 interface scl = line_SCL.io;
868 interface I2C_out out;
869 method Bit#(1) i2c_DRV0;
872 method Bit#(1) i2c_DRV1;
875 method Bit#(1) i2c_DRV2;
878 method Bit#(1) i2c_PD;
881 method Bit#(1) i2c_PPEN;
884 method Bit#(1) i2c_PRG_SLEW;
885 return prg_slew_rg[0];
887 method Bit#(1) i2c_PUQ;
890 method Bit#(1) i2c_PWRUPZHL;
891 return pwrupzhl_rg[0];
893 method Bit#(1) i2c_PWRUP_PULL_EN;
894 return pwrup_pull_en_rg[0];
896 interface scl_out = interface Get
897 method ActionValue#(Bit#(1)) get;
900 interface scl_in = interface Put
901 method Action put(Bit#(1) in);
905 interface scl_out_en = interface Get
906 method ActionValue#(Bit#(1)) get;
907 return pack(cOutEn && eso == 1'b1);
910 interface sda_out = interface Get
911 method ActionValue#(Bit#(1)) get;
914 interface sda_in = interface Put
915 method Action put(Bit#(1) in);
919 interface sda_out_en = interface Get
920 method ActionValue#(Bit#(1)) get;
921 return pack(dOutEn && eso == 1'b1);
927 interface slave_i2c_axi = s_xactor.axi_side;
929 method Bit#(1) isint=~pin & eni;
932 $display($time,"I2C: Interrupt is high");
936 method Bit#(1) isber = ber;
938 method Bit#(1) timerint();
942 method Action resetc( Bit#(1) rst );
946 /* method Action set_eso(Bit#(1) temp_eso);
950 method Action set_s2(Bit#(8) temp_s2);
954 method Action set_s1(Bit#(8) temp_s1);
955 mcontrolReg <= temp_s1;
964 $display("temp_s1: %b",temp_s1);
967 method Action set_s0(Bit#(8) temp_s0);
974 // module mkI2CController_wrap(I2C_IFC_wrap);
975 // I2C_IFC dut <- mkI2CController();
976 // TriState#(Bit#(1)) line_SCL <- mkTriState(dut.out.scl_out_en, dut.out.scl_out);
977 // TriState#(Bit#(1)) line_SDA <- mkTriState(dut.out.sda_out_en, dut.out.sda_out);
978 // rule send_input_scl;
979 // dut.out.scl_in(line_SCL._read);
981 // rule send_input_sda;
982 // dut.out.sda_in(line_SDA._read);
984 // interface slave_i2c_axi_wrap = dut.slave_i2c_axi;
985 // method isint_wrap = dut.isint;
986 // method resetc_wrap = dut.resetc;
987 // method timerint_wrap = dut.timerint;
988 // method isber_wrap = dut.isber;
989 // interface I2C_out_tri out_tri;
990 // interface sda = line_SDA.io;
991 // interface scl = line_SCL.io;
994 // ===============================================
996 // ===============================================
999 Reg#(Bit#(32)) counter <- mkReg(0);
1000 //Reg#(Bit#(1)) scl_dr <- mkReg(0);
1001 //Reg#(Bit#(1)) sda_dr <- mkReg(0);
1002 TriState#(Bit#(1)) scl_dr <- mkTriState(False,0);
1003 TriState#(Bit#(1)) sda_dr <- mkTriState(False,0);
1004 I2C_IFC test <- mkI2CController();
1007 counter <= counter + 1;
1008 //$display("counter : %d",counter);
1009 if(counter == 50000)
1013 rule send_values(counter == 1);
1014 //test.set_eso(1'b1);
1021 // ===============================================