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