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