1 //
2 // Copyright (c) 2010-2021 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System;
9 using System.Linq;
10 using System.Collections.Generic;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Utilities;
13 using Antmicro.Renode.Core.Structure;
14 using Antmicro.Renode.Core.Structure.Registers;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Logging;
17 using Antmicro.Renode.Debugging;
18 
19 namespace Antmicro.Renode.Peripherals.I2C
20 {
21     public class LiteX_I2C_Zephyr : SimpleContainer<II2CPeripheral>, IDoubleWordPeripheral, IKnownSize
22     {
LiteX_I2C_Zephyr(IMachine machine)23         public LiteX_I2C_Zephyr(IMachine machine) : base(machine)
24         {
25             // 0 - clock, 1 - data
26             i2cDecoder = new BitPatternDetector(new [] { true, true }, this);
27             i2cDecoder.RegisterPatternHandler((prev, curr) => !prev[ClockSignal] && curr[ClockSignal], name: "clockRising", action: HandleClockRising);
28             i2cDecoder.RegisterPatternHandler((prev, curr) => prev[ClockSignal] && !curr[ClockSignal], name: "clockFalling", action: HandleClockFalling);
29             i2cDecoder.RegisterPatternHandler((prev, curr) => prev[ClockSignal] && curr[ClockSignal] && prev[DataSignal] && !curr[DataSignal], name: "start", action: HandleStartCondition);
30             i2cDecoder.RegisterPatternHandler((prev, curr) => prev[ClockSignal] && curr[ClockSignal] && !prev[DataSignal] && curr[DataSignal], name: "stop", action: HandleStopCondition);
31 
32 
33             IFlagRegisterField clockSignal, directionSignal, dataSignal;
34             var registers = new Dictionary<long, DoubleWordRegister>
35             {
36                 {(long)Registers.BitBang, new DoubleWordRegister(this, 0x5) // SCL && SDA are high by default
37                     .WithFlag(0, out clockSignal, name: "SCL")
38                     .WithFlag(1, out directionSignal, name: "OE")
39                     .WithFlag(2, out dataSignal, name: "SDA")
40                     .WithWriteCallback((_, val) => i2cDecoder.AcceptState(new [] { clockSignal.Value, dataSignal.Value }))
41                 },
42 
43                 {(long)Registers.Data, new DoubleWordRegister(this)
44                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ =>
45                     {
46                         if(directionSignal.Value)
47                         {
48                             this.Log(LogLevel.Warning, "Trying to read data, but the direction signal is set to OUTPUT");
49                             return true;
50                         }
51 
52                         if(bufferFromDevice.Count == 0)
53                         {
54                             this.Log(LogLevel.Noisy, "There are no more output bits to read");
55                             // SDA is high when no data
56                             return true;
57                         }
58 
59                         return bufferFromDevice.Peek();
60                     })
61                 },
62             };
63 
64             bufferFromDevice = new Queue<bool>();
65             bufferToDevice = new Stack<bool>();
66             bytesToDevice = new Queue<byte>();
67 
68             registersCollection = new DoubleWordRegisterCollection(this, registers);
69             Reset();
70         }
71 
Reset()72         public override void Reset()
73         {
74             registersCollection.Reset();
75             i2cDecoder.Reset();
76             ResetBuffers();
77 
78             state = State.Idle;
79             tickCounter = 0;
80             slave = null;
81             isRead = false;
82         }
83 
ReadDoubleWord(long offset)84         public uint ReadDoubleWord(long offset)
85         {
86             return registersCollection.Read(offset);
87         }
88 
WriteDoubleWord(long offset, uint value)89         public void WriteDoubleWord(long offset, uint value)
90         {
91             registersCollection.Write(offset, value);
92         }
93 
94         public long Size { get { return 0x10; } }
95 
HandleStopCondition(bool[] signals)96         private void HandleStopCondition(bool[] signals)
97         {
98             if(slave != null && bytesToDevice.Count > 0)
99             {
100                 this.Log(LogLevel.Noisy, "Writing data to the device");
101                 slave.Write(bytesToDevice.DequeueAll());
102             }
103 
104             ResetBuffers();
105 
106             this.Log(LogLevel.Noisy, "Stop condition detected in state: {0}", state);
107             state = State.Idle;
108         }
109 
HandleStartCondition(bool[] signals)110         private void HandleStartCondition(bool[] signals)
111         {
112             if(slave != null && bytesToDevice.Count > 0)
113             {
114                 this.Log(LogLevel.Noisy, "Writing data to the device");
115                 slave.Write(bytesToDevice.DequeueAll());
116             }
117 
118             ResetBuffers();
119 
120             this.Log(LogLevel.Noisy, "(repeated) Start condition detected in state: {0}", state);
121             state = State.Address;
122         }
123 
HandleClockRising(bool[] signals)124         private void HandleClockRising(bool[] signals)
125         {
126             switch(state)
127             {
128                 case State.Address:
129                 {
130                     this.Log(LogLevel.Noisy, "Appending address bit #{0}: {1}", bufferToDevice.Count, signals[DataSignal]);
131                     bufferToDevice.Push(signals[DataSignal]);
132 
133                     if(bufferToDevice.Count == 7)
134                     {
135                         var address = (int)BitHelper.GetValueFromBitsArray(bufferToDevice.PopAll());
136 
137                         this.Log(LogLevel.Noisy, "Address decoded: 0x{0:X}", address);
138                         state = State.Operation;
139 
140                         if(!TryGetByAddress(address, out slave))
141                         {
142                             this.Log(LogLevel.Warning, "Trying to access a non-existing I2C device at address 0x{0:X}", address);
143                         }
144                     }
145                     break;
146                 }
147 
148                 case State.Operation:
149                 {
150                     isRead = signals[DataSignal];
151                     this.Log(LogLevel.Noisy, "Operation decoded: {0}", isRead ? "read" : "write");
152 
153                     // write ACK(false) or NACK(true)
154                     bufferFromDevice.Enqueue(slave == null);
155 
156                     state = State.AddressAck;
157                     break;
158                 }
159 
160                 case State.AddressAck:
161                 {
162                     if(slave == null)
163                     {
164                         // ignore the rest of transmission until the next (repeated) start condition
165                         state = State.Idle;
166                     }
167                     else if(isRead)
168                     {
169                         this.Log(LogLevel.Noisy, "Reading from device");
170                         foreach(var @byte in slave.Read(6))
171                         {
172                             foreach(var bit in BitHelper.GetBits(@byte).Take(8).Reverse())
173                             {
174                                 this.Log(LogLevel.Noisy, "Enqueuing bit: {0}", bit);
175                                 bufferFromDevice.Enqueue(bit);
176                             }
177                         }
178 
179                         tickCounter = 0;
180                         state = State.Read;
181                     }
182                     else // it must be write
183                     {
184                         state = State.Write;
185                     }
186                     break;
187                 }
188 
189                 case State.Read:
190                 {
191                     tickCounter++;
192                     if(tickCounter == 8)
193                     {
194                         state = State.ReadAck;
195                     }
196                     break;
197                 }
198 
199                 case State.ReadAck:
200                 {
201                     tickCounter = 0;
202                     state = State.Read;
203                     break;
204                 }
205 
206                 case State.Write:
207                 {
208                     this.Log(LogLevel.Noisy, "Latching data bit #{0}: {1}", bufferToDevice.Count, signals[DataSignal]);
209                     bufferToDevice.Push(signals[DataSignal]);
210 
211                     if(bufferToDevice.Count == 8)
212                     {
213                         state = State.WriteAck;
214                     }
215                     break;
216                 }
217 
218                 case State.WriteAck:
219                 {
220                     DebugHelper.Assert(bufferToDevice.Count == 8);
221 
222                     var dataByte = (byte)BitHelper.GetValueFromBitsArray(bufferToDevice.PopAll());
223                     this.Log(LogLevel.Noisy, "Decoded data byte #{0}: 0x{1:X}", bytesToDevice.Count, dataByte);
224 
225                     bytesToDevice.Enqueue(dataByte);
226 
227                     // ACK
228                     this.Log(LogLevel.Noisy, "Enqueuing ACK");
229                     bufferFromDevice.Enqueue(false);
230 
231                     state = State.Write;
232                     break;
233                 }
234             }
235         }
236 
HandleClockFalling(bool[] signals)237         private void HandleClockFalling(bool[] signals)
238         {
239             bool unused;
240             if(state == State.Read) {
241                 var isEmpty = bufferFromDevice.TryDequeue(out unused);
242             }
243         }
244 
ResetBuffers()245         private void ResetBuffers()
246         {
247             bufferToDevice.Clear();
248             bufferFromDevice.Clear();
249             bytesToDevice.Clear();
250 
251             state = State.Idle;
252             slave = null;
253             isRead = false;
254         }
255 
256         private readonly DoubleWordRegisterCollection registersCollection;
257         private readonly BitPatternDetector i2cDecoder;
258         private readonly Stack<bool> bufferToDevice;
259         private readonly Queue<bool> bufferFromDevice;
260         private readonly Queue<byte> bytesToDevice;
261 
262         private State state;
263         private int tickCounter;
264         private II2CPeripheral slave;
265         private bool isRead;
266 
267         private const int ClockSignal = 0;
268         private const int DataSignal = 1;
269 
270         private enum Registers
271         {
272             BitBang = 0x0,
273             Data = 0x4
274         }
275 
276         private enum State
277         {
278             Idle,
279             Address,
280             AddressAck,
281             Operation,
282             Write,
283             WriteAck,
284             Read,
285             ReadAck
286         }
287     }
288 }
289 
290