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     public class ImxUart : IBytePeripheral, IUART, IKnownSize
18     {
ImxUart()19         public ImxUart()
20         {
21             IRQ = new GPIO();
22             charFifo = new Queue<byte>();
23         }
24 
25         public long Size
26         {
27             get
28             {
29                 return 0x1000;
30             }
31         }
32 
33         public GPIO IRQ { get; private set; }
34 
35         [field: Transient]
36         public event Action<byte> CharReceived;
37 
WriteChar(byte value)38         public void WriteChar(byte value)
39         {
40             lock(charFifo)
41             {
42                 charFifo.Enqueue(value);
43                 UpdateIRQ();
44             }
45         }
46 
ReadByte(long address)47         public byte ReadByte(long address)
48         {
49             switch((Register)address)
50             {
51             case Register.FifoParameters:
52                 return fifoParametersRegister;
53             case Register.FifoWatermark:
54                 return fifoWatermarkRegister;
55             case Register.Modem:
56                 return modemRegister;
57             case Register.BaudRateH:
58                 return baudRateH;
59             case Register.Control1:
60                 return control1Register;
61             case Register.BaudRateL:
62                 return baudRateL;
63             case Register.Control4:
64                 return control4Register;
65             case Register.Status1:
66                 return status1Register;
67             case Register.FifoStatus:
68                 return (byte) ((charFifo.Count > 0) ? (1<<7) : ((1<<7) | (1<<6)));
69             case Register.Control2:
70                 return control2Register;
71             case Register.Control3:
72                 return 0;
73             case Register.Data:
74                 lock(charFifo)
75                 {
76                     byte returnValue = (byte)0;
77                     if(charFifo.Count > 0)
78                     {
79                         returnValue = charFifo.Dequeue();
80                     }
81                     UpdateIRQ();
82                     return returnValue;
83                 }
84             case Register.Control5:
85                 return control5Register;
86             default:
87                 this.LogUnhandledRead(address);
88                 return 0;
89             }
90         }
91 
WriteByte(long address, byte value)92         public void WriteByte(long address, byte value)
93         {
94             switch((Register)address)
95             {
96             case Register.FifoParameters:
97                 fifoParametersRegister = value;
98                 break;
99             case Register.FifoWatermark:
100                 fifoWatermarkRegister = value;
101                 break;
102             case Register.Modem:
103                 modemRegister = value;
104                 break;
105             case Register.Control1:
106                 control1Register = value;
107                 break;
108             case Register.Control2:
109                 control2Register = value;
110                 //bool rx_enabled = ((value & (1u << 2)) != 0);
111                 //bool tx_enabled = ((value & (1u << 3)) != 0);
112                 enableIRQ = /*(rx_enabled || tx_enabled) &&*/ (((value & (1u << 7)) != 0) || ((value & (1u << 5)) != 0)); // TX_IRQ_DMA | RX_IRQ_DMA
113                 UpdateIRQ();
114                 break;
115             case Register.Control4:
116                 control4Register = value;
117                 break;
118             case Register.Control5:
119                 control5Register = value;
120                 break;
121             case Register.Data:
122                 var handler = CharReceived;
123                 if(handler != null)
124                 {
125                     handler(value);
126                 }
127                 break;
128             case Register.BaudRateH:
129                 baudRateHBuffer = value;
130                 break;
131             case Register.BaudRateL:
132                 baudRateH = baudRateHBuffer;
133                 baudRateL = value;
134                 break;
135             case Register.InterruptEnable:
136                 break;
137             default:
138                 this.LogUnhandledWrite(address, value);
139                 break;
140             }
141             UpdateIRQ();
142         }
143 
UpdateIRQ()144         private void UpdateIRQ()
145         {
146             TDRE    = true;
147             TC      = true;
148             RDRF    = charFifo.Count > 0;
149             IDLE    = !RDRF;
150 
151             var irqState = ((TDRE && TIE && !TDMAS) ||
152                 (TC && TCIE) ||
153                 (IDLE && ILIE) ||
154                 (RDRF && RIE && !RDMAS));
155             IRQ.Set(enableIRQ && irqState);
156         }
157 
Reset()158         public void Reset()
159         {
160             // TODO!
161         }
162 
163         private bool enableIRQ;
164 
165         private byte status1Register = (byte)((1u << 7) | (1u << 6));
166 
167         private byte control1Register;
168         private byte control2Register;
169         private byte control4Register;
170         private byte control5Register;
171 
172         private byte fifoWatermarkRegister;
173         private byte fifoParametersRegister;
174 
175         private readonly Queue<byte> charFifo;
176 
177         private byte baudRateHBuffer;
178         private byte baudRateH;
179         private byte baudRateL;
180         private byte modemRegister;
181 
182         [Flags]
183         private enum Control1 : byte
184         {
185             ParityEnable = 1 << 1,
186             ParityType   = 1
187         }
188 
189         private enum Register : long
190         {
191             BaudRateH       = 0x00,
192             BaudRateL       = 0x01,
193             Control1        = 0x02,
194             Control2        = 0x03,
195             Status1         = 0x04,
196             Control3        = 0x06,
197             Data            = 0x07,
198             Control4        = 0x0A,
199             Control5        = 0x0B,
200             Modem           = 0x0D,
201             FifoParameters  = 0x10,
202             FifoStatus      = 0x12,
203             FifoWatermark   = 0x13,
204             InterruptEnable = 0x19
205         }
206         #region Bits
207 
208         private bool TDMAS { get { return (control5Register & (1u << 7)) != 0; } }
209         private bool RDMAS { get { return (control5Register & (1u << 5)) != 0; } }
210         private bool TIE   { get { return (control2Register & (1u << 7)) != 0; } }
211         private bool RIE   { get { return (control2Register & (1u << 5)) != 0; } }
212         private bool TCIE  { get { return (control2Register & (1u << 6)) != 0; } }
213         private bool ILIE  { get { return (control2Register & (1u << 4)) != 0; } }
214 
215         private bool TDRE
216         {
217             get { return (status1Register & (1u << 7)) != 0; }
218             set
219             {
220                 if (value)
221                 {
222                     status1Register |= (byte)(1u << 7);
223                 }
224             }
225         }
226         private bool TC
227         {
228             get { return (status1Register & (1u << 6)) != 0; }
229             set
230             {
231                 if (value)
232                 {
233                     status1Register |= (byte)(1u << 6);
234                 }
235             }
236         }
237         private bool IDLE
238         {
239             get { return (status1Register & (1u << 4)) != 0; }
240             set
241             {
242                 if (value)
243                 {
244                     status1Register |= (byte)(1u << 4);
245                 }
246                 else
247                 {
248                     status1Register &= (byte.MaxValue - (byte)(1u << 4));
249                 }
250             }
251         }
252         private bool RDRF
253         {
254             get { return (status1Register & (1u << 5)) != 0; }
255             set
256             {
257                 if (value)
258                 {
259                     status1Register |= (byte)(1u << 5);
260                 }
261                 else
262                 {
263                     status1Register &= (byte.MaxValue - (byte)(1u << 5));
264                 }
265             }
266         }
267 
268         #endregion
269 
270         public Bits StopBits
271         {
272             get
273             {
274                 return Bits.One;
275             }
276         }
277         public Parity ParityBit
278         {
279             get
280             {
281                 if ((control1Register & (byte)Control1.ParityEnable) == 0)
282                 {
283                     return Parity.None;
284                 }
285                 else
286                 {
287                     return ((control1Register & (byte)Control1.ParityType) == 0) ? Parity.Even : Parity.Odd;
288                 }
289             }
290         }
291 
292         public uint BaudRate
293         {
294             get
295             {
296                 var divisor = (16 * (((baudRateH & 0x1F) << 8) + baudRateL) + ((control4Register & 0x1F) / 32));
297                 return divisor == 0 ? 0 : (uint)(SystemClockFrequency / divisor);
298             }
299         }
300 
301         private uint SystemClockFrequency = 0;
302     }
303 }
304 
305