1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using Antmicro.Renode.Core; 8 using Antmicro.Renode.Core.Structure.Registers; 9 using Antmicro.Renode.Logging; 10 using Antmicro.Renode.Peripherals.Bus; 11 using Antmicro.Renode.Utilities; 12 using Antmicro.Migrant; 13 using System; 14 using System.Collections.Generic; 15 16 namespace Antmicro.Renode.Peripherals.UART 17 { 18 // Due to unusual register offsets we cannot use address translations 19 public class SAMD20_UART : IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, IUART, IKnownSize 20 { SAMD20_UART(IMachine machine)21 public SAMD20_UART(IMachine machine) 22 { 23 IRQ = new GPIO(); 24 25 var registersMap = new Dictionary<long, DoubleWordRegister> 26 { 27 {(long)Registers.ControlA, new DoubleWordRegister(this) 28 .WithFlag(0, 29 writeCallback: (_, val) => 30 { 31 if(!val) 32 { 33 return; 34 } 35 // According to the docs writing '1' to this bit should reset all registers except Debug Control, 36 // but since that register is a stub, we don't bother. 37 Reset(); 38 enabled.Value = false; 39 }, 40 valueProviderCallback: _ => false, 41 name: "Software reset (SWRST)") 42 .WithFlag(1, out enabled, name: "Enable (ENABLE)") 43 .WithTag("Operating mode (MODE)", 2, 3) 44 .WithReservedBits(5, 2) 45 .WithTag("Run in standby (RUNSTDBY)", 7, 1) 46 .WithTag("Immediate buffer overflow notification (IBON)", 8, 1) 47 .WithReservedBits(9, 7) 48 .WithTag("Transmit data pinout (TXPO)", 16, 1) 49 .WithReservedBits(17, 3) 50 .WithTag("Receive data pinout (RXPO)", 20, 2) 51 .WithReservedBits(22, 2) 52 .WithEnumField(24, 4, out frameFormat, name: "Frame format (FORM)") 53 .WithTag("Communication mode (CMODE)", 28, 1) 54 .WithTag("Clock polarity (CPOL)", 29, 1) 55 .WithTag("Data order (DORD)", 30, 1) 56 .WithReservedBits(31, 1) 57 }, 58 59 {(long)Registers.ControlB, new DoubleWordRegister(this) 60 .WithTag("Character Size (CHSIZE)", 0, 3) 61 .WithReservedBits(3, 3) 62 .WithFlag(6, out stopBitMode, name: "Stop bit mode (SBMODE)") 63 .WithReservedBits(7, 6) 64 .WithFlag(13, out parityMode, name: "Parity mode (PMODE)") 65 .WithReservedBits(14, 2) 66 .WithFlag(16, out transmitterEnabled, name: "Transmitter enable (TXEN)") 67 .WithFlag(17, out receiverEnabled, name: "Receiver enable (RXEN)") 68 .WithReservedBits(18, 14) 69 }, 70 71 {(long)Registers.DebugControl, new DoubleWordRegister(this) 72 .WithTag("Debug stop mode (DGBSTOP)", 0, 1) 73 .WithReservedBits(1, 7) 74 .WithIgnoredBits(8, 24) 75 }, 76 77 {(long)Registers.Baudrate, new DoubleWordRegister(this) 78 .WithValueField(0, 16, out baudrate, name: "Baudrate (BAUD)") 79 .WithIgnoredBits(16, 16) 80 }, 81 82 {(long)Registers.InterruptEnableClear, new DoubleWordRegister(this) 83 .WithFlag(0, out dataRegisterEmptyInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Data register empty interrupt disabled (DRE)") 84 .WithFlag(1, out transmitCompleteInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Transmit complete interrupt disabled (TXC)") 85 .WithFlag(2, out receiveCompleteInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Receive complete interrupt disabled (RXC)") 86 .WithFlag(3, out receiveStartedInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Receive start interrupt disabled (RXS)") 87 .WithReservedBits(4, 4) 88 .WithIgnoredBits(8, 24) 89 .WithWriteCallback((_, __) => UpdateInterrupts()) 90 }, 91 92 {(long)Registers.InterruptEnableSet, new DoubleWordRegister(this) 93 .WithFlag(0, 94 writeCallback: (_, val) => dataRegisterEmptyInterruptEnabled.Value |= val, 95 valueProviderCallback: _ => dataRegisterEmptyInterruptEnabled.Value, 96 name: "Data register empty interrupt enabled (DRE)") 97 .WithFlag(1, 98 writeCallback: (_, val) => transmitCompleteInterruptEnabled.Value |= val, 99 valueProviderCallback: _ => transmitCompleteInterruptEnabled.Value, 100 name: "Transmit complete interrupt enabled (TXC)") 101 .WithFlag(2, 102 writeCallback: (_, val) => receiveCompleteInterruptEnabled.Value |= val, 103 valueProviderCallback: _ => receiveCompleteInterruptEnabled.Value, 104 name: "Receive complete interrupt enabled (RXC)") 105 .WithFlag(3, 106 writeCallback: (_, val) => receiveStartedInterruptEnabled.Value |= val, 107 valueProviderCallback: _ => receiveStartedInterruptEnabled.Value, 108 name: "Receive start interrupt enabled (RXS)") 109 .WithReservedBits(4, 4) 110 .WithIgnoredBits(8, 24) 111 .WithWriteCallback((_, __) => UpdateInterrupts()) 112 }, 113 114 {(long)Registers.InterruptFlagStatusAndClear, new DoubleWordRegister(this) 115 .WithFlag(0, FieldMode.Read, 116 valueProviderCallback: _ => receiveQueue.Count == 0, name: "Data register empty (DRE)") 117 .WithFlag(1, out transmitComplete, FieldMode.WriteOneToClear | FieldMode.Read, name: "Transmit complete (TXC)") 118 .WithFlag(2, FieldMode.Read, 119 valueProviderCallback: _ => receiveQueue.Count > 0, name: "Receive complete (RXC)") 120 .WithTag("Receive start (RXS)", 3, 1) 121 .WithReservedBits(4, 4) 122 .WithIgnoredBits(8, 24) 123 }, 124 125 {(long)Registers.Status, new DoubleWordRegister(this) 126 .WithTag("Parity error (PERR)", 0, 1) 127 .WithTag("Frame error (FERR)", 1, 1) 128 .WithTag("Buffer overflow (BUFOVF)", 2, 1) 129 .WithReservedBits(3, 12) 130 .WithTag("Synchronization busy (SYNCBUSY))", 15, 1) 131 .WithIgnoredBits(16, 16) 132 }, 133 134 {(long)Registers.Data, new DoubleWordRegister(this) 135 .WithValueField(0, 9, 136 writeCallback: (_, val) => HandleTransmitData((uint)val), 137 valueProviderCallback: _ => HandleReceiveData(), 138 name: "DATA") 139 .WithReservedBits(9, 7) 140 .WithIgnoredBits(16, 16) 141 } 142 }; 143 144 registers = new DoubleWordRegisterCollection(this, registersMap); 145 Reset(); 146 } 147 Reset()148 public void Reset() 149 { 150 registers.Reset(); 151 receiveQueue.Clear(); 152 UpdateInterrupts(); 153 } 154 ReadDoubleWord(long offset)155 public uint ReadDoubleWord(long offset) 156 { 157 return registers.Read(offset); 158 } 159 WriteDoubleWord(long offset, uint value)160 public void WriteDoubleWord(long offset, uint value) 161 { 162 registers.Write(offset, value); 163 } 164 ReadWord(long offset)165 public ushort ReadWord(long offset) 166 { 167 return (ushort)ReadDoubleWord(offset); 168 } 169 WriteWord(long offset, ushort value)170 public void WriteWord(long offset, ushort value) 171 { 172 WriteDoubleWord(offset, value); 173 } 174 ReadByte(long offset)175 public byte ReadByte(long offset) 176 { 177 return (byte) ReadDoubleWord(offset); 178 } 179 WriteByte(long offset, byte value)180 public void WriteByte(long offset, byte value) 181 { 182 WriteDoubleWord(offset, value); 183 } 184 WriteChar(byte value)185 public void WriteChar(byte value) 186 { 187 if(!enabled.Value || !receiverEnabled.Value) 188 { 189 this.Log(LogLevel.Warning, "Char was received, but the receiver (or the whole USART) is not enabled. Ignoring."); 190 return; 191 } 192 receiveQueue.Enqueue(value); 193 UpdateInterrupts(); 194 } 195 196 public uint BaudRate => (uint)baudrate.Value; 197 198 public Bits StopBits => stopBitMode.Value ? Bits.Two : Bits.One; 199 200 public Parity ParityBit 201 { 202 get 203 { 204 if(frameFormat.Value == FrameFormat.WithParity) 205 { 206 return parityMode.Value ? Parity.Odd : Parity.Even; 207 } 208 return Parity.None; 209 } 210 } 211 212 public GPIO IRQ { get; } 213 214 [field: Transient] 215 public event Action<byte> CharReceived; 216 217 public long Size => 0x100; 218 HandleTransmitData(uint value)219 private void HandleTransmitData(uint value) 220 { 221 if(!enabled.Value || !transmitterEnabled.Value) 222 { 223 this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring."); 224 return; 225 } 226 CharReceived?.Invoke((byte)value); 227 transmitComplete.Value = true; 228 UpdateInterrupts(); 229 } 230 HandleReceiveData()231 private uint HandleReceiveData() 232 { 233 if(receiveQueue.TryDequeue(out var result)) 234 { 235 UpdateInterrupts(); 236 } 237 return result; 238 } 239 UpdateInterrupts()240 private void UpdateInterrupts() 241 { 242 var value = (transmitComplete.Value && transmitCompleteInterruptEnabled.Value) 243 || (receiveQueue.Count == 0 && dataRegisterEmptyInterruptEnabled.Value) 244 || (receiveQueue.Count > 0 && receiveCompleteInterruptEnabled.Value); 245 IRQ.Set(value); 246 } 247 248 private readonly IFlagRegisterField dataRegisterEmptyInterruptEnabled; 249 private readonly IFlagRegisterField transmitCompleteInterruptEnabled; 250 private readonly IFlagRegisterField receiveCompleteInterruptEnabled; 251 private readonly IFlagRegisterField receiveStartedInterruptEnabled; 252 private readonly IFlagRegisterField enabled; 253 private readonly IFlagRegisterField transmitterEnabled; 254 private readonly IFlagRegisterField receiverEnabled; 255 private readonly IFlagRegisterField transmitComplete; 256 private readonly IFlagRegisterField parityMode; 257 private readonly IEnumRegisterField<FrameFormat> frameFormat; 258 private readonly IFlagRegisterField stopBitMode; 259 260 private readonly IValueRegisterField baudrate; 261 262 private readonly DoubleWordRegisterCollection registers; 263 private readonly Queue<byte> receiveQueue = new Queue<byte>(); 264 265 private enum FrameFormat : int 266 { 267 NoParity = 0x0, 268 WithParity = 0x1 269 // 0x2-0xF Reserved 270 } 271 272 private enum Registers : long 273 { 274 ControlA = 0x00, 275 ControlB = 0x04, 276 DebugControl = 0x08, 277 // 0x9 - reserved 278 Baudrate = 0x0A, 279 InterruptEnableClear = 0x0C, 280 InterruptEnableSet = 0x0D, 281 InterruptFlagStatusAndClear = 0x0E, 282 // 0xF - reserved 283 Status = 0x10, 284 // 0x11:0x17 - reserved 285 Data = 0x18 286 } 287 } 288 } 289