1 // 2 // Copyright (c) 2010-2023 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 public class LEUART : IDoubleWordPeripheral, IUART 18 { LEUART()19 public LEUART() 20 { 21 queueLock = new object(); 22 IRQ = new GPIO(); 23 Reset(); 24 } 25 26 public GPIO IRQ { get; private set; } 27 ReadDoubleWord(long offset)28 public uint ReadDoubleWord(long offset) 29 { 30 switch((Register)offset) 31 { 32 case Register.Status: 33 this.NoisyLog("Status register read, returned {0}.", currentStatus); 34 return (uint)currentStatus; 35 case Register.InterruptFlag: 36 this.NoisyLog("Interrupt flag register read, returned {0}.", interruptFlag); 37 return (uint)interruptFlag; 38 case Register.InterruptEnable: 39 return interruptEnable; 40 case Register.ReceiveBufferData: 41 return HandleReadCharacter(); 42 case Register.Freeze: 43 return 0; 44 case Register.SyncBusy: 45 return 0; 46 default: 47 this.LogUnhandledRead(offset); 48 break; 49 } 50 return 0; 51 } 52 WriteDoubleWord(long offset, uint value)53 public void WriteDoubleWord(long offset, uint value) 54 { 55 switch((Register)offset) 56 { 57 case Register.Control: 58 controlRegister = value; 59 break; 60 case Register.TransmitBufferData: 61 TransmitCharacter((byte)value); 62 UpdateInterrupts(); 63 break; 64 case Register.InterruptClear: 65 ClearInterrupt(); 66 break; 67 case Register.InterruptEnable: 68 interruptEnable = value; 69 UpdateInterrupts(); 70 break; 71 case Register.ClockControl: 72 clockControl = value & 0x7FF8; 73 break; 74 default: 75 this.LogUnhandledWrite(offset, value); 76 break; 77 } 78 } 79 Reset()80 public void Reset() 81 { 82 currentStatus = Status.TransmitBufferEmpty; 83 // Assume that TX buffer is always empty 84 interruptFlag = InterruptFlag.TxCompleteInterrutpt | InterruptFlag.TxBufferLevelInterrupt; 85 waitingChars = new Queue<byte>(); 86 } 87 WriteChar(byte data)88 public void WriteChar(byte data) 89 { 90 this.NoisyLog("Char 0x{0:X} written.", data); 91 interruptFlag |= InterruptFlag.RxDataAvailable; 92 lock(queueLock) 93 { 94 waitingChars.Enqueue(data); 95 currentStatus |= Status.RxDataAvailable; 96 } 97 UpdateInterrupts(); 98 } 99 100 [field: Transient] 101 public event Action<byte> CharReceived; 102 HandleReadCharacter()103 private uint HandleReadCharacter() 104 { 105 lock(queueLock) 106 { 107 if(waitingChars.Count == 0) 108 { 109 return 0; 110 } 111 var waitingChar = waitingChars.Dequeue(); 112 if(waitingChars.Count == 0) 113 { 114 currentStatus &= ~Status.RxDataAvailable; 115 } 116 UpdateInterrupts(); 117 this.NoisyLog("ReceiveBufferData read, returned {0}", waitingChar); 118 return waitingChar; 119 } 120 } 121 TransmitCharacter(byte data)122 private void TransmitCharacter(byte data) 123 { 124 var charReceived = CharReceived; 125 if(charReceived != null) 126 { 127 charReceived(data); 128 } 129 } 130 ClearInterrupt()131 private void ClearInterrupt() 132 { 133 IRQ.Set(false); 134 interruptFlag &= ~InterruptFlag.RxDataAvailable; 135 } 136 UpdateInterrupts()137 private void UpdateInterrupts() 138 { 139 IRQ.Set( 140 ((interruptEnable & (uint)InterruptEnable.RxDataAvailable) != 0 && waitingChars.Count > 0) || 141 (interruptEnable & (uint)InterruptEnable.TxBufferLevelInterrupt) != 0 || 142 (interruptEnable & (uint)InterruptEnable.TxCompleteInterrutpt) != 0 143 ); 144 } 145 146 private uint controlRegister; 147 private uint clockControl; 148 private uint interruptEnable; 149 150 private Status currentStatus; 151 private InterruptFlag interruptFlag; 152 private Queue<byte> waitingChars; 153 private readonly object queueLock; 154 155 [Flags] 156 private enum InterruptFlag 157 { 158 RxDataAvailable = 1 << 2, 159 TxBufferLevelInterrupt = 1 << 1, 160 TxCompleteInterrutpt = 1 << 0 161 } 162 163 [Flags] 164 private enum InterruptEnable 165 { 166 RxDataAvailable = 1 << 2, 167 TxBufferLevelInterrupt = 1 << 1, 168 TxCompleteInterrutpt = 1 << 0 169 } 170 171 [Flags] 172 private enum Status 173 { 174 TransmitBufferEmpty = 1 << 4, 175 RxDataAvailable = 1 << 5 176 } 177 178 [Flags] 179 private enum Control 180 { 181 ParityL = 1 << 2, 182 ParityH = 1 << 3, 183 StopBits = 1 << 4 184 } 185 186 private enum Register 187 { 188 Control = 0x000, 189 Status = 0x008, 190 ReceiveBufferData = 0x01C, 191 TransmitBufferData = 0x028, 192 InterruptFlag = 0x02C, 193 InterruptClear = 0x034, 194 InterruptEnable = 0x038, 195 Freeze = 0x040, 196 SyncBusy = 0x044, 197 ClockControl = 0x00C 198 } 199 200 public Bits StopBits 201 { 202 get 203 { 204 return (controlRegister & (uint)Control.StopBits) != 0 ? Bits.Two : Bits.One; 205 } 206 } 207 208 public Parity ParityBit 209 { 210 get 211 { 212 var bits = ((controlRegister & (uint)(Control.ParityH | Control.ParityL)) >> 2); 213 switch(bits) 214 { 215 case 0: 216 return Parity.None; 217 case 2: 218 return Parity.Even; 219 case 3: 220 return Parity.Odd; 221 default: 222 throw new ArgumentException("Wrong parity bits register value"); 223 } 224 } 225 } 226 227 public uint BaudRate 228 { 229 get 230 { 231 // divisor cannot be 0, so there is no need to check it 232 return UARTClockFrequency / (1 + clockControl/256); 233 } 234 } 235 236 private const uint UARTClockFrequency = 0; 237 } 238 } 239 240