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