1 // 2 // Copyright (c) 2010-2022 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 Antmicro.Renode.Core; 9 using Antmicro.Renode.Logging; 10 using Antmicro.Renode.Peripherals.Bus; 11 using System.Collections.Generic; 12 using Antmicro.Renode.Core.Structure; 13 using System; 14 using Antmicro.Renode.Exceptions; 15 16 namespace Antmicro.Renode.Peripherals.UART 17 { 18 public class EFM32_UART : UARTBase, IDoubleWordPeripheral 19 { EFM32_UART(IMachine machine)20 public EFM32_UART(IMachine machine) : base(machine) 21 { 22 TransmitIRQ = new GPIO(); 23 ReceiveIRQ = new GPIO(); 24 } 25 26 public GPIO TransmitIRQ{get; private set;} 27 public GPIO ReceiveIRQ{get; private set;} 28 29 private uint frameFormatRegister; 30 private uint clockControlRegister; 31 private bool txInterruptEnabled = false; WriteDoubleWord(long address, uint value)32 public void WriteDoubleWord(long address, uint value) 33 { 34 switch((Registers)address) 35 { 36 case Registers.FrameFormat: 37 frameFormatRegister = value; 38 break; 39 case Registers.Command: 40 break; 41 case Registers.TxBufferData: 42 TransmitCharacter((byte)value); 43 // HACK: 44 if(txInterruptEnabled) 45 TransmitIRQ.Blink(); 46 break; 47 case Registers.InterruptEnable: 48 txInterruptEnabled = (value & 0x3) > 0; 49 break; 50 case Registers.ClockControl: 51 clockControlRegister = value & 0x1FFFE0; 52 break; 53 default: 54 this.LogUnhandledWrite(address, value); 55 break; 56 } 57 } 58 ReadDoubleWord(long offset)59 public uint ReadDoubleWord(long offset) 60 { 61 this.NoisyLog("Read {0}", (Registers)offset); 62 switch((Registers)offset) 63 { 64 case Registers.Status: 65 uint res = 0x40; 66 if(Count > 0) 67 { 68 res |= 0x80; 69 } 70 this.NoisyLog("Returned {0:X}.", res); 71 return res; 72 case Registers.RxBufferData: 73 case Registers.RxBufferDataExtended: 74 this.NoisyLog("Read data"); 75 byte character; 76 if(!TryGetCharacter(out character)) 77 { 78 this.NoisyLog("Failed"); 79 return 0; 80 } 81 this.NoisyLog("Succeeded"); 82 return character; 83 case Registers.TxBufferData: 84 return 0; 85 case Registers.InterruptFlag: 86 return 4; 87 default: 88 this.LogUnhandledRead(offset); 89 return 0x00; 90 } 91 } 92 CharWritten()93 protected override void CharWritten() 94 { 95 this.NoisyLog("Char written. Count is {0}.", Count); 96 ReceiveIRQ.Set(); 97 } 98 QueueEmptied()99 protected override void QueueEmptied() 100 { 101 this.NoisyLog("Queue empty."); 102 ReceiveIRQ.Unset(); 103 } 104 105 [Flags] 106 private enum FrameFormat 107 { 108 StopBitsH = 1 << 13, 109 StopBitsL = 1 << 12, 110 ParityH = 1 << 9, 111 ParityL = 1 << 8 112 } 113 114 private enum Registers 115 { 116 FrameFormat = 0x004, // USARTn_FRAME 117 Command = 0x00C, // USARTn_CMD 118 Status = 0x010, // USARTn_STATUS 119 RxBufferDataExtended = 0x018, // USARTn_RXDATAX 120 RxBufferData = 0x01C, // USARTn_RXDATA 121 TxBufferData = 0x034, // USARTn_TXDATA 122 InterruptFlag = 0x040, // USARTn_IF 123 InterruptEnable = 0x04C, // USARTn_IEN 124 ClockControl = 0x014 // USARTn_CLKDIV 125 } 126 127 public override Parity ParityBit 128 { 129 get 130 { 131 var parity = (frameFormatRegister & (uint)(FrameFormat.ParityH | FrameFormat.ParityL)) >> 8; 132 switch (parity) 133 { 134 case 0: 135 return Parity.None; 136 case 2: 137 return Parity.Even; 138 case 3: 139 return Parity.Odd; 140 default: 141 throw new ArgumentException("Wrong parity bits register value"); 142 } 143 } 144 } 145 146 public override Bits StopBits 147 { 148 get 149 { 150 var bits = (frameFormatRegister & (uint)(FrameFormat.StopBitsH | FrameFormat.StopBitsL)) >> 12; 151 switch (bits) 152 { 153 case 0: 154 return Bits.Half; 155 case 1: 156 return Bits.One; 157 case 2: 158 return Bits.OneAndAHalf; 159 default: 160 return Bits.Two; 161 } 162 } 163 } 164 165 public override uint BaudRate 166 { 167 get 168 { 169 // divisor cannot be 0, so there is no need to check it 170 return UARTClockFrequency / (2 * (1 + clockControlRegister/256)); 171 } 172 } 173 174 private const uint UARTClockFrequency = 0; 175 } 176 } 177 178