1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Time; 16 using Antmicro.Renode.Utilities; 17 18 namespace Antmicro.Renode.Peripherals.I2C 19 { 20 public class RenesasRA_IIC : SimpleContainer<II2CPeripheral>, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize 21 { RenesasRA_IIC(IMachine machine)22 public RenesasRA_IIC(IMachine machine) : base(machine) 23 { 24 RegistersCollection = new ByteRegisterCollection(this); 25 26 ReceiveIRQ = new GPIO(); 27 TransmitIRQ = new GPIO(); 28 TransmitEndIRQ = new GPIO(); 29 ErrorOrEventIRQ = new GPIO(); 30 31 writeQueue = new Queue<byte>(); 32 readQueue = new Queue<byte>(); 33 34 startCondition = new Condition(this, "Start", HandleStartCondition); 35 stopCondition = new Condition(this, "Stop", HandleStopCondition); 36 restartCondition = new Condition(this, "Restart", HandleRestartCondition); 37 38 DefineRegisters(); 39 Reset(); 40 } 41 ReadByte(long offset)42 public byte ReadByte(long offset) 43 { 44 return RegistersCollection.Read(offset); 45 } 46 WriteByte(long offset, byte value)47 public void WriteByte(long offset, byte value) 48 { 49 RegistersCollection.Write(offset, value); 50 } 51 Reset()52 public override void Reset() 53 { 54 RegistersCollection.Reset(); 55 InternalReset(); 56 } 57 58 public ByteRegisterCollection RegistersCollection { get; } 59 public long Size => 0x20; 60 61 public GPIO ReceiveIRQ { get; } 62 public GPIO TransmitIRQ { get; } 63 public GPIO TransmitEndIRQ { get; } 64 public GPIO ErrorOrEventIRQ { get; } 65 DefineRegisters()66 private void DefineRegisters() 67 { 68 Registers.Control1.Define(this, 0x1F) 69 .WithTaggedFlag("SDAI", 0) 70 .WithTaggedFlag("SCLI", 1) 71 .WithTaggedFlag("SDAO", 2) 72 .WithTaggedFlag("SCLO", 3) 73 .WithTaggedFlag("SOWP", 4) 74 .WithTaggedFlag("CLO", 5) 75 .WithFlag(6, out var iicReset, name: "IICRST") 76 .WithFlag(7, out peripheralEnable, name: "ICE") 77 .WithWriteCallback((_, __) => 78 { 79 if(!iicReset.Value) 80 { 81 return; 82 } 83 84 // Both IICRST and ICE fields are not affected by this reset operation. 85 // See: Table 31.3 in RA6M5 Group User's Manual 86 // We only need to save the value of ICE as we know IICRST is 1 here 87 var peripheralEnableValue = peripheralEnable.Value; 88 89 if(peripheralEnable.Value) 90 { 91 InternalReset(); 92 this.DebugLog("Internal reset performed"); 93 } 94 else 95 { 96 Reset(); 97 this.DebugLog("IIC reset performed"); 98 } 99 100 iicReset.Value = true; 101 peripheralEnable.Value = peripheralEnableValue; 102 }); 103 104 control2Register = Registers.Control2.Define(this) 105 .WithReservedBits(0, 1) 106 .WithFlag(1, out startCondition.RequestFlag, name: "ST", 107 changeCallback: (_, __) => 108 { 109 if(!startCondition.Requested) 110 { 111 return; 112 } 113 114 if(!peripheralEnable.Value) 115 { 116 this.ErrorLog("Attempted to start transmission on a disabled peripheral, clearing the request"); 117 stopCondition.Requested = false; 118 return; 119 } 120 121 if(currentTransmissionState != TransmissionState.Idle) 122 { 123 this.WarningLog("Attempted to start a transaction while one is already running, clearing the request"); 124 startCondition.Requested = false; 125 return; 126 } 127 128 startCondition.TryPerform(); 129 }) 130 .WithFlag(2, out restartCondition.RequestFlag, name: "RS", 131 changeCallback: (_, __) => 132 { 133 if(!restartCondition.Requested) 134 { 135 return; 136 } 137 138 if(!peripheralEnable.Value) 139 { 140 this.ErrorLog("Attempted to restart transmission on a disabled peripheral, clearing the request"); 141 restartCondition.Requested = false; 142 return; 143 } 144 145 // When reading the condition will be generated after the last read has been performed 146 if(currentTransmissionState != TransmissionState.Read) 147 { 148 restartCondition.TryPerform(); 149 } 150 }) 151 .WithFlag(3, out stopCondition.RequestFlag, name: "SP", 152 changeCallback: (_, __) => 153 { 154 // When reading the condition will be generated after the last read has been performed 155 if(currentTransmissionState != TransmissionState.Read) 156 { 157 stopCondition.TryPerform(); 158 } 159 }) 160 .WithReservedBits(4, 1) 161 .WithFlag(5, name: "TRS", 162 valueProviderCallback: _ => currentTransmissionState != TransmissionState.Read, 163 changeCallback: (_, __) => this.WarningLog("Writing to TRS (Transmit/Receive Mode) is not supported in this model and has no effect")) 164 .WithFlag(6, name: "MST", 165 valueProviderCallback: _ => currentTransmissionState != TransmissionState.Idle, 166 changeCallback: (_, __) => this.WarningLog("Writing to MST (Master/Slave Mode) is not supported in this model and has no effect")) 167 .WithFlag(7, FieldMode.Read, name: "BBSY", 168 valueProviderCallback: _ => currentTransmissionState != TransmissionState.Idle); 169 170 Registers.Mode1.Define(this, 0x8) 171 .WithTag("BC[2:0]", 0, 3) 172 .WithTaggedFlag("BCWP", 3) 173 .WithTag("CKS[2:0]", 4, 3) 174 .WithTaggedFlag("MTWP", 7); 175 176 Registers.Mode2.Define(this, 0x6) 177 .WithTaggedFlag("TMOS", 0) 178 .WithTaggedFlag("TMOL", 1) 179 .WithTaggedFlag("TMOH", 2) 180 .WithReservedBits(3, 1) 181 .WithTag("SDDL[2:0]", 4, 3) 182 .WithTaggedFlag("DLCS", 7); 183 184 Registers.Mode3.Define(this) 185 .WithTag("NF[1:0]", 0, 2) 186 .WithTaggedFlag("ACKBR", 2) 187 .WithFlag(3, out transmitNegativeAcknowledge, name: "ACKBT", 188 changeCallback: (previous, _) => 189 { 190 if(!transmitAcknowledgeWriteEnable.Value) 191 { 192 this.WarningLog("Attempted to set ACKBT (Transmit Acknowledge) without disabling write protection, ignoring"); 193 transmitNegativeAcknowledge.Value = previous; 194 } 195 }) 196 .WithFlag(4, out transmitAcknowledgeWriteEnable, name: "ACKWP") 197 .WithTaggedFlag("RDRFS", 5) 198 .WithTaggedFlag("WAIT", 6) 199 .WithTaggedFlag("SMBS", 7); 200 201 Registers.FunctionEnable.Define(this, 0x72) 202 .WithTaggedFlag("TMOE", 0) 203 .WithTaggedFlag("MALE", 1) 204 .WithTaggedFlag("NALE", 2) 205 .WithTaggedFlag("SALE", 3) 206 .WithTaggedFlag("NACKE", 4) 207 .WithTaggedFlag("NFE", 5) 208 .WithTaggedFlag("SCLE", 6) 209 .WithTaggedFlag("FMPE", 7); 210 211 Registers.StatusEnable.Define(this, 0x9) 212 .WithTaggedFlag("SAR0E", 0) 213 .WithTaggedFlag("SAR1E", 1) 214 .WithTaggedFlag("SAR2E", 2) 215 .WithTaggedFlag("GCAE", 3) 216 .WithReservedBits(4, 1) 217 .WithTaggedFlag("DIDE", 5) 218 .WithReservedBits(6, 1) 219 .WithTaggedFlag("HOAE", 7); 220 221 Registers.InterruptEnable.Define(this) 222 .WithTaggedFlag("TMOIE", 0) 223 .WithTaggedFlag("ALIE", 1) 224 .WithFlag(2, out startInterrupt.Enable, name: "STIE") 225 .WithFlag(3, out stopInterrupt.Enable, name: "SPIE") 226 .WithFlag(4, out nackInterrupt.Enable, name: "NAKIE") 227 .WithFlag(5, out receiveInterrupt.Enable, name: "RIE") 228 .WithFlag(6, out transmitEndInterrupt.Enable, name: "TEIE") 229 .WithFlag(7, out transmitInterrupt.Enable, name: "TIE") 230 .WithChangeCallback((_, __) => UpdateInterrupts()); 231 232 status1Register = Registers.Status1.Define(this) 233 .WithTaggedFlag("AAS0", 0) 234 .WithTaggedFlag("AAS1", 1) 235 .WithTaggedFlag("AAS2", 2) 236 .WithTaggedFlag("GCA", 3) 237 .WithReservedBits(4, 1) 238 .WithTaggedFlag("DID", 5) 239 .WithReservedBits(6, 1) 240 .WithTaggedFlag("HOA", 7); 241 242 status2Register = Registers.Status2.Define(this) 243 .WithTaggedFlag("TMOF", 0) 244 .WithTaggedFlag("AL", 1) 245 .WithFlag(2, out startInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "START") 246 .WithFlag(3, out stopInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "STOP") 247 .WithFlag(4, out nackInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "NACKF") 248 .WithFlag(5, out receiveInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "RDRF") 249 .WithFlag(6, out transmitEndInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TEND") 250 .WithFlag(7, out transmitInterrupt.FlagField, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TDRE") 251 .WithChangeCallback((_, __) => UpdateInterrupts()); 252 253 for(var i = 0; i < SlaveAddressCount; i++) 254 { 255 (Registers.SlaveAddressLower0 + 0x2 * i).Define(this) 256 .WithTaggedFlag("SVA0", 0) 257 .WithTag("SVA[6:0]", 1, 7); 258 259 (Registers.SlaveAddressUpper0 + 0x2 * i).Define(this) 260 .WithTaggedFlag("FS", 0) 261 .WithTag("SVA[1:0]", 1, 2) 262 .WithReservedBits(3, 5); 263 } 264 265 Registers.BitRateLowLevel.Define(this, 0xFF) 266 .WithTag("BRL[4:0]", 0, 5) 267 .WithReservedBits(5, 3, 0x7); 268 269 Registers.BitRateHighLevel.Define(this, 0xFF) 270 .WithTag("BRH[4:0]", 0, 5) 271 .WithReservedBits(5, 3, 0x7); 272 273 Registers.TransmitData.Define(this) 274 .WithValueField(0, 8, FieldMode.Write, name: "ICDRT", 275 writeCallback: (_, value) => 276 { 277 // TXI and TEI flags should be automatically cleared by a write to the ICDRT register 278 transmitInterrupt.Flag = false; 279 transmitEndInterrupt.Flag = false; 280 if(currentTransmissionState == TransmissionState.WriteAddress) 281 { 282 // In Renode I2C transmissions generally happen instantly. Since software may not be prepared for that 283 // we artificially delay the start of the transaction by delaying the write of the target peripheral address 284 // This is the best place for delays as software will always perform the address write regardless of how it 285 // starts the transmission (either via the Start or Restart conditions) 286 machine.ScheduleAction(addressWriteDelay, ___ => 287 { 288 WriteData((byte)value); 289 UpdateInterrupts(); 290 }); 291 } 292 else 293 { 294 WriteData((byte)value); 295 } 296 UpdateInterrupts(); 297 }); 298 299 Registers.ReceiveData.Define(this) 300 .WithValueField(0, 8, FieldMode.Read, name: "ICDRR", 301 valueProviderCallback: _ => 302 { 303 // RXI flag should be automatically cleared by reading the ICDRR register 304 receiveInterrupt.Flag = false; 305 var result = ReadData(); 306 UpdateInterrupts(); 307 return result; 308 }); 309 310 Registers.WakeupUnit.Define(this, 0x10) 311 .WithTaggedFlag("WUAFA", 0) 312 .WithReservedBits(1, 3) 313 .WithTaggedFlag("WUAFA", 4) 314 .WithTaggedFlag("WUF", 5) 315 .WithTaggedFlag("WUIE", 6) 316 .WithTaggedFlag("WUE", 7); 317 318 Registers.WakeupUnit2.Define(this, 0xFD) 319 .WithTaggedFlag("WUSEN", 0) 320 .WithTaggedFlag("WUASYF", 1) 321 .WithTaggedFlag("WUSYF", 2) 322 .WithReservedBits(3, 5); 323 } 324 WriteData(byte value)325 private void WriteData(byte value) 326 { 327 switch(currentTransmissionState) 328 { 329 case TransmissionState.WriteAddress: 330 { 331 if((value >> 3) == ExtendedAddressPrefix) 332 { 333 this.ErrorLog("10-bit addressing is currently not supported"); 334 nackInterrupt.Flag = true; 335 return; 336 } 337 338 var isRead = BitHelper.IsBitSet(value, 0); 339 var address = value >> 1; 340 if(!TryGetByAddress(address, out selectedPeripheral)) 341 { 342 nackInterrupt.Flag = true; 343 this.ErrorLog("Invalid slave peripheral address 0x{0:X}", address); 344 return; 345 } 346 this.DebugLog("Selected peripheral 0x{0:X} ({1})", address, selectedPeripheral.GetName()); 347 currentTransmissionState = isRead ? TransmissionState.Read : TransmissionState.Write; 348 receiveInterrupt.Flag = isRead; 349 transmitInterrupt.Flag = !isRead; 350 transmitEndInterrupt.Flag = transmitInterrupt.Flag; 351 if(isRead) 352 { 353 // Software should discard the first read, as reading it is used for starting the transmission 354 // on real hardware. Add a dummy value to make sure that a value read from a sensor is not 355 // accidentally discarded. 356 readQueue.Enqueue(0x0); 357 } 358 break; 359 } 360 case TransmissionState.Write: 361 writeQueue.Enqueue(value); 362 transmitInterrupt.Flag = true; 363 transmitEndInterrupt.Flag = true; 364 break; 365 default: 366 this.ErrorLog("Transmission state: {0} is not valid when writing data (value 0x{1:X})", currentTransmissionState, value); 367 return; 368 } 369 } 370 ReadData()371 private byte ReadData() 372 { 373 switch(currentTransmissionState) 374 { 375 case TransmissionState.Read: 376 { 377 if(readQueue.Count == 0) 378 { 379 if(selectedPeripheral == null) 380 { 381 this.WarningLog("Attempted to perform a peripheral read without selecting one"); 382 } 383 else 384 { 385 // From IIC controller's perspective there is no way to determine 386 // how many bytes is software intending to read. Since some peripherals 387 // assume that the entire read operation will be performed using a single `Read` call 388 // we request more bytes, buffer them and return those values during subsequent reads 389 // The amount of bytes to buffer was chosen randomly and may be adjusted if required. 390 var data = selectedPeripheral.Read(ReadByteCount); 391 this.DebugLog("Read {0} from peripheral", data.ToLazyHexString()); 392 readQueue.EnqueueRange(data); 393 } 394 } 395 396 if(!readQueue.TryDequeue(out var result)) 397 { 398 this.ErrorLog("Empty read buffer, returning 0x0"); 399 nackInterrupt.Flag = true; 400 return 0x0; 401 } 402 403 // Issue Stop or Restart if a NACK was requested during the last read 404 if(finishReading) 405 { 406 finishReading = false; 407 // Perform restart if it was requested. Otherwise always stop 408 if(!restartCondition.TryPerform()) 409 { 410 stopCondition.Perform(); 411 } 412 return result; 413 } 414 415 finishReading = transmitNegativeAcknowledge.Value; 416 receiveInterrupt.Flag = true; 417 return result; 418 } 419 default: 420 this.ErrorLog("Transmission state: {0} is not valid when reading data", currentTransmissionState); 421 return 0x0; 422 } 423 } 424 UpdateInterrupts()425 private void UpdateInterrupts() 426 { 427 var rxi = receiveInterrupt.InterruptState; 428 var txi = transmitInterrupt.InterruptState; 429 var tei = transmitEndInterrupt.InterruptState; 430 var eri = startInterrupt.InterruptState || 431 stopInterrupt.InterruptState || 432 nackInterrupt.InterruptState; 433 434 // Both IICn_TXI and IICn_RXI interrupts are edge detected. 435 // See Note 1 and 2 in Table 31.10 in RA6M5 Group User's Manual 436 if(rxi) 437 { 438 ReceiveIRQ.Blink(); 439 } 440 if(txi) 441 { 442 TransmitIRQ.Blink(); 443 } 444 TransmitEndIRQ.Set(tei); 445 ErrorOrEventIRQ.Set(eri); 446 447 this.DebugLog("{0}: {1}, {2}: {3}, {4}: {5}, {6}: {7}", 448 nameof(ReceiveIRQ), rxi ? "Blinking" : "Not blinking", 449 nameof(TransmitIRQ), txi ? "Blinking" : "Not blinking", 450 nameof(TransmitEndIRQ), tei, 451 nameof(ErrorOrEventIRQ), eri 452 ); 453 } 454 HandleStartCondition()455 private void HandleStartCondition() 456 { 457 currentTransmissionState = TransmissionState.WriteAddress; 458 transmitInterrupt.Flag = true; 459 startInterrupt.Flag = true; 460 stopInterrupt.Flag = false; 461 } 462 HandleStopCondition()463 private void HandleStopCondition() 464 { 465 stopInterrupt.Flag = true; 466 startInterrupt.Flag = false; 467 transmitNegativeAcknowledge.Value = false; 468 transmitInterrupt.Flag = false; 469 transmitEndInterrupt.Flag = false; 470 finishReading = false; 471 472 // Flush the transmit buffer to the peripheral 473 if(selectedPeripheral != null && currentTransmissionState == TransmissionState.Write) 474 { 475 if(writeQueue.Count == 0) 476 { 477 this.WarningLog("No data in the write buffer, aborting transmission"); 478 } 479 else 480 { 481 var content = writeQueue.ToArray(); 482 writeQueue.Clear(); 483 484 this.DebugLog("Writing {0} to peripheral", content.ToLazyHexString()); 485 selectedPeripheral.Write(content); 486 } 487 } 488 489 // Reset transmission state 490 currentTransmissionState = TransmissionState.Idle; 491 selectedPeripheral?.FinishTransmission(); 492 selectedPeripheral = null; 493 readQueue.Clear(); 494 writeQueue.Clear(); 495 } 496 HandleRestartCondition()497 private void HandleRestartCondition() 498 { 499 stopCondition.Perform(silent: true); 500 startCondition.Perform(silent: true); 501 } 502 InternalReset()503 private void InternalReset() 504 { 505 status1Register.Reset(); 506 status2Register.Reset(); 507 control2Register.Reset(); 508 509 ReceiveIRQ.Unset(); 510 TransmitIRQ.Unset(); 511 TransmitEndIRQ.Unset(); 512 ErrorOrEventIRQ.Unset(); 513 514 currentTransmissionState = TransmissionState.Idle; 515 writeQueue.Clear(); 516 readQueue.Clear(); 517 selectedPeripheral = null; 518 finishReading = false; 519 } 520 521 private InterruptConfig receiveInterrupt; 522 private InterruptConfig transmitInterrupt; 523 private InterruptConfig transmitEndInterrupt; 524 private InterruptConfig startInterrupt; 525 private InterruptConfig stopInterrupt; 526 private InterruptConfig nackInterrupt; 527 528 private IFlagRegisterField transmitNegativeAcknowledge; 529 private IFlagRegisterField transmitAcknowledgeWriteEnable; 530 private IFlagRegisterField peripheralEnable; 531 532 private ByteRegister status1Register; 533 private ByteRegister status2Register; 534 private ByteRegister control2Register; 535 536 private TransmissionState currentTransmissionState; 537 private II2CPeripheral selectedPeripheral; 538 private bool finishReading; 539 540 private readonly Queue<byte> writeQueue; 541 private readonly Queue<byte> readQueue; 542 543 private readonly Condition startCondition; 544 private readonly Condition stopCondition; 545 private readonly Condition restartCondition; 546 547 private static readonly TimeInterval addressWriteDelay = TimeInterval.FromMicroseconds(100); 548 549 private const int SlaveAddressCount = 3; 550 private const int ExtendedAddressPrefix = 0x1E; 551 private const int ReadByteCount = 24; 552 553 private struct InterruptConfig 554 { 555 public bool InterruptState => Enable.Value && Flag; 556 public bool Flag 557 { 558 get => FlagField.Value; 559 set => FlagField.Value = value; 560 } 561 562 public IFlagRegisterField Enable; 563 public IFlagRegisterField FlagField; 564 } 565 566 private class Condition 567 { Condition(RenesasRA_IIC parent, string name, Action handler)568 public Condition(RenesasRA_IIC parent, string name, Action handler) 569 { 570 this.parent = parent; 571 this.name = name; 572 this.handler = handler; 573 } 574 TryPerform()575 public bool TryPerform() 576 { 577 if(Requested) 578 { 579 Perform(); 580 return true; 581 } 582 return false; 583 } 584 Perform(bool silent = false)585 public void Perform(bool silent = false) 586 { 587 if(!silent) 588 { 589 parent.DebugLog("Handling {0} condition", name); 590 } 591 handler(); 592 RequestFlag.Value = false; 593 parent.UpdateInterrupts(); 594 } 595 596 public bool Requested 597 { 598 get => RequestFlag.Value; 599 set => RequestFlag.Value = value; 600 } 601 602 public IFlagRegisterField RequestFlag; 603 604 private readonly RenesasRA_IIC parent; 605 private readonly string name; 606 private readonly Action handler; 607 } 608 609 private enum TransmissionState 610 { 611 Idle, 612 WriteAddress, 613 Write, 614 Read, 615 } 616 617 private enum Registers 618 { 619 Control1 = 0x00, // ICCR1 620 Control2 = 0x01, // ICCR2 621 Mode1 = 0x02, // ICMR1 622 Mode2 = 0x03, // ICMR2 623 Mode3 = 0x04, // ICMR3 624 FunctionEnable = 0x05, // ICFER 625 StatusEnable = 0x06, // ICSER 626 InterruptEnable = 0x07, // ICIER 627 Status1 = 0x08, // ICSR1 628 Status2 = 0x09, // ICSR2 629 SlaveAddressLower0 = 0x0A, // SARL0 630 SlaveAddressUpper0 = 0x0B, // SARU0 631 SlaveAddressLower1 = 0x0C, // SARL1 632 SlaveAddressUpper1 = 0x0D, // SARU1 633 SlaveAddressLower2 = 0x0E, // SARL2 634 SlaveAddressUpper2 = 0x0F, // SARU2 635 BitRateLowLevel = 0x10, // ICBRL 636 BitRateHighLevel = 0x11, // ICBRH 637 TransmitData = 0x12, // ICDRT 638 ReceiveData = 0x13, // ICDRR 639 WakeupUnit = 0x16, // ICWUR 640 WakeupUnit2 = 0x17, // ICWUR2 641 } 642 } 643 } 644