1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Exceptions;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.Bus;
14 using Antmicro.Renode.Utilities;
15 
16 namespace Antmicro.Renode.Peripherals.UART
17 {
18     public class NXP_LPUART : UARTBase, IUARTWithBufferState, ILINController, IBytePeripheral, IDoubleWordPeripheral, IKnownSize
19     {
NXP_LPUART(IMachine machine, long frequency = 8000000, bool hasGlobalRegisters = true, bool hasFifoRegisters = true, uint fifoSize = DefaultFIFOSize, bool separateIRQs = false)20         public NXP_LPUART(IMachine machine, long frequency = 8000000, bool hasGlobalRegisters = true, bool hasFifoRegisters = true, uint fifoSize = DefaultFIFOSize, bool separateIRQs = false) : base(machine)
21         {
22             this.frequency = frequency;
23             this.hasGlobalRegisters = hasGlobalRegisters;
24             this.separateIRQs = separateIRQs;
25 
26             locker = new object();
27             IRQ = new GPIO();
28             SeparateRxIRQ = new GPIO();
29             DMA = new GPIO();
30             txQueue = new Queue<byte>();
31             if (!Misc.IsPowerOfTwo(fifoSize))
32             {
33                 throw new ConstructionException($"The `{nameof(fifoSize)}` argument must be a power of 2, given: {fifoSize}.");
34             }
35             rxFIFOCapacity = fifoSize;
36             txFIFOCapacity = fifoSize;
37 
38             var registersMap = new Dictionary<long, DoubleWordRegister>();
39 
40             if (hasGlobalRegisters)
41             {
42                 registersMap.Add((long)GlobalRegs.Global, new DoubleWordRegister(this)
43                     .WithReservedBits(0, 1)
44                     .WithFlag(1, out reset, name: "RST / Software Reset", writeCallback: (_, val) =>
45                         {
46                             if (val)
47                             {
48                                 Reset();
49                             }
50                         })
51                     .WithReservedBits(2, 30)
52                 );
53             }
54 
55             registersMap.Add(CommonRegistersOffset + (long)CommonRegs.BaudRate, new DoubleWordRegister(this)
56                 .WithValueField(0, 13, out baudRateModuloDivisor, name: "SBR / Baud Rate Modulo Divisor")
57                 .WithFlag(13, out stopBitNumberSelect, name: "SBNS / Stop Bit Number Select")
58                 .WithTaggedFlag("RXEDGIE / RX Input Active Edge Interrupt Enable", 14)
59                 .WithFlag(15, out linBreakDetectInterruptEnable, name: "LBKDIE / LIN Break Detect Interrupt Enable")
60                 .WithTaggedFlag("RESYNCDIS / Resynchronization Disable", 16)
61                 .WithFlag(17, out bothEdgeSampling, name: "BOTHEDGE / Both Edge Sampling")
62                 .WithTag("MATCFG / Match Configuration", 18, 2)
63                 .WithTaggedFlag("RIDMAE / Receiver Idle DMA Enable", 20)
64                 .WithFlag(21, out receiverDMAEnabled, name: "RDMAE / Receiver Full DMA Enable")
65                 .WithReservedBits(22, 1)
66                 .WithFlag(23, out transmitterDMAEnabled, name: "TDMAE / Transmitter DMA Enable")
67                 .WithValueField(24, 5, out oversamplingRatio, name: "OSR / Oversampling Ratio", writeCallback: (current, val) =>
68                     {
69                         if (1 == val || 2 == val)
70                         {
71                             this.Log(LogLevel.Warning, "Tried to set the Oversampling Ratio to reserved value: 0x{0:X}. Old value kept.", val);
72                             oversamplingRatio.Value = current;
73                         }
74                     })
75                 .WithTaggedFlag("M10 / 10-bit Mode select", 29)
76                 .WithTaggedFlag("MAEN2 / Match Address Mode Enable 2", 30)
77                 .WithTaggedFlag("MAEN1 / Match Address Mode Enable 1", 31)
78                 .WithWriteCallback((_, __) =>
79                     {
80                         if ((3 >= oversamplingRatio.Value && 6 <= oversamplingRatio.Value) && !bothEdgeSampling.Value)
81                         {
82                             this.Log(LogLevel.Warning, "Oversampling Ratio set to value: 0x{0:X}, but this requires Both Edge Sampling to be set.", oversamplingRatio.Value);
83                         }
84                         UpdateGPIOOutputs();
85                     })
86             );
87 
88             registersMap.Add(CommonRegistersOffset + (long)CommonRegs.Status, new DoubleWordRegister(this)
89                 .WithReservedBits(0, 14)
90                 .WithTaggedFlag("MA2F / Match 2 Flag", 14)
91                 .WithTaggedFlag("MA1F / Match 1 Flag", 15)
92                 .WithTaggedFlag("PF / Parity Error Flag", 16)
93                 .WithTaggedFlag("FE / Framing Error Flag", 17)
94                 .WithTaggedFlag("NF / Noise Flag", 18)
95                 .WithFlag(19, out receiverOverrun, FieldMode.Read | FieldMode.WriteOneToClear, name: "OR / Receiver Overrun Flag")
96                 .WithTaggedFlag("IDLE / Idle Line Flag", 20)
97                 // Despite the name below flag should be set when Watermark level is exceeded
98                 .WithFlag(21, FieldMode.Read, valueProviderCallback: _ => BufferState == BufferState.Ready, name: "RDRF / Receive Data Register Full")
99                 .WithFlag(22, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "TC / Transmission Complete Flag")
100                 .WithFlag(23, out transmitDataRegisterEmpty, FieldMode.Read, name: "TDRE / Transmission Data Register Empty Flag")
101                 .WithTaggedFlag("RAF / Receiver Active Flag", 24)
102                 .WithFlag(25, out linBreakDetection, name: "LBKDE / LIN Break Detection Enable")
103                 .WithTaggedFlag("BRK13 / Break Character Generation Length", 26)
104                 .WithTaggedFlag("RWUID / Receive Wake Up Idle Detect", 27)
105                 .WithTaggedFlag("RXINV / Receive Data Inversion", 28)
106                 .WithTaggedFlag("MSBF / MSB First", 29)
107                 .WithTaggedFlag("RXEDGIF / RXD Pin Active Edge Interrupt Flag", 30)
108                 .WithFlag(31, out linBreakDetect, FieldMode.Read | FieldMode.WriteOneToClear, name: "LBKDIF / LIN Break Detect Interrupt Flag")
109             );
110 
111             registersMap.Add(CommonRegistersOffset + (long)CommonRegs.Control, new DoubleWordRegister(this)
112                 .WithFlag(0, out parityType, name: "PT / Parity Type")
113                 .WithFlag(1, out parityEnabled, name: "PE / Parity Enable")
114                 .WithTaggedFlag("ILT / Idle Line Type Select", 2)
115                 .WithTaggedFlag("WAKE / Receiver Wakeup Method Select", 3)
116                 .WithTaggedFlag("M / 9-Bit or 8-Bit Mode Select", 4)
117                 .WithFlag(5, out receiverSource, name: "RSRC / Receiver Source Select")
118                 .WithTaggedFlag("DOZEEN / Doze Enable", 6)
119                 .WithFlag(7, out loopMode, name: "LOOPS / Loop Mode Select")
120                 .WithTag("IDLECFG / Idle Configuration", 8, 3)
121                 .WithTaggedFlag("M7 / 7-Bit Mode Select", 11)
122                 .WithReservedBits(12, 2)
123                 .WithTaggedFlag("MA2IE / Match 2 Interrupt Enable", 14)
124                 .WithTaggedFlag("MA1IE / Match 1 Interrupt Enable", 15)
125                 .WithTaggedFlag("SBK / Send Break", 16)
126                 .WithTaggedFlag("RWU / Receiver Wakeup Control", 17)
127                 .WithFlag(18, out receiverEnabled, name: "RE / Receiver Enable")
128                 .WithFlag(19, out transmitterEnabled, name: "TE / Transmitter Enable", writeCallback: (_, val) =>
129                     {
130                         if (val)
131                         {
132                             foreach (var value in txQueue)
133                             {
134                                 TransmitData(value);
135                             }
136                             txQueue.Clear();
137                         }
138                     })
139                 .WithTaggedFlag("ILIE / Idle Line Interrupt Enable", 20)
140                 .WithFlag(21, out receiverInterruptEnabled, name: "RIE / Receiver Interrupt Enable")
141                 .WithFlag(22, out transmissionCompleteInterruptEnabled, name: "TCIE / Transmission Complete Interrupt Enable")
142                 .WithFlag(23, out transmitterInterruptEnabled, name: "TIE / Transmission Interrupt Enable")
143                 .WithTaggedFlag("PEIE / Parity Error Interrupt Enable", 24)
144                 .WithTaggedFlag("FEIE / Framing Error Interrupt Enable", 25)
145                 .WithTaggedFlag("NEIE / Noise Error Interrupt Enable", 26)
146                 .WithTaggedFlag("ORIE / Overrun Interrupt Enable", 27)
147                 .WithTaggedFlag("TXINV / Transmit Data Inversion", 28)
148                 .WithFlag(29, out transmissionPinDirectionOutNotIn, name: "TXDIR / TXD Pin Direction in Single-Wire Mode")
149                 .WithTaggedFlag("R9T8 / Receive Bit 9 / Transmit Bit 8", 30)
150                 .WithTaggedFlag("R8T9 / Receive Bit 8 / Transmit Bit 9", 31)
151                 .WithWriteCallback((_, __) => UpdateGPIOOutputs())
152             );
153 
154             registersMap.Add(CommonRegistersOffset + (long)CommonRegs.Data, new DoubleWordRegister(this)
155                 .WithValueField(0, 9, valueProviderCallback: _ =>
156                     {
157                         if (!this.TryGetCharacter(out var b))
158                         {
159                             receiveFifoUnderflowInterrupt.Value = true;
160                             this.Log(LogLevel.Warning, "Trying to read form an empty fifo");
161                         }
162                         else
163                         {
164                             OnBufferStateChanged();
165                         }
166                         return b;
167                     },
168                     writeCallback: (_, val) =>
169                     {
170                         var breakCharacter = transmitSpecialCharacter.Value && val == 0;
171                         if (breakCharacter && linBreakDetection.Value)
172                         {
173                             // We have to broadcast LIN break
174                             BroadcastLINBreak?.Invoke();
175                         }
176                         else if (transmitterEnabled.Value)
177                         {
178                             TransmitData((byte)val);
179                         }
180                         else if (txQueue.Count < txMaxBytes)
181                         {
182                             txQueue.Enqueue((byte)val);
183 
184                             UpdateFillLevels();
185                         }
186                         else
187                         {
188                             transmitFifoOverflowInterrupt.Value = true;
189                             this.Log(LogLevel.Warning, "Trying to write to a full Tx FIFO.");
190                         }
191                         UpdateGPIOOutputs();
192 
193                     })
194                 .WithReservedBits(10, 1)
195                 .WithTaggedFlag("IDLINE / Idle Line", 11)
196                 .WithFlag(12, FieldMode.Read, valueProviderCallback: _ => BufferState == BufferState.Empty, name: "RXEMPT / Receive Buffer Empty")
197                 .WithFlag(13, out transmitSpecialCharacter, name: "FRETSC / Frame Error / Transmit Special Character")
198                 .WithFlag(14, FieldMode.Read, valueProviderCallback: _ => false, name: "PARITYE / PARITYE")
199                 .WithFlag(15, FieldMode.Read, valueProviderCallback: _ => false, name: "NOISY / NOISY")
200                 .WithReservedBits(16, 16)
201                 .WithReadCallback((_, __) =>
202                 {
203                     UpdateBufferState();
204                     UpdateInterrupt();
205                 })
206             );
207 
208             registersMap.Add(CommonRegistersOffset + (long)CommonRegs.MatchAddress, new DoubleWordRegister(this)
209                 .WithTag("MA1 / Match Address 1", 0, 10)
210                 .WithReservedBits(10, 6)
211                 .WithTag("MA2 / Match Address 2", 16, 10)
212                 .WithReservedBits(26, 6)
213             );
214 
215             if (hasFifoRegisters)
216             {
217                 registersMap.Add(FifoRegistersOffset + (long)FifoRegs.Fifo, new DoubleWordRegister(this)
218                     .WithValueField(0, 3, FieldMode.Read, valueProviderCallback: _ => CalculateFIFODatawordsCount(rxFIFOCapacity), name: "RXFIFOSIZE / Receive FIFO Buffer Depth")
219                     .WithFlag(3, out receiveFifoEnabled, name: "RXFE / Receive FIFO Enable", writeCallback: (current, val) =>
220                         {
221                             if (current != val && (transmitterEnabled.Value || receiverEnabled.Value))
222                             {
223                                 this.Log(LogLevel.Warning, "Both CTRL[TE] and CTRL[RE] must be cleared prior to changing this field.");
224                                 return;
225                             }
226                             if (!val)
227                             {
228                                 rxMaxBytes = 1;
229                                 // assuming that disabling fifo clears it
230                                 ClearBuffer();
231                             }
232                             else
233                             {
234                                 rxMaxBytes = (int)rxFIFOCapacity;
235                             }
236                         })
237                     .WithValueField(4, 3, FieldMode.Read, valueProviderCallback: _ => CalculateFIFODatawordsCount(txFIFOCapacity), name: "TXFIFOSIZE / Transmit FIFO Buffer Depth")
238                     .WithFlag(7, out transmitFifoEnabled, name: "TXFE / Transmit FIFO Enable", writeCallback: (current, val) =>
239                         {
240                             if (current != val && (transmitterEnabled.Value || receiverEnabled.Value))
241                             {
242                                 this.Log(LogLevel.Warning, "Both CTRL[TE] and CTRL[RE] must be cleared prior to changing this field.");
243                                 return;
244                             }
245                             if (!val)
246                             {
247                                 txMaxBytes = 1;
248                                 // assuming that disabling fifo clears it
249                                 txQueue.Clear();
250                             }
251                             else
252                             {
253                                 txMaxBytes = (int)txFIFOCapacity;
254                             }
255                         })
256                     .WithFlag(8, out receiveFifoUnderflowEnabled, name: "RXUFE / Receive FIFO Underflow Interrupt Enable")
257                     .WithFlag(9, out transmitFifoOverflowEnabled, name: "TXOFE / Transmit FIFO Overflow Interrupt Enable")
258                     .WithTag("RXIDEN / Receiver Idle Empty Enable", 10, 3)
259                     .WithReservedBits(13, 1)
260                     .WithFlag(14, FieldMode.Write, name: "RXFLUSH / Receive FIFO/Buffer Flush", writeCallback: (_, val) =>
261                         {
262                             if (val)
263                             {
264                                 ClearBuffer();
265                             }
266                         })
267                     .WithFlag(15, FieldMode.Write, name: "TXFLUSH / Transmit FIFO/Buffer Flush", writeCallback: (_, val) =>
268                         {
269                             if (val)
270                             {
271                                 txQueue.Clear();
272                             }
273                         })
274                     .WithFlag(16, out receiveFifoUnderflowInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "RXUF / Receiver Buffer Underflow Flag")
275                     .WithFlag(17, out transmitFifoOverflowInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "TXOF / Transmitter Buffer Overflow Flag")
276                     .WithReservedBits(18, 4)
277                     .WithFlag(22, FieldMode.Read, valueProviderCallback: _ => BufferState == BufferState.Empty, name: "RXEMPT / Receive Buffer Empty")
278                     .WithFlag(23, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "TXEMPT / Transmit Buffer Empty")
279                     .WithReservedBits(24, 8)
280                     .WithWriteCallback((_, __) => UpdateGPIOOutputs())
281                 );
282 
283                 registersMap.Add(FifoRegistersOffset + (long)FifoRegs.Watermark, new DoubleWordRegister(this)
284                     .WithValueField(0, 2, writeCallback: (_, val) => { transmitWatermark = DecodeFifoCount(val); }, name: "TXWATER / Transmit Watermark")
285                     .WithReservedBits(2, 6)
286                     .WithValueField(8, 3, FieldMode.Read, valueProviderCallback: _ => (uint)txQueue.Count, name: "TXCOUNT / Transmit Counter")
287                     .WithReservedBits(11, 5)
288                     .WithValueField(16, 2, writeCallback: (_, val) => { receiveWatermark = (uint)val; }, name: "RXWATER / Receive Watermark")
289                     .WithReservedBits(18, 6)
290                     .WithValueField(24, 3, FieldMode.Read, valueProviderCallback: _ =>
291                     {
292                         /* This value is not backed by the manual.
293                          * Since the manual is vague in this regard it is impossible to tell if this should be encoded the same
294                          * way as Fifo depth (FIFO_SIZE) or real count clipped at the maximum possible to express with just 3 bits.
295                          * As the available drivers suggest the second approach -  this is what we use here.
296                          * But this should be adjusted if proven to not work or if the manual gets updated */
297                         return (uint)Math.Min(Count, 0b111);
298                     }, name: "RXCOUNT / Receive Counter")
299                     .WithReservedBits(27, 5)
300                     .WithWriteCallback((_, __) => UpdateGPIOOutputs())
301                 );
302             }
303 
304             registers = new DoubleWordRegisterCollection(this, registersMap);
305         }
306 
Reset()307         public override void Reset()
308         {
309             lock (locker)
310             {
311                 base.Reset();
312                 registers.Reset();
313                 txQueue.Clear();
314                 latestBufferState = BufferState.Empty;
315                 rxMaxBytes = 1;
316                 txMaxBytes = 1;
317                 UpdateGPIOOutputs();
318                 reset.Value = true;
319             }
320         }
321 
ReadByte(long offset)322         public byte ReadByte(long offset)
323         {
324             lock (locker)
325             {
326                 if (!IsDataRegister(offset))
327                 {
328                     this.Log(LogLevel.Warning, "Trying to read byte from {0} (0x{0:X}), not supported", offset);
329                     return 0;
330                 }
331 
332                 return (byte)registers.Read(offset);
333             }
334         }
335 
WriteByte(long offset, byte value)336         public void WriteByte(long offset, byte value)
337         {
338             lock (locker)
339             {
340                 if (!IsDataRegister(offset))
341                 {
342                     this.Log(LogLevel.Warning, "Trying to read byte from {0} (0x{0:X}), not supported", offset);
343                     return;
344                 }
345 
346                 registers.Write(offset, value);
347             }
348         }
349 
ReadDoubleWord(long offset)350         public uint ReadDoubleWord(long offset)
351         {
352             lock (locker)
353             {
354                 return registers.Read(offset);
355             }
356         }
357 
WriteDoubleWord(long offset, uint value)358         public void WriteDoubleWord(long offset, uint value)
359         {
360             lock (locker)
361             {
362                 registers.Write(offset, value);
363             }
364         }
365 
WriteChar(byte data)366         public override void WriteChar(byte data)
367         {
368             lock (locker)
369             {
370                 if (loopMode.Value)
371                 {
372                     if (receiverSource.Value && transmissionPinDirectionOutNotIn.Value)
373                     {
374                         this.Log(LogLevel.Warning, "Data ignored, uart operates in Single-Wire mode and txPin is set to output. (value: 0x{0:X})", data);
375                         return;
376                     }
377 
378                     if (!receiverSource.Value)
379                     {
380                         this.Log(LogLevel.Warning, "Data ignored, uart operates in Loop mode. (value: 0x{0:X})", data);
381                         return;
382                     }
383                 }
384 
385                 if (receiverOverrun.Value)
386                 {
387                     this.Log(LogLevel.Info, "Data ignored, receiver has been overrun. (value: 0x{0:X})", data);
388                     return;
389                 }
390 
391                 if (Count >= rxMaxBytes)
392                 {
393                     this.Log(LogLevel.Info, "rxFIFO/Buffer is overflowing but we are buffering character", data, rxMaxBytes);
394                 }
395 
396                 base.WriteChar(data);
397                 UpdateBufferState();
398                 UpdateInterrupt();
399             }
400         }
401 
ReceiveLINBreak()402         public void ReceiveLINBreak()
403         {
404             linBreakDetect.Value |= linBreakDetection.Value;
405             UpdateGPIOOutputs();
406         }
407 
408         public event Action BroadcastLINBreak;
409         public event Action<BufferState> BufferStateChanged;
410 
411         public BufferState BufferState { get; private set; }
412 
413         public long Size => 0x30;
414 
415         public override Bits StopBits => stopBitNumberSelect.Value ? Bits.Two : Bits.One;
416 
417         public override Parity ParityBit => parityEnabled.Value ? Parity.None : parityType.Value ? Parity.Odd : Parity.Even;
418 
419         public override uint BaudRate => (baudRateModuloDivisor.Value == 0)
420             ? 0
421             : (uint)(frequency / ((oversamplingRatio.Value == 0 ? 16 : (uint)(oversamplingRatio.Value + 1)) * (uint)baudRateModuloDivisor.Value));
422 
423         public GPIO IRQ { get; }
424         public GPIO SeparateRxIRQ { get; }
425         public GPIO DMA { get; }
426 
UpdateBufferState()427         private void UpdateBufferState()
428         {
429             var count = Count;
430             if (count == 0)
431             {
432                 BufferState = BufferState.Empty;
433                 return;
434             }
435 
436             if (receiveFifoEnabled.Value)
437             {
438                 if ((ulong)count > receiveWatermark)
439                 {
440                     BufferState = BufferState.Ready;
441                     return;
442                 }
443             }
444 
445             if (count >= rxMaxBytes)
446             {
447                 BufferState = BufferState.Full;
448             }
449             BufferState = BufferState.Ready;
450         }
451 
TransmitData(byte data)452         protected void TransmitData(byte data)
453         {
454             if (!loopMode.Value)
455             {
456                 TransmitCharacter(data);
457             }
458             else if (receiverSource.Value)
459             {
460                 if (!transmissionPinDirectionOutNotIn.Value)
461                 {
462                     this.Log(LogLevel.Warning, "Data not transmitted, uart operates in Single-Wire mode and txPin set to input. (value: 0x{0:X})", data);
463                     return;
464                 }
465                 TransmitCharacter(data);
466             }
467             else
468             {
469                 WriteChar(data);
470             }
471         }
472 
CharWritten()473         protected override void CharWritten()
474         {
475             UpdateGPIOOutputs();
476         }
477 
QueueEmptied()478         protected override void QueueEmptied()
479         {
480             UpdateGPIOOutputs();
481         }
482 
483         private long CommonRegistersOffset => hasGlobalRegisters ? 0x10 : 0x0;
484         private long FifoRegistersOffset => 0x18 + CommonRegistersOffset;
485 
UpdateGPIOOutputs()486         private void UpdateGPIOOutputs()
487         {
488             UpdateFillLevels();
489             UpdateInterrupt();
490             UpdateDMA();
491         }
492 
UpdateInterrupt()493         private void UpdateInterrupt()
494         {
495             var rxUnderflow = receiveFifoUnderflowEnabled.Value && receiveFifoUnderflowInterrupt.Value;
496             var rx = receiverInterruptEnabled.Value && BufferState == BufferState.Ready; // Watermark level exceeded
497             var linBreak = linBreakDetect.Value && linBreakDetectInterruptEnable.Value;
498             var rxRequest = rxUnderflow || rx || linBreak;
499 
500             var txOverflow = transmitFifoOverflowEnabled.Value && transmitFifoOverflowInterrupt.Value;
501             var tx = transmitterInterruptEnabled.Value && transmitDataRegisterEmpty.Value;
502             var txComplete = transmissionCompleteInterruptEnabled.Value && (txQueue.Count == 0);
503             var txRequest = txOverflow || tx || txComplete;
504 
505             if (separateIRQs)
506             {
507                 SeparateRxIRQ.Set(rxRequest);
508                 this.Log(LogLevel.Debug, "Setting SeparateRxIRQ to {0}; rxUnderflow {1}, rx {2}, linBreak {3}", rxRequest, rxUnderflow, rx, linBreak);
509 
510                 IRQ.Set(txRequest);
511                 this.Log(LogLevel.Debug, "Setting IRQ to {0}; txOverflow {1}, tx {2}, txComplete {3}", txRequest, txOverflow, tx, txComplete);
512             }
513             else
514             {
515                 var irqState = txRequest || rxRequest;
516                 this.Log(LogLevel.Noisy, "Setting IRQ to {0}, rxUnderflow {1}, txOverflow {2}, tx {3}, rx {4}, txComplete {5}, linBreak {6}", irqState, rxUnderflow, txOverflow, tx, rx, txComplete, linBreak);
517                 IRQ.Set(irqState);
518             }
519         }
520 
UpdateDMA()521         private void UpdateDMA()
522         {
523             var drqState = false;
524 
525             drqState |= transmitterDMAEnabled.Value && transmitDataRegisterEmpty.Value;
526             drqState |= receiverDMAEnabled.Value && BufferState == BufferState.Full;
527 
528             DMA.Set(drqState);
529             this.Log(LogLevel.Noisy, "Setting DMA request to {0}", drqState);
530         }
531 
UpdateFillLevels()532         private void UpdateFillLevels()
533         {
534             OnBufferStateChanged();
535             if (transmitFifoEnabled.Value)
536             {
537                 transmitDataRegisterEmpty.Value = txQueue.Count <= (int)transmitWatermark;
538             }
539             else
540             {
541                 transmitDataRegisterEmpty.Value = txQueue.Count == 0;
542             }
543         }
544 
OnBufferStateChanged()545         private void OnBufferStateChanged()
546         {
547             var state = BufferState;
548             if (latestBufferState != state)
549             {
550                 latestBufferState = state;
551                 BufferStateChanged?.Invoke(state);
552             }
553         }
554 
IsDataRegister(long offset)555         private bool IsDataRegister(long offset)
556         {
557             return offset == CommonRegistersOffset + (long)CommonRegs.Data;
558         }
559 
CalculateFIFODatawordsCount(uint capacity)560         private uint CalculateFIFODatawordsCount(uint capacity)
561         {
562             if (capacity == 1)
563             {
564                 return 0;
565             }
566             return (uint)Misc.Logarithm2((int)capacity) - 1;
567         }
568 
DecodeFifoCount(ulong encodedValue)569         private uint DecodeFifoCount(ulong encodedValue)
570         {
571             if (encodedValue == 0)
572             {
573                 return 1;
574             }
575             return (uint)Math.Pow(2, encodedValue + 1);
576         }
577 
578         private BufferState latestBufferState = BufferState.Empty;
579         private int rxMaxBytes = 1;
580         private int txMaxBytes = 1;
581         private readonly object locker;
582         private readonly Queue<byte> txQueue;
583         private readonly DoubleWordRegisterCollection registers;
584         private readonly IFlagRegisterField reset;
585         private readonly IFlagRegisterField stopBitNumberSelect;
586         private readonly IFlagRegisterField bothEdgeSampling;
587         private readonly IFlagRegisterField transmitterDMAEnabled;
588         private readonly IFlagRegisterField receiverDMAEnabled;
589         private readonly IFlagRegisterField receiverOverrun;
590         private readonly IFlagRegisterField transmitDataRegisterEmpty;
591         private readonly IFlagRegisterField parityType;
592         private readonly IFlagRegisterField parityEnabled;
593         private readonly IFlagRegisterField receiverSource;
594         private readonly IFlagRegisterField loopMode;
595         private readonly IFlagRegisterField receiverEnabled;
596         private readonly IFlagRegisterField transmitterEnabled;
597         private readonly IFlagRegisterField receiverInterruptEnabled;
598         private readonly IFlagRegisterField transmissionCompleteInterruptEnabled;
599         private readonly IFlagRegisterField transmitterInterruptEnabled;
600         private readonly IFlagRegisterField transmissionPinDirectionOutNotIn;
601         private readonly IFlagRegisterField receiveFifoEnabled;
602         private readonly IFlagRegisterField transmitFifoEnabled;
603         private readonly IFlagRegisterField receiveFifoUnderflowEnabled;
604         private readonly IFlagRegisterField transmitFifoOverflowEnabled;
605         private readonly IFlagRegisterField receiveFifoUnderflowInterrupt;
606         private readonly IFlagRegisterField transmitFifoOverflowInterrupt;
607         private readonly IFlagRegisterField linBreakDetectInterruptEnable;
608         private readonly IFlagRegisterField transmitSpecialCharacter;
609         private readonly IFlagRegisterField linBreakDetect;
610         private readonly IFlagRegisterField linBreakDetection;
611         private readonly IValueRegisterField baudRateModuloDivisor;
612         private readonly IValueRegisterField oversamplingRatio;
613         private readonly long frequency;
614         private readonly bool hasGlobalRegisters;
615         private readonly bool separateIRQs;
616         private readonly uint txFIFOCapacity;
617         private readonly uint rxFIFOCapacity;
618         private uint transmitWatermark;
619         private uint receiveWatermark;
620 
621         private const uint DefaultFIFOSize = 256;
622         private const int DataSize = 8;
623 
624         // enum belows intentionally do not contain `Register(s)` in the name
625         // to avoid using them when logging accesses (which might have been
626         // misleading depending on `hasGlobalRegisters` and `hasFifoRegisters` configuration)
627         private enum GlobalRegs
628         {
629             VersionID = 0x0,
630             Parameter = 0x4,
631             Global = 0x8,
632             PinConfiguration = 0xc,
633         }
634 
635         private enum CommonRegs
636         {
637             BaudRate = 0x0,
638             Status = 0x4,
639             Control = 0x8,
640             Data = 0xc,
641             MatchAddress = 0x10,
642             ModemIrDA = 0x14,
643         }
644 
645         private enum FifoRegs
646         {
647             Fifo = 0x0,
648             Watermark = 0x4,
649         }
650     }
651 }
652