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.Renode.Utilities;
14 using Antmicro.Migrant;
15 
16 namespace Antmicro.Renode.Peripherals.UART
17 {
18     public class Atmel91DebugUnit : IDoubleWordPeripheral, IUART, IKnownSize
19     {
Atmel91DebugUnit()20         public Atmel91DebugUnit()
21         {
22             buffer = new Queue<byte>();
23             Reset();
24             IRQ = new GPIO();
25         }
26 
27         public GPIO IRQ { get; private set; }
28 
29         [field: Transient]
30         public event Action<byte> CharReceived;
31 
WriteChar(byte value)32         public void WriteChar(byte value)
33         {
34             lock(buffer)
35             {
36                 buffer.Enqueue(value);
37                 if((InterruptEnable & 0x01) != 0)
38                 {
39                     InterruptStatus |= 0x01;
40                     IRQ.Set();
41                     this.Log(LogLevel.Noisy, "GPIO IRQ set to {0} due to new character in a buffer", value);
42                 }
43             }
44         }
45 
WriteDoubleWord(long offset, uint value)46         public void WriteDoubleWord(long offset, uint value)
47         {
48             switch ( (Offset)offset)
49             {
50             case Offset.Control:
51                 ControlRegister = (uint)(value & 0xFCu);
52                 return;
53 
54             case Offset.Mode:
55                 ModeRegister = (uint)(value & 0xFFFu);
56                 return;
57 
58             case Offset.InterruptEnable:
59                 InterruptEnable |= value;
60                 return;
61 
62             case Offset.InterruptDisable:
63                 InterruptEnable &= ~(value);
64                 return;
65 
66             case Offset.BaudRateGen:
67                 BaudRateGenerator = value & 0xFFFF;
68                 return;
69 
70             case Offset.TransmitHoldingRegister:
71                 var handler = CharReceived;
72                 if(handler != null)
73                 {
74                     handler((byte)(value & 0xFF));
75                 }
76                 if (BitHelper.IsBitSet(InterruptEnable, 4))
77                 {
78                     BitHelper.SetBit(ref InterruptStatus, 4, true);
79                     IRQ.Set();
80                 }
81                 return;
82 
83             default:
84                 this.LogUnhandledWrite(offset, value);
85                 return;
86             }
87         }
88 
ReadDoubleWord(long offset)89         public uint ReadDoubleWord(long offset)
90         {
91             switch( (Offset)offset)
92             {
93             case Offset.Control:
94                 return ControlRegister;
95 
96             case Offset.Mode:
97                 return ModeRegister;
98 
99             case Offset.InterruptMask:
100                 return InterruptEnable;
101 
102             case Offset.Status:
103                     // status register
104 		        uint res = 0;
105                 lock(buffer)
106                 {
107                 if (buffer.Count != 0)
108                     {
109                     res |= 0x1; // RXRDY
110                     }
111 		    res |= (1<<9); // TXEMPTY
112     		        res |= (1<<11); // TXBUFE
113 		    res |= (1<<1); // TXRDY
114                     if (buffer.Count == 0)
115                     {
116                         InterruptStatus = 0;
117                         IRQ.Unset();
118                     }
119                 }
120 		        return res;
121 
122             case Offset.ReceiveHoldingRegister: // data register
123 	    	    lock(buffer) {
124 			        if (buffer.Count == 0) {
125                         return 0;
126                     }
127 			        var waitingChar = buffer.Dequeue();
128                     return waitingChar;
129                 }
130             case Offset.PDCTransferStatusRegister:
131                 return 0u;
132             default:
133                 this.LogUnhandledRead(offset);
134                 return 0x00;
135 
136             }
137 
138         }
139 
Reset()140         public void Reset()
141         {
142             buffer.Clear();
143         }
144 
145     	private readonly Queue<byte> buffer;
146 
147         private uint InterruptEnable = 0x08;
148         private uint InterruptStatus = 0x14;
149         private uint ControlRegister = 0x00;
150         private uint ModeRegister = 0x04;
151         private uint BaudRateGenerator = 0x0;
152 
153         private enum Offset:uint
154         {
155             Control = 0x00,
156             Mode = 0x04,
157             InterruptEnable = 0x08,
158             InterruptDisable = 0x0C,
159             InterruptMask = 0x10,
160             Status = 0x14,
161             ReceiveHoldingRegister = 0x18,
162             TransmitHoldingRegister = 0x1C,
163             BaudRateGen = 0x20,
164             PDCTransferStatusRegister = 0x124,
165         }
166 
167         public long Size => 0x200;
168 
169         public Bits StopBits { get { return Bits.One; } }
170 
171         public Parity ParityBit
172         {
173             get
174             {
175                 var parity = ((ModeRegister >> 9) & 7u);
176                 switch (parity)
177                 {
178                 case 0:
179                     return Parity.Even;
180                 case 1:
181                     return Parity.Odd;
182                 case 2:
183                     return Parity.Forced0;
184                 case 3:
185                     return Parity.Forced1;
186                 default:
187                     return Parity.None;
188                 }
189             }
190         }
191 
192         public uint BaudRate
193         {
194             get
195             {
196                 return BaudRateGenerator == 0 ? 0 : (MasterClockFrequency / (BaudRateGenerator == 1 ? 1 : 16 * BaudRateGenerator));
197             }
198         }
199 
200         public const int MasterClockFrequency = 0;
201     }
202 }
203 
204