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.Utilities;
16 
17 namespace Antmicro.Renode.Peripherals.I2C
18 {
19     /// <summary>
20     /// This peripheral implements <see cref="IWordPeripheral"/> and <see cref="IBytePeripheral"/>
21     /// for the sake of correct handling of DMA access to <see cref="Registers.DataCommand"/> register.
22     /// Enabling automatic access translation using attributes
23     /// <see cref="AllowedTranslationsAttribute.ByteToDoubleWord"/> and <see cref="AllowedTranslationsAttribute.WordToDoubleWord"/>
24     /// wouldn't ensure correct operation, because there is an implicit double word read of an old register value for every translated write access.
25     /// Reading from <see cref="data"/> field of <see cref="Registers.DataCommand"/> register
26     /// triggers side effect that results in dequeuing single byte from receive FIFO.
27     /// Therefore for widths other than double word, we handle accesses to that register manually.
28     /// It ensures correct operation for e.g. DMA transfers.
29     /// </summary>
30     public class RenesasDA_I2C : SimpleContainer<II2CPeripheral>, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IWordPeripheral, IBytePeripheral, IKnownSize
31     {
RenesasDA_I2C(IMachine machine, IGPIOReceiver dma = null)32         public RenesasDA_I2C(IMachine machine, IGPIOReceiver dma = null) : base(machine)
33         {
34             this.dma = dma;
35             txFifo = new Queue<byte>();
36             transmission = new Queue<byte>();
37             rxFifo = new Queue<byte>();
38             IRQ = new GPIO();
39             RegistersCollection = new DoubleWordRegisterCollection(this);
40             DefineRegisters();
41         }
42 
Reset()43         public override void Reset()
44         {
45             txFifo.Clear();
46             transmission.Clear();
47             rxFifo.Clear();
48             var previousSlaveAddress = SlaveAddress;
49             RegistersCollection.Reset();
50             if(SlaveAddress != previousSlaveAddress)
51             {
52                 AddressChanged?.Invoke(SlaveAddress);
53             }
54             UpdateInterrupts();
55         }
56 
ReadDoubleWord(long offset)57         public uint ReadDoubleWord(long offset)
58         {
59             return RegistersCollection.Read(offset);
60         }
61 
WriteDoubleWord(long offset, uint value)62         public void WriteDoubleWord(long offset, uint value)
63         {
64             RegistersCollection.Write(offset, value);
65         }
66 
ReadWord(long offset)67         public ushort ReadWord(long offset)
68         {
69             if(offset == (long)Registers.DataCommand)
70             {
71                 return (ushort)RegistersCollection.Read(offset);
72             }
73             this.Log(LogLevel.Warning, "Unsupported read word access to offset {0:X}", offset);
74             return 0;
75         }
76 
WriteWord(long offset, ushort value)77         public void WriteWord(long offset, ushort value)
78         {
79             if(offset == (long)Registers.DataCommand)
80             {
81                 RegistersCollection.Write(offset, value);
82             }
83             else
84             {
85                 this.Log(LogLevel.Warning, "Unsupported write word access to offset {0:X}", offset);
86             }
87         }
88 
ReadByte(long offset)89         public byte ReadByte(long offset)
90         {
91             switch(offset)
92             {
93                 case (long)Registers.DataCommand:
94                     return ReadData();
95                 case (long)Registers.DataCommand + 1:
96                     return dataCommandOffset1Shadow.Read();
97                 default:
98                     this.Log(LogLevel.Warning, "Unsupported read byte access to offset {0:X}", offset);
99                     return 0;
100             }
101         }
102 
WriteByte(long offset, byte value)103         public void WriteByte(long offset, byte value)
104         {
105             switch(offset)
106             {
107                 case (long)Registers.DataCommand:
108                     data.Value = value;
109                     WriteCommand();
110                     break;
111                 case (long)Registers.DataCommand + 1:
112                     dataCommandOffset1Shadow.Write(0, value);
113                     break;
114                 default:
115                     this.Log(LogLevel.Warning, "Unsupported write byte access to offset {0:X}", offset);
116                     break;
117             }
118         }
119 
120         public DoubleWordRegisterCollection RegistersCollection { get; }
121 
122         public GPIO IRQ { get; }
123 
124         public long Size => 0x100;
125 
126         public int SlaveAddress => TrimAddress(slaveAddress.Value, use10BitSlaveAddressing.Value);
127 
128         public event Action<int> AddressChanged;
129 
130         public const int DefaultSlaveAddress = 0x55;
131 
DefineRegisters()132         private void DefineRegisters()
133         {
134             Registers.Control.Define(this, 0x0000007f)
135                 .WithFlag(0, out masterEnabled, name: "I2C_MASTER_MODE")
136                 .WithEnumField<DoubleWordRegister, SpeedMode>(1, 2, out speedMode, name: "I2C_SPEED",
137                     changeCallback: (value, previousValue) =>
138                     {
139                         switch(value)
140                         {
141                             case SpeedMode.Standard:
142                             case SpeedMode.Fast:
143                             case SpeedMode.HighSpeed:
144                                 break;
145                             default:
146                                 this.Log(LogLevel.Warning, "Attempted write with reserved value to I2C_SPEED (0x{0:X}), ignoring", value);
147                                 speedMode.Value = previousValue;
148                                 break;
149                         }
150                     }
151                 )
152                 .WithFlag(3, out use10BitSlaveAddressing, name: "I2C_10BITADDR_SLAVE",
153                     changeCallback: (_, previousValue) => HandleSlaveAddressChange(previousUse10Bit: previousValue)
154                 )
155                 .WithFlag(4, out use10BitTargetAddressing, name: "I2C_10BITADDR_MASTER",
156                     changeCallback: (_, previousValue) => HandleTargetAddressChange(previousUse10Bit: previousValue)
157                 )
158                 .WithFlag(5, out restartEnabled, name: "I2C_RESTART_EN")
159                 .WithTaggedFlag("I2C_SLAVE_DISABLE", 6)
160                 .WithTaggedFlag("I2C_STOP_DET_IFADDRESSED", 7)
161                 .WithTaggedFlag("I2C_TX_EMPTY_CTRL", 8)
162                 .WithTaggedFlag("I2C_RX_FIFO_FULL_HLD_CTRL", 9)
163                 .WithTaggedFlag("I2C_STOP_DET_IF_MASTER_ACTIVE", 10)
164                 .WithReservedBits(11, 21)
165                 .WithWriteCallback((_, __) =>
166                 {
167                     activityDetected.Value = true;
168                     UpdateInterrupts();
169                 })
170             ;
171 
172             Registers.TargetAddress.Define(this, DefaultSlaveAddress)
173                 .WithValueField(0, 10, out targetAddress, name: "IC_TAR",
174                     changeCallback: (_, previousValue) =>
175                     {
176                         if(IsControllerEnabled(targetAddress, previousValue, "IC_TAR"))
177                         {
178                             return;
179                         }
180                         HandleTargetAddressChange(previousAddress: previousValue);
181                     }
182                 )
183                 .WithTaggedFlag("GC_OR_START", 10)
184                 .WithTaggedFlag("SPECIAL", 11)
185                 .WithReservedBits(12, 20)
186             ;
187 
188             Registers.SlaveAddress.Define(this, 0x00000055)
189                 .WithValueField(0, 10, out slaveAddress, name: "IC_SAR",
190                     changeCallback: (_, previousValue) =>
191                     {
192                         if(IsControllerEnabled(slaveAddress, previousValue, "IC_SAR"))
193                         {
194                             return;
195                         }
196                         HandleSlaveAddressChange(previousAddress: previousValue);
197                     }
198                 )
199                 .WithReservedBits(10, 22)
200             ;
201 
202             Registers.HighSpeedMasterModeCodeAddress.Define(this, 0x00000001)
203                 .WithTag("I2C_IC_HS_MAR", 0, 3)
204                 .WithReservedBits(3, 29)
205             ;
206 
207             Registers.DataCommand.Define(this)
208                 .WithValueField(0, 8, out data, valueProviderCallback: _ => ReadData(), name: "I2C_DAT")
209                 .WithEnumField<DoubleWordRegister, Command>(8, 1, out command, FieldMode.Write, name: "I2C_CMD")
210                 .WithFlag(9, out stop, FieldMode.Write, name: "I2C_STOP")
211                 .WithFlag(10, out restart, FieldMode.Write, name: "I2C_RESTART")
212                 .WithReservedBits(11, 21)
213                 .WithWriteCallback((_, __) => WriteCommand())
214             ;
215 
216             dataCommandOffset1Shadow = new ByteRegister(this)
217                 .WithEnumField<ByteRegister, Command>(0, 1, FieldMode.Write, writeCallback: (_, value) => command.Value = value, name: "I2C_CMD")
218                 .WithFlag(1, FieldMode.Write, writeCallback: (_, value) => stop.Value = value, name: "I2C_STOP")
219                 .WithFlag(2, FieldMode.Write, writeCallback: (_, value) => restart.Value = value, name: "I2C_RESTART");
220 
221             Registers.StandardSpeedSCLHighCount.Define(this, 0x00000091)
222                 .WithValueField(0, 16, out standardSpeedClockHighCount, name: "IC_SS_SCL_HCNT",
223                     changeCallback: (value, previousValue) =>
224                     {
225                         if(IsControllerEnabled(standardSpeedClockHighCount, previousValue, "IC_SS_SCL_HCNT"))
226                         {
227                             return;
228                         }
229                         if(value < ClockHighMinCount)
230                         {
231                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to IC_SS_SCL_HCNT (0x{0:X}), setting to {1}", value, ClockHighMinCount);
232                             standardSpeedClockHighCount.Value = ClockHighMinCount;
233                             return;
234                         }
235                         if(value > StandardSpeedClockHighMaxCount)
236                         {
237                             this.Log(LogLevel.Warning, "Attempted write with value greater then {1} to IC_SS_SCL_HCNT (0x{0:X}), ignoring", value, StandardSpeedClockHighMaxCount);
238                             standardSpeedClockHighCount.Value = previousValue;
239                         }
240                     }
241                 )
242                 .WithReservedBits(16, 16)
243             ;
244 
245             Registers.StandardSpeedSCLLowCount.Define(this, 0x000000ab)
246                 .WithValueField(0, 16, out standardSpeedClockLowCount, name: "IC_SS_SCL_LCNT",
247                     changeCallback: (value, previousValue) =>
248                     {
249                         if(IsControllerEnabled(standardSpeedClockLowCount, previousValue, "IC_SS_SCL_LCNT"))
250                         {
251                             return;
252                         }
253                         if(value < ClockLowMinCount)
254                         {
255                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to IC_SS_SCL_LCNT (0x{0:X}), setting to {1}", value, ClockLowMinCount);
256                             standardSpeedClockLowCount.Value = ClockLowMinCount;
257                         }
258                     }
259                 )
260                 .WithReservedBits(16, 16)
261             ;
262 
263             Registers.FastSpeedSCLHighCount.Define(this, 0x0000001a)
264                 .WithValueField(0, 16, out fastSpeedClockHighCount, name: "IC_FS_SCL_HCNT",
265                     changeCallback: (value, previousValue) =>
266                     {
267                         if(IsControllerEnabled(fastSpeedClockHighCount, previousValue, "IC_FS_SCL_HCNT"))
268                         {
269                             return;
270                         }
271                         if(value < ClockHighMinCount)
272                         {
273                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to IC_FS_SCL_HCNT (0x{0:X}), setting to {1}", value, ClockHighMinCount);
274                             fastSpeedClockHighCount.Value = ClockHighMinCount;
275                         }
276                     }
277                 )
278                 .WithReservedBits(16, 16)
279             ;
280 
281             Registers.FastSpeedSCLLowCount.Define(this, 0x00000032)
282                 .WithValueField(0, 16, out fastSpeedClockLowCount, name: "IC_FS_SCL_LCNT",
283                     changeCallback: (value, previousValue) =>
284                     {
285                         if(IsControllerEnabled(fastSpeedClockLowCount, previousValue, "IC_FS_SCL_LCNT"))
286                         {
287                             return;
288                         }
289                         if(value < ClockLowMinCount)
290                         {
291                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to IC_FS_SCL_LCNT (0x{0:X}), setting to {1}", value, ClockLowMinCount);
292                             fastSpeedClockLowCount.Value = ClockLowMinCount;
293                         }
294                     }
295                 )
296                 .WithReservedBits(16, 16)
297             ;
298 
299             Registers.HighSpeedSCLHighCount.Define(this, 0x00000006)
300                 .WithValueField(0, 16, out highSpeedClockHighCount, name: "IC_HS_SCL_HCNT",
301                     changeCallback: (value, previousValue) =>
302                     {
303                         if(IsControllerEnabled(highSpeedClockHighCount, previousValue, "IC_HS_SCL_HCNT"))
304                         {
305                             return;
306                         }
307                         if(value < ClockHighMinCount)
308                         {
309                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to IC_HS_SCL_HCNT (0x{0:X}), setting to {1}", value, ClockHighMinCount);
310                             highSpeedClockHighCount.Value = ClockHighMinCount;
311                         }
312                     }
313                 )
314                 .WithReservedBits(16, 16)
315             ;
316 
317             Registers.HighSpeedSCLLowCount.Define(this, 0x00000010)
318                 .WithValueField(0, 16, out highSpeedClockLowCount, name: "IC_HS_SCL_LCNT",
319                     changeCallback: (value, previousValue) =>
320                     {
321                         if(IsControllerEnabled(highSpeedClockLowCount, previousValue, "IC_HS_SCL_LCNT"))
322                         {
323                             return;
324                         }
325                         if(value < ClockLowMinCount)
326                         {
327                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to IC_HS_SCL_LCNT (0x{0:X}), setting to {1}", value, ClockLowMinCount);
328                             highSpeedClockLowCount.Value = ClockLowMinCount;
329                         }
330                     }
331                 )
332                 .WithReservedBits(16, 16)
333             ;
334 
335             Registers.InterruptStatus.Define(this)
336                 .WithFlag(0, FieldMode.Read, name: "R_RX_UNDER",
337                     valueProviderCallback: _ => rxUnderflow.Value
338                 )
339                 .WithTaggedFlag("R_RX_OVER", 1)
340                 .WithFlag(2, FieldMode.Read, name: "R_RX_FULL",
341                     valueProviderCallback: _ => RxFull
342                 )
343                 .WithFlag(3, FieldMode.Read, name: "R_TX_OVER",
344                     valueProviderCallback: _ => txOverflow.Value
345                 )
346                 .WithFlag(4, FieldMode.Read, name: "R_TX_EMPTY",
347                     valueProviderCallback: _ => TxEmpty
348                 )
349                 .WithTaggedFlag("R_RD_REQ", 5)
350                 .WithFlag(6, FieldMode.Read, name: "R_TX_ABRT",
351                     valueProviderCallback: _ => txAbort.Value
352                 )
353                 .WithTaggedFlag("R_RX_DONE", 7)
354                 .WithFlag(8, FieldMode.Read, name: "R_ACTIVITY",
355                     valueProviderCallback: _ => activityDetected.Value
356                 )
357                 .WithFlag(9, FieldMode.Read, name: "R_STOP_DET",
358                     valueProviderCallback: _ => stopDetected.Value
359                 )
360                 .WithTaggedFlag("R_START_DET", 10)
361                 .WithTaggedFlag("R_GEN_CALL", 11)
362                 .WithTaggedFlag("R_RESTART_DET", 12)
363                 .WithTaggedFlag("R_MASTER_ON_HOLD", 13)
364                 .WithFlag(14, FieldMode.Read, name: "R_SCL_STUCK_AT_LOW",
365                     valueProviderCallback: _ => false
366                 )
367                 .WithReservedBits(15, 17)
368             ;
369 
370             Registers.InterruptMask.Define(this, 0x000008ff)
371                 .WithFlag(0, out rxUnderflowMask, name: "M_RX_UNDER")
372                 .WithFlag(1, name: "M_RX_OVER")
373                 .WithFlag(2, out rxFullMask, name: "M_RX_FULL")
374                 .WithFlag(3, out txOverflowMask, name: "M_TX_OVER")
375                 .WithFlag(4, out txEmptyMask, name: "M_TX_EMPTY")
376                 .WithTaggedFlag("M_RD_REQ", 5)
377                 .WithFlag(6, out txAbortMask, name: "M_TX_ABRT")
378                 .WithTaggedFlag("M_RX_DONE", 7)
379                 .WithFlag(8, out activityDetectedMask, name: "M_ACTIVITY")
380                 .WithFlag(9, out stopDetectedMask, name: "M_STOP_DET")
381                 .WithTaggedFlag("M_START_DET", 10)
382                 .WithTaggedFlag("M_GEN_CALL", 11)
383                 .WithTaggedFlag("M_RESTART_DET", 12)
384                 .WithTaggedFlag("M_MASTER_ON_HOLD", 13)
385                 .WithFlag(14, name: "M_SCL_STUCK_AT_LOW")
386                 .WithReservedBits(15, 17)
387                 .WithChangeCallback((_ ,__) => UpdateInterrupts())
388             ;
389 
390             Registers.RawInterruptStatus.Define(this)
391                 .WithFlag(0, out rxUnderflow, FieldMode.Read, name: "RX_UNDER")
392                 .WithTaggedFlag("RX_OVER", 1)
393                 .WithFlag(2, FieldMode.Read, name: "RX_FULL",
394                     valueProviderCallback: _ => RxFull
395                 )
396                 .WithFlag(3, out txOverflow, FieldMode.Read, name: "TX_OVER")
397                 .WithFlag(4, FieldMode.Read, name: "TX_EMPTY",
398                     valueProviderCallback: _ => TxEmpty
399                 )
400                 .WithTaggedFlag("RD_REQ", 5)
401                 .WithFlag(6, out txAbort, FieldMode.Read, name: "TX_ABRT")
402                 .WithTaggedFlag("RX_DONE", 7)
403                 .WithFlag(8, out activityDetected, FieldMode.Read, name: "ACTIVITY")
404                 .WithFlag(9, out stopDetected, FieldMode.Read, name: "STOP_DET")
405                 .WithTaggedFlag("START_DET", 10)
406                 .WithTaggedFlag("GEN_CALL", 11)
407                 .WithTaggedFlag("RESTART_DET", 12)
408                 .WithTaggedFlag("MASTER_ON_HOLD", 13)
409                 .WithFlag(14, FieldMode.Read, name: "SCL_STUCK_AT_LOW",
410                     valueProviderCallback: _ => false
411                 )
412                 .WithReservedBits(15, 17)
413             ;
414 
415             Registers.ReceiveFIFOThreshold.Define(this)
416                 .WithValueField(0, 5, out rxFifoThreshold, name: "RX_TL")
417                 .WithReservedBits(5, 27)
418                 .WithChangeCallback((_ ,__) => UpdateInterrupts())
419                 .WithWriteCallback((_, value) =>
420                     {
421                         if(value >= FifoSize)
422                         {
423                             rxFifoThreshold.Value = FifoSize - 1;
424                             UpdateInterrupts();
425                         }
426                     }
427                 )
428             ;
429 
430             Registers.TransmitFIFOThreshold.Define(this)
431                 .WithValueField(0, 5, out txFifoThreshold, name: "TX_TL")
432                 .WithReservedBits(5, 27)
433                 .WithChangeCallback((_ ,__) => UpdateInterrupts())
434                 .WithWriteCallback((_, value) =>
435                     {
436                         if(value >= FifoSize)
437                         {
438                             txFifoThreshold.Value = FifoSize - 1;
439                             UpdateInterrupts();
440                         }
441                     }
442                 )
443             ;
444 
445             Registers.ClearCombinedAndIndividualInterrupt.Define(this)
446                 .WithTaggedFlag("CLR_INTR", 0)
447                 .WithReservedBits(1, 31)
448                 .WithReadCallback((_, __) =>
449                     {
450                         rxUnderflow.Value = false;
451                         txOverflow.Value = false;
452                         txAbort.Value = false;
453                         activityDetected.Value = false;
454                         stopDetected.Value = false;
455                         UpdateInterrupts();
456                     }
457                 )
458             ;
459 
460             Registers.ClearRX_UNDERInterrupt.Define(this)
461                 .WithTaggedFlag("CLR_RX_UNDER", 0)
462                 .WithReservedBits(1, 31)
463                 .WithReadCallback((_, __) =>
464                     {
465                         rxUnderflow.Value = false;
466                         UpdateInterrupts();
467                     }
468                 )
469             ;
470 
471             Registers.ClearRX_OVERInterrupt.Define(this)
472                 .WithTaggedFlag("CLR_RX_OVER", 0)
473                 .WithReservedBits(1, 31)
474             ;
475 
476             Registers.ClearTX_OVERInterrupt.Define(this)
477                 .WithTaggedFlag("CLR_TX_OVER", 0)
478                 .WithReservedBits(1, 31)
479                 .WithReadCallback((_, __) =>
480                     {
481                         txOverflow.Value = false;
482                         UpdateInterrupts();
483                     }
484                 )
485             ;
486 
487             Registers.ClearRD_REQInterrupt.Define(this)
488                 .WithTaggedFlag("CLR_RD_REQ", 0)
489                 .WithReservedBits(1, 31)
490             ;
491 
492             Registers.ClearTX_ABRTInterrupt.Define(this)
493                 .WithTaggedFlag("CLR_TX_ABRT", 0)
494                 .WithReadCallback((_, __) =>
495                     {
496                         txAbort.Value = false;
497                         UpdateInterrupts();
498                     }
499                 )
500                 .WithReservedBits(1, 31)
501             ;
502 
503             Registers.ClearRX_DONEInterrupt.Define(this)
504                 .WithTaggedFlag("CLR_RX_DONE", 0)
505                 .WithReservedBits(1, 31)
506             ;
507 
508             Registers.ClearACTIVITYInterrupt.Define(this)
509                 .WithTaggedFlag("CLR_ACTIVITY", 0)
510                 .WithReservedBits(1, 31)
511                 .WithReadCallback((_, __) =>
512                     {
513                         activityDetected.Value = false;
514                         UpdateInterrupts();
515                     }
516                 )
517             ;
518 
519             Registers.ClearSTOP_DETInterrupt.Define(this)
520                 .WithTaggedFlag("CLR_STOP_DET", 0)
521                 .WithReservedBits(1, 31)
522                 .WithReadCallback((_, __) =>
523                     {
524                         stopDetected.Value = false;
525                         UpdateInterrupts();
526                     }
527                 )
528             ;
529 
530             Registers.ClearSTART_DETInterrupt.Define(this)
531                 .WithTaggedFlag("CLR_START_DET", 0)
532                 .WithReservedBits(1, 31)
533             ;
534 
535             Registers.ClearGEN_CALLInterrupt.Define(this)
536                 .WithTaggedFlag("CLR_GEN_CALL", 0)
537                 .WithReservedBits(1, 31)
538             ;
539 
540             Registers.Enable.Define(this)
541                 .WithFlag(0, out controllerEnabled, name: "I2C_EN")
542                 .WithFlag(1, name: "I2C_ABORT",
543                     valueProviderCallback: _ => false,
544                     writeCallback: (_, value) => { if(value && controllerEnabled.Value) AbortTransmission(); }
545                 )
546                 .WithFlag(2, out txBlocked, name: "I2C_TX_CMD_BLOCK",
547                     changeCallback: (_, newValue) =>
548                     {
549                         if(!newValue)
550                         {
551                             transmission.EnqueueRange(txFifo);
552                             txFifo.Clear();
553                             UpdateInterrupts();
554                         }
555                     }
556                 )
557                 .WithReservedBits(3, 29)
558             ;
559 
560             Registers.Status.Define(this, 0x00000006)
561                 .WithFlag(0, FieldMode.Read, name: "I2C_ACTIVITY",
562                     valueProviderCallback: _ => bytesToReceive != 0 || transmission.Count != 0
563                 )
564                 .WithFlag(1, FieldMode.Read, name: "TFNF",
565                     valueProviderCallback: _ => txFifo.Count != FifoSize
566                 )
567                 .WithFlag(2, FieldMode.Read, name: "TFE",
568                     valueProviderCallback: _ => txFifo.Count == 0
569                 )
570                 .WithFlag(3, FieldMode.Read, name: "RFNE",
571                     valueProviderCallback: _ => rxFifo.Count != 0
572                 )
573                 .WithFlag(4, FieldMode.Read, name: "RFF",
574                     valueProviderCallback: _ => rxFifo.Count >= FifoSize
575                 )
576                 .WithFlag(5, FieldMode.Read, name: "MST_ACTIVITY",
577                     valueProviderCallback: _ => bytesToReceive != 0 || transmission.Count != 0
578                 )
579                 .WithFlag(6, FieldMode.Read, name: "SLV_ACTIVITY",
580                     valueProviderCallback: _ => false
581                 )
582                 .WithFlag(7, FieldMode.Read, name: "MST_HOLD_TX_FIFO_EMPTY",
583                     valueProviderCallback: _ => txFifo.Count == 0 && !stop.Value
584                 )
585                 .WithFlag(8, FieldMode.Read, name: "MST_HOLD_RX_FIFO_FULL",
586                     valueProviderCallback: _ => rxFifo.Count > FifoSize
587                 )
588                 .WithFlag(9, FieldMode.Read, name: "SLV_HOLD_TX_FIFO_EMPTY",
589                     valueProviderCallback: _ => false
590                 )
591                 .WithFlag(10, FieldMode.Read, name: "LV_HOLD_RX_FIFO_FULL",
592                     valueProviderCallback: _ => false
593                 )
594                 .WithReservedBits(11, 21)
595             ;
596 
597             Registers.TransmitFIFOLevel.Define(this)
598                 .WithValueField(0, 6, FieldMode.Read, name: "TXFLR",
599                     valueProviderCallback: _ => (ulong)txFifo.Count
600                 )
601                 .WithReservedBits(6, 26)
602             ;
603 
604             Registers.ReceiveFIFOLevel.Define(this)
605                 .WithValueField(0, 6, FieldMode.Read, name: "RXFLR",
606                     valueProviderCallback: _ =>
607                     {
608                         if(rxFifo.Count == 0)
609                         {
610                             // if software polls this register for RX then perform read
611                             PerformReception();
612                         }
613                         return (ulong)rxFifo.Count.Clamp(0, FifoSize);
614                     }
615                 )
616                 .WithReservedBits(6, 26)
617             ;
618 
619             Registers.SDAHoldTimeLength.Define(this, 0x00000001)
620                 .WithTag("I2C_SDA_TX_HOLD", 0, 16)
621                 .WithTag("I2C_SDA_RX_HOLD", 16, 8)
622                 .WithReservedBits(24, 8)
623             ;
624 
625             Registers.TransmitAbortSource.Define(this)
626                 .WithTaggedFlag("ABRT_7B_ADDR_NOACK", 0)
627                 .WithTaggedFlag("ABRT_10ADDR1_NOACK", 1)
628                 .WithTaggedFlag("ABRT_10ADDR2_NOACK", 2)
629                 .WithTaggedFlag("ABRT_TXDATA_NOACK", 3)
630                 .WithTaggedFlag("ABRT_GCALL_NOACK", 4)
631                 .WithTaggedFlag("ABRT_GCALL_READ", 5)
632                 .WithTaggedFlag("ABRT_HS_ACKDET", 6)
633                 .WithTaggedFlag("ABRT_SBYTE_ACKDET", 7)
634                 .WithTaggedFlag("ABRT_HS_NORSTRT", 8)
635                 .WithTaggedFlag("ABRT_SBYTE_NORSTRT", 9)
636                 .WithTaggedFlag("ABRT_10B_RD_NORSTRT", 10)
637                 .WithTaggedFlag("ABRT_MASTER_DIS", 11)
638                 .WithTaggedFlag("ARB_LOST", 12)
639                 .WithTaggedFlag("ABRT_SLVFLUSH_TXFIFO", 13)
640                 .WithTaggedFlag("ABRT_SLV_ARBLOST", 14)
641                 .WithTaggedFlag("ABRT_SLVRD_INTX", 15)
642                 .WithTaggedFlag("ABRT_USER_ABRT", 16)
643                 .WithReservedBits(17, 15)
644             ;
645 
646             Registers.DMAControl.Define(this)
647                 .WithFlag(0, out dmaReceiveEnabled, name: "RDMAE")
648                 .WithFlag(1, out dmaTransmitEnabled, name: "TDMAE")
649                 .WithReservedBits(2, 30)
650                 .WithWriteCallback((_, __) => CheckDMATriggers())
651             ;
652 
653             Registers.DMATransmitDataLevel.Define(this)
654                 .WithValueField(0, 5, out transmitDataLevel, name: "DMATDL")
655                 .WithReservedBits(5, 27)
656             ;
657 
658             Registers.ReceiveDataLevel.Define(this)
659                 .WithValueField(0, 5, out receiveDataLevel, name: "DMARDL")
660                 .WithReservedBits(5, 27)
661             ;
662 
663             Registers.SDASetup.Define(this, 0x00000064)
664                 .WithTag("SDA_SETUP", 0, 8)
665                 .WithReservedBits(8, 24)
666             ;
667 
668             Registers.ACKGeneralCall.Define(this)
669                 .WithTaggedFlag("ACK_GEN_CALL", 0)
670                 .WithReservedBits(1, 31)
671             ;
672 
673             Registers.EnableStatus.Define(this)
674                 .WithFlag(0, FieldMode.Read, name: "IC_EN",
675                     valueProviderCallback: _ => controllerEnabled.Value
676                 )
677                 .WithTaggedFlag("SLV_DISABLED_WHILE_BUSY", 1)
678                 .WithTaggedFlag("SLV_RX_DATA_LOST", 2)
679                 .WithReservedBits(3, 29)
680             ;
681 
682             Registers.StandardSpeedAndFastSpeedSpikeSuppressionLmitSize.Define(this, 0x00000001)
683                 .WithValueField(0, 8, out fastSpeedSpikeLength, name: "I2C_FS_SPKLEN",
684                     changeCallback: (value, previousValue) =>
685                     {
686                         if(IsControllerEnabled(fastSpeedSpikeLength, previousValue, "I2C_FS_SPKLEN"))
687                         {
688                             return;
689                         }
690                         if(value < MinSpikeLength)
691                         {
692                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to I2C_FS_SPKLEN (0x{0:X}), setting to {1}", value, MinSpikeLength);
693                             fastSpeedSpikeLength.Value = MinSpikeLength;
694                         }
695                     }
696                 )
697                 .WithReservedBits(8, 24)
698             ;
699 
700             Registers.HighSpeedSpikeSuppressionLimitSize.Define(this, 0x00000001)
701                 .WithValueField(0, 8, out highSpeedSpikeLength, name: "I2C_HS_SPKLEN",
702                     changeCallback: (value, previousValue) =>
703                     {
704                         if(IsControllerEnabled(highSpeedSpikeLength, previousValue, "I2C_HS_SPKLEN"))
705                         {
706                             return;
707                         }
708                         if(value < MinSpikeLength)
709                         {
710                             this.Log(LogLevel.Warning, "Attempted write with value lesser than {1} to I2C_HS_SPKLEN (0x{0:X}), setting to {1}", value, MinSpikeLength);
711                             highSpeedSpikeLength.Value = MinSpikeLength;
712                         }
713                     }
714                 )
715                 .WithReservedBits(8, 24)
716             ;
717         }
718 
UpdateInterrupts()719         private void UpdateInterrupts()
720         {
721             var irq = false;
722             irq |= rxUnderflow.Value && rxUnderflowMask.Value;
723             irq |= RxFull && rxFullMask.Value;
724             irq |= txOverflow.Value && txOverflowMask.Value;
725             irq |= TxEmpty && txEmptyMask.Value;
726             irq |= txAbort.Value && txAbortMask.Value;
727             irq |= activityDetected.Value && activityDetectedMask.Value;
728             irq |= stopDetected.Value && stopDetectedMask.Value;
729             this.Log(LogLevel.Debug, "IRQ {0}", irq ? "set" : "unset");
730             IRQ.Set(irq);
731         }
732 
CheckDMATriggers()733         private void CheckDMATriggers()
734         {
735             if(dmaTransmitEnabled.Value && txFifo.Count <= (int)transmitDataLevel.Value && !dmaTxInProgress)
736             {
737                 if(dma == null)
738                 {
739                     this.Log(LogLevel.Warning, "DMA TX trigger activated, but no DMA module is available. Make sure to pass reference to it to the constructor.");
740                     return;
741                 }
742                 // Trigger DMA TX transfer
743                 dmaTxInProgress = true;
744                 dma.OnGPIO(DmaTxRequest, true);
745                 dmaTxInProgress = false;
746             }
747 
748             if(dmaReceiveEnabled.Value && rxFifo.Count >= (int)receiveDataLevel.Value + 1 && !dmaRxInProgress)
749             {
750                 if(dma == null)
751                 {
752                     this.Log(LogLevel.Warning, "DMA RX trigger activated, but no DMA module is available. Make sure to pass reference to it to the constructor.");
753                     return;
754                 }
755                 // Trigger DMA RX transfer
756                 dmaRxInProgress = true;
757                 dma.OnGPIO(DmaRxRequest, true);
758                 dmaRxInProgress = false;
759             }
760         }
761 
AbortTransmission()762         private void AbortTransmission()
763         {
764             txFifo.Clear();
765             txAbort.Value = true;
766             UpdateInterrupts();
767         }
768 
ReadData()769         private byte ReadData()
770         {
771             if(!controllerEnabled.Value)
772             {
773                 this.Log(LogLevel.Debug, "Attempted read from FIFO, but controller is not enabled");
774                 return 0x0;
775             }
776             if(!masterEnabled.Value)
777             {
778                 this.Log(LogLevel.Debug, "Attempted read from FIFO, but master mode is not enabled");
779                 return 0x0;
780             }
781             var dataByte = HandleReadFromReceiveFIFO();
782             UpdateInterrupts();
783             return dataByte;
784         }
785 
WriteCommand()786         private void WriteCommand()
787         {
788             if(!controllerEnabled.Value)
789             {
790                 this.Log(LogLevel.Debug, "Attempted to perform a {0}, but controller is not enabled", command.Value);
791                 return;
792             }
793             if(!masterEnabled.Value)
794             {
795                 this.Log(LogLevel.Debug, "Attempted to perform a {0}, but master mode is not enabled", command.Value);
796                 return;
797             }
798 
799             switch(command.Value)
800             {
801                 case Command.Write:
802                     if(restart.Value)
803                     {
804                         PerformTransmission();
805                         if(!restartEnabled.Value)
806                         {
807                             // Restart capability is not enabled.
808                             // Finish current transmission before starting the new one.
809                             SendFinishTransmission();
810                         }
811                     }
812                     // On hardware, the data byte would be transmitted on bus immediately when bus bandwidth allows it.
813                     // As a kind of emulation's optimization, we handle it at a higher transaction level.
814                     // We buffer bytes for transmission until STOP or RESTART condtion,
815                     // then we perform a batch transmission to I2C peripheral.
816                     HandleWriteToTransmitFIFO((byte)data.Value);
817                     if(stop.Value)
818                     {
819                         PerformTransmission();
820                         SendFinishTransmission();
821                         stopDetected.Value = true;
822                     }
823                     break;
824                 case Command.Read:
825                     // Flush an ongoing transfer in the opposite direction (TX).
826                     // If there was no ongoing TX transfer, this is no-op.
827                     // If there was an ongoing TX transfer, I2C peripheral should see all queued data until now.
828                     PerformTransmission();
829                     if(restart.Value)
830                     {
831                         PerformReception();
832                         if(!restartEnabled.Value)
833                         {
834                             // Restart capability is not enabled.
835                             // Finish current transmission before starting the new one.
836                             SendFinishTransmission();
837                         }
838                     }
839                     // We just increment an internal counter, but do not perform the actual reception.
840                     // It is a kind of emulation's optimization to not transfer byte by byte.
841                     // Instead track the number of bytes belonging to a transaction
842                     // and perform a batch reception on STOP or RESTART condition.
843                     bytesToReceive = checked(bytesToReceive + 1);
844                     if(stop.Value)
845                     {
846                         PerformReception();
847                         SendFinishTransmission();
848                         stopDetected.Value = true;
849                     }
850                     break;
851                 default:
852                     throw new Exception("Unreachable");
853             }
854             UpdateInterrupts();
855             CheckDMATriggers();
856         }
857 
HandleReadFromReceiveFIFO()858         private byte HandleReadFromReceiveFIFO()
859         {
860             if(!rxFifo.TryDequeue(out var data))
861             {
862                 PerformReception();
863 
864                 if(!rxFifo.TryDequeue(out data))
865                 {
866                     rxUnderflow.Value = true;
867                     return 0x0;
868                 }
869             }
870             return data;
871         }
872 
PerformReception()873         private void PerformReception()
874         {
875             if(bytesToReceive == 0)
876             {
877                 return;
878             }
879 
880             if(!TryGetByAddress(TargetAddress, out var target))
881             {
882                 this.Log(LogLevel.Warning, "Attempted reading of {1} bytes from an unregistered slave at 0x{0:X}", TargetAddress, bytesToReceive);
883                 return;
884             }
885 
886             var data = target.Read(bytesToReceive);
887             rxFifo.EnqueueRange(data);
888 
889             if(data.Length != bytesToReceive)
890             {
891                 this.Log(LogLevel.Noisy, "Attempted reading of {0} bytes, but received {1}", bytesToReceive, data.Length);
892                 var bytesMissing = bytesToReceive - data.Length;
893                 if(bytesMissing > 0)
894                 {
895                      // read 0x0 bytes when slave doesn't return enough data
896                     this.Log(LogLevel.Warning, "Padding data received from a slave with {0} zeros to match expected number of bytes", bytesMissing);
897                     rxFifo.EnqueueRange(Enumerable.Repeat<byte>(0x0, bytesMissing));
898                 }
899             }
900             bytesToReceive = 0;
901 
902             this.Log(LogLevel.Debug, "Reading from a slave at 0x{0:X}, data: {1}", TargetAddress, data.ToLazyHexString());
903         }
904 
HandleWriteToTransmitFIFO(byte data)905         private void HandleWriteToTransmitFIFO(byte data)
906         {
907             if(txBlocked.Value)
908             {
909                 if(txFifo.Count == FifoSize)
910                 {
911                     txOverflow.Value = true;
912                     return;
913                 }
914                 txFifo.Enqueue(data);
915             }
916             else
917             {
918                 transmission.Enqueue(data);
919             }
920         }
921 
PerformTransmission()922         private void PerformTransmission()
923         {
924             if(transmission.Count == 0)
925             {
926                 return;
927             }
928             var data = transmission.ToArray();
929             transmission.Clear();
930 
931             if(!TryGetByAddress(TargetAddress, out var target))
932             {
933                 this.Log(LogLevel.Warning, "Writing to an unregistered slave at 0x{0:X}, data: {1}", TargetAddress, data.ToLazyHexString());
934                 return;
935             }
936 
937             this.Log(LogLevel.Debug, "Writing to a slave at 0x{0:X}, data: {1}", TargetAddress, data.ToLazyHexString());
938             target.Write(data);
939         }
940 
SendFinishTransmission()941         private void SendFinishTransmission()
942         {
943             if(!TryGetByAddress(TargetAddress, out var target))
944             {
945                 return;
946             }
947             target.FinishTransmission();
948         }
949 
TrimAddress(ulong address, bool use10Bit)950         private int TrimAddress(ulong address, bool use10Bit) => (int)address & (use10Bit ? 0x3ff : 0x7f);
951 
HandleSlaveAddressChange(ulong? previousAddress = null, bool? previousUse10Bit = null)952         private void HandleSlaveAddressChange(ulong? previousAddress = null, bool? previousUse10Bit = null)
953         {
954             if(SlaveAddress != TrimAddress(previousAddress ?? slaveAddress.Value, previousUse10Bit ?? use10BitSlaveAddressing.Value))
955             {
956                 AddressChanged?.Invoke(SlaveAddress);
957             }
958         }
959 
HandleTargetAddressChange(ulong? previousAddress = null, bool? previousUse10Bit = null)960         private void HandleTargetAddressChange(ulong? previousAddress = null, bool? previousUse10Bit = null)
961         {
962             if(TargetAddress != TrimAddress(previousAddress ?? targetAddress.Value, previousUse10Bit ?? use10BitTargetAddressing.Value)
963                 && !TryGetByAddress(TargetAddress, out var __))
964             {
965                 this.Log(LogLevel.Debug, "Addressing unregistered slave at 0x{0:X}", TargetAddress);
966             }
967         }
968 
IsControllerEnabled(IRegisterField<T> field, T previousValue, string targetName)969         private bool IsControllerEnabled<T>(IRegisterField<T> field, T previousValue, string targetName)
970         {
971             if(controllerEnabled.Value)
972             {
973                 field.Value = previousValue;
974                 this.Log(LogLevel.Warning, "Attempted write to {0} while controller enabled, ignoring", targetName);
975                 return true;
976             }
977             return false;
978         }
979 
980         private int TargetAddress => TrimAddress(targetAddress.Value, use10BitTargetAddressing.Value);
981 
982         private bool RxFull => (int)rxFifoThreshold.Value < rxFifo.Count;
983         private bool TxEmpty => txFifo.Count < (int)txFifoThreshold.Value;
984 
985         private IFlagRegisterField masterEnabled;
986         private IEnumRegisterField<SpeedMode> speedMode;
987         private IFlagRegisterField use10BitSlaveAddressing;
988         private IFlagRegisterField use10BitTargetAddressing;
989         private IValueRegisterField targetAddress;
990         private IValueRegisterField slaveAddress;
991         private IValueRegisterField standardSpeedClockHighCount;
992         private IValueRegisterField standardSpeedClockLowCount;
993         private IValueRegisterField fastSpeedClockHighCount;
994         private IValueRegisterField fastSpeedClockLowCount;
995         private IValueRegisterField highSpeedClockHighCount;
996         private IValueRegisterField highSpeedClockLowCount;
997         private IFlagRegisterField rxUnderflowMask;
998         private IFlagRegisterField rxFullMask;
999         private IFlagRegisterField txOverflowMask;
1000         private IFlagRegisterField txEmptyMask;
1001         private IFlagRegisterField txAbortMask;
1002         private IFlagRegisterField activityDetectedMask;
1003         private IFlagRegisterField stopDetectedMask;
1004         private IFlagRegisterField rxUnderflow;
1005         private IFlagRegisterField txOverflow;
1006         private IFlagRegisterField txAbort;
1007         private IFlagRegisterField activityDetected;
1008         private IFlagRegisterField stopDetected;
1009         private IValueRegisterField rxFifoThreshold;
1010         private IValueRegisterField txFifoThreshold;
1011         private IFlagRegisterField controllerEnabled;
1012         private IFlagRegisterField txBlocked;
1013         private IFlagRegisterField dmaReceiveEnabled;
1014         private IFlagRegisterField dmaTransmitEnabled;
1015         private IValueRegisterField fastSpeedSpikeLength;
1016         private IValueRegisterField highSpeedSpikeLength;
1017         private IValueRegisterField transmitDataLevel;
1018         private IValueRegisterField receiveDataLevel;
1019         private IValueRegisterField data;
1020         private IEnumRegisterField<Command> command;
1021         private IFlagRegisterField stop;
1022         private IFlagRegisterField restart;
1023         private IFlagRegisterField restartEnabled;
1024 
1025         private ByteRegister dataCommandOffset1Shadow;
1026         private bool dmaRxInProgress;
1027         private bool dmaTxInProgress;
1028         private int bytesToReceive;
1029 
1030         private readonly Queue<byte> txFifo;
1031         private readonly Queue<byte> transmission;
1032         private readonly Queue<byte> rxFifo;
1033         private readonly IGPIOReceiver dma;
1034 
1035         private const uint ClockHighMinCount = 6;
1036         private const uint StandardSpeedClockHighMaxCount = 65525;
1037         private const uint ClockLowMinCount = 8;
1038         private const uint MinSpikeLength = 1;
1039         private const int FifoSize = 32;
1040         private const int DmaRxRequest = 6;
1041         private const int DmaTxRequest = 7;
1042 
1043         private enum Registers
1044         {
1045             Control = 0x0,
1046             TargetAddress = 0x4,
1047             SlaveAddress = 0x8,
1048             HighSpeedMasterModeCodeAddress = 0xC,
1049             DataCommand = 0x10,
1050             StandardSpeedSCLHighCount = 0x14,
1051             StandardSpeedSCLLowCount = 0x18,
1052             FastSpeedSCLHighCount = 0x1C,
1053             FastSpeedSCLLowCount = 0x20,
1054             HighSpeedSCLHighCount = 0x24,
1055             HighSpeedSCLLowCount = 0x28,
1056             InterruptStatus = 0x2C,
1057             InterruptMask = 0x30,
1058             RawInterruptStatus = 0x34,
1059             ReceiveFIFOThreshold = 0x38,
1060             TransmitFIFOThreshold = 0x3C,
1061             ClearCombinedAndIndividualInterrupt = 0x40,
1062             ClearRX_UNDERInterrupt = 0x44,
1063             ClearRX_OVERInterrupt = 0x48,
1064             ClearTX_OVERInterrupt = 0x4C,
1065             ClearRD_REQInterrupt = 0x50,
1066             ClearTX_ABRTInterrupt = 0x54,
1067             ClearRX_DONEInterrupt = 0x58,
1068             ClearACTIVITYInterrupt = 0x5C,
1069             ClearSTOP_DETInterrupt = 0x60,
1070             ClearSTART_DETInterrupt = 0x64,
1071             ClearGEN_CALLInterrupt = 0x68,
1072             Enable = 0x6C,
1073             Status = 0x70,
1074             TransmitFIFOLevel = 0x74,
1075             ReceiveFIFOLevel = 0x78,
1076             SDAHoldTimeLength = 0x7C,
1077             TransmitAbortSource = 0x80,
1078             DMAControl = 0x88,
1079             DMATransmitDataLevel = 0x8C,
1080             ReceiveDataLevel = 0x90,
1081             SDASetup = 0x94,
1082             ACKGeneralCall = 0x98,
1083             EnableStatus = 0x9C,
1084             StandardSpeedAndFastSpeedSpikeSuppressionLmitSize = 0xA0,
1085             HighSpeedSpikeSuppressionLimitSize = 0xA4,
1086         }
1087 
1088         private enum SpeedMode
1089         {
1090             Standard = 1,
1091             Fast = 2,
1092             HighSpeed = 3,
1093         }
1094 
1095         private enum Command
1096         {
1097             Write = 0,
1098             Read = 1,
1099         }
1100     }
1101 }
1102