1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Bus;
12 using System.Collections.Generic;
13 using Antmicro.Migrant;
14 
15 namespace Antmicro.Renode.Peripherals.UART
16 {
17     [AllowedTranslations(AllowedTranslation.WordToDoubleWord)]
18     public class NS16550 :  IBytePeripheral, IDoubleWordPeripheral, IUART, IKnownSize
19     {
NS16550(bool wideRegisters = false)20         public NS16550(bool wideRegisters = false)
21         {
22             mode32 = wideRegisters;
23             IRQ = new GPIO();
24             Reset();
25         }
26 
27         public GPIO IRQ { get; private set; }
28 
29         public long Size
30         {
31             get
32             {
33                 return 0x100;
34             }
35         }
36 
WriteChar(byte value)37         public void WriteChar(byte value)
38         {
39             lock(UARTLock)
40             {
41                 if((fifoControl & FifoControl.Enable) != 0 || true)//HACK : fifo always enabled
42                 {
43                     recvFifo.Enqueue(value);
44                     lineStatus |= LineStatus.DataReady;
45                 }
46                 else
47                 {
48                     if((lineStatus & LineStatus.DataReady) != 0)
49                     {
50                         lineStatus |= LineStatus.OverrunErrorIndicator;
51                     }
52                     receiverBuffer = value;
53                     lineStatus |= LineStatus.DataReady;
54                 }
55                 Update();
56             }
57         }
58 
WriteByte(long offset, byte value)59         public void WriteByte(long offset, byte value)
60         {
61             var originalOffset = offset;
62             if(mode32 && ((offset % 4) == 0))
63             {
64                 offset = offset / 4;
65             }
66             lock(UARTLock)
67             {
68                 if((lineControl & LineControl.DivisorLatchAccess) != 0)
69                 {
70                     switch((Register)offset)
71                     {
72                     case Register.DivisorLatchL:
73                         divider = (ushort)((divider & 0xff00) | value);
74                         return;
75 
76                     case Register.DivisorLatchH:
77                         divider = (ushort)((divider & 0x00ff) | (value << 8));
78                         return;
79 
80                     case Register.PrescalerDivision:
81                         prescaler = (byte)(value & 0x0f);
82                         return;
83                     }
84                 }
85 
86                 switch((Register)offset)
87                 {
88                 case Register.Data:
89                     var handler = CharReceived;
90                     if(handler != null)
91                     {
92                         handler((byte)(value & 0xFF));
93                     }
94 
95                     transmitNotPending = 0;
96                     lineStatus &= ~LineStatus.TransmitHoldEmpty;
97                     if((fifoControl & FifoControl.IsEnabled) != 0)
98                     {
99                         lineStatus &= ~LineStatus.TransmitterEmpty;
100                     }
101                     Update();
102 
103                     if((fifoControl & FifoControl.IsEnabled) == 0 || (interruptEnable & InterruptEnableLevel.ProgrammableTransmitHoldEmptyInterruptMode) == 0)
104                     {
105                         lineStatus |= LineStatus.TransmitHoldEmpty;
106                     }
107                     lineStatus |= LineStatus.TransmitterEmpty;
108                     transmitNotPending = 1;
109                     Update();
110                     break;
111 
112                 case Register.InterruptEnable:
113                     interruptEnable = (InterruptEnableLevel)value;
114                     if((fifoControl & FifoControl.IsEnabled) != 0 && (interruptEnable & InterruptEnableLevel.ProgrammableTransmitHoldEmptyInterruptMode) != 0)
115                     {
116                         lineStatus &= ~LineStatus.TransmitHoldEmpty;
117                     }
118 
119                     if((lineStatus & LineStatus.TransmitHoldEmpty) != 0)
120                     {
121                         transmitNotPending = 1;
122                         Update();
123                     }
124                     break;
125 
126                 case Register.FIFOControl:
127                     var val = (FifoControl)value;
128                     if(fifoControl == val)
129                     {
130                         break;
131                     }
132                     /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
133                     if(((val ^ fifoControl) & FifoControl.Enable) != 0)
134                     {
135                         val |= (FifoControl.TransmitReset | FifoControl.ReceiveReset);
136                     }
137 
138                     /* FIFO clear */
139                     if((val & FifoControl.ReceiveReset) != 0)
140                     {
141                         recvFifo.Clear();
142 
143                     }
144                     if((val & FifoControl.TransmitReset) != 0)
145                     {
146                         //clear xmit
147                     }
148 
149                     if((val & FifoControl.Enable) != 0)
150                     {
151                         interruptIdentification |= (InterruptLevel)FifoControl.IsEnabled;
152                         /* Set RECV_FIFO trigger Level */
153                         switch(val & (FifoControl)0XC0)
154                         {
155                         case FifoControl.IrqTriggerLevel1:
156                             interruptTriggerLevel = 1;
157                             break;
158                         case FifoControl.IrqTriggerLevel2:
159                             interruptTriggerLevel = 4;
160                             break;
161                         case FifoControl.IrqTriggerLevel3:
162                             interruptTriggerLevel = 8;
163                             break;
164                         case FifoControl.IrqTriggerLevel4:
165                             interruptTriggerLevel = 14;
166                             break;
167                         }
168                     }
169                     else
170                     {
171                         interruptIdentification &= (InterruptLevel)unchecked((byte)(~FifoControl.IsEnabled));
172                     }
173                     /* Set fifoControl - or at least the bits in it that are supposed to "stick" */
174                     fifoControl = (val & (FifoControl)0xC9);
175                     Update();
176                     break;
177 
178                 case Register.LineControl:
179                     lineControl = (LineControl)value;
180                     break;
181 
182                 case Register.ModemControl:
183                     modemControl = (ModemControl)(value & 0x1F);
184                     break;
185 
186                 case Register.LineStatus:
187                     //Linux should not write here, but it does
188                     break;
189 
190                 case Register.TriggerLevelScratchpad:
191                     scratchRegister = value;
192                     break;
193 
194                 case Register.MultiModeControl0:
195                     this.Log(LogLevel.Warning, "Unsupported write to LIN mode configuration register at offset 0x{0:X}.", originalOffset);
196                     break;
197                 case Register.MultiModeControl1:
198                     this.Log(LogLevel.Warning, "Unsupported write to RZI mode configuration register at offset 0x{0:X}.", originalOffset);
199                     break;
200                 case Register.MultiModeControl2:
201                 case Register.MultiModeInterruptEnable:
202                 case Register.TransmitterTimeGuard:
203                 case Register.ReceiverTimeOut:
204                     this.Log(LogLevel.Warning, "Unsupported write to multi-mode configuration register at offset 0x{0:X}.", originalOffset);
205                     break;
206                 case Register.FractionalDivisor:
207                 case Register.GlitchFilter:
208                     this.Log(LogLevel.Warning, "Unsupported write to configuration register at offset 0x{0:X}.", originalOffset);
209                     break;
210 
211                 default:
212                     this.LogUnhandledWrite(originalOffset, value);
213                     break;
214                 }
215 
216             }
217         }
218 
ReadByte(long offset)219         public byte ReadByte(long offset)
220         {
221             var originalOffset = offset;
222             if(mode32 && ((offset % 4) == 0))
223             {
224                 offset = offset / 4;
225             }
226             lock(UARTLock)
227             {
228                 byte value = 0x0;
229                 if((lineControl & LineControl.DivisorLatchAccess) != 0)
230                 {
231                     switch((Register)offset)
232                     {
233                     case Register.DivisorLatchL:
234                         value = (byte)(divider & 0xFF);
235                         goto ret;
236 
237                     case Register.DivisorLatchH:
238                         value = (byte)((divider >> 8) & 0xFF);
239                         goto ret;
240                     }
241                 }
242                 else
243                 {
244                     switch((Register)offset)
245                     {
246                     case Register.Data:
247                         if((fifoControl & FifoControl.Enable) != 0 || true /*HACK*/)
248                         {
249                             if(recvFifo.Count > 0)
250                             {
251                                 value = recvFifo.Dequeue();
252                             }
253                             else
254                             {
255                                 value = 0;
256                             }
257                             if(recvFifo.Count == 0)
258                             {
259                                 lineStatus &= ~(LineStatus.DataReady | LineStatus.BreakIrqIndicator);
260                             }
261                         }
262                         else
263                         {
264                             value = receiverBuffer;
265                             lineStatus &= ~(LineStatus.DataReady | LineStatus.BreakIrqIndicator);
266                         }
267                         Update();
268                         if((modemControl & ModemControl.Loopback) == 0)
269                         {
270                             /* in loopback mode, don't receive any data */
271                         }
272 
273                         break;
274 
275                     case Register.InterruptEnable:
276                         value = (byte)interruptEnable;
277                         break;
278 
279                     case Register.InterruptIdentification:
280                         value = (byte)interruptIdentification;
281                         if((value & MaskInterruptId) == (byte)InterruptLevel.TransmitterHoldingRegEmpty)
282                         {
283                             transmitNotPending = 0;
284                             Update();
285                         }
286                         break;
287 
288                     case Register.LineControl:
289                         value = (byte)lineControl;
290                         break;
291 
292                     case Register.ModemControl:
293                         //this.DebugLog("modem control read");
294                         value = (byte)modemControl;
295                         break;
296 
297                     case Register.LineStatusHack: //TODO: HACK! Why does it work?
298                         goto case Register.LineStatus;
299 
300                     case Register.LineStatus:
301                         value = (byte)lineStatus;
302                         if((lineStatus & (LineStatus.BreakIrqIndicator | LineStatus.OverrunErrorIndicator)) != 0)
303                         {
304                             lineStatus &= ~(LineStatus.BreakIrqIndicator | LineStatus.OverrunErrorIndicator);
305                             Update();
306                         }
307                         lineStatus &= ~(LineStatus.OverrunErrorIndicator | LineStatus.ParityErrorIndicator | LineStatus.FrameErrorIndicator | LineStatus.BreakIrqIndicator | LineStatus.ReceiverFIFOError);
308                         break;
309 
310                     case Register.ModemStatusRegister:
311                 //    this.DebugLog("6 modem control read");
312                         if((modemControl & ModemControl.Loopback) != 0)
313                         {
314                             /* in loopback, the modem output pins are connected to the inputs */
315                             value = (byte)(((byte)modemControl & 0x0c) << 4);
316                             value |= (byte)(((byte)modemControl & 0x02) << 3);
317                             value |= (byte)(((byte)modemControl & 0x01) << 5);
318                         }
319                         else
320                         {
321                             value = (byte)modemStatus;
322                             /* Clear delta bits & msr int after read, if they were set */
323                             if((modemStatus & ModemStatus.AnyDelta) != 0)
324                             {
325                                 modemStatus &= (ModemStatus)0xF0;
326                                 Update();
327                             }
328                         }
329                         break;
330 
331                     case Register.TriggerLevelScratchpad:
332                         value = scratchRegister;
333                         break;
334 
335                     case Register.MultiModeControl0:
336                         this.Log(LogLevel.Warning, "Unsupported read from LIN configuration register at offset 0x{0:X}.", originalOffset);
337                         break;
338                     case Register.MultiModeControl1:
339                         this.Log(LogLevel.Warning, "Unsupported read from RZI configuration register at offset 0x{0:X}.", originalOffset);
340                         break;
341                     case Register.MultiModeControl2:
342                     case Register.MultiModeInterruptEnable:
343                     case Register.TransmitterTimeGuard:
344                     case Register.ReceiverTimeOut:
345                         this.Log(LogLevel.Warning, "Unsupported read from multi-mode configuration register at offset 0x{0:X}.", originalOffset);
346                         break;
347                     case Register.FractionalDivisor:
348                     case Register.GlitchFilter:
349                         this.Log(LogLevel.Warning, "Unsupported read from configuration register at offset 0x{0:X}.", originalOffset);
350                         break;
351 
352                     default:
353                     this.LogUnhandledRead(originalOffset);
354                     break;
355                     }
356                 }
357                 ret:
358                 return value;
359             }
360         }
361 
Reset()362         public void Reset()
363         {
364             lock(UARTLock)
365             {
366                 receiverBuffer = 0;
367                 interruptEnable = 0;
368                 interruptIdentification = InterruptLevel.NoInterruptsPending;
369                 lineControl = 0;
370                 lineStatus = LineStatus.TransmitterEmpty | LineStatus.TransmitHoldEmpty;
371                 modemStatus = ModemStatus.DataCarrierDetect | ModemStatus.DataSetReady | ModemStatus.ClearToSend;
372                 divider = 0x0C;
373                 modemControl = ModemControl.ForceDataCarrierDetect;
374                 scratchRegister = 0;
375                 transmitNotPending = 0;
376             }
377         }
378 
ReadDoubleWord(long offset)379         public uint ReadDoubleWord(long offset)
380         {
381             return (uint)ReadByte(offset);
382         }
383 
WriteDoubleWord(long offset, uint value)384         public void WriteDoubleWord(long offset, uint value)
385         {
386             WriteByte(offset, (byte)(value & 0xFF));
387         }
388 
Update()389         private void Update()
390         {
391             var interruptId = InterruptLevel.NoInterruptsPending;
392             if(((interruptEnable & InterruptEnableLevel.ReceiverLineStatus) != 0) && ((lineStatus & LineStatus.InterruptAny) != 0))
393             {
394                 interruptId = InterruptLevel.ReceiverLineStatusIrq;
395             }
396             else if(((interruptEnable & InterruptEnableLevel.ReceiverData) != 0) && ((lineStatus & LineStatus.DataReady) != 0) && (((fifoControl & FifoControl.Enable) == 0) || true /* HACK */ || recvFifo.Count > interruptTriggerLevel))
397             {
398                 interruptId = InterruptLevel.ReceiverDataIrq;
399             }
400             else if(((interruptEnable & InterruptEnableLevel.TransmitterHoldingReg) != 0) && (transmitNotPending != 0))
401             {
402                 interruptId = InterruptLevel.TransmitterHoldingRegEmpty;
403             }
404             else if(((interruptEnable & InterruptEnableLevel.ModemStatus) != 0) && ((modemStatus & ModemStatus.AnyDelta) != 0))
405             {
406                 interruptId = InterruptLevel.ModemStatusIrq;
407             }
408 
409             interruptIdentification = interruptId | (interruptIdentification & (InterruptLevel)0xF0);
410 
411             if(interruptId != InterruptLevel.NoInterruptsPending)
412             {
413                 this.NoisyLog("IRQ true");
414                 IRQ.Set(true);
415             }
416             else
417             {
418                 this.NoisyLog("IRQ false");
419                 IRQ.Set(false);
420             }
421         }
422 
423         [field: Transient]
424         public event Action<byte> CharReceived;
425 
426         private Queue<byte> recvFifo = new Queue<byte>();
427         private object UARTLock = new object();
428 
429         private InterruptEnableLevel interruptEnable;
430         private InterruptLevel interruptIdentification;
431         /* read only */
432         private LineControl lineControl;
433         private ModemControl modemControl;
434         private LineStatus lineStatus;
435         /* read only */
436         private ModemStatus modemStatus;
437         /* read only */
438         private FifoControl fifoControl;
439         private bool mode32;
440         private byte scratchRegister;
441 
442         private byte interruptTriggerLevel;
443         private ushort divider;
444         private byte prescaler;
445         private byte receiverBuffer;
446         /* receive register */
447         private int transmitNotPending;
448 
449         private const int ReceiveFIFOSize = 16;
450         private const byte MaskInterruptId = 0x06;
451         /* Mask for the interrupt ID */
452 
453 
454         private enum Register:uint
455         {
456             Data = 0x00,
457             DivisorLatchL = 0x00,
458             // the same as Data but accessible only when DLAB bit is set
459             InterruptEnable = 0x01,
460             DivisorLatchH = 0x01,
461             // the same as Interrupt enabel but accessible only when DLAB bit is set
462             InterruptIdentification = 0x02,
463             FIFOControl = 0x02,
464             LineControl = 0x03,
465             ModemControl = 0x04,
466             LineStatus = 0x05,
467             PrescalerDivision = 0x05,
468             // the same as Line Status but accessible only when DLAB bit is set
469             LineStatusHack = 0x14,
470             ModemStatusRegister = 0x06,
471             TriggerLevelScratchpad = 0x07,
472 
473             MultiModeInterruptEnable = 0x09,
474             MultiModeControl0 = 0x0C,
475             MultiModeControl1 = 0x0D,
476             MultiModeControl2 = 0x0E,
477             FractionalDivisor = 0x0F,
478             GlitchFilter = 0x11,
479             TransmitterTimeGuard = 0x12,
480             ReceiverTimeOut = 0x13
481         }
482 
483         [Flags]
484         private enum LineControl : byte
485         {
486             DivisorLatchAccess = 0x80,
487             ParityEnable = 0x08,
488             EvenParity = 0x10,
489             ForceParity = 0x20,
490             StopBits = 0x04,
491             WordLengthH = 0x02,
492             WordLengthL = 0x01
493         }
494 
495         /*
496          * Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher.
497          */
498         [Flags]
499         private enum InterruptLevel : byte
500         {
501             NoInterruptsPending = 0x01,
502             TransmitterHoldingRegEmpty = 0x02,
503             ReceiverDataIrq = 0x04,
504             ReceiverLineStatusIrq = 0x06,
505             CharacterTimeoutIndication = 0x0C,
506             /*not used at the moment*/
507             ModemStatusIrq = 0x00
508             /* "Other" irq - NoInterrupts is disabled, but no other bit is enabled, so check in another register */
509         }
510 
511         [Flags]
512         private enum InterruptEnableLevel : byte
513         {
514             ProgrammableTransmitHoldEmptyInterruptMode = 0x80,
515             ModemStatus = 0x08,
516             ReceiverLineStatus = 0x04,
517             TransmitterHoldingReg = 0x02,
518             ReceiverData = 0x01
519         }
520 
521         /*
522          * These are the definitions for the Modem Control Register
523          * KKRU: This comment is useful as hell.
524          */
525         [Flags]
526         private enum ModemControl : byte
527         {
528             Loopback = 0x10,
529             ForceDataCarrierDetect = 0x08,
530             ForceRingIndicator = 0x04,
531             ForceRequestToSend = 0x02,
532             ForceDataTerminalReady = 0x01
533 
534         }
535 
536         /*
537          * These are the definitions for the Modem Status Register
538          */
539         [Flags]
540         private enum ModemStatus : byte
541         {
542             DataCarrierDetect = 0x80,
543             RingIndicator = 0x40,
544             DataSetReady = 0x20,
545             ClearToSend = 0x10,
546             DeltaDataCarrierDetect = 0x08,
547             TrailingEdgeRingIndicator = 0x04,
548             DeltaDataSetReady = 0x02,
549             DeltaClearToSend = 0x01,
550             AnyDelta = 0x0F
551         }
552 
553 
554         /*
555          * These are the definitions for the Line Status Register
556          */
557         [Flags]
558         private enum LineStatus : byte
559         {
560             ReceiverFIFOError = 0x80,
561             TransmitterEmpty = 0x40,
562             TransmitHoldEmpty = 0x20,
563             BreakIrqIndicator = 0x10,
564             FrameErrorIndicator = 0x08,
565             ParityErrorIndicator = 0x04,
566             OverrunErrorIndicator = 0x02,
567             DataReady = 0x01,
568             InterruptAny = 0x1E
569         }
570 
571         /*
572          * These are the definitions for the FIFO Control Register
573          */
574         [Flags]
575         private enum FifoControl : byte
576         {
577             Enable = 0x01,
578             ReceiveReset = 0x02,
579             TransmitReset = 0x04,
580             DMAModeSelect = 0x08,
581 
582             IsEnabledNotFunc = 0x80,
583             IsEnabled = 0xC0,
584 
585             IrqTriggerLevel1 = 0x00,
586             IrqTriggerLevel2 = 0x40,
587             IrqTriggerLevel3 = 0x80,
588             IrqTriggerLevel4 = 0xC0
589         }
590 
591         public Bits StopBits
592         {
593             get
594             {
595                 if((lineControl & LineControl.StopBits) == 0)
596                 {
597                     return Bits.One;
598                 }
599                 // is word length is equal to 5? then 1.5 else 2
600                 return ((byte)lineControl & 3u) == 0 ? Bits.OneAndAHalf : Bits.Two;
601             }
602         }
603 
604         public Parity ParityBit
605         {
606             get
607             {
608                 if((lineControl & LineControl.ParityEnable) == 0)
609                 {
610                     return Parity.None;
611                 }
612                 if((lineControl & LineControl.ForceParity) == 0)
613                 {
614                     return (lineControl & LineControl.EvenParity) == 0 ? Parity.Odd : Parity.Even;
615                 }
616                 return (lineControl & LineControl.EvenParity) == 0 ? Parity.Forced1 : Parity.Forced0;
617             }
618         }
619 
620         public uint BaudRate
621         {
622             get
623             {
624                 var divisor = (16 * (prescaler + 1) * divider);
625                 return divisor == 0 ? 0 : (uint)(SystemClockFrequency / divisor);
626             }
627         }
628 
629         private const uint SystemClockFrequency = 0;
630     }
631 }
632 
633