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.Collections.Generic;
8 using System.Linq;
9 
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.Utilities;
15 using Antmicro.Renode.Peripherals.Bus;
16 
17 namespace Antmicro.Renode.Peripherals.I2C
18 {
19     [AllowedTranslations(AllowedTranslation.DoubleWordToByte)]
20     public class S32K3XX_LowPowerInterIntegratedCircuit : SimpleContainer<II2CPeripheral>, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
21     {
S32K3XX_LowPowerInterIntegratedCircuit(IMachine machine)22         public S32K3XX_LowPowerInterIntegratedCircuit(IMachine machine) : base(machine)
23         {
24             IRQ = new GPIO();
25 
26             rxQueue = new Queue<byte>();
27             txQueue = new Queue<byte>();
28 
29             RegistersCollection = new DoubleWordRegisterCollection(this);
30             DefineRegisters();
31         }
32 
ReadDoubleWord(long offset)33         public uint ReadDoubleWord(long offset)
34         {
35             return RegistersCollection.Read(offset);
36         }
37 
WriteDoubleWord(long offset, uint value)38         public void WriteDoubleWord(long offset, uint value)
39         {
40             RegistersCollection.Write(offset, value);
41         }
42 
Reset()43         public override void Reset()
44         {
45             RegistersCollection.Reset();
46 
47             rxQueue.Clear();
48             txQueue.Clear();
49             UpdateInterrupts();
50         }
51 
52         public DoubleWordRegisterCollection RegistersCollection { get; }
53         public GPIO IRQ { get; }
54         public long Size => 0x1000;
55 
UpdateInterrupts()56         private void UpdateInterrupts()
57         {
58             var interrupt = false;
59             interrupt |= transmitDataInterruptEnabled.Value;
60             interrupt |= receiveDataInterruptEnabled.Value && ReceiveDataFlag;
61             interrupt |= stopDetectFlag.Value && stopDetectInterruptEnabled.Value;
62             interrupt |= endPacketFlag.Value && endPacketInterruptEnabled.Value;
63             interrupt |= nackDetectFlag.Value && nackDetectInterruptEnabled.Value;
64 
65             this.Log(LogLevel.Debug, "IRQ={0}, transmitDataInterrupt={1}, receiveDataInterrupt={2}, stopDetectInterrupt={3}, endPacketInterrupt={4}, nackDetectInterrupt={5}",
66                 interrupt,
67                 transmitDataInterruptEnabled.Value,
68                 receiveDataInterruptEnabled.Value && ReceiveDataFlag,
69                 stopDetectFlag.Value && stopDetectInterruptEnabled.Value,
70                 endPacketFlag.Value && endPacketInterruptEnabled.Value,
71                 nackDetectFlag.Value && nackDetectInterruptEnabled.Value);
72             IRQ.Set(interrupt);
73         }
74 
HandleCommand(Command command)75         private void HandleCommand(Command command)
76         {
77             if(command != Command.TransmitData)
78             {
79                 TryFlushTransmitFIFO();
80             }
81 
82             switch(command)
83             {
84                 case Command.TransmitData:
85                     if(AssertActivePeripheral("transmit data"))
86                     {
87                         txQueue.Enqueue((byte)transmitData.Value);
88                         UpdateInterrupts();
89                     }
90                     break;
91 
92                 case Command.ReceiveData:
93                 case Command.ReceiveDataAndDiscard:
94                     if(!AssertActivePeripheral("receive data"))
95                     {
96                         break;
97                     }
98 
99                     // transmitData now contains `amount of data - 1` we would want to receive
100                     var receivedData = activePeripheral.Read((int)transmitData.Value + 1);
101 
102                     if(command != Command.ReceiveDataAndDiscard)
103                     {
104                         rxQueue.EnqueueRange(RunDataMatcher(receivedData));
105                         UpdateInterrupts();
106                     }
107                     break;
108 
109                 case Command.GenerateSTOP:
110                     GenerateStopCondition();
111                     break;
112 
113                 case Command.Start:
114                 case Command.HiSpeedStart:
115                     if(activePeripheral != null)
116                     {
117                         // This is RESTART condition
118                         endPacketFlag.Value = true;
119                         UpdateInterrupts();
120                     }
121 
122                     if(automaticSTOPGeneration.Value)
123                     {
124                         GenerateStopCondition();
125                     }
126 
127                     // transmitData now contains I2C address
128                     if(!TryGetByAddress((int)transmitData.Value >> 1, out activePeripheral))
129                     {
130                         nackDetectFlag.Value = true;
131                         UpdateInterrupts();
132                     }
133 
134                     break;
135 
136                 case Command.StartExpectsNACK:
137                 case Command.HiSpeedStartExpectsNACK:
138                     if(activePeripheral != null)
139                     {
140                         // This is RESTART condition
141                         endPacketFlag.Value = true;
142                         UpdateInterrupts();
143                     }
144 
145                     if(TryGetByAddress((int)transmitData.Value, out var _))
146                     {
147                         // We should write 1 to NACK Detect Flag (NDF) in case we don't expect ACK
148                         nackDetectFlag.Value = true;
149                         UpdateInterrupts();
150                     }
151 
152                     break;
153             }
154         }
155 
RunDataMatcher(IEnumerable<byte> bytes)156         private IEnumerable<byte> RunDataMatcher(IEnumerable<byte> bytes)
157         {
158             if(matchConfiguration.Value == MatchMode.Disabled || matchConfiguration.Value == MatchMode.Reserved)
159             {
160                 return bytes;
161             }
162 
163             int? found = null;
164             var bytesIterator = bytes;
165             switch(matchConfiguration.Value)
166             {
167                 case MatchMode.FirstMatch0OrMatch1:
168                     bytesIterator = bytesIterator.Take(1);
169                     goto case MatchMode.AnyMatch0OrMatch1;
170                 case MatchMode.AnyMatch0OrMatch1:
171                     found = bytesIterator
172                         .Select((Byte, Index) => new { Byte, Index })
173                         .FirstOrDefault(item => item.Byte == match0Value.Value || item.Byte == match1Value.Value)
174                         ?.Index;
175                     break;
176 
177                 case MatchMode.FirstMatch0ThenMatch1:
178                     bytesIterator = bytesIterator.Take(2);
179                     goto case MatchMode.AnyMatch0ThenMatch1;
180                 case MatchMode.AnyMatch0ThenMatch1:
181                     found = bytesIterator
182                         .Zip(bytesIterator.Skip(1), (First, Second) => new { First, Second })
183                         .Select((Byte, Index) => new { Byte, Index })
184                         .FirstOrDefault(item => item.Byte.First == match0Value.Value && item.Byte.Second == match1Value.Value)
185                         ?.Index;
186                     break;
187 
188                 case MatchMode.FirstAndMatch1EqualMatch0AndMatch1:
189                     bytesIterator = bytesIterator.Take(1);
190                     goto case MatchMode.AnyAndMatch1EqualMatch0AndMatch1;
191                 case MatchMode.AnyAndMatch1EqualMatch0AndMatch1:
192                     var maskedValue = match0Value.Value & match1Value.Value;
193                     found = bytesIterator
194                         .Select((Byte, Index) => new { Byte, Index })
195                         .FirstOrDefault(item => (item.Byte & match1Value.Value) == maskedValue)
196                         ?.Index;
197                     break;
198             }
199 
200             dataMatchFlag.Value |= found.HasValue;
201             UpdateInterrupts();
202 
203             if(receiveDataMatchOnly.Value)
204             {
205                 return found.HasValue ? bytes.Skip(found.Value) : Enumerable.Empty<byte>();
206             }
207             return bytes;
208         }
209 
GenerateStopCondition()210         private void GenerateStopCondition()
211         {
212             TryFlushTransmitFIFO();
213             activePeripheral?.FinishTransmission();
214             activePeripheral = null;
215             stopDetectFlag.Value = true;
216             endPacketFlag.Value = true;
217             UpdateInterrupts();
218         }
219 
AssertActivePeripheral(string reason)220         private bool AssertActivePeripheral(string reason)
221         {
222             if(activePeripheral == null)
223             {
224                 this.Log(LogLevel.Warning, "Tried to {0}, but target device wasn't chosen", reason);
225                 return false;
226             }
227             return true;
228         }
229 
TryFlushTransmitFIFO()230         private void TryFlushTransmitFIFO()
231         {
232             if(txQueue.Count > 0 && controllerEnabled.Value)
233             {
234                 activePeripheral?.Write(txQueue.ToArray());
235             }
236 
237             txQueue.Clear();
238             UpdateInterrupts();
239         }
240 
DefineRegisters()241         private void DefineRegisters()
242         {
243             Registers.VersionID.Define(this, 0x1203)
244                 .WithTag("FeatureSpecificationNumber", 0, 16)
245                 .WithTag("MinorVersionNumber", 16, 8)
246                 .WithTag("MajorVersionNumber", 24, 8)
247             ;
248 
249             Registers.Parameter.Define(this, 0x22)
250                 .WithTag("ControllerTransmitFIFOSize", 0, 4)
251                 .WithReservedBits(4, 4)
252                 .WithTag("ControllerReceiveFIFOSize", 8, 4)
253                 .WithReservedBits(12, 20)
254             ;
255 
256             Registers.ControllerControl.Define(this)
257                 .WithFlag(0, out controllerEnabled, name: "ControllerEnable",
258                     changeCallback: (_, value) => { if(value) TryFlushTransmitFIFO(); })
259                 .WithTaggedFlag("SoftwareReset", 1)
260                 .WithTaggedFlag("DozeModeEnable", 2)
261                 .WithTaggedFlag("DebugEnable", 3)
262                 .WithReservedBits(4, 4)
263                 .WithFlag(8, FieldMode.Read | FieldMode.WriteOneToClear, name: "ResetTransmitFIFO",
264                     // If controller is enabled, we really shouldn't have anything in the FIFO anyway, so
265                     // we can try to flush instead of just clearing buffer
266                     writeCallback: (_, value) => { if(value) TryFlushTransmitFIFO(); })
267                 .WithFlag(9, FieldMode.Read | FieldMode.WriteOneToClear, name: "ResetReceiveFIFO",
268                     writeCallback: (_, value) => { if(value) rxQueue.Clear(); })
269                 .WithReservedBits(10, 22)
270                 .WithWriteCallback((_, __) => UpdateInterrupts())
271             ;
272 
273             Registers.ControllerStatus.Define(this, 0x1)
274                 .WithFlag(0, FieldMode.Read, name: "TransmitDataFlag",
275                     valueProviderCallback: _ => true)
276                 .WithFlag(1, FieldMode.Read, name: "ReceiveDataFlag",
277                     valueProviderCallback: _ => ReceiveDataFlag)
278                 .WithReservedBits(2, 6)
279                 .WithFlag(8, out endPacketFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "EndPacketFlag")
280                 .WithFlag(9, out stopDetectFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "STOPDetectFlag")
281                 .WithFlag(10, out nackDetectFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "NACKDetectFlag")
282                 .WithTaggedFlag("ArbitrationLostFlag", 11)
283                 .WithTaggedFlag("FIFOErrorFlag", 12)
284                 .WithTaggedFlag("PinLowTimeoutFlag", 13)
285                 .WithFlag(14, out dataMatchFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "DataMatchFlag")
286                 .WithReservedBits(15, 9)
287                 .WithTaggedFlag("ControllerBusyFlag", 24)
288                 .WithTaggedFlag("BusBusyFlag", 25)
289                 .WithReservedBits(26, 6)
290                 .WithChangeCallback((_, __) => UpdateInterrupts());
291             ;
292 
293             Registers.ControllerInterruptEnable.Define(this)
294                 .WithFlag(0, out transmitDataInterruptEnabled, name: "TransmitDataInterruptEnable")
295                 .WithFlag(1, out receiveDataInterruptEnabled, name: "ReceiveDataInterruptEnable")
296                 .WithReservedBits(2, 6)
297                 .WithFlag(8, out endPacketInterruptEnabled, name: "EndPacketInterruptEnable")
298                 .WithFlag(9, out stopDetectInterruptEnabled, name: "STOPDetectInterruptEnable")
299                 .WithFlag(10, out nackDetectInterruptEnabled, name: "NACKDetectInterruptEnable")
300                 .WithTaggedFlag("ArbitrationLostInterruptEnable", 11)
301                 .WithTaggedFlag("FIFOErrorInterruptEnable", 12)
302                 .WithTaggedFlag("PinLowTimeoutInterruptEnable", 13)
303                 .WithFlag(14, out dataMatchInterruptEnabled, name: "DataMatchInterruptEnable")
304                 .WithReservedBits(15, 7)
305                 .WithChangeCallback((_, __) => UpdateInterrupts());
306             ;
307 
308             Registers.ControllerDMAEnable.Define(this)
309                 .WithTaggedFlag("TransmitDataDMAEnable", 0)
310                 .WithTaggedFlag("ReceiveDataDMAEnable", 1)
311                 .WithReservedBits(3, 29)
312             ;
313 
314             Registers.ControllerConfiguration0.Define(this)
315                 .WithTaggedFlag("HostRequestEnable", 0)
316                 .WithTaggedFlag("HostRequestPolarity", 1)
317                 .WithTaggedFlag("HostRequestSelect", 2)
318                 .WithReservedBits(3, 5)
319                 .WithTaggedFlag("CircularFIFOEnable", 8)
320                 .WithFlag(9, out receiveDataMatchOnly, name: "ReceiveDataMatchOnly")
321                 .WithReservedBits(10, 12)
322             ;
323 
324             Registers.ControllerConfiguration1.Define(this)
325                 .WithTag("Prescaler", 0, 3)
326                 .WithReservedBits(4, 4)
327                 .WithFlag(8, out automaticSTOPGeneration, name: "AutomaticSTOPGeneration")
328                 .WithTaggedFlag("IgnoreNACK", 9)
329                 .WithTaggedFlag("TimeoutConfiguration", 10)
330                 .WithReservedBits(11, 5)
331                 .WithEnumField(16, 3, out matchConfiguration, name: "MatchConfiguration")
332                 .WithReservedBits(19, 4)
333                 .WithTag("PinConfiguration", 24, 3)
334                 .WithReservedBits(27, 5)
335             ;
336 
337             Registers.ControllerConfiguration2.Define(this)
338                 .WithTag("BusIdleTimeout", 0, 12)
339                 .WithReservedBits(12, 4)
340                 .WithTag("GlitchFilterSCL", 16, 4)
341                 .WithReservedBits(20, 4)
342                 .WithTag("GlitchFilterSDA", 24, 4)
343                 .WithReservedBits(28, 4)
344             ;
345 
346             Registers.ControllerConfiguration3.Define(this)
347                 .WithReservedBits(0, 8)
348                 .WithTag("PinLowTimeout", 8, 12)
349                 .WithReservedBits(20, 12)
350             ;
351 
352             Registers.ControllerDataMatch.Define(this)
353                 .WithValueField(0, 8, out match0Value, name: "Match0Value")
354                 .WithReservedBits(8, 8)
355                 .WithValueField(16, 8, out match1Value, name: "Match1Value")
356                 .WithReservedBits(24, 8)
357             ;
358 
359             Registers.ControllerClockConfiguration0.Define(this)
360                 .WithTag("ClockLowPeriod", 0, 6)
361                 .WithReservedBits(6, 2)
362                 .WithTag("ClockHighPeriod", 8, 5)
363                 .WithReservedBits(14, 2)
364                 .WithTag("SetupHoldDelay", 16, 6)
365                 .WithReservedBits(22, 2)
366                 .WithTag("DataValidDelay", 24, 6)
367                 .WithReservedBits(30, 2)
368             ;
369 
370             Registers.ControllerClockConfiguration1.Define(this)
371                 .WithTag("ClockLowPeriod", 0, 6)
372                 .WithReservedBits(6, 2)
373                 .WithTag("ClockHighPeriod", 8, 5)
374                 .WithReservedBits(14, 2)
375                 .WithTag("SetupHoldDelay", 16, 6)
376                 .WithReservedBits(22, 2)
377                 .WithTag("DataValidDelay", 24, 6)
378                 .WithReservedBits(30, 2)
379             ;
380 
381             Registers.ControllerFIFOControl.Define(this)
382                 .WithValueField(0, 2, out txWatermark, name: "TransmitFIFOWatermark")
383                 .WithReservedBits(2, 14)
384                 .WithValueField(16, 2, out rxWatermark, name: "ReceiveFIFOWatermark")
385                 .WithReservedBits(18, 14)
386                 .WithChangeCallback((_, __) => UpdateInterrupts())
387             ;
388 
389             Registers.ControllerFIFOStatus.Define(this)
390                 .WithValueField(0, 2, FieldMode.Read, name: "TransmitFIFOCount",
391                     valueProviderCallback: _ => 0)
392                 .WithReservedBits(2, 14)
393                 .WithValueField(16, 2, FieldMode.Read, name: "ReceiveFIFOCount",
394                     valueProviderCallback: _ => (ulong)rxQueue.Count.Clamp(0, 2))
395                 .WithReservedBits(18, 14)
396             ;
397 
398             Registers.ControllerTransmitData.Define(this)
399                 .WithValueField(0, 8, out transmitData, name: "TransmitData")
400                 .WithEnumField<DoubleWordRegister, Command>(8, 3, name: "CommandData",
401                     writeCallback: (_, value) => HandleCommand(value))
402                 .WithReservedBits(11, 21)
403             ;
404 
405             Registers.ControllerReceiveData.Define(this)
406                 .WithValueField(0, 8, FieldMode.Read, name: "ReceiveData",
407                     valueProviderCallback: _ =>
408                     {
409                         if(!rxQueue.TryDequeue(out var b))
410                         {
411                             this.Log(LogLevel.Warning, "Trying to read from empty rx fifo");
412                             return default(byte);
413                         }
414                         if(rxQueue.Count == 0 && automaticSTOPGeneration.Value)
415                         {
416                             GenerateStopCondition();
417                         }
418                         return b;
419                     })
420                 .WithReservedBits(8, 6)
421                 .WithFlag(14, FieldMode.Read, name: "ReceiveEmpty",
422                     valueProviderCallback: _ => rxQueue.Count == 0)
423                 .WithReservedBits(15, 17)
424                 .WithReadCallback((_, __) => UpdateInterrupts())
425             ;
426 
427             Registers.TargetControl.Define(this)
428                 .WithTaggedFlag("TargetEnable", 0)
429                 .WithTaggedFlag("SoftwareReset", 1)
430                 .WithReservedBits(2, 2)
431                 .WithTaggedFlag("FilterEnable", 4)
432                 .WithTaggedFlag("FilterDozeEnable", 5)
433                 .WithReservedBits(6, 2)
434                 .WithTaggedFlag("ResetTransmitFIFO", 8)
435                 .WithTaggedFlag("ResetReceiveFIFO", 9)
436                 .WithReservedBits(10, 22)
437             ;
438 
439             Registers.TargetStatus.Define(this)
440                 .WithTaggedFlag("TransmitDataFlag", 0)
441                 .WithTaggedFlag("ReceiveDataFlag", 1)
442                 .WithTaggedFlag("AddressValidFlag", 2)
443                 .WithTaggedFlag("TransmitACKFlag", 3)
444                 .WithReservedBits(4, 4)
445                 .WithTaggedFlag("RepeatedStartFlag", 8)
446                 .WithTaggedFlag("STOPDetectFlag", 9)
447                 .WithTaggedFlag("BitErrorFlag", 10)
448                 .WithTaggedFlag("FIFOErrorFlag", 11)
449                 .WithTaggedFlag("AddressMatch0Flag", 12)
450                 .WithTaggedFlag("AddressMatch1Flag", 13)
451                 .WithTaggedFlag("GeneralCallFlag", 14)
452                 .WithTaggedFlag("SMBusAlertResponseFlag", 15)
453                 .WithReservedBits(16, 8)
454                 .WithTaggedFlag("TargetBusyFlag", 24)
455                 .WithTaggedFlag("BusBusyFlag", 25)
456                 .WithReservedBits(26, 6)
457             ;
458 
459             Registers.TargetInterruptEnable.Define(this)
460                 .WithTaggedFlag("TransmitDataInterruptEnable", 0)
461                 .WithTaggedFlag("ReceiveDataInterruptEnable", 1)
462                 .WithTaggedFlag("AddressValidInterruptEnable", 2)
463                 .WithTaggedFlag("TransmitACKInterruptEnable", 3)
464                 .WithReservedBits(4, 4)
465                 .WithTaggedFlag("RepeatedStartInterruptEnable", 8)
466                 .WithTaggedFlag("STOPDetectInterruptEnable", 9)
467                 .WithTaggedFlag("BitErrorInterruptEnable", 10)
468                 .WithTaggedFlag("FIFOErrorInterruptEnable", 11)
469                 .WithTaggedFlag("AddressMatch0InterruptEnable", 12)
470                 .WithTaggedFlag("AddressMatch1InterruptEnable", 13)
471                 .WithTaggedFlag("GeneralCallInterruptEnable", 14)
472                 .WithTaggedFlag("SMBusAlertResponseInterruptEnable", 15)
473                 .WithReservedBits(16, 16)
474             ;
475 
476             Registers.TargetDMAEnable.Define(this)
477                 .WithTaggedFlag("TransmitDataDMAEnable", 0)
478                 .WithTaggedFlag("ReceiveDataDMAEnable", 1)
479                 .WithTaggedFlag("AddressValidDMAEnable", 2)
480                 .WithReservedBits(3, 29)
481             ;
482 
483             Registers.TargetConfiguration1.Define(this)
484                 .WithTaggedFlag("AddressSCLStall", 0)
485                 .WithTaggedFlag("RXSCLStall", 1)
486                 .WithTaggedFlag("TransmitDataSCLStall", 2)
487                 .WithTaggedFlag("ACKSCLStall", 3)
488                 .WithReservedBits(4, 4)
489                 .WithTaggedFlag("GeneralCallEnable", 8)
490                 .WithTaggedFlag("SMBusAlertEnable", 9)
491                 .WithTaggedFlag("TransmitFlagConfiguration", 10)
492                 .WithTaggedFlag("ReceiveDataConfiguration", 11)
493                 .WithTaggedFlag("IgnoreNACK", 12)
494                 .WithTaggedFlag("HighSpeedModeEnable,", 13)
495                 .WithReservedBits(14, 2)
496                 .WithTag("AddressConfiguration", 16, 3)
497                 .WithReservedBits(19, 13)
498             ;
499 
500             Registers.TargetConfiguration2.Define(this)
501                 .WithTag("ClockHoldTime", 0, 4)
502                 .WithReservedBits(4, 4)
503                 .WithTag("DataValidDelay", 8, 4)
504                 .WithReservedBits(14, 2)
505                 .WithTag("GlitchFilterSCL", 16, 4)
506                 .WithTag("GlitchFilterSDA", 24, 4)
507             ;
508 
509             Registers.TargetAddressMatch.Define(this)
510                 .WithReservedBits(0, 1)
511                 .WithTag("Address0Value", 1, 10)
512                 .WithReservedBits(11, 6)
513                 .WithTag("Address0Value", 17, 10)
514                 .WithReservedBits(27, 5)
515             ;
516 
517             Registers.TargetAddressStatus.Define(this)
518                 .WithTag("ReceivedAddress", 0, 11)
519                 .WithReservedBits(11, 3)
520                 .WithTaggedFlag("AddressNotValid", 14)
521                 .WithReservedBits(15, 17)
522             ;
523 
524             Registers.TargetTransmitACK.Define(this)
525                 .WithTaggedFlag("TransmitNACK", 0)
526                 .WithReservedBits(1, 31)
527             ;
528 
529             Registers.TargetTransmitData.Define(this)
530                 .WithTag("TransmitData", 0, 8)
531                 .WithReservedBits(8, 24)
532             ;
533 
534             Registers.TargetReceiveData.Define(this)
535                 .WithTag("ReceiveData", 0, 8)
536                 .WithTag("ReceivedAddress", 8, 3)
537                 .WithReservedBits(11, 3)
538                 .WithTaggedFlag("ReceiveEmpty", 14)
539                 .WithTaggedFlag("StartOfFrame", 15)
540                 .WithReservedBits(16, 16)
541             ;
542         }
543 
544         private bool ReceiveDataFlag => rxQueue.Count > (int)rxWatermark.Value;
545 
546         private readonly Queue<byte> txQueue;
547         private readonly Queue<byte> rxQueue;
548 
549         private II2CPeripheral activePeripheral;
550 
551         private IEnumRegisterField<MatchMode> matchConfiguration;
552 
553         private IValueRegisterField transmitData;
554         private IValueRegisterField txWatermark;
555         private IValueRegisterField rxWatermark;
556         private IValueRegisterField match0Value;
557         private IValueRegisterField match1Value;
558 
559         private IFlagRegisterField controllerEnabled;
560         private IFlagRegisterField automaticSTOPGeneration;
561 
562         private IFlagRegisterField endPacketFlag;
563         private IFlagRegisterField nackDetectFlag;
564         private IFlagRegisterField stopDetectFlag;
565         private IFlagRegisterField dataMatchFlag;
566 
567         private IFlagRegisterField transmitDataInterruptEnabled;
568         private IFlagRegisterField receiveDataInterruptEnabled;
569         private IFlagRegisterField endPacketInterruptEnabled;
570         private IFlagRegisterField nackDetectInterruptEnabled;
571         private IFlagRegisterField stopDetectInterruptEnabled;
572         private IFlagRegisterField dataMatchInterruptEnabled;
573         private IFlagRegisterField receiveDataMatchOnly;
574 
575         private enum MatchMode
576         {
577             Disabled,
578             Reserved,
579             FirstMatch0OrMatch1,
580             AnyMatch0OrMatch1,
581             FirstMatch0ThenMatch1,
582             AnyMatch0ThenMatch1,
583             FirstAndMatch1EqualMatch0AndMatch1,
584             AnyAndMatch1EqualMatch0AndMatch1,
585         }
586 
587         private enum Command
588         {
589             TransmitData,
590             ReceiveData,
591             GenerateSTOP,
592             ReceiveDataAndDiscard,
593             Start,
594             StartExpectsNACK,
595             HiSpeedStart,
596             HiSpeedStartExpectsNACK
597         }
598 
599         private enum Registers
600         {
601             VersionID = 0x0,
602             Parameter = 0x4,
603             ControllerControl = 0x10,
604             ControllerStatus = 0x14,
605             ControllerInterruptEnable = 0x18,
606             ControllerDMAEnable = 0x1c,
607             ControllerConfiguration0 = 0x20,
608             ControllerConfiguration1 = 0x24,
609             ControllerConfiguration2 = 0x28,
610             ControllerConfiguration3 = 0x2C,
611             ControllerDataMatch = 0x40,
612             ControllerClockConfiguration0 = 0x48,
613             ControllerClockConfiguration1 = 0x50,
614             ControllerFIFOControl = 0x58,
615             ControllerFIFOStatus = 0x5C,
616             ControllerTransmitData = 0x60,
617             ControllerReceiveData = 0x70,
618             TargetControl = 0x110,
619             TargetStatus = 0x114,
620             TargetInterruptEnable = 0x118,
621             TargetDMAEnable = 0x11C,
622             TargetConfiguration1 = 0x124,
623             TargetConfiguration2 = 0x128,
624             TargetAddressMatch = 0x140,
625             TargetAddressStatus = 0x150,
626             TargetTransmitACK = 0x154,
627             TargetTransmitData = 0x160,
628             TargetReceiveData = 0x170,
629         }
630     }
631 }
632