1 // 2 // Copyright (c) 2010-2022 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.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Debugging; 14 using Antmicro.Renode.Exceptions; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Peripherals.Bus; 17 using Antmicro.Renode.Utilities; 18 19 namespace Antmicro.Renode.Peripherals.I2C 20 { 21 public class OpenTitan_I2C : SimpleContainer<II2CPeripheral>, II2CPeripheral, IDoubleWordPeripheral, IKnownSize 22 { OpenTitan_I2C(IMachine machine)23 public OpenTitan_I2C(IMachine machine) : base(machine) 24 { 25 FormatWatermarkIRQ = new GPIO(); 26 RxWatermarkIRQ = new GPIO(); 27 FormatOverflowIRQ = new GPIO(); 28 RxOverflowIRQ = new GPIO(); 29 NakIRQ = new GPIO(); 30 SclInterfaceIRQ = new GPIO(); 31 SdaInterfaceIRQ = new GPIO(); 32 StretchTimeoutIRQ = new GPIO(); 33 SdaUnstableIRQ = new GPIO(); 34 TransactionCompleteIRQ = new GPIO(); 35 TxEmptyIRQ = new GPIO(); 36 TxNonEmptyIRQ = new GPIO(); 37 TxOverflowIRQ = new GPIO(); 38 AcqOverflowIRQ = new GPIO(); 39 AckAfterStopIRQ = new GPIO(); 40 HostTimeoutIRQ = new GPIO(); 41 42 FatalAlert = new GPIO(); 43 44 acquiredFifo = new Queue<AcquireFormatIndicator>(); 45 formatFifo = new Queue<FormatIndicator>(); 46 rxFifo = new Queue<byte>(); 47 txFifo = new Queue<byte>(); 48 49 var registers = new Dictionary<long, DoubleWordRegister> 50 { 51 {(long)Registers.InterruptState, new DoubleWordRegister(this, 0x0) 52 .WithFlag(0, out formatWatermarkInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "fmt_watermark") 53 .WithFlag(1, out rxWatermarkInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "rx_watermark") 54 .WithFlag(2, out formatOverflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "fmt_overflow") 55 .WithFlag(3, out rxOverflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "rx_overflow") 56 .WithFlag(4, out nakInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "nak") 57 .WithFlag(5, out sclInterfaceInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "scl_interference") 58 .WithFlag(6, out sdaInterfaceInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "sda_interference") 59 .WithFlag(7, out stretchTimeoutInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "stretch_timeout") 60 .WithFlag(8, out sdaUnstableInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "sda_unstable") 61 .WithFlag(9, out transactionCompleteInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "trans_complete") 62 .WithFlag(10, out txEmptyInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_empty") 63 .WithFlag(11, out txNonEmptyInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_nonempty") 64 .WithFlag(12, out txOverflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_overflow") 65 .WithFlag(13, out acqOverflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "acq_overflow") 66 .WithFlag(14, out ackAfterStopInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "ack_stop") 67 .WithFlag(15, out hostTimeoutInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "host_timeout") 68 .WithReservedBits(16, 16) 69 .WithChangeCallback((_, __) => UpdateInterrupts()) 70 }, 71 72 {(long)Registers.InterruptEnable, new DoubleWordRegister(this, 0x0) 73 .WithFlag(0, out formatWatermarkInterruptEnable, name: "fmt_watermark") 74 .WithFlag(1, out rxWatermarkInterruptEnable, name: "rx_watermark") 75 .WithFlag(2, out formatOverflowInterruptEnable, name: "fmt_overflow") 76 .WithFlag(3, out rxOverflowInterruptEnable, name: "rx_overflow") 77 .WithFlag(4, out nakInterruptEnable, name: "nak") 78 .WithFlag(5, out sclInterfaceInterruptEnable, name: "scl_interference") 79 .WithFlag(6, out sdaInterfaceInterruptEnable, name: "sda_interference") 80 .WithFlag(7, out stretchTimeoutInterruptEnable, name: "stretch_timeout") 81 .WithFlag(8, out sdaUnstableInterruptEnable, name: "sda_unstable") 82 .WithFlag(9, out transactionCompleteInterruptEnable, name: "trans_complete") 83 .WithFlag(10, out txEmptyInterruptEnable, name: "tx_empty") 84 .WithFlag(11, out txNonEmptyInterruptEnable, name: "tx_nonempty") 85 .WithFlag(12, out txOverflowInterruptEnable, name: "tx_overflow") 86 .WithFlag(13, out acqOverflowInterruptEnable, name: "acq_overflow") 87 .WithFlag(14, out ackAfterStopInterruptEnable, name: "ack_stop") 88 .WithFlag(15, out hostTimeoutInterruptEnable, name: "host_timeout") 89 .WithReservedBits(16, 16) 90 .WithChangeCallback((_, __) => UpdateInterrupts()) 91 }, 92 93 {(long)Registers.InterruptTest, new DoubleWordRegister(this, 0x0) 94 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) formatWatermarkInterruptState.Value = true; }, name: "fmt_watermark") 95 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) rxWatermarkInterruptState.Value = true; }, name: "rx_watermark") 96 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { if(val) formatOverflowInterruptState.Value = true; }, name: "fmt_overflow") 97 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { if(val) rxOverflowInterruptState.Value = true; }, name: "rx_overflow") 98 .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { if(val) nakInterruptState.Value = true; }, name: "nak") 99 .WithFlag(5, FieldMode.Write, writeCallback: (_, val) => { if(val) sclInterfaceInterruptState.Value = true; }, name: "scl_interference") 100 .WithFlag(6, FieldMode.Write, writeCallback: (_, val) => { if(val) sdaInterfaceInterruptState.Value = true; }, name: "sda_interference") 101 .WithFlag(7, FieldMode.Write, writeCallback: (_, val) => { if(val) stretchTimeoutInterruptState.Value = true; }, name: "stretch_timeout") 102 .WithFlag(8, FieldMode.Write, writeCallback: (_, val) => { if(val) sdaUnstableInterruptState.Value = true; }, name: "sda_unstable") 103 .WithFlag(9, FieldMode.Write, writeCallback: (_, val) => { if(val) transactionCompleteInterruptState.Value = true; }, name: "trans_complete") 104 .WithFlag(10, FieldMode.Write, writeCallback: (_, val) => { if(val) txEmptyInterruptState.Value = true; }, name: "tx_empty") 105 .WithFlag(11, FieldMode.Write, writeCallback: (_, val) => { if(val) txNonEmptyInterruptState.Value = true; }, name: "tx_nonempty") 106 .WithFlag(12, FieldMode.Write, writeCallback: (_, val) => { if(val) txOverflowInterruptState.Value = true; }, name: "tx_overflow") 107 .WithFlag(13, FieldMode.Write, writeCallback: (_, val) => { if(val) acqOverflowInterruptState.Value = true; }, name: "acq_overflow") 108 .WithFlag(14, FieldMode.Write, writeCallback: (_, val) => { if(val) ackAfterStopInterruptState.Value = true; }, name: "ack_stop") 109 .WithFlag(15, FieldMode.Write, writeCallback: (_, val) => { if(val) hostTimeoutInterruptState.Value = true; }, name: "host_timeout") 110 .WithReservedBits(16,16) 111 .WithChangeCallback((_, __) => UpdateInterrupts()) 112 }, 113 114 {(long)Registers.AlertTest, new DoubleWordRegister(this, 0x0) 115 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") 116 .WithReservedBits(1, 31) 117 }, 118 119 {(long)Registers.Control, new DoubleWordRegister(this, 0x0) 120 .WithFlag(0, out enabledHost, name: "ENABLEHOST") 121 .WithFlag(1, out enabledTarget, name: "ENABLETARGET") 122 .WithTaggedFlag("LLPBK", 2) 123 .WithReservedBits(3, 29) 124 .WithWriteCallback((_, __) => { 125 if(enabledHost.Value && enabledTarget.Value) 126 { 127 this.Log(LogLevel.Warning, "This peripheral does not support working in both target and host mode in the same time. " + 128 "The mode is now set to the host mode."); 129 enabledHost.Value = true; 130 enabledTarget.Value = false; 131 } 132 this.NoisyLog("The mode set to {0}", enabledHost.Value ? "host" : (enabledTarget.Value ? "target" : "none")); 133 if(enabledHost.Value) 134 { 135 ExecuteCommands(); 136 } 137 }) 138 }, 139 140 {(long)Registers.Status, new DoubleWordRegister(this, 0x3c ) 141 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => (formatFifo.Count == MaximumFifoDepth), name: "FMTFULL") 142 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => (rxFifo.Count == MaximumFifoDepth), name: "RXFULL") 143 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => (formatFifo.Count == 0), name: "FMTEMPTY") 144 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => true, name: "HOSTIDLE") 145 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => true, name: "TARGETIDLE") 146 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => (rxFifo.Count == 0), name: "RXEMPTY") 147 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => (txFifo.Count == MaximumFifoDepth), name: "TXFULL") 148 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => (acquiredFifo.Count == MaximumFifoDepth), name: "ACQFULL") 149 .WithFlag(8, FieldMode.Read, valueProviderCallback: _ => (txFifo.Count == 0), name: "TXEMPTY") 150 .WithFlag(9, FieldMode.Read, valueProviderCallback: _ => (acquiredFifo.Count == 0), name: "ACQEMPTY") 151 .WithReservedBits(10, 22) 152 }, 153 154 {(long)Registers.ReadData, new DoubleWordRegister(this, 0x0) 155 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => 156 { 157 if(!Misc.TryDequeue(rxFifo, out var value)) 158 { 159 this.Log(LogLevel.Error, "Queue empty, not able to dequeue"); 160 } 161 return value; 162 }, name: "RDATA") 163 .WithReservedBits(8, 24) 164 }, 165 166 {(long)Registers.FormatData, new DoubleWordRegister(this, 0x0) 167 .WithValueField(0, 8, out formatByte, name: "FBYTE") 168 .WithFlag(8, out startFlag, name: "START") 169 .WithFlag(9, out stopFlag, name: "STOP") 170 .WithFlag(10, out readFlag, name: "READ") 171 .WithFlag(11, out readContinueFlag, name: "RCONT") 172 .WithFlag(12, out nakOkFlag, name: "NAKOK") 173 .WithReservedBits(13, 19) 174 .WithWriteCallback((_, __) => EnqueueFormat()) 175 }, 176 177 {(long)Registers.FifoControl, new DoubleWordRegister(this, 0x0) 178 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) rxFifo.Clear(); }, name: "RXRST") 179 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) formatFifo.Clear(); }, name: "FMTRST") 180 .WithEnumField<DoubleWordRegister, WatermarkLevel>(2, 3, out rxWatermarkLevel, name: "RXILVL") 181 .WithEnumField<DoubleWordRegister, WatermarkLevel>(5, 2, out fmtWatermarkLevel, name: "FMTILVL_FIELD") 182 .WithFlag(7, FieldMode.Write, writeCallback: (_, val) => { if(val) acquiredFifo.Clear(); }, name:"ACQRST") 183 .WithFlag(8, FieldMode.Write, writeCallback: (_, val) => { if(val) txFifo.Clear(); }, name:"TXRST") 184 .WithReservedBits(9, 23) 185 .WithWriteCallback((_, __) => UpdateWatermarks()) 186 }, 187 188 {(long)Registers.FifoStatus, new DoubleWordRegister(this, 0x0) 189 .WithValueField(0, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)formatFifo.Count, name: "FMTLVL") 190 .WithReservedBits(7, 1) 191 .WithValueField(8, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)txFifo.Count, name: "TXLVL") 192 .WithReservedBits(15, 1) 193 .WithValueField(16, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)rxFifo.Count, name: "RXLVL") 194 .WithReservedBits(23, 1) 195 .WithValueField(24, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)acquiredFifo.Count, name:"ACQLVL") 196 .WithReservedBits(31, 1) 197 }, 198 199 {(long)Registers.OverrideControl, new DoubleWordRegister(this, 0x0) 200 .WithTaggedFlag("TXOVRDEN", 0) 201 .WithTaggedFlag("SCLVAL", 1) 202 .WithTaggedFlag("SDAVAL", 2) 203 .WithReservedBits(3, 29) 204 }, 205 206 {(long)Registers.OversampledValues, new DoubleWordRegister(this, 0x0) 207 .WithTag("SCL_RX", 0, 16) 208 .WithTag("SDA_RX", 16, 16) 209 }, 210 211 {(long)Registers.Timing0, new DoubleWordRegister(this, 0x0) 212 .WithTag("THIGH", 0, 16) 213 .WithTag("TLOW", 16, 16) 214 }, 215 216 {(long)Registers.Timing1, new DoubleWordRegister(this, 0x0) 217 .WithTag("T_R", 0, 16) 218 .WithTag("T_F", 16, 16) 219 }, 220 221 {(long)Registers.Timing2, new DoubleWordRegister(this, 0x0) 222 .WithTag("TSU_STA", 0, 16) 223 .WithTag("THD_STA", 16, 16) 224 }, 225 226 {(long)Registers.Timing3, new DoubleWordRegister(this, 0x0) 227 .WithTag("TSU_DAT", 0, 16) 228 .WithTag("THD_DAT", 16, 16) 229 }, 230 231 {(long)Registers.Timing4, new DoubleWordRegister(this, 0x0) 232 .WithTag("TSU_STO", 0, 16) 233 .WithTag("T_BUF", 16, 16) 234 }, 235 236 {(long)Registers.ClockStrechingTimeout, new DoubleWordRegister(this, 0x0) 237 .WithTag("VAL", 0, 31) 238 .WithTaggedFlag("EN", 31) 239 }, 240 241 {(long)Registers.TargetId, new DoubleWordRegister(this, 0x0) 242 .WithTag("ADDRESS0", 0, 7) 243 .WithTag("MASK0", 7, 7) 244 .WithTag("ADDRESS1", 14, 7) 245 .WithTag("MASK1", 21, 7) 246 .WithReservedBits(28, 4) 247 }, 248 249 {(long)Registers.AcquiredData, new DoubleWordRegister(this, 0x0) 250 .WithValueField(0, 10, FieldMode.Read, valueProviderCallback: (_) => 251 { 252 return acquiredFifo.TryDequeue(out var output) ? output.ToRegisterValue() : 0; 253 }, name:"ABYTE and SIGNAL") 254 .WithReservedBits(10, 22) 255 }, 256 257 {(long)Registers.TransmitData, new DoubleWordRegister(this, 0x0) 258 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, val) => EnqueueTx((byte)val), name: "TXDATA") 259 .WithReservedBits(8, 24) 260 }, 261 262 {(long)Registers.TargetClockStretching, new DoubleWordRegister(this, 0x0) 263 .WithTaggedFlag("I2C_STRETCH_CTRL_EN_ADDR_TX", 0) 264 .WithTaggedFlag("I2C_STRETCH_CTRL_EN_ADDR_ACQ", 1) 265 .WithTaggedFlag("I2C_STRETCH_CTRL_STOP_TX", 2) 266 .WithTaggedFlag("I2C_STRETCH_CTRL_STOP_ACQ", 3) 267 .WithReservedBits(4, 28) 268 }, 269 270 {(long)Registers.HostClockGenerationTimeout, new DoubleWordRegister(this, 0x0) 271 .WithTag("HOST_TIMEOUT_CTRL", 0, 32) 272 } 273 }; 274 275 acquiredFifo = new Queue<AcquireFormatIndicator>(); 276 formatFifo = new Queue<FormatIndicator>(); 277 rxFifo = new Queue<byte>(); 278 txFifo = new Queue<byte>(); 279 280 registersCollection = new DoubleWordRegisterCollection(this, registers); 281 Reset(); 282 } 283 Reset()284 public override void Reset() 285 { 286 registersCollection.Reset(); 287 UpdateWatermarks(); 288 ResetBuffers(); 289 290 currentState = State.Idle; 291 transactionAddress = null; 292 selectedSlave = null; 293 } 294 ReadDoubleWord(long offset)295 public uint ReadDoubleWord(long offset) 296 { 297 return registersCollection.Read(offset); 298 } 299 WriteDoubleWord(long offset, uint value)300 public void WriteDoubleWord(long offset, uint value) 301 { 302 registersCollection.Write(offset, value); 303 } 304 305 // Write, Read and FinishTransmission methods are meant to be used only in the target mode Write(byte[] data)306 public void Write(byte[] data) 307 { 308 if(data.Length == 0) 309 { 310 return; 311 } 312 313 var index = 0; 314 if(currentState == State.Idle || currentState == State.Transaction) 315 { 316 // Handle the start/repeated start byte 317 EnqueueAcquired(new AcquireFormatIndicator(data[0], start: true, stop: currentState == State.Transaction)); 318 currentState = State.Transaction; 319 index += 1; 320 } 321 for(; index < data.Length; index++) 322 { 323 EnqueueAcquired(new AcquireFormatIndicator(data[index], start: false, stop: false)); 324 } 325 } 326 Read(int count)327 public byte[] Read(int count) 328 { 329 var temp = new List<byte>(); 330 for(var i = 0; i < count; i++) 331 { 332 if(!txFifo.TryDequeue(out var data)) 333 { 334 break; 335 } 336 temp.Add(data); 337 } 338 return temp.ToArray(); 339 } 340 FinishTransmission()341 public void FinishTransmission() 342 { 343 if(enabledHost.Value) 344 { 345 throw new RecoverableException("This should never be called in the host mode"); 346 } 347 EnqueueAcquired(new AcquireFormatIndicator(0x0, start: false, stop: true)); 348 currentState = State.Idle; 349 350 transactionCompleteInterruptState.Value = true; 351 UpdateInterrupts(); 352 } 353 354 public long Size => 0x1000; 355 356 public GPIO FormatWatermarkIRQ { get; } 357 public GPIO RxWatermarkIRQ { get; } 358 public GPIO FormatOverflowIRQ { get; } 359 public GPIO RxOverflowIRQ { get; } 360 public GPIO NakIRQ { get; } 361 public GPIO SclInterfaceIRQ { get; } 362 public GPIO SdaInterfaceIRQ { get; } 363 public GPIO StretchTimeoutIRQ { get; } 364 public GPIO SdaUnstableIRQ { get; } 365 public GPIO TransactionCompleteIRQ { get; } 366 public GPIO TxEmptyIRQ { get; } 367 public GPIO TxNonEmptyIRQ { get; } 368 public GPIO TxOverflowIRQ { get; } 369 public GPIO AcqOverflowIRQ { get; } 370 public GPIO AckAfterStopIRQ { get; } 371 public GPIO HostTimeoutIRQ { get; } 372 373 public GPIO FatalAlert { get; } 374 UpdateInterrupts()375 private void UpdateInterrupts() 376 { 377 FormatWatermarkIRQ.Set(formatWatermarkInterruptState.Value && formatWatermarkInterruptEnable.Value); 378 RxWatermarkIRQ.Set(rxWatermarkInterruptState.Value && rxWatermarkInterruptEnable.Value); 379 FormatOverflowIRQ.Set(formatOverflowInterruptState.Value && formatOverflowInterruptEnable.Value); 380 RxOverflowIRQ.Set(rxOverflowInterruptState.Value && rxOverflowInterruptEnable.Value); 381 NakIRQ.Set(nakInterruptState.Value && nakInterruptEnable.Value); 382 SclInterfaceIRQ.Set(sclInterfaceInterruptState.Value && sclInterfaceInterruptEnable.Value); 383 SdaInterfaceIRQ.Set(sdaInterfaceInterruptState.Value && sdaInterfaceInterruptEnable.Value); 384 StretchTimeoutIRQ.Set(stretchTimeoutInterruptState.Value && stretchTimeoutInterruptEnable.Value); 385 SdaUnstableIRQ.Set(sdaUnstableInterruptState.Value && sdaUnstableInterruptEnable.Value); 386 TransactionCompleteIRQ.Set(transactionCompleteInterruptState.Value && transactionCompleteInterruptEnable.Value); 387 TxEmptyIRQ.Set(txEmptyInterruptState.Value && txEmptyInterruptEnable.Value); 388 TxNonEmptyIRQ.Set(txNonEmptyInterruptState.Value && txNonEmptyInterruptEnable.Value); 389 TxOverflowIRQ.Set(txOverflowInterruptState.Value && txOverflowInterruptEnable.Value); 390 AcqOverflowIRQ.Set(acqOverflowInterruptState.Value && acqOverflowInterruptEnable.Value); 391 AckAfterStopIRQ.Set(ackAfterStopInterruptState.Value && ackAfterStopInterruptEnable.Value); 392 HostTimeoutIRQ.Set(hostTimeoutInterruptState.Value && hostTimeoutInterruptEnable.Value); 393 } 394 UpdateWatermarks()395 private void UpdateWatermarks() 396 { 397 fmtWatermark = WatermarkEnumToValue(fmtWatermarkLevel.Value); 398 rxWatermark = WatermarkEnumToValue(rxWatermarkLevel.Value); 399 } 400 WatermarkEnumToValue(WatermarkLevel value)401 private uint WatermarkEnumToValue(WatermarkLevel value) 402 { 403 switch(value) 404 { 405 case WatermarkLevel.Char1: 406 return 1; 407 case WatermarkLevel.Char4: 408 return 4; 409 case WatermarkLevel.Char8: 410 return 8; 411 case WatermarkLevel.Char16: 412 return 16; 413 default: 414 throw new ArgumentException("Illegal value"); 415 } 416 } 417 ExecuteCommands()418 private void ExecuteCommands() 419 { 420 if(enabledTarget.Value) 421 { 422 throw new ApplicationException("This should not be possible in the target mode"); 423 } 424 this.NoisyLog("Executing queued commands"); 425 while(formatFifo.Count > 0) 426 { 427 HandleCommand(formatFifo.Dequeue()); 428 } 429 } 430 HandleCommand(FormatIndicator command)431 private void HandleCommand(FormatIndicator command) 432 { 433 DebugHelper.Assert(selectedSlave != null || currentState == State.Idle, $"Cannot have no selected slave in the state {currentState}. This should have never happend"); 434 435 switch(currentState) 436 { 437 case State.Idle: 438 if(!command.StartOnly) 439 { 440 this.Log(LogLevel.Error, "Only a format code with a start is accepted in the idle state"); 441 return; 442 } 443 if(!TryGetByAddress(command.Data, out selectedSlave)) 444 { 445 this.Log(LogLevel.Error, "No device available under address {0}. All further transactions until STOP will be ignored", command.Data); 446 nakInterruptState.Value = true; 447 UpdateInterrupts(); 448 currentState = State.Error; 449 return; 450 } 451 currentState = State.AwaitingAddress; 452 break; 453 case State.AwaitingAddress: 454 if(!command.NoFlags) 455 { 456 this.Log(LogLevel.Error, "Expected slave address, but some of the flags are set [{0}]. Skipping", command.FlagsToString()); 457 return; 458 } 459 transactionAddress = (byte)command.Data; 460 currentState = State.Transaction; 461 break; 462 case State.Transaction: 463 if(command.IsRead) 464 { 465 ReadFromSlave(command.Data); 466 } 467 else if(command.NoFlags) 468 { 469 WriteToSlave(command.Data); 470 } 471 else 472 { 473 this.Log(LogLevel.Error, "Incorrect command in the 'Transaction' state. Expected read flag, or no flag when writing. Flags set: {0}", command.FlagsToString()); 474 return; 475 } 476 477 if(command.StopFlag) 478 { 479 selectedSlave.FinishTransmission(); 480 CleanupTransaction(); 481 } 482 break; 483 case State.Error: 484 if(command.StopFlag) 485 { 486 CleanupTransaction(); 487 } 488 break; 489 default: 490 throw new ArgumentException($"Illegal state: {currentState}"); 491 } 492 } 493 CleanupTransaction()494 private void CleanupTransaction() 495 { 496 transactionAddress = null; 497 selectedSlave = null; 498 currentState = State.Idle; 499 } 500 ReadFromSlave(byte count)501 private void ReadFromSlave(byte count) 502 { 503 // Specification does not allow a zero value - it is treated as a 256 504 var bytesCount = (count == 0) ? 256 : count; 505 selectedSlave.Write(new byte[] { transactionAddress.Value }); 506 foreach(var b in selectedSlave.Read(bytesCount)) 507 { 508 EnqueueRx(b); 509 } 510 } 511 WriteToSlave(byte data)512 private void WriteToSlave(byte data) 513 { 514 DebugHelper.Assert(transactionAddress != null, "Address not selected when performing read operation."); 515 516 selectedSlave.Write(new byte[] { transactionAddress.Value, data }); 517 } 518 HandleEnqueue(Queue<T> queue, T value, IFlagRegisterField overflowInterrupt = null, IFlagRegisterField watermarkInterrupt = null, uint watermarkLevel = 0)519 private void HandleEnqueue<T>(Queue<T> queue, T value, IFlagRegisterField overflowInterrupt = null, 520 IFlagRegisterField watermarkInterrupt = null, uint watermarkLevel = 0) 521 { 522 if(queue.Count == MaximumFifoDepth && overflowInterrupt != null) 523 { 524 overflowInterrupt.Value = true; 525 UpdateInterrupts(); 526 this.Log(LogLevel.Warning, "Fifo {0} is at its maximum capacity of {1} elements. Dropping incoming element", queue.GetType().Name, MaximumFifoDepth); 527 return; 528 } 529 queue.Enqueue(value); 530 if(watermarkInterrupt != null && queue.Count == watermarkLevel) 531 { 532 watermarkInterrupt.Value = true; 533 UpdateInterrupts(); 534 } 535 } 536 EnqueueFormat()537 private void EnqueueFormat() 538 { 539 if(enabledTarget.Value) 540 { 541 this.Log(LogLevel.Warning, "Cannot enqueue commands when in target mode."); 542 return; 543 } 544 var format = new FormatIndicator((byte)formatByte.Value, startFlag.Value, stopFlag.Value, readFlag.Value, readContinueFlag.Value, 545 nakOkFlag.Value); 546 HandleEnqueue(formatFifo, format, formatOverflowInterruptState, formatWatermarkInterruptState, fmtWatermark); 547 this.Log(LogLevel.Noisy, "Enqueued format data: {0}", format); 548 if(enabledHost.Value) 549 { 550 ExecuteCommands(); 551 } 552 } 553 EnqueueAcquired(AcquireFormatIndicator acquired)554 private void EnqueueAcquired(AcquireFormatIndicator acquired) 555 { 556 if(enabledHost.Value) 557 { 558 this.Log(LogLevel.Warning, "Cannot enqueue acquired data when in target mode"); 559 return; 560 } 561 HandleEnqueue(acquiredFifo, acquired, acqOverflowInterruptState); 562 } 563 EnqueueRx(uint value)564 private void EnqueueRx(uint value) 565 { 566 HandleEnqueue(rxFifo, (byte)value, rxOverflowInterruptState, rxWatermarkInterruptState, rxWatermark); 567 } 568 EnqueueTx(byte value)569 private void EnqueueTx(byte value) 570 { 571 if(enabledHost.Value) 572 { 573 this.Log(LogLevel.Warning, "Tried to enqueue byte 0x{0:X} to the Tx fifo in the host mode. Tx Fifo is available only in the target mode"); 574 return; 575 } 576 HandleEnqueue(txFifo, value, txOverflowInterruptState); 577 } 578 ResetBuffers()579 private void ResetBuffers() 580 { 581 rxFifo.Clear(); 582 acquiredFifo.Clear(); 583 formatFifo.Clear(); 584 txFifo.Clear(); 585 } 586 587 private IFlagRegisterField formatWatermarkInterruptState; 588 private IFlagRegisterField rxWatermarkInterruptState; 589 private IFlagRegisterField formatOverflowInterruptState; 590 private IFlagRegisterField rxOverflowInterruptState; 591 private IFlagRegisterField nakInterruptState; 592 private IFlagRegisterField sclInterfaceInterruptState; 593 private IFlagRegisterField sdaInterfaceInterruptState; 594 private IFlagRegisterField stretchTimeoutInterruptState; 595 private IFlagRegisterField sdaUnstableInterruptState; 596 private IFlagRegisterField transactionCompleteInterruptState; 597 private IFlagRegisterField txEmptyInterruptState; 598 private IFlagRegisterField txNonEmptyInterruptState; 599 private IFlagRegisterField txOverflowInterruptState; 600 private IFlagRegisterField acqOverflowInterruptState; 601 private IFlagRegisterField ackAfterStopInterruptState; 602 private IFlagRegisterField hostTimeoutInterruptState; 603 private IFlagRegisterField formatWatermarkInterruptEnable; 604 private IFlagRegisterField rxWatermarkInterruptEnable; 605 private IFlagRegisterField formatOverflowInterruptEnable; 606 private IFlagRegisterField rxOverflowInterruptEnable; 607 private IFlagRegisterField nakInterruptEnable; 608 private IFlagRegisterField sclInterfaceInterruptEnable; 609 private IFlagRegisterField sdaInterfaceInterruptEnable; 610 private IFlagRegisterField stretchTimeoutInterruptEnable; 611 private IFlagRegisterField sdaUnstableInterruptEnable; 612 private IFlagRegisterField transactionCompleteInterruptEnable; 613 private IFlagRegisterField txEmptyInterruptEnable; 614 private IFlagRegisterField txNonEmptyInterruptEnable; 615 private IFlagRegisterField txOverflowInterruptEnable; 616 private IFlagRegisterField acqOverflowInterruptEnable; 617 private IFlagRegisterField ackAfterStopInterruptEnable; 618 private IFlagRegisterField hostTimeoutInterruptEnable; 619 620 private IFlagRegisterField enabledHost; 621 private IFlagRegisterField enabledTarget; 622 private IFlagRegisterField startFlag; 623 private IFlagRegisterField stopFlag; 624 private IFlagRegisterField readFlag; 625 private IFlagRegisterField readContinueFlag; 626 private IFlagRegisterField nakOkFlag; 627 private IValueRegisterField formatByte; 628 629 private IEnumRegisterField<WatermarkLevel> rxWatermarkLevel; 630 private IEnumRegisterField<WatermarkLevel> fmtWatermarkLevel; 631 private uint rxWatermark; 632 private uint fmtWatermark; 633 634 private readonly DoubleWordRegisterCollection registersCollection; 635 private readonly Queue<FormatIndicator> formatFifo; 636 private readonly Queue<AcquireFormatIndicator> acquiredFifo; 637 private readonly Queue<byte> rxFifo; 638 private readonly Queue<byte> txFifo; 639 640 private II2CPeripheral selectedSlave; 641 private byte? transactionAddress; 642 private State currentState; 643 644 private const int MaximumFifoDepth = 64; 645 646 public enum Registers 647 { 648 InterruptState = 0x0, 649 InterruptEnable = 0x4, 650 InterruptTest = 0x8, 651 AlertTest = 0xc, 652 Control = 0x10, 653 Status = 0x14, 654 ReadData = 0x18, 655 FormatData = 0x1c, 656 FifoControl = 0x20, 657 FifoStatus = 0x24, 658 OverrideControl = 0x28, 659 OversampledValues = 0x2c, 660 Timing0 = 0x30, 661 Timing1 = 0x34, 662 Timing2 = 0x38, 663 Timing3 = 0x3c, 664 Timing4 = 0x40, 665 ClockStrechingTimeout = 0x44, 666 TargetId = 0x48, 667 AcquiredData = 0x4c, 668 TransmitData = 0x50, 669 TargetClockStretching = 0x54, 670 HostClockGenerationTimeout = 0x58, 671 } 672 673 public struct AcquireFormatIndicator 674 { AcquireFormatIndicatorAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator675 public AcquireFormatIndicator(byte data, bool start, bool stop) 676 { 677 this.Data = data; 678 if(start) 679 { 680 ReadFlag = ((data & 0x1) == 1); 681 } 682 else 683 { 684 ReadFlag = false; 685 } 686 this.StartFlag = start; 687 this.StopFlag = stop; 688 } 689 ToStringAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator690 public override string ToString() 691 { 692 return $"{Data:X2} with start: {StartFlag}, stop: {StopFlag}, read: {ReadFlag}"; 693 } 694 ToRegisterValueAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator695 public uint ToRegisterValue() 696 { 697 uint flags = (StartFlag ? 1u : 0u) | ((StopFlag ? 1u : 0u) << 1); 698 return (uint)Data | (flags << 8); 699 } 700 FromRegisterAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.AcquireFormatIndicator701 public static AcquireFormatIndicator FromRegister(uint registerValue) 702 { 703 var data = (byte)registerValue; 704 705 var startFlag = ((registerValue >> 8) & 1) == 1; 706 var stopFlag = ((registerValue >> 9) & 1) == 1; 707 708 return new AcquireFormatIndicator(data, start: startFlag, stop: stopFlag); 709 } 710 711 public byte Data { get; } 712 public bool ReadFlag { get; } 713 public bool StartFlag { get; } 714 public bool StopFlag { get; } 715 } 716 717 public struct FormatIndicator 718 { FormatIndicatorAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator719 public FormatIndicator(byte data, bool start = false, bool stop = false, bool read = false, bool readContinue = false, bool nakOk = false) 720 { 721 this.Data = data; 722 this.ReadFlag = read; 723 this.ReadContinueFlag = readContinue; 724 this.StartFlag = start; 725 this.StopFlag = stop; 726 this.NakOkFlag = nakOk; 727 } 728 729 public byte Data { get; } 730 public bool ReadFlag { get; } 731 public bool ReadContinueFlag { get; } 732 public bool StartFlag { get; } 733 public bool StopFlag { get; } 734 public bool NakOkFlag { get; } 735 736 public bool StartOnly => StopFlag == false && ReadFlag == false && ReadContinueFlag == false && StartFlag == true; 737 public bool IsRead => ReadFlag == true || ReadContinueFlag == true; 738 public bool NoFlags => StopFlag == false && ReadFlag == false && ReadContinueFlag == false && StartFlag == false; 739 ToStringAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator740 public override string ToString() 741 { 742 return $"{Data:X2} with {FlagsToString()}"; 743 } 744 FlagsToStringAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator745 public string FlagsToString() 746 { 747 return $"start:{StartFlag}, stop:{StopFlag}, read:{ReadFlag}, readContinue:{ReadContinueFlag}, nakOk:{NakOkFlag}"; 748 } 749 ToRegisterFormatAntmicro.Renode.Peripherals.I2C.OpenTitan_I2C.FormatIndicator750 public uint ToRegisterFormat() 751 { 752 var flags = ((StartFlag ? 1 : 0) << 0) | 753 ((StopFlag ? 1 : 0) << 1) | 754 ((ReadFlag ? 1 : 0) << 2) | 755 ((ReadContinueFlag ? 1 : 0) << 3) | 756 ((NakOkFlag ? 1 : 0) << 4); 757 return (uint)(Data | (flags << 8)); 758 } 759 } 760 761 private enum WatermarkLevel 762 { 763 Char1 = 0x0, 764 Char4 = 0x1, 765 Char8 = 0x2, 766 Char16 = 0x3, 767 Char30 = 0x4, 768 } 769 770 private enum State 771 { 772 Idle, 773 AwaitingAddress, 774 Transaction, 775 Error, 776 } 777 } 778 } 779