1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.UART 17 { 18 public class MSP430_USCIA : IUART, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize 19 { MSP430_USCIA()20 public MSP430_USCIA() 21 { 22 RegistersCollection = new ByteRegisterCollection(this); 23 InterruptEnableRegister = new ByteRegister(this); 24 InterruptStatusRegister = new ByteRegister(this, resetValue: 0x02); 25 26 DefineRegisters(); 27 Reset(); 28 } 29 Reset()30 public void Reset() 31 { 32 RegistersCollection.Reset(); 33 InterruptEnableRegister.Reset(); 34 InterruptStatusRegister.Reset(); 35 36 interruptTransmitPending.Value = true; 37 UpdateInterrupts(); 38 39 queue.Clear(); 40 } 41 WriteChar(byte character)42 public void WriteChar(byte character) 43 { 44 queue.Enqueue(character); 45 interruptReceivePending.Value = true; 46 UpdateInterrupts(); 47 } 48 49 [ConnectionRegionAttribute("interruptEnable")] WriteByteToInterruptEnable(long offset, byte value)50 public void WriteByteToInterruptEnable(long offset, byte value) 51 { 52 InterruptEnableRegister.Write(offset, value); 53 } 54 55 [ConnectionRegionAttribute("interruptEnable")] ReadByteFromInterruptEnable(long offset)56 public byte ReadByteFromInterruptEnable(long offset) 57 { 58 return InterruptEnableRegister.Read(); 59 } 60 61 [ConnectionRegionAttribute("interruptStatus")] WriteByteToInterruptStatus(long offset, byte value)62 public void WriteByteToInterruptStatus(long offset, byte value) 63 { 64 InterruptStatusRegister.Write(offset, value); 65 UpdateInterrupts(); 66 } 67 68 [ConnectionRegionAttribute("interruptStatus")] ReadByteFromInterruptStatus(long offset)69 public byte ReadByteFromInterruptStatus(long offset) 70 { 71 return InterruptStatusRegister.Read(); 72 } 73 WriteByte(long offset, byte value)74 public void WriteByte(long offset, byte value) 75 { 76 RegistersCollection.Write(offset, value); 77 } 78 ReadByte(long offset)79 public byte ReadByte(long offset) 80 { 81 return RegistersCollection.Read(offset); 82 } 83 84 public ByteRegisterCollection RegistersCollection { get; } 85 public ByteRegister InterruptEnableRegister { get; } 86 public ByteRegister InterruptStatusRegister { get; } 87 88 public long Size => 0xB; 89 90 public GPIO RxInterrupt { get; } = new GPIO(); 91 public GPIO TxInterrupt { get; } = new GPIO(); 92 93 public Bits StopBits { get; } 94 public Parity ParityBit { get; } 95 public uint BaudRate { get; } 96 97 public event Action<byte> CharReceived; 98 UpdateInterrupts()99 private void UpdateInterrupts() 100 { 101 var rxInterrupt = interruptReceivePending.Value && interruptReceiveEnabled.Value; 102 var txInterrupt = interruptTransmitPending.Value && interruptTransmitEnabled.Value; 103 104 this.Log(LogLevel.Debug, "RxInterrupt={0} TxInterrupt={1}", rxInterrupt, txInterrupt); 105 106 RxInterrupt.Set(rxInterrupt); 107 TxInterrupt.Set(txInterrupt); 108 } 109 DefineRegisters()110 private void DefineRegisters() 111 { 112 Registers.Control0.Define(this) 113 .WithFlag(0, out syncMode, name: "UCSYNC") 114 .WithValueField(1, 2, out usciMode, name: "UCMODEx") 115 .WithTaggedFlag("UCSPB", 3) 116 .WithTaggedFlag("UC7BIT", 4) 117 .WithTaggedFlag("UCMSB", 5) 118 .WithTaggedFlag("UCPAR", 6) 119 .WithTaggedFlag("UCPEN", 7) 120 ; 121 122 Registers.Control1.Define(this) 123 .WithTaggedFlag("UCSWRST", 0) 124 .WithTaggedFlag("UCTXBRK", 1) 125 .WithTaggedFlag("UCTXADDR", 2) 126 .WithTaggedFlag("UCDORM", 3) 127 .WithTaggedFlag("UCBRKIE", 4) 128 .WithTaggedFlag("UCRXEIE", 5) 129 .WithTag("UCSSEL", 6, 2) 130 ; 131 132 Registers.Status.Define(this) 133 .WithTaggedFlag("UCBUSY", 0) 134 .WithFlag(1, FieldMode.Read, name: "UCADDR", 135 valueProviderCallback: _ => false) 136 .WithTaggedFlag("UCRXERR", 2) 137 .WithTaggedFlag("UCBRK", 3) 138 .WithTaggedFlag("UCPE", 4) 139 .WithTaggedFlag("UCOE", 5) 140 .WithTaggedFlag("UCFE", 6) 141 .WithFlag(7, out loopbackEnabled, name: "UCLISTEN") 142 ; 143 144 Registers.ReceiveBuffer.Define(this) 145 .WithValueField(0, 8, name: "UCRXBUFx", 146 valueProviderCallback: _ => 147 { 148 var returnValue = queue.TryDequeue(out var character) ? (byte)character : (byte)0; 149 150 if(queue.Count > 0) 151 { 152 interruptReceivePending.Value = true; 153 UpdateInterrupts(); 154 } 155 156 return returnValue; 157 }) 158 ; 159 160 Registers.TransmitBuffer.Define(this) 161 .WithValueField(0, 8, name: "UCTXBUFx", 162 valueProviderCallback: _ => 0, 163 writeCallback: (_, value) => 164 { 165 CharReceived?.Invoke((byte)value); 166 167 interruptTransmitPending.Value = true; 168 UpdateInterrupts(); 169 170 if(loopbackEnabled.Value) 171 { 172 WriteChar((byte)value); 173 } 174 }) 175 ; 176 177 InterruptEnableRegister 178 .WithFlag(0, out interruptReceiveEnabled, name: "UCAxRXIE") 179 .WithFlag(1, out interruptTransmitEnabled, name: "UCAxTXIE") 180 .WithValueField(2, 6, name: "RESERVED") 181 .WithWriteCallback((_, __) => UpdateInterrupts()) 182 ; 183 184 InterruptStatusRegister 185 .WithFlag(0, out interruptReceivePending, name: "UCAxRXIFG") 186 .WithFlag(1, out interruptTransmitPending, name: "UCAxTXIFG") 187 .WithValueField(2, 6, name: "RESERVED") 188 .WithWriteCallback((_, __) => UpdateInterrupts()) 189 ; 190 } 191 192 private Mode CurrentMode => 193 !syncMode.Value ? Mode.UART : usciMode.Value == 0x3 ? Mode.I2C : Mode.SPI; 194 195 private IFlagRegisterField syncMode; 196 private IValueRegisterField usciMode; 197 198 private IFlagRegisterField interruptTransmitEnabled; 199 private IFlagRegisterField interruptReceiveEnabled; 200 201 private IFlagRegisterField interruptTransmitPending; 202 private IFlagRegisterField interruptReceivePending; 203 204 private IFlagRegisterField loopbackEnabled; 205 206 private readonly Queue<byte> queue = new Queue<byte>(); 207 208 public enum Mode 209 { 210 UART, 211 SPI, 212 I2C, 213 } 214 215 public enum Registers 216 { 217 AutoBaud, 218 IrDATransmit, 219 IrDAReceive, 220 Control0, 221 Control1, 222 BaudRate0, 223 BaudRate1, 224 Modulation, 225 Status, 226 ReceiveBuffer, 227 TransmitBuffer, 228 } 229 } 230 } 231