1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 14 namespace Antmicro.Renode.Peripherals.UART 15 { 16 // This model currently does not support timeout feature, rx break detection and software tx pin override 17 public class OpenTitan_UART : UARTBase, IUARTWithBufferState, IDoubleWordPeripheral, IKnownSize 18 { OpenTitan_UART(IMachine machine)19 public OpenTitan_UART(IMachine machine) : base(machine) 20 { 21 TxWatermarkIRQ = new GPIO(); 22 RxWatermarkIRQ = new GPIO(); 23 TxEmptyIRQ = new GPIO(); 24 RxOverflowIRQ = new GPIO(); 25 RxFrameErrorIRQ = new GPIO(); 26 RxBreakErrorIRQ = new GPIO(); 27 RxTimeoutIRQ = new GPIO(); 28 RxParityErrorIRQ = new GPIO(); 29 30 FatalAlert = new GPIO(); 31 32 registers = new DoubleWordRegisterCollection(this, BuildRegisterMap()); 33 txQueue = new Queue<byte>(); 34 } 35 ReadDoubleWord(long offset)36 public uint ReadDoubleWord(long offset) 37 { 38 return registers.Read(offset); 39 } 40 WriteDoubleWord(long offset, uint value)41 public void WriteDoubleWord(long offset, uint value) 42 { 43 registers.Write(offset, value); 44 } 45 WriteChar(byte value)46 public override void WriteChar(byte value) 47 { 48 if(lineLoopbackEnabled.Value) 49 { 50 txOngoing = true; 51 TransmitCharacter(value); 52 this.Log(LogLevel.Noisy, "Line Loopback Enabled, byte echoed by hardware."); 53 } 54 55 if(systemLoopbackEnabled.Value) 56 { 57 this.Log(LogLevel.Warning, "Sytem Loopback Enabled, incoming byte not queued."); 58 return; 59 } 60 61 if(!rxEnabled.Value) 62 { 63 this.Log(LogLevel.Warning, "CTRL.RX is unset, incoming byte not queued."); 64 return; 65 } 66 67 if(Count < rxFIFOCapacity) 68 { 69 base.WriteChar(value); 70 } 71 else 72 { 73 rxOverflowPending.Value = true; 74 this.Log(LogLevel.Warning, "RX FIFO overflowed, incoming byte not queued."); 75 } 76 UpdateBufferState(); 77 UpdateInterrupts(); 78 } 79 Reset()80 public override void Reset() 81 { 82 base.Reset(); 83 registers.Reset(); 84 txQueue.Clear(); 85 UpdateInterrupts(); 86 FatalAlert.Unset(); 87 88 txOngoing = false; 89 txWatermarkCrossed = false; 90 } 91 92 public long Size => 0x30; 93 public BufferState BufferState => bufferState; 94 95 public GPIO TxWatermarkIRQ { get; } 96 public GPIO RxWatermarkIRQ { get; } 97 public GPIO TxEmptyIRQ { get; } 98 public GPIO RxOverflowIRQ { get; } 99 public GPIO RxFrameErrorIRQ { get; } 100 public GPIO RxBreakErrorIRQ { get; } 101 public GPIO RxTimeoutIRQ { get; } 102 public GPIO RxParityErrorIRQ { get; } 103 public GPIO FatalAlert { get; } 104 105 public event Action<BufferState> BufferStateChanged; 106 107 public override Bits StopBits => Bits.One; 108 109 public override Parity ParityBit => parityTypeField.Value == ParityType.Odd ? Parity.Odd : Parity.Even; 110 111 public override uint BaudRate => (uint)((baudClockRate.Value * fixedClockFrequency) >> 20); 112 CharWritten()113 protected override void CharWritten() 114 { 115 // intentionally left empty 116 } 117 QueueEmptied()118 protected override void QueueEmptied() 119 { 120 // intentionally left empty 121 } 122 BuildRegisterMap()123 private Dictionary<long, DoubleWordRegister> BuildRegisterMap() 124 { 125 return new Dictionary<long, DoubleWordRegister> 126 { 127 {(long)Registers.InterruptState, new DoubleWordRegister(this) 128 .WithFlag(0, out txWatermarkPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.tx_watermark") 129 .WithFlag(1, out rxWatermarkPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_watermark") 130 .WithFlag(2, out txEmptyPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.tx_empty") 131 .WithFlag(3, out rxOverflowPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_overflow") 132 .WithFlag(4, out rxFrameErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_frame_err") 133 .WithFlag(5, out rxBreakErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_break_err") 134 .WithFlag(6, out rxTimeoutPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_timeout") 135 .WithFlag(7, out rxParityErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_parity_err") 136 .WithReservedBits(8, 24) 137 .WithWriteCallback((_, __) => UpdateInterrupts()) 138 }, 139 {(long)Registers.InterruptEnable, new DoubleWordRegister(this) 140 .WithFlag(0, out txWatermarkEnabled, name: "INTR_ENABLE.tx_watermark") 141 .WithFlag(1, out rxWatermarkEnabled, name: "INTR_ENABLE.rx_watermark") 142 .WithFlag(2, out txEmptyEnabled, name: "INTR_ENABLE.tx_empty") 143 .WithFlag(3, out rxOverflowEnabled, name: "INTR_ENABLE.rx_overflow") 144 .WithFlag(4, out rxFrameErrorEnabled, name: "INTR_ENABLE.rx_frame_err") 145 .WithFlag(5, out rxBreakErrorEnabled, name: "INTR_ENABLE.rx_break_err") 146 .WithFlag(6, out rxTimeoutEnabled, name: "INTR_ENABLE.rx_timeout") 147 .WithFlag(7, out rxParityErrorEnabled, name: "INTR_ENABLE.rx_parity_err") 148 .WithReservedBits(8, 24) 149 .WithWriteCallback((_, __) => UpdateInterrupts()) 150 }, 151 {(long)Registers.InterruptTest, new DoubleWordRegister(this) 152 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { txWatermarkPending.Value |= val; }, name: "INTR_TEST.tx_watermark") 153 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { rxWatermarkPending.Value |= val; }, name: "INTR_TEST.rx_watermark") 154 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { txEmptyPending.Value |= val; }, name: "INTR_TEST.tx_empty") 155 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { rxOverflowPending.Value |= val; }, name: "INTR_TEST.rx_overflow") 156 .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { rxFrameErrorPending.Value |= val; }, name: "INTR_TEST.rx_frame_err") 157 .WithFlag(5, FieldMode.Write, writeCallback: (_, val) => { rxBreakErrorPending.Value |= val; }, name: "INTR_TEST.rx_break_err") 158 .WithFlag(6, FieldMode.Write, writeCallback: (_, val) => { rxTimeoutPending.Value |= val; }, name: "INTR_TEST.rx_timeout") 159 .WithFlag(7, FieldMode.Write, writeCallback: (_, val) => { rxParityErrorPending.Value |= val; }, name: "INTR_TEST.rx_parity_err") 160 .WithReservedBits(8, 24) 161 .WithWriteCallback((_, __) => UpdateInterrupts()) 162 }, 163 {(long)Registers.AlertTest, new DoubleWordRegister(this) 164 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") 165 .WithIgnoredBits(1, 31) 166 }, 167 {(long)Registers.Control, new DoubleWordRegister(this) 168 .WithFlag(0, out txEnabled, name: "CTRL.TX", writeCallback: (_, val) => 169 { 170 if(val) 171 { 172 if(!lineLoopbackEnabled.Value) 173 { 174 foreach(byte value in txQueue) 175 { 176 txOngoing = true; 177 TransmitCharacter(value); 178 } 179 } 180 txQueue.Clear(); 181 UpdateInterrupts(); 182 } 183 }) 184 .WithFlag(1, out rxEnabled, name: "CTRL.RX") 185 .WithFlag(2, out noiseFilterEnabled, name: "CTRL.NF") 186 .WithReservedBits(3, 1) 187 .WithFlag(4, out systemLoopbackEnabled, name: "CTRL.SLPBK") 188 .WithFlag(5, out lineLoopbackEnabled, name: "CTRL.LLPBK") 189 .WithFlag(6, out parityEnabled, name: "CTRL.PARITY_EN") 190 .WithEnumField(7, 1, out parityTypeField, name: "CTRL.PARITY_ODD") 191 .WithTag("CTRL.RXBLVL", 8, 2) 192 .WithReservedBits(10, 6) 193 .WithValueField(16, 16, out baudClockRate, name: "CTRL.NCO") 194 }, 195 {(long)Registers.LiveStatus, new DoubleWordRegister(this) 196 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == txFIFOCapacity, name: "STATUS.TXFULL") 197 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => Count == rxFIFOCapacity, name: "STATUS.RXFULL") 198 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "STATUS.TXEMPTY") 199 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "STATUS.TXIDLE") 200 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => true, name: "STATUS.RXIDLE") 201 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => Count == 0, name: "STATUS.RXEMPTY") 202 .WithReservedBits(6, 26) 203 }, 204 {(long)Registers.ReadData, new DoubleWordRegister(this) 205 .WithValueField(0, 8, FieldMode.Read, name: "RDATA", valueProviderCallback: _ => 206 { 207 if(!TryGetCharacter(out var character)) 208 { 209 this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO."); 210 } 211 UpdateBufferState(); 212 return character; 213 }) 214 .WithReservedBits(8, 24) 215 .WithWriteCallback((_, __) => UpdateInterrupts()) 216 }, 217 {(long)Registers.WriteData, new DoubleWordRegister(this) 218 .WithValueField(0, 8, FieldMode.Write, name: "WDATA", writeCallback: (_, val) => 219 { 220 if(systemLoopbackEnabled.Value) 221 { 222 base.WriteChar((byte)val); 223 UpdateBufferState(); 224 return; 225 } 226 227 if(txEnabled.Value) 228 { 229 txOngoing = true; 230 TransmitCharacter((byte)val); 231 } 232 else if(txQueue.Count < txFIFOCapacity) 233 { 234 txQueue.Enqueue((byte)val); 235 if(txQueue.Count >= TxWatermarkValue) { 236 txWatermarkCrossed = true; 237 } 238 } 239 else 240 { 241 this.Log(LogLevel.Warning, "Trying to write to a full Tx FIFO."); 242 } 243 }) 244 .WithReservedBits(8, 24) 245 .WithWriteCallback((_, __) => UpdateInterrupts()) 246 }, 247 {(long)Registers.FIFOControl, new DoubleWordRegister(this) 248 .WithFlag(0, FieldMode.Write, name: "FIFO_CTRL.RXRST", writeCallback: (_, val) => 249 { 250 if(val) 251 { 252 ClearBuffer(); 253 } 254 }) 255 .WithFlag(1, FieldMode.Write, name: "FIFO_CTRL.TXRST", writeCallback: (_, val) => 256 { 257 if(val) 258 { 259 txQueue.Clear(); 260 txWatermarkCrossed = false; 261 } 262 }) 263 .WithEnumField(2, 3, out rxWatermarkField, name: "FIFO_CTRL.RXILVL") 264 .WithEnumField(5, 2, out txWatermarkField, name: "FIFO_CTRL.TXILVL") 265 .WithReservedBits(7, 25) 266 .WithWriteCallback((_, __) => UpdateInterrupts()) 267 }, 268 {(long)Registers.FIFOStatus, new DoubleWordRegister(this) 269 .WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => (uint)txQueue.Count, name: "FIFO_STATUS.TXLVL") 270 .WithReservedBits(6, 10) 271 .WithValueField(16, 6, FieldMode.Read, valueProviderCallback: _ => (uint)Count, name: "FIFO_STATUS.RXLVL") 272 .WithReservedBits(22, 10) 273 }, 274 {(long)Registers.TxPinOverrideControl, new DoubleWordRegister(this) 275 .WithTaggedFlag("OVRD.TXEN", 0) 276 .WithTaggedFlag("OVRD.TXVAL", 1) 277 .WithReservedBits(2, 30) 278 }, 279 {(long)Registers.OversampledValues, new DoubleWordRegister(this) 280 .WithTag("VAL.RX", 0, 16) 281 .WithReservedBits(16, 16) 282 }, 283 {(long)Registers.RxTimeoutControl, new DoubleWordRegister(this) 284 .WithTag("TIMEOUT_CTRL.VAL", 0, 24) 285 .WithReservedBits(24, 7) 286 .WithTaggedFlag("TIMEOUT_CTRL.EN", 31) 287 } 288 }; 289 } 290 UpdateInterrupts()291 private void UpdateInterrupts() 292 { 293 rxWatermarkPending.Value |= RxWatermarkValue <= Count; 294 295 if (txWatermarkCrossed && txQueue.Count < TxWatermarkValue) { 296 txWatermarkPending.Value = true; 297 txWatermarkCrossed = false; 298 } 299 300 if(txOngoing && txQueue.Count == 0) 301 { 302 txOngoing = false; 303 txEmptyPending.Value = true; 304 } 305 306 TxWatermarkIRQ.Set(txWatermarkPending.Value && txWatermarkEnabled.Value); 307 RxWatermarkIRQ.Set(rxWatermarkPending.Value && rxWatermarkEnabled.Value); 308 TxEmptyIRQ.Set(txEmptyPending.Value && txEmptyEnabled.Value); 309 RxOverflowIRQ.Set(rxOverflowPending.Value && rxOverflowEnabled.Value); 310 RxFrameErrorIRQ.Set(rxFrameErrorPending.Value && rxFrameErrorEnabled.Value); 311 RxBreakErrorIRQ.Set(rxBreakErrorPending.Value && rxBreakErrorEnabled.Value); 312 RxTimeoutIRQ.Set(rxTimeoutPending.Value && rxTimeoutEnabled.Value); 313 RxParityErrorIRQ.Set(rxParityErrorPending.Value && rxParityErrorEnabled.Value); 314 } 315 UpdateBufferState()316 private void UpdateBufferState() 317 { 318 if((Count < rxFIFOCapacity && bufferState == BufferState.Full) || 319 (Count != 0 && bufferState == BufferState.Empty) || 320 ((Count == 0 || Count >= rxFIFOCapacity) && bufferState == BufferState.Ready)) 321 { 322 if(Count == 0) 323 { 324 bufferState = BufferState.Empty; 325 } 326 else if(Count >= rxFIFOCapacity) 327 { 328 bufferState = BufferState.Full; 329 } 330 else 331 { 332 bufferState = BufferState.Ready; 333 } 334 335 BufferStateChanged?.Invoke(bufferState); 336 } 337 } 338 339 private int RxWatermarkValue 340 { 341 get 342 { 343 switch(rxWatermarkField.Value) 344 { 345 default: 346 this.Log(LogLevel.Error, "Unexpected state of rxWatermarkField ({0})", rxWatermarkField.Value); 347 return 1; 348 case RxWatermarkLevel.Level1: 349 return 1; 350 case RxWatermarkLevel.Level4: 351 return 4; 352 case RxWatermarkLevel.Level8: 353 return 8; 354 case RxWatermarkLevel.Level16: 355 return 16; 356 case RxWatermarkLevel.Level30: 357 return 30; 358 } 359 } 360 } 361 362 private int TxWatermarkValue 363 { 364 get 365 { 366 switch(txWatermarkField.Value) 367 { 368 default: 369 this.Log(LogLevel.Error, "Unexpected state of txWatermarkField ({0})", txWatermarkField.Value); 370 return 2; 371 case TxWatermarkLevel.Level1: 372 return 2; 373 case TxWatermarkLevel.Level4: 374 return 4; 375 case TxWatermarkLevel.Level8: 376 return 8; 377 case TxWatermarkLevel.Level16: 378 return 16; 379 } 380 } 381 } 382 383 private readonly DoubleWordRegisterCollection registers; 384 private readonly Queue<byte> txQueue; 385 // InterruptState 386 private IFlagRegisterField txWatermarkPending; 387 private IFlagRegisterField rxWatermarkPending; 388 private IFlagRegisterField txEmptyPending; 389 private IFlagRegisterField rxOverflowPending; 390 private IFlagRegisterField rxFrameErrorPending; 391 private IFlagRegisterField rxBreakErrorPending; 392 private IFlagRegisterField rxTimeoutPending; 393 private IFlagRegisterField rxParityErrorPending; 394 // InterruptEnable 395 private IFlagRegisterField txWatermarkEnabled; 396 private IFlagRegisterField rxWatermarkEnabled; 397 private IFlagRegisterField txEmptyEnabled; 398 private IFlagRegisterField rxOverflowEnabled; 399 private IFlagRegisterField rxFrameErrorEnabled; 400 private IFlagRegisterField rxBreakErrorEnabled; 401 private IFlagRegisterField rxTimeoutEnabled; 402 private IFlagRegisterField rxParityErrorEnabled; 403 // Control 404 private IFlagRegisterField txEnabled; 405 private IFlagRegisterField rxEnabled; 406 private IFlagRegisterField noiseFilterEnabled; 407 private IFlagRegisterField systemLoopbackEnabled; 408 private IFlagRegisterField lineLoopbackEnabled; 409 private IFlagRegisterField parityEnabled; 410 private IEnumRegisterField<ParityType> parityTypeField; 411 private IValueRegisterField baudClockRate; 412 // FIFOControl 413 private IEnumRegisterField<RxWatermarkLevel> rxWatermarkField; 414 private IEnumRegisterField<TxWatermarkLevel> txWatermarkField; 415 416 private bool txOngoing; 417 private bool txWatermarkCrossed; 418 private BufferState bufferState; 419 420 private const int rxFIFOCapacity = 32; 421 private const int txFIFOCapacity = 32; 422 private const ulong fixedClockFrequency = 50000000; 423 424 private enum ParityType 425 { 426 Even = 0, 427 Odd = 1 428 } 429 430 private enum RxWatermarkLevel 431 { 432 Level1 = 0, 433 Level4 = 1, 434 Level8 = 2, 435 Level16 = 3, 436 Level30 = 4 437 } 438 439 private enum TxWatermarkLevel 440 { 441 Level1 = 0, 442 Level4 = 1, 443 Level8 = 2, 444 Level16 = 3 445 } 446 447 private enum Registers : long 448 { 449 InterruptState = 0x0, 450 InterruptEnable = 0x4, 451 InterruptTest = 0x8, 452 AlertTest = 0xC, 453 Control = 0x10, 454 LiveStatus = 0x14, 455 ReadData = 0x18, 456 WriteData = 0x1C, 457 FIFOControl = 0x20, 458 FIFOStatus = 0x24, 459 TxPinOverrideControl = 0x28, 460 OversampledValues = 0x2C, 461 RxTimeoutControl = 0x30, 462 } 463 } 464 } 465