1 //
2 // Copyright (c) 2010-2025 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Peripherals.DMA;
17 using Antmicro.Renode.Utilities;
18 
19 namespace Antmicro.Renode.Peripherals.I2C
20 {
21     public class SAM4S_TWI : SimpleContainer<II2CPeripheral>, IDoubleWordPeripheral, IKnownSize,
22         IProvidesRegisterCollection<DoubleWordRegisterCollection>, ISamPdcBytePeripheral, ISamPdcBlockBytePeripheral
23     {
SAM4S_TWI(Machine machine)24         public SAM4S_TWI(Machine machine) : base(machine)
25         {
26             RegistersCollection = new DoubleWordRegisterCollection(this);
27             DefineRegisters();
28             pdc = new SAM_PDC(machine, this, (long)Registers.PdcReceivePointer, HandlePdcStatusChange);
29         }
30 
ReadDoubleWord(long offset)31         public uint ReadDoubleWord(long offset)
32         {
33             return RegistersCollection.Read(offset);
34         }
35 
WriteDoubleWord(long offset, uint value)36         public void WriteDoubleWord(long offset, uint value)
37         {
38             RegistersCollection.Write(offset, value);
39         }
40 
DmaByteRead()41         public byte? DmaByteRead() => ReadByteFromBuffer();
42         public void DmaByteWrite(byte data) => WriteByteToBuffer(data);
43 
DmaBlockByteRead(int count)44         public byte[] DmaBlockByteRead(int count) => ReadBuffer(count);
45 
DmaBlockByteWrite(byte[] data)46         public void DmaBlockByteWrite(byte[] data)
47         {
48             if(state == State.WriteFinished)
49             {
50                 state = State.Write;
51             }
52             WriteBuffer(data);
53         }
54 
Reset()55         public override void Reset()
56         {
57             state = State.Idle;
58             delayRxReady = false;
59             rxBuffer.Clear();
60             txBuffer.Clear();
61             RegistersCollection.Reset();
62             selectedPeripheral = FindPeripheral();
63             pdc.Reset();
64             UpdateInterrupts();
65         }
66 
67         public GPIO IRQ { get; } = new GPIO();
68 
69         public DoubleWordRegisterCollection RegistersCollection { get; }
70 
71         public long Size => 0x128;
72 
73         public TransferType DmaReadAccessWidth => TransferType.Byte;
74         public TransferType DmaWriteAccessWidth => TransferType.Byte;
75 
DefineRegisters()76         private void DefineRegisters()
77         {
78             Registers.Control.Define(this)
79                 .WithFlag(0, out var start, FieldMode.Write, name: "START",
80                     changeCallback: (_, value) => { if(value) SendInternalAddress(); })
81                 .WithFlag(1, out var stop, FieldMode.Write, name: "STOP")
82                 .WithFlag(2, out masterEnabled, FieldMode.Set, name: "MSEN - Master Mode Enabled")
83                 .WithFlag(3, FieldMode.WriteOneToClear, name: "MSDIS - Master Mode Disabled",
84                     writeCallback: (_, value) =>
85                     {
86                         if(value)
87                         {
88                             this.Log(LogLevel.Error, "Tried to disable master mode! Only master mode is supported");
89                         }
90                     })
91                 .WithFlag(4, FieldMode.Set, name: "SVEN - Slave Mode Enabled",
92                     writeCallback: (_, value) =>
93                     {
94                         if(value)
95                         {
96                             this.Log(LogLevel.Error, "Tried to enable slave mode! Only master mode is supported");
97                         }
98                     })
99                 .WithFlag(5, FieldMode.WriteOneToClear, name: "SVDIS - Slave Mode Disabled")
100                 .WithReservedBits(6, 1)
101                 .WithFlag(7, FieldMode.Set, writeCallback: (_, value) => { if(value) Reset(); }, name: "SWRST")
102                 .WithReservedBits(8, 24)
103                 .WithWriteCallback((_, __) => TriggerAction(start.Value, stop.Value))
104             ;
105 
106             Registers.MasterMode.Define(this)
107                 .WithReservedBits(0, 8)
108                 .WithEnumField(8, 2, out internalAddressSize, name: "IADRSZ - Internal Device Address Size")
109                 .WithReservedBits(10, 2)
110                 .WithEnumField(12, 1, out readDirection, name: "MREAD - Master Read Direction")
111                 .WithReservedBits(13, 3)
112                 .WithValueField(16, 7, out deviceAddress, name: "DADR - Device Address")
113                 .WithReservedBits(23, 9)
114                 .WithChangeCallback((_, __) =>
115                 {
116                     selectedPeripheral = FindPeripheral();
117                     if(selectedPeripheral == null)
118                     {
119                         this.WarningLog("Selected SPI peripheral is not registered");
120                     }
121                     switch(readDirection.Value)
122                     {
123                     case ReadDirection.MasterWrite:
124                         state = State.Write;
125                         break;
126                     case ReadDirection.MasterRead:
127                         state = State.Idle;
128                         break;
129                     default:
130                         throw new Exception("Unreachable");
131                     }
132                 })
133             ;
134 
135             Registers.SlaveMode.Define(this)
136                 .WithReservedBits(0, 16)
137                 .WithTag("SADR - Slave Address", 16, 7)
138                 .WithReservedBits(23, 9)
139             ;
140 
141             Registers.InternalAddress.Define(this)
142                 .WithValueField(0, 24, out internalAddress, name: "IADR - Internal Address")
143                 .WithReservedBits(24, 8)
144             ;
145 
146             Registers.ClockWaveformGenerator.Define(this)
147                 .WithTag("CLDIV - Clock Low Divider", 0, 8)
148                 .WithTag("CHDIV - Clock High Divider", 8, 8)
149                 .WithTag("CKDIV - Clock Divide", 16, 3)
150                 .WithReservedBits(19, 13)
151             ;
152 
153             Registers.Status.Define(this)
154                 .WithFlag(0, out txCompleted, FieldMode.Read, name: "TXCOMP")
155                 .WithFlag(1, FieldMode.Read, name: "RXDRY",
156                     valueProviderCallback: _ =>
157                     {
158                         // NOTE: This is a simple delay mechanism for data receive with PDC
159                         //       it assumes that Status register is read in interrupt handler
160                         var value = RxReady && !delayRxReady;
161                         delayRxReady = false;
162                         return value;
163                     })
164                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => masterEnabled.Value, name: "TXRDY")
165                 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => false, name: "SVREAD")
166                 .WithTaggedFlag("SVACC", 4)
167                 .WithTaggedFlag("GACC", 5)
168                 .WithTaggedFlag("OVRE", 6)
169                 .WithReservedBits(7, 1)
170                 .WithFlag(8, out notAcknowledged, FieldMode.Read, name: "NACK")
171                 .WithTaggedFlag("ARBLST", 9)
172                 .WithTaggedFlag("SCLWS", 10)
173                 .WithTaggedFlag("EOSACC", 11)
174                 .WithFlag(12, FieldMode.Read, valueProviderCallback: _ => EndOfRxBuffer, name: "ENDRX")
175                 .WithFlag(13, FieldMode.Read, valueProviderCallback: _ => EndOfTxBuffer, name: "ENDTX")
176                 .WithFlag(14, FieldMode.Read, valueProviderCallback: _ => RxBufferFull, name: "RXBUFF")
177                 .WithFlag(15, FieldMode.Read, valueProviderCallback: _ => TxBufferEmpty, name: "TXBUFE")
178                 .WithReservedBits(16, 16)
179             ;
180 
181             Registers.InterruptEnable.Define(this)
182                 .WithFlag(0, FieldMode.Set, writeCallback: (_, value) => { if(value) txCompletedInterruptEnable.Value = true; }, name: "TXCOMP")
183                 .WithFlag(1, FieldMode.Set, writeCallback: (_, value) => { if(value) rxDataReadyInterruptEnable.Value = true; }, name: "RXRDY")
184                 .WithFlag(2, FieldMode.Set, writeCallback: (_, value) => { if(value) txDataReadyInterruptEnable.Value = true; }, name: "TXRDY")
185                 .WithReservedBits(3, 1)
186                 .WithFlag(4, FieldMode.Set, writeCallback: (_, value) => { if(value) slaveAccessInterruptEnable.Value = true; }, name: "SVACC")
187                 .WithFlag(5, FieldMode.Set, writeCallback: (_, value) => { if(value) generalCallAccessInterruptEnable.Value = true; }, name: "GACC")
188                 .WithFlag(6, FieldMode.Set, writeCallback: (_, value) => { if(value) overrunErrorInterruptEnable.Value = true; }, name: "OVRE")
189                 .WithReservedBits(7, 1)
190                 .WithFlag(8, FieldMode.Set, writeCallback: (_, value) => { if(value) notAcknowledgeInterruptEnable.Value = true; }, name: "NACK")
191                 .WithFlag(9, FieldMode.Set, writeCallback: (_, value) => { if(value) arbitrationLostInterruptEnable.Value = true; }, name: "ARBLST")
192                 .WithFlag(10, FieldMode.Set, writeCallback: (_, value) => { if(value) clockWaitStateInterruptEnable.Value = true; }, name: "SCL_WS")
193                 .WithFlag(11, FieldMode.Set, writeCallback: (_, value) => { if(value) endOfSlaveAccessInterruptEnable.Value = true; }, name: "EOSACC")
194                 .WithFlag(12, FieldMode.Set, writeCallback: (_, value) => { if(value) endOfRxBufferInterruptEnable.Value = true; }, name: "ENDRX")
195                 .WithFlag(13, FieldMode.Set, writeCallback: (_, value) => { if(value) endOfTxBufferInterruptEnable.Value = true; }, name: "ENDTX")
196                 .WithFlag(14, FieldMode.Set, writeCallback: (_, value) => { if(value) rxBufferFullInterruptEnable.Value = true; }, name: "RXBUFF")
197                 .WithFlag(15, FieldMode.Set, writeCallback: (_, value) => { if(value) txBufferEmptyInterruptEnable.Value = true; }, name: "TXBUFE")
198                 .WithWriteCallback((_, __) => UpdateInterrupts())
199             ;
200 
201             Registers.InterruptDisable.Define(this)
202                 .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) txCompletedInterruptEnable.Value = false; }, name: "TXCOMP")
203                 .WithFlag(1, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) rxDataReadyInterruptEnable.Value = false; }, name: "RXRDY")
204                 .WithFlag(2, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) txDataReadyInterruptEnable.Value = false; }, name: "TXRDY")
205                 .WithReservedBits(3, 1)
206                 .WithFlag(4, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) slaveAccessInterruptEnable.Value = false; }, name: "SVACC")
207                 .WithFlag(5, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) generalCallAccessInterruptEnable.Value = false; }, name: "GACC")
208                 .WithFlag(6, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) overrunErrorInterruptEnable.Value = false; }, name: "OVRE")
209                 .WithReservedBits(7, 1)
210                 .WithFlag(8, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) notAcknowledgeInterruptEnable.Value = false; }, name: "NACK")
211                 .WithFlag(9, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) arbitrationLostInterruptEnable.Value = false; }, name: "ARBLST")
212                 .WithFlag(10, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) clockWaitStateInterruptEnable.Value = false; }, name: "SCL_WS")
213                 .WithFlag(11, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) endOfSlaveAccessInterruptEnable.Value = false; }, name: "EOSACC")
214                 .WithFlag(12, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) endOfRxBufferInterruptEnable.Value = false; }, name: "ENDRX")
215                 .WithFlag(13, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) endOfTxBufferInterruptEnable.Value = false; }, name: "ENDTX")
216                 .WithFlag(14, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) rxBufferFullInterruptEnable.Value = false; }, name: "RXBUFF")
217                 .WithFlag(15, FieldMode.WriteOneToClear, writeCallback: (_, value) => { if(value) txBufferEmptyInterruptEnable.Value = false; }, name: "TXBUFE")
218                 .WithWriteCallback((_, __) => UpdateInterrupts())
219             ;
220 
221             Registers.InterruptMask.Define(this)
222                 .WithFlag(0, out txCompletedInterruptEnable, FieldMode.Read, name: "TXCOMP")
223                 .WithFlag(1, out rxDataReadyInterruptEnable, FieldMode.Read, name: "RXRDY")
224                 .WithFlag(2, out txDataReadyInterruptEnable, FieldMode.Read, name: "TXRDY")
225                 .WithReservedBits(3, 1)
226                 .WithFlag(4, out slaveAccessInterruptEnable, FieldMode.Read, name: "SVACC")
227                 .WithFlag(5, out generalCallAccessInterruptEnable, FieldMode.Read, name: "GACC")
228                 .WithFlag(6, out overrunErrorInterruptEnable, FieldMode.Read, name: "OVRE")
229                 .WithReservedBits(7, 1)
230                 .WithFlag(8, out notAcknowledgeInterruptEnable, FieldMode.Read, name: "NACK")
231                 .WithFlag(9, out arbitrationLostInterruptEnable, FieldMode.Read, name: "ARBLST")
232                 .WithFlag(10, out clockWaitStateInterruptEnable, FieldMode.Read, name: "SCL_WS")
233                 .WithFlag(11, out endOfSlaveAccessInterruptEnable, FieldMode.Read, name: "EOSACC")
234                 .WithFlag(12, out endOfRxBufferInterruptEnable, FieldMode.Read, name: "ENDRX")
235                 .WithFlag(13, out endOfTxBufferInterruptEnable, FieldMode.Read, name: "ENDTX")
236                 .WithFlag(14, out rxBufferFullInterruptEnable, FieldMode.Read, name: "RXBUFF")
237                 .WithFlag(15, out txBufferEmptyInterruptEnable, FieldMode.Read, name: "TXBUFE")
238             ;
239 
240             Registers.ReceiveHolding.Define(this)
241                 .WithValueField(0, 8, FieldMode.Read, name: "RXDATA",
242                     valueProviderCallback: _ =>
243                     {
244                         var data = ReadByteFromBuffer(dmaAccess: false) ?? 0x0;
245 
246                         switch(state)
247                         {
248                         case State.ReadLastButOne:
249                             state = State.ReadLast;
250                             break;
251                         case State.ReadLast:
252                             state = State.ReadFinished;
253                             rxBuffer.Clear();
254                             selectedPeripheral?.FinishTransmission();
255                             break;
256                         }
257                         return data;
258                     })
259                 .WithReservedBits(8, 24)
260                 .WithReadCallback((_, __) => UpdateInterrupts())
261             ;
262 
263             Registers.TransmitHolding.Define(this)
264                 .WithValueField(0, 8, FieldMode.Write, name: "TXDATA",
265                     writeCallback: (_, value) =>
266                     {
267                         WriteByteToBuffer((byte)value, dmaAccess: false);
268                         if(state == State.WriteLast)
269                         {
270                             state = State.WriteFinished;
271                             FinalizeWrite();
272                             txCompleted.Value = true;
273                             selectedPeripheral?.FinishTransmission();
274                         }
275                         UpdateInterrupts();
276                     })
277                 .WithReservedBits(8, 24)
278             ;
279         }
280 
281         /// <summary>
282         /// Find peripheral from bus based on <see cref="deviceAddress"/> and <see cref="internalAddress"/>
283         /// </summary>
284         /// <returns><see cref="II2CPeripheral"/> when found or null when not found</returns>
FindPeripheral()285         private II2CPeripheral FindPeripheral()
286         {
287             slaveAddress = 0;
288 
289             // 10-bit addressing
290             if(BitHelper.GetValue(deviceAddress.Value, offset: 2, size: 5) == _10BitAddressingPrefix)
291             {
292                 if(internalAddressSize.Value == InternalAddressSize.None)
293                 {
294                     this.ErrorLog("Decoding 10-bit target address from data is not implemented");
295                 }
296                 slaveAddress.ReplaceBits(deviceAddress.Value, width: 2, destinationPosition: 7);
297                 slaveAddress.ReplaceBits(internalAddress.Value, width: 8, destinationPosition: 0);
298             }
299             else
300             {
301                 slaveAddress = BitHelper.GetValue(deviceAddress.Value, offset: 0, size: 7);
302             }
303 
304             this.NoisyLog("Selected slave 0x{0:X}", slaveAddress);
305             return ChildCollection.GetOrDefault((int)slaveAddress);
306         }
307 
308         /// <summary>
309         /// Convert <see cref="internalAddress"/> to byte array
310         /// </summary>
311         /// <returns>
312         /// Byte array which length equals <see cref="internalAddressSize"/> or null if it's either 0 or > 3
313         /// </returns>
GetInternalAddressBytes()314         private byte[] GetInternalAddressBytes()
315         {
316             if(internalAddressSize.Value == InternalAddressSize.None)
317             {
318                 return null;
319             }
320             return BitHelper.GetBytesFromValue(internalAddress.Value, (int)internalAddressSize.Value);
321         }
322 
ReadByteFromBuffer(bool dmaAccess = true)323         private byte? ReadByteFromBuffer(bool dmaAccess = true)
324         {
325             return ReadBuffer(1, dmaAccess)?[0];
326         }
327 
ReadBuffer(int count, bool dmaAccess = true)328         private byte[] ReadBuffer(int count, bool dmaAccess = true)
329         {
330             FinalizeWrite();
331 
332             if(dmaAccess && state != State.Read)
333             {
334                 return null;
335             }
336 
337             if(!ReadMode)
338             {
339                 this.WarningLog("Attempted to perform read, but it's not enabled");
340                 return null;
341             }
342 
343             EnsureRxDataReady(count);
344             var data = rxBuffer.DequeueRange(count);
345             this.NoisyLog("Reading from slave 0x{0:X}: {1}", slaveAddress, data.ToLazyHexString());
346             return data;
347         }
348 
WriteByteToBuffer(byte value, bool dmaAccess = true)349         private void WriteByteToBuffer(byte value, bool dmaAccess = true)
350         {
351             WriteBuffer(new byte[] { value }, dmaAccess);
352         }
353 
WriteBuffer(byte[] data, bool dmaAccess = true)354         private void WriteBuffer(byte[] data, bool dmaAccess = true)
355         {
356             if(!WriteMode)
357             {
358                 this.WarningLog("Attempted to perform write{0}, but it's not enabled", dmaAccess ? " via dma" : "");
359                 return;
360             }
361 
362             if(selectedPeripheral == null)
363             {
364                 notAcknowledged.Value = true;
365                 return;
366             }
367 
368             if(dmaAccess && txBuffer.Count == 0)
369             {
370                 // This is a first write initiated by PDC,
371                 // so the internal address is sent as it's start of a new frame
372                 SendInternalAddress();
373             }
374 
375             txBuffer.EnqueueRange(data);
376         }
377 
FinalizeWrite()378         private void FinalizeWrite()
379         {
380             if(txBuffer.Count == 0)
381             {
382                 return;
383             }
384             var data = txBuffer.ToArray();
385             this.NoisyLog("Writing to slave 0x{0:X}: {1}", slaveAddress, data.ToLazyHexString());
386             selectedPeripheral.Write(data);
387             txBuffer.Clear();
388         }
389 
EnsureRxDataReady(int count)390         private void EnsureRxDataReady(int count)
391         {
392             if(rxBuffer.Count >= count)
393             {
394                 return;
395             }
396 
397             IEnumerable<byte> data;
398             if(selectedPeripheral == null)
399             {
400                 this.DebugLog("SPI peripheral not connected, reading zeros");
401                 data = Enumerable.Repeat<byte>(0x0, count);
402             }
403             else
404             {
405                 data = selectedPeripheral.Read(count);
406             }
407             rxBuffer.EnqueueRange(data);
408         }
409 
SendInternalAddress()410         private void SendInternalAddress()
411         {
412             if(selectedPeripheral == null)
413             {
414                 notAcknowledged.Value = true;
415                 return;
416             }
417 
418             var addressBytes = GetInternalAddressBytes();
419             if(addressBytes != null)
420             {
421                 this.NoisyLog("Writing to slave 0x{0:X}: {1}", slaveAddress, addressBytes.ToLazyHexString());
422                 selectedPeripheral.Write(addressBytes);
423             }
424         }
425 
HandlePdcStatusChange()426         private void HandlePdcStatusChange()
427         {
428             delayRxReady = EndOfRxBuffer || RxBufferFull;
429             UpdateInterrupts();
430         }
431 
TriggerAction(bool start, bool stop)432         private void TriggerAction(bool start, bool stop)
433         {
434             this.NoisyLog("TWI_CR.START={0}, TWI_CR.STOP={1}, TWI_MMR.MREAD={2}", start, stop, readDirection.Value);
435             if(!start && !stop)
436             {
437                 return;
438             }
439 
440             if(start)
441             {
442                 notAcknowledged.Value = false;
443                 txCompleted.Value = false;
444 
445                 if(selectedPeripheral == null)
446                 {
447                     this.NoisyLog("No action performed, SPI peripheral not found");
448                     notAcknowledged.Value = true;
449                     UpdateInterrupts();
450                     return;
451                 }
452             }
453 
454             switch(readDirection.Value)
455             {
456             case ReadDirection.MasterWrite:
457                 state = stop ? State.WriteLast : State.Write;
458                 break;
459             case ReadDirection.MasterRead:
460                 if(start && stop)
461                 {
462                     state = State.ReadLast;
463                 }
464                 else if(start)
465                 {
466                     state = State.Read;
467                     pdc.TriggerReceiver();
468                 }
469                 else
470                 {
471                     state = State.ReadLastButOne;
472                 }
473                 break;
474             default:
475                 throw new Exception("Unreachable");
476             }
477             UpdateInterrupts();
478         }
479 
UpdateInterrupts()480         private void UpdateInterrupts()
481         {
482             var state = (txCompletedInterruptEnable.Value && txCompleted.Value)
483                 || (rxDataReadyInterruptEnable.Value && RxReady && !delayRxReady)
484                 || (txDataReadyInterruptEnable.Value && masterEnabled.Value)
485                 || (notAcknowledgeInterruptEnable.Value && notAcknowledged.Value)
486                 || (endOfRxBufferInterruptEnable.Value && EndOfRxBuffer)
487                 || (endOfTxBufferInterruptEnable.Value && EndOfTxBuffer)
488                 || (rxBufferFullInterruptEnable.Value && RxBufferFull)
489                 || (txBufferEmptyInterruptEnable.Value && TxBufferEmpty)
490             ;
491 
492             this.DebugLog("IRQ {0}", state ? "set" : "unset");
493             IRQ.Set(state);
494         }
495 
496         private bool EndOfRxBuffer => pdc?.EndOfRxBuffer ?? false;
497         private bool EndOfTxBuffer => pdc?.EndOfTxBuffer ?? false;
498         private bool RxBufferFull => pdc?.RxBufferFull ?? false;
499         private bool TxBufferEmpty => pdc?.TxBufferEmpty ?? false;
500 
501         private bool RxReady
502         {
503             get
504             {
505                 switch(state)
506                 {
507                 case State.Read:
508                 case State.ReadLastButOne:
509                 case State.ReadLast:
510                     return true;
511                 default:
512                     return false;
513                 }
514             }
515         }
516 
517         private bool ReadMode => RxReady;
518 
519         private bool WriteMode
520         {
521             get
522             {
523                 switch(state)
524                 {
525                 case State.Write:
526                 case State.WriteLast:
527                     return true;
528                 default:
529                     return false;
530                 }
531             }
532         }
533 
534         private State state;
535         private bool delayRxReady;
536         private ulong slaveAddress;
537         private IFlagRegisterField masterEnabled;
538         private IEnumRegisterField<InternalAddressSize> internalAddressSize;
539         private IEnumRegisterField<ReadDirection> readDirection;
540         private IValueRegisterField deviceAddress;
541         private IValueRegisterField internalAddress;
542         private IFlagRegisterField txCompleted;
543         private IFlagRegisterField notAcknowledged;
544         private IFlagRegisterField txBufferEmptyInterruptEnable;
545         private IFlagRegisterField rxBufferFullInterruptEnable;
546         private IFlagRegisterField endOfTxBufferInterruptEnable;
547         private IFlagRegisterField endOfRxBufferInterruptEnable;
548         private IFlagRegisterField endOfSlaveAccessInterruptEnable;
549         private IFlagRegisterField clockWaitStateInterruptEnable;
550         private IFlagRegisterField arbitrationLostInterruptEnable;
551         private IFlagRegisterField notAcknowledgeInterruptEnable;
552         private IFlagRegisterField overrunErrorInterruptEnable;
553         private IFlagRegisterField generalCallAccessInterruptEnable;
554         private IFlagRegisterField slaveAccessInterruptEnable;
555         private IFlagRegisterField txDataReadyInterruptEnable;
556         private IFlagRegisterField rxDataReadyInterruptEnable;
557         private IFlagRegisterField txCompletedInterruptEnable;
558 
559         private II2CPeripheral selectedPeripheral;
560 
561         private readonly Queue<byte> rxBuffer = new Queue<byte>();
562         private readonly Queue<byte> txBuffer = new Queue<byte>();
563         private readonly SAM_PDC pdc;
564 
565         private const ulong _10BitAddressingPrefix = 0x1e;
566 
567         private enum State
568         {
569             Idle,
570             Read,
571             ReadLastButOne,
572             ReadLast,
573             ReadFinished,
574             Write,
575             WriteLast,
576             WriteFinished,
577         }
578 
579         public enum InternalAddressSize
580         {
581             None = 0,
582             OneByte,
583             TwoByte,
584             ThreeByte
585         }
586 
587         public enum ReadDirection
588         {
589             MasterWrite = 0x00,
590             MasterRead = 0x01
591         }
592 
593         public enum Registers : uint
594         {
595             Control = 0x00,
596             MasterMode = 0x04,
597             SlaveMode = 0x08,
598             InternalAddress = 0x0C,
599             ClockWaveformGenerator = 0x10,
600             Reserved1 = 0x14,
601             Reserved2 = 0x1C,
602             Status = 0x20,
603             InterruptEnable = 0x24,
604             InterruptDisable = 0x28,
605             InterruptMask = 0x2C,
606             ReceiveHolding = 0x30,
607             TransmitHolding = 0x34,
608             PdcReceivePointer = 0x100,
609             PdcReceiveCounter = 0x104,
610             PdcTransmitPointer = 0x108,
611             PdcTransmitCounter = 0x10C,
612             PdcReceiveNextPointer = 0x110,
613             PdcReceiveNextCounter = 0x114,
614             PdcTransmitNextPointer = 0x118,
615             PdcTransmitNextCounter = 0x11C,
616             PdcTransferControl = 0x120,
617             PdcTransferStatus = 0x124,
618         }
619     }
620 }
621