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.Peripherals.Bus;
11 using Antmicro.Renode.Peripherals.Helpers;
12 using Antmicro.Renode.Core;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Logging;
15 
16 namespace Antmicro.Renode.Peripherals.UART
17 {
18     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
19     public class Cadence_UART : UARTBase, IUARTWithBufferState, IDoubleWordPeripheral, IKnownSize
20     {
Cadence_UART(IMachine machine, bool clearInterruptStatusOnRead = false, ulong clockFrequency = 50000000)21         public Cadence_UART(IMachine machine, bool clearInterruptStatusOnRead = false, ulong clockFrequency = 50000000) : base(machine)
22         {
23             this.clearInterruptStatusOnRead = clearInterruptStatusOnRead;
24             this.clockFrequency = clockFrequency;
25             registers = new DoubleWordRegisterCollection(this, BuildRegisterMap());
26 
27             rxFifoOverflow = new CadenceInterruptFlag(() => false);
28             rxFifoFull = new CadenceInterruptFlag(() => Count >= FifoCapacity);
29             rxFifoTrigger = new CadenceInterruptFlag(() => Count >= (int)rxTriggerLevel.Value && rxTriggerLevel.Value > 0);
30             rxFifoEmpty = new CadenceInterruptFlag(() => Count == 0);
31             rxTimeoutError = new CadenceInterruptFlag(() => false);
32             txFifoEmpty = new CadenceInterruptFlag(() => true);
33         }
34 
WriteDoubleWord(long offset, uint value)35         public void WriteDoubleWord(long offset, uint value)
36         {
37             registers.Write(offset, value);
38         }
39 
ReadDoubleWord(long offset)40         public uint ReadDoubleWord(long offset)
41         {
42             return registers.Read(offset);
43         }
44 
WriteChar(byte value)45         public override void WriteChar(byte value)
46         {
47             if(!RxEnabled)
48             {
49                 this.Log(LogLevel.Warning, "Receiver isn't enabled, incoming byte not queued.");
50                 return;
51             }
52 
53             if(Count < FifoCapacity)
54             {
55                 base.WriteChar(value);
56                 UpdateBufferState();
57                 // Trigger the timeout interrupt immediately after each reception
58                 rxTimeoutError.SetSticky(true);
59             }
60             else
61             {
62                 rxFifoOverflow.SetSticky(true);
63                 this.Log(LogLevel.Warning, "Rx FIFO overflowed, incoming byte not queued.");
64             }
65             UpdateSticky();
66             UpdateInterrupts();
67         }
68 
Reset()69         public override void Reset()
70         {
71             base.Reset();
72             registers.Reset();
73             foreach(var flag in GetInterruptFlags())
74             {
75                 flag.Reset();
76             }
77             UpdateInterrupts();
78         }
79 
80         public long Size => 0x80;
81         public BufferState BufferState { get; private set; }
82 
83         [DefaultInterrupt]
84         public GPIO IRQ { get; } = new GPIO();
85 
86         public GPIO RxFifoFullIRQ { get; } = new GPIO();
87         public GPIO RxFifoFillLevelTriggerIRQ { get; } = new GPIO();
88         public GPIO RxFifoEmptyIRQ { get; } = new GPIO();
89 
90         public GPIO TxFifoEmptyIRQ { get; } = new GPIO();
91         public GPIO TxFifoFullIRQ { get; } = new GPIO();
92         public GPIO TxFifoFillLevelTriggerIRQ { get; } = new GPIO();
93         public GPIO TxFifoNearlyFullIRQ { get; } = new GPIO();
94 
95         public event Action<BufferState> BufferStateChanged;
96 
97         public override Bits StopBits => ConvertInternalStop(stopBitsField.Value);
98 
99         public override Parity ParityBit => ConvertInternalParity(parityField.Value);
100 
101         public override uint BaudRate => (uint)(clockFrequency / (clockSource.Value ? 8U : 1U) / baudGenerator.Value / (baudDivider.Value + 1));
102 
CharWritten()103         protected override void CharWritten()
104         {
105             // Intentionally leaved empty
106         }
107 
QueueEmptied()108         protected override void QueueEmptied()
109         {
110             UpdateSticky();
111             UpdateInterrupts();
112         }
113 
ConvertInternalStop(InternalStop stop)114         private static Bits ConvertInternalStop(InternalStop stop)
115         {
116             switch(stop)
117             {
118                 default:
119                 case InternalStop.One:
120                     return Bits.One;
121                 case InternalStop.OneAndHalf:
122                     return Bits.OneAndAHalf;
123                 case InternalStop.Two:
124                     return Bits.Two;
125             }
126         }
127 
ConvertInternalParity(InternalParity parity)128         private static Parity ConvertInternalParity(InternalParity parity)
129         {
130             switch(parity)
131             {
132                 case InternalParity.Even:
133                     return Parity.Even;
134                 case InternalParity.Odd:
135                     return Parity.Odd;
136                 case InternalParity.Forced0:
137                     return Parity.Forced0;
138                 case InternalParity.Forced1:
139                     return Parity.Forced1;
140                 default:
141                     return Parity.None;
142             }
143         }
144 
UpdateSticky()145         private void UpdateSticky()
146         {
147             foreach(CadenceInterruptFlag flag in GetInterruptFlags())
148             {
149                 flag.UpdateStickyStatus();
150             }
151         }
152 
UpdateInterrupts()153         private void UpdateInterrupts()
154         {
155             IRQ.Set(GetInterruptFlags().Any(x => x.InterruptStatus));
156             RxFifoFullIRQ.Set(rxFifoFull.InterruptStatus);
157             RxFifoFillLevelTriggerIRQ.Set(rxFifoTrigger.InterruptStatus);
158             RxFifoEmptyIRQ.Set(rxFifoEmpty.InterruptStatus);
159             TxFifoEmptyIRQ.Set(txFifoEmpty.InterruptStatus);
160         }
161 
UpdateBufferState()162         private void UpdateBufferState()
163         {
164             if((!rxFifoFull.Status && BufferState == BufferState.Full) ||
165                (!rxFifoEmpty.Status && BufferState == BufferState.Empty) ||
166                ((rxFifoFull.Status || rxFifoEmpty.Status) && BufferState == BufferState.Ready))
167             {
168                 if(rxFifoEmpty.Status)
169                 {
170                     BufferState = BufferState.Empty;
171                 }
172                 else if(rxFifoFull.Status)
173                 {
174                     BufferState = BufferState.Full;
175                 }
176                 else
177                 {
178                     BufferState = BufferState.Ready;
179                 }
180 
181                 BufferStateChanged?.Invoke(BufferState);
182             }
183         }
184 
BuildRegisterMap()185         private Dictionary<long, DoubleWordRegister> BuildRegisterMap()
186         {
187             var interruptStatusFieldMode = FieldMode.Read | (clearInterruptStatusOnRead ? 0 : FieldMode.Write);
188             return new Dictionary<long, DoubleWordRegister>
189             {
190                 {(long)Registers.Control, new DoubleWordRegister(this, 0x00000128)
191                     .WithReservedBits(9, 23)
192                     .WithTaggedFlag("stopTxBreak", 8)
193                     .WithTaggedFlag("startTxBreak", 7)
194                     .WithFlag(6, FieldMode.Read | FieldMode.WriteOneToClear, name: "restartRxTimeout",
195                         writeCallback:
196                             // Trigger the timeout interrupt immediately after each timeout counter restart
197                             (_, val) => rxTimeoutError.SetSticky(val)
198                     )
199                     .WithFlag(5, out txDisabledReg, name: "txDisabled")
200                     .WithFlag(4, out txEnabledReg, name: "txEnabled")
201                     .WithFlag(3, out rxDisabledReg, name: "rxDisabled")
202                     .WithFlag(2, out rxEnabledReg, name: "rxEnabled")
203                     .WithFlag(1, valueProviderCallback: _ => false, name: "txReset")
204                     .WithFlag(0, valueProviderCallback: _ => false, name: "rxReset",
205                         writeCallback:
206                             (_, val) => { if(val) this.ClearBuffer(); }
207                     )
208                     .WithWriteCallback((_, __) =>
209                     {
210                         UpdateSticky();
211                         UpdateInterrupts();
212                     })
213                 },
214                 {(long)Registers.Mode, new DoubleWordRegister(this)
215                     .WithReservedBits(14, 18)
216                     .WithTag("accessSize", 12, 2)
217                     .WithReservedBits(10, 2)
218                     .WithTag("channelMode", 8, 2)
219                     .WithEnumField(6, 2, out stopBitsField, name: "stopBits")
220                     .WithEnumField(3, 3, out parityField, name: "parityType")
221                     .WithTag("characterLength", 1, 2)
222                     .WithFlag(0, out clockSource, name: "clockSourceSelect")
223                 },
224                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
225                     .WithReservedBits(14, 18)
226                     .WithTaggedFlag("rxBreakDetectInterruptEnable", 13)
227                     .WithTaggedFlag("txFifoOverflowInterruptEnable", 12)
228                     .WithTaggedFlag("txFifoNearlyFullInterruptEnable", 11)
229                     .WithTaggedFlag("txFifoTriggerInterruptEnable", 10)
230                     .WithTaggedFlag("deltaModemStatusInterruptEnable", 9)
231                     .WithFlag(8, FieldMode.Write,
232                         writeCallback: (_, val) => rxTimeoutError.InterruptEnable(val),
233                         name: "rxTimeoutErrorInterruptEnable"
234                     )
235                     .WithTaggedFlag("rxParityErrorInterruptEnable", 7)
236                     .WithTaggedFlag("rxFramingErrorInterruptEnable", 6)
237                     .WithFlag(5, FieldMode.Write,
238                         writeCallback: (_, val) => rxFifoOverflow.InterruptEnable(val),
239                         name: "rxFifoOverflowInterruptEnable"
240                     )
241                     .WithTaggedFlag("txFifoFullInterruptEnable", 4)
242                     .WithFlag(3, FieldMode.Write,
243                         writeCallback: (_, val) => txFifoEmpty.InterruptEnable(val),
244                         name: "txFifoEmptyInterruptEnable"
245                     )
246                     .WithFlag(2, FieldMode.Write,
247                         writeCallback: (_, val) => rxFifoFull.InterruptEnable(val),
248                         name: "rxFifoFullInterruptEnable"
249                     )
250                     .WithFlag(1, FieldMode.Write,
251                         writeCallback: (_, val) => rxFifoEmpty.InterruptEnable(val),
252                         name: "rxFifoEmptyInterruptEnable"
253                     )
254                     .WithFlag(0, FieldMode.Write,
255                         writeCallback: (_, val) => rxFifoTrigger.InterruptEnable(val),
256                         name: "rxFifoTriggerInterruptEnable"
257                     )
258                     .WithWriteCallback((_, __) => UpdateInterrupts())
259                 },
260                 {(long)Registers.InterruptDisable, new DoubleWordRegister(this)
261                     .WithReservedBits(14, 18)
262                     .WithTaggedFlag("rxBreakDetectInterruptDisable", 13)
263                     .WithTaggedFlag("txFifoOverflowInterruptDisable", 12)
264                     .WithTaggedFlag("txFifoNearlyFullInterruptDisable", 11)
265                     .WithTaggedFlag("txFifoTriggerInterruptDisable", 10)
266                     .WithTaggedFlag("deltaModemStatusInterruptDisable", 9)
267                     .WithFlag(8, FieldMode.Write,
268                         writeCallback: (_, val) => rxTimeoutError.InterruptDisable(val),
269                         name: "rxTimeoutErrorInterruptDisable"
270                     )
271                     .WithTaggedFlag("rxParityErrorInterruptDisable", 7)
272                     .WithTaggedFlag("rxFramingErrorInterruptDisable", 6)
273                     .WithFlag(5, FieldMode.Write,
274                         writeCallback: (_, val) => rxFifoOverflow.InterruptDisable(val),
275                         name: "rxFifoOverflowInterruptDisable"
276                     )
277                     .WithTaggedFlag("txFifoFullInterruptDisable", 4)
278                     .WithFlag(3, FieldMode.Write,
279                         writeCallback: (_, val) => txFifoEmpty.InterruptDisable(val),
280                         name: "txFifoEmptyInterruptDisable"
281                     )
282                     .WithFlag(2, FieldMode.Write,
283                         writeCallback: (_, val) => rxFifoFull.InterruptDisable(val),
284                         name: "rxFifoFullInterruptDisable"
285                     )
286                     .WithFlag(1, FieldMode.Write,
287                         writeCallback: (_, val) => rxFifoEmpty.InterruptDisable(val),
288                         name: "rxFifoEmptyInterruptDisable"
289                     )
290                     .WithFlag(0, FieldMode.Write,
291                         writeCallback: (_, val) => rxFifoTrigger.InterruptDisable(val),
292                         name: "rxFifoTriggerInterruptDisable"
293                     )
294                     .WithWriteCallback((_, __) => UpdateInterrupts())
295                 },
296                 {(long)Registers.InterruptMask, new DoubleWordRegister(this)
297                     .WithReservedBits(14, 18)
298                     .WithTaggedFlag("rxBreakDetectInterruptMask", 13)
299                     .WithTaggedFlag("txFifoOverflowInterruptMask", 12)
300                     .WithTaggedFlag("txFifoNearlyFullInterruptMask", 11)
301                     .WithTaggedFlag("txFifoTriggerInterruptMask", 10)
302                     .WithTaggedFlag("deltaModemStatusInterruptMask", 9)
303                     .WithFlag(8, FieldMode.Read,
304                         valueProviderCallback: (_) => rxTimeoutError.InterruptMask,
305                         name: "rxTimeoutErrorInterruptMask"
306                     )
307                     .WithTaggedFlag("rxParityErrorInterruptMask", 7)
308                     .WithTaggedFlag("rxFramingErrorInterruptMask", 6)
309                     .WithFlag(5, FieldMode.Read,
310                         valueProviderCallback: (_) => rxFifoOverflow.InterruptMask,
311                         name: "rxFifoOverflowInterruptMask"
312                     )
313                     .WithTaggedFlag("txFifoFullInterruptMask", 4)
314                     .WithFlag(3, FieldMode.Read,
315                         valueProviderCallback: (_) => txFifoEmpty.InterruptMask,
316                         name: "txFifoEmptyInterruptMask"
317                     )
318                     .WithFlag(2, FieldMode.Read,
319                         valueProviderCallback: (_) => rxFifoFull.InterruptMask,
320                         name: "rxFifoFullInterruptMask"
321                     )
322                     .WithFlag(1, FieldMode.Read,
323                         valueProviderCallback: (_) => rxFifoEmpty.InterruptMask,
324                         name: "rxFifoEmptyInterruptMask"
325                     )
326                     .WithFlag(0, FieldMode.Read,
327                         valueProviderCallback: (_) => rxFifoTrigger.InterruptMask,
328                         name: "rxFifoTriggerInterruptMask"
329                     )
330                 },
331                 {(long)Registers.ChannelInterruptStatus, new DoubleWordRegister(this)
332                     .WithReservedBits(14, 18)
333                     .WithTaggedFlag("rxBreakDetectInterruptStatus", 13)
334                     .WithTaggedFlag("txFifoOverflowInterruptStatus", 12)
335                     .WithTaggedFlag("txFifoNearlyFullInterruptStatus", 11)
336                     .WithTaggedFlag("txFifoTriggerInterruptStatus", 10)
337                     .WithTaggedFlag("deltaModemStatusInterruptStatus", 9)
338                     .WithFlag(8, interruptStatusFieldMode,
339                         valueProviderCallback: (_) => rxTimeoutError.StickyStatus,
340                         readCallback: (_, __) => rxTimeoutError.ClearSticky(clearInterruptStatusOnRead),
341                         writeCallback: (_, val) => rxTimeoutError.ClearSticky(val && !clearInterruptStatusOnRead),
342                         name: "rxTimeoutErrorInterruptStatus"
343                     )
344                     .WithTaggedFlag("rxParityErrorInterruptStatus", 7)
345                     .WithTaggedFlag("rxFramingErrorInterruptStatus", 6)
346                     .WithFlag(5, interruptStatusFieldMode,
347                         valueProviderCallback: (_) => rxFifoOverflow.StickyStatus,
348                         readCallback: (_, __) => rxFifoOverflow.ClearSticky(clearInterruptStatusOnRead),
349                         writeCallback: (_, val) => rxFifoOverflow.ClearSticky(val && !clearInterruptStatusOnRead),
350                         name: "rxFifoOverflowInterruptStatus"
351                     )
352                     .WithTaggedFlag("txFifoFullInterruptStatus", 4)
353                     .WithFlag(3, interruptStatusFieldMode,
354                         valueProviderCallback: (_) => txFifoEmpty.StickyStatus,
355                         // There is no sense to clear the txFifoEmptyInterruptStatus flag, because a Tx FIFO is always empty
356                         name: "txFifoEmptyInterruptStatus"
357                     )
358                     .WithFlag(2, interruptStatusFieldMode,
359                         valueProviderCallback: (_) => rxFifoFull.StickyStatus,
360                         readCallback: (_, __) => rxFifoFull.ClearSticky(clearInterruptStatusOnRead),
361                         writeCallback: (_, val) => rxFifoFull.ClearSticky(val && !clearInterruptStatusOnRead),
362                         name: "rxFifoFullInterruptStatus"
363                     )
364                     .WithFlag(1, interruptStatusFieldMode,
365                         valueProviderCallback: (_) => rxFifoEmpty.StickyStatus,
366                         readCallback: (_, __) => rxFifoEmpty.ClearSticky(clearInterruptStatusOnRead),
367                         writeCallback: (_, val) => rxFifoEmpty.ClearSticky(val && !clearInterruptStatusOnRead),
368                         name: "rxFifoEmptyInterruptMStatus"
369                     )
370                     .WithFlag(0, interruptStatusFieldMode,
371                         valueProviderCallback: (_) => rxFifoTrigger.StickyStatus,
372                         readCallback: (_, __) => rxFifoTrigger.ClearSticky(clearInterruptStatusOnRead),
373                         writeCallback: (_, val) => rxFifoTrigger.ClearSticky(val && !clearInterruptStatusOnRead),
374                         name: "rxFifoTriggerInterruptStatus"
375                     )
376                     .WithReadCallback((_, __) =>
377                     {
378                         if(clearInterruptStatusOnRead)
379                         {
380                             UpdateSticky();
381                             UpdateInterrupts();
382                         }
383                     })
384                     .WithWriteCallback((_, __) =>
385                     {
386                         if(!clearInterruptStatusOnRead)
387                         {
388                             UpdateSticky();
389                             UpdateInterrupts();
390                         }
391                     })
392                 },
393                 {(long)Registers.BaudRateGenerator, new DoubleWordRegister(this, resetValue: 0x0000028B)
394                     .WithReservedBits(16, 16)
395                     .WithValueField(0, 16, out baudGenerator, writeCallback: (oldVal, newVal) =>
396                     {
397                         if(newVal == 0)
398                         {
399                             // https://docs.xilinx.com/r/en-US/ug585-zynq-7000-SoC-TRM/Baud-Rate-Generator
400                             this.Log(LogLevel.Warning, "Attempt to write 0 to Baud Rate Generator register was ignored. It can be programmed with a value between 1 and 65535.");
401                             baudGenerator.Value = oldVal;
402                         }
403                     }, name: "baudRateGenerator")
404                 },
405                 {(long)Registers.RxFifoTriggerLevel, new DoubleWordRegister(this, 0x00000020)
406                     .WithReservedBits(6, 26)
407                     .WithValueField(0, 6, out rxTriggerLevel)
408                     .WithWriteCallback((_, __) =>
409                     {
410                         UpdateSticky();
411                         UpdateInterrupts();
412                     })
413                 },
414                 {(long)Registers.ChannelStatus, new DoubleWordRegister(this)
415                     .WithReservedBits(15, 17)
416                     .WithFlag(14, FieldMode.Read, valueProviderCallback: _ => false, name: "txFifoTriggerStatus")
417                     .WithTaggedFlag("rxFlowDelayTriggerStatus", 12)
418                     .WithTaggedFlag("txStateMachineActiveStatus", 11)
419                     .WithTaggedFlag("rxStateMachineActiveStatus", 10)
420                     .WithReservedBits(5, 4)
421                     .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "txFifoFullStatus")
422                     .WithFlag(3, FieldMode.Read,
423                         valueProviderCallback: _ => txFifoEmpty.Status,
424                         name: "txFifoEmptyStatus")
425                     .WithFlag(2, FieldMode.Read,
426                         valueProviderCallback: _ => rxFifoFull.Status,
427                         name: "rxFifoFullStatus")
428                     .WithFlag(1, FieldMode.Read,
429                         valueProviderCallback: _ => rxFifoEmpty.Status,
430                         name: "rxFifoEmptyStatus")
431                     .WithFlag(0, FieldMode.Read,
432                         valueProviderCallback: _ => rxFifoTrigger.Status,
433                         name: "rxFifoTriggerStatus")
434                 },
435                 {(long)Registers.RxTxFifo, new DoubleWordRegister(this)
436                     .WithValueField(0, 8,
437                         writeCallback: (_, value) =>
438                         {
439                             if(!TxEnabled)
440                             {
441                                 this.Log(LogLevel.Warning, "Trying to write to a disabled Tx.");
442                                 return;
443                             }
444                             this.TransmitCharacter((byte)value);
445                         },
446                         valueProviderCallback: _ =>
447                         {
448                             if(!RxEnabled)
449                             {
450                                 this.Log(LogLevel.Warning, "Reading from disabled Rx FIFO.");
451                             }
452                             if(!TryGetCharacter(out var character))
453                             {
454                                 this.Log(LogLevel.Warning, "Reading from an empty Rx FIFO, dummy data returned.");
455                             }
456                             return character;
457                         })
458                     .WithWriteCallback((_, __) =>
459                     {
460                         UpdateSticky();
461                         UpdateInterrupts();
462                     })
463                     .WithReadCallback((_, __) =>
464                     {
465                         UpdateBufferState();
466                         UpdateSticky();
467                         UpdateInterrupts();
468                     })
469                 },
470                 {(long)Registers.BaudRateDivider, new DoubleWordRegister(this, resetValue: 0x0000000F)
471                     .WithReservedBits(8, 24)
472                     .WithValueField(0, 8, out baudDivider, name: "baudRateDivider")
473                 }
474             };
475         }
476 
GetInterruptFlags()477         private IEnumerable<CadenceInterruptFlag> GetInterruptFlags()
478         {
479             yield return rxFifoOverflow;
480             yield return rxFifoFull;
481             yield return rxFifoTrigger;
482             yield return rxFifoEmpty;
483             yield return rxTimeoutError;
484             yield return txFifoEmpty;
485         }
486 
487         private bool TxEnabled => txEnabledReg.Value && !txDisabledReg.Value;
488         private bool RxEnabled => rxEnabledReg.Value && !rxDisabledReg.Value;
489 
490         private IFlagRegisterField txDisabledReg;
491         private IFlagRegisterField txEnabledReg;
492         private IFlagRegisterField rxDisabledReg;
493         private IFlagRegisterField rxEnabledReg;
494         private IEnumRegisterField<InternalStop> stopBitsField;
495         private IEnumRegisterField<InternalParity> parityField;
496         private IFlagRegisterField clockSource;
497         private IValueRegisterField baudGenerator;
498         private IValueRegisterField rxTriggerLevel;
499         private IValueRegisterField baudDivider;
500 
501         private readonly CadenceInterruptFlag rxFifoOverflow;
502         private readonly CadenceInterruptFlag rxFifoFull;
503         private readonly CadenceInterruptFlag rxFifoTrigger;
504         private readonly CadenceInterruptFlag rxFifoEmpty;
505         private readonly CadenceInterruptFlag rxTimeoutError;
506         private readonly CadenceInterruptFlag txFifoEmpty;
507 
508         private readonly DoubleWordRegisterCollection registers;
509         private readonly bool clearInterruptStatusOnRead;
510         private readonly ulong clockFrequency;
511 
512         private const int FifoCapacity = 64;
513 
514         private enum InternalStop
515         {
516             One = 0b00,
517             OneAndHalf = 0b01,
518             Two = 0b10
519         }
520 
521         private enum InternalParity
522         {
523             Even = 0b000,
524             Odd = 0b001,
525             Forced0 = 0b010,
526             Forced1 = 0b011,
527             None = 0b100
528         }
529 
530         private enum Registers : long
531         {
532             Control = 0x00,
533             Mode = 0x04,
534             InterruptEnable = 0x08,
535             InterruptDisable = 0x0c,
536             InterruptMask = 0x10,
537             ChannelInterruptStatus = 0x14,
538             BaudRateGenerator = 0x18,
539             RxTimeout = 0x1c,
540             RxFifoTriggerLevel = 0x20,
541             ModemControl = 0x24,
542             ModemStatus = 0x28,
543             ChannelStatus = 0x2c,
544             RxTxFifo = 0x30,
545             BaudRateDivider = 0x34,
546             FlowDelay = 0x38,
547             TxFifoTriggerLevel = 0x44,
548             RxFifoByteStatus = 0x48
549         }
550     }
551 }
552