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 System; 8 using System.Collections.Generic; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Exceptions; 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 NXP_LPUART : UARTBase, IUARTWithBufferState, ILINController, IBytePeripheral, IDoubleWordPeripheral, IKnownSize 19 { NXP_LPUART(IMachine machine, long frequency = 8000000, bool hasGlobalRegisters = true, bool hasFifoRegisters = true, uint fifoSize = DefaultFIFOSize, bool separateIRQs = false)20 public NXP_LPUART(IMachine machine, long frequency = 8000000, bool hasGlobalRegisters = true, bool hasFifoRegisters = true, uint fifoSize = DefaultFIFOSize, bool separateIRQs = false) : base(machine) 21 { 22 this.frequency = frequency; 23 this.hasGlobalRegisters = hasGlobalRegisters; 24 this.separateIRQs = separateIRQs; 25 26 locker = new object(); 27 IRQ = new GPIO(); 28 SeparateRxIRQ = new GPIO(); 29 DMA = new GPIO(); 30 txQueue = new Queue<byte>(); 31 if (!Misc.IsPowerOfTwo(fifoSize)) 32 { 33 throw new ConstructionException($"The `{nameof(fifoSize)}` argument must be a power of 2, given: {fifoSize}."); 34 } 35 rxFIFOCapacity = fifoSize; 36 txFIFOCapacity = fifoSize; 37 38 var registersMap = new Dictionary<long, DoubleWordRegister>(); 39 40 if (hasGlobalRegisters) 41 { 42 registersMap.Add((long)GlobalRegs.Global, new DoubleWordRegister(this) 43 .WithReservedBits(0, 1) 44 .WithFlag(1, out reset, name: "RST / Software Reset", writeCallback: (_, val) => 45 { 46 if (val) 47 { 48 Reset(); 49 } 50 }) 51 .WithReservedBits(2, 30) 52 ); 53 } 54 55 registersMap.Add(CommonRegistersOffset + (long)CommonRegs.BaudRate, new DoubleWordRegister(this) 56 .WithValueField(0, 13, out baudRateModuloDivisor, name: "SBR / Baud Rate Modulo Divisor") 57 .WithFlag(13, out stopBitNumberSelect, name: "SBNS / Stop Bit Number Select") 58 .WithTaggedFlag("RXEDGIE / RX Input Active Edge Interrupt Enable", 14) 59 .WithFlag(15, out linBreakDetectInterruptEnable, name: "LBKDIE / LIN Break Detect Interrupt Enable") 60 .WithTaggedFlag("RESYNCDIS / Resynchronization Disable", 16) 61 .WithFlag(17, out bothEdgeSampling, name: "BOTHEDGE / Both Edge Sampling") 62 .WithTag("MATCFG / Match Configuration", 18, 2) 63 .WithTaggedFlag("RIDMAE / Receiver Idle DMA Enable", 20) 64 .WithFlag(21, out receiverDMAEnabled, name: "RDMAE / Receiver Full DMA Enable") 65 .WithReservedBits(22, 1) 66 .WithFlag(23, out transmitterDMAEnabled, name: "TDMAE / Transmitter DMA Enable") 67 .WithValueField(24, 5, out oversamplingRatio, name: "OSR / Oversampling Ratio", writeCallback: (current, val) => 68 { 69 if (1 == val || 2 == val) 70 { 71 this.Log(LogLevel.Warning, "Tried to set the Oversampling Ratio to reserved value: 0x{0:X}. Old value kept.", val); 72 oversamplingRatio.Value = current; 73 } 74 }) 75 .WithTaggedFlag("M10 / 10-bit Mode select", 29) 76 .WithTaggedFlag("MAEN2 / Match Address Mode Enable 2", 30) 77 .WithTaggedFlag("MAEN1 / Match Address Mode Enable 1", 31) 78 .WithWriteCallback((_, __) => 79 { 80 if ((3 >= oversamplingRatio.Value && 6 <= oversamplingRatio.Value) && !bothEdgeSampling.Value) 81 { 82 this.Log(LogLevel.Warning, "Oversampling Ratio set to value: 0x{0:X}, but this requires Both Edge Sampling to be set.", oversamplingRatio.Value); 83 } 84 UpdateGPIOOutputs(); 85 }) 86 ); 87 88 registersMap.Add(CommonRegistersOffset + (long)CommonRegs.Status, new DoubleWordRegister(this) 89 .WithReservedBits(0, 14) 90 .WithTaggedFlag("MA2F / Match 2 Flag", 14) 91 .WithTaggedFlag("MA1F / Match 1 Flag", 15) 92 .WithTaggedFlag("PF / Parity Error Flag", 16) 93 .WithTaggedFlag("FE / Framing Error Flag", 17) 94 .WithTaggedFlag("NF / Noise Flag", 18) 95 .WithFlag(19, out receiverOverrun, FieldMode.Read | FieldMode.WriteOneToClear, name: "OR / Receiver Overrun Flag") 96 .WithTaggedFlag("IDLE / Idle Line Flag", 20) 97 // Despite the name below flag should be set when Watermark level is exceeded 98 .WithFlag(21, FieldMode.Read, valueProviderCallback: _ => BufferState == BufferState.Ready, name: "RDRF / Receive Data Register Full") 99 .WithFlag(22, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "TC / Transmission Complete Flag") 100 .WithFlag(23, out transmitDataRegisterEmpty, FieldMode.Read, name: "TDRE / Transmission Data Register Empty Flag") 101 .WithTaggedFlag("RAF / Receiver Active Flag", 24) 102 .WithFlag(25, out linBreakDetection, name: "LBKDE / LIN Break Detection Enable") 103 .WithTaggedFlag("BRK13 / Break Character Generation Length", 26) 104 .WithTaggedFlag("RWUID / Receive Wake Up Idle Detect", 27) 105 .WithTaggedFlag("RXINV / Receive Data Inversion", 28) 106 .WithTaggedFlag("MSBF / MSB First", 29) 107 .WithTaggedFlag("RXEDGIF / RXD Pin Active Edge Interrupt Flag", 30) 108 .WithFlag(31, out linBreakDetect, FieldMode.Read | FieldMode.WriteOneToClear, name: "LBKDIF / LIN Break Detect Interrupt Flag") 109 ); 110 111 registersMap.Add(CommonRegistersOffset + (long)CommonRegs.Control, new DoubleWordRegister(this) 112 .WithFlag(0, out parityType, name: "PT / Parity Type") 113 .WithFlag(1, out parityEnabled, name: "PE / Parity Enable") 114 .WithTaggedFlag("ILT / Idle Line Type Select", 2) 115 .WithTaggedFlag("WAKE / Receiver Wakeup Method Select", 3) 116 .WithTaggedFlag("M / 9-Bit or 8-Bit Mode Select", 4) 117 .WithFlag(5, out receiverSource, name: "RSRC / Receiver Source Select") 118 .WithTaggedFlag("DOZEEN / Doze Enable", 6) 119 .WithFlag(7, out loopMode, name: "LOOPS / Loop Mode Select") 120 .WithTag("IDLECFG / Idle Configuration", 8, 3) 121 .WithTaggedFlag("M7 / 7-Bit Mode Select", 11) 122 .WithReservedBits(12, 2) 123 .WithTaggedFlag("MA2IE / Match 2 Interrupt Enable", 14) 124 .WithTaggedFlag("MA1IE / Match 1 Interrupt Enable", 15) 125 .WithTaggedFlag("SBK / Send Break", 16) 126 .WithTaggedFlag("RWU / Receiver Wakeup Control", 17) 127 .WithFlag(18, out receiverEnabled, name: "RE / Receiver Enable") 128 .WithFlag(19, out transmitterEnabled, name: "TE / Transmitter Enable", writeCallback: (_, val) => 129 { 130 if (val) 131 { 132 foreach (var value in txQueue) 133 { 134 TransmitData(value); 135 } 136 txQueue.Clear(); 137 } 138 }) 139 .WithTaggedFlag("ILIE / Idle Line Interrupt Enable", 20) 140 .WithFlag(21, out receiverInterruptEnabled, name: "RIE / Receiver Interrupt Enable") 141 .WithFlag(22, out transmissionCompleteInterruptEnabled, name: "TCIE / Transmission Complete Interrupt Enable") 142 .WithFlag(23, out transmitterInterruptEnabled, name: "TIE / Transmission Interrupt Enable") 143 .WithTaggedFlag("PEIE / Parity Error Interrupt Enable", 24) 144 .WithTaggedFlag("FEIE / Framing Error Interrupt Enable", 25) 145 .WithTaggedFlag("NEIE / Noise Error Interrupt Enable", 26) 146 .WithTaggedFlag("ORIE / Overrun Interrupt Enable", 27) 147 .WithTaggedFlag("TXINV / Transmit Data Inversion", 28) 148 .WithFlag(29, out transmissionPinDirectionOutNotIn, name: "TXDIR / TXD Pin Direction in Single-Wire Mode") 149 .WithTaggedFlag("R9T8 / Receive Bit 9 / Transmit Bit 8", 30) 150 .WithTaggedFlag("R8T9 / Receive Bit 8 / Transmit Bit 9", 31) 151 .WithWriteCallback((_, __) => UpdateGPIOOutputs()) 152 ); 153 154 registersMap.Add(CommonRegistersOffset + (long)CommonRegs.Data, new DoubleWordRegister(this) 155 .WithValueField(0, 9, valueProviderCallback: _ => 156 { 157 if (!this.TryGetCharacter(out var b)) 158 { 159 receiveFifoUnderflowInterrupt.Value = true; 160 this.Log(LogLevel.Warning, "Trying to read form an empty fifo"); 161 } 162 else 163 { 164 OnBufferStateChanged(); 165 } 166 return b; 167 }, 168 writeCallback: (_, val) => 169 { 170 var breakCharacter = transmitSpecialCharacter.Value && val == 0; 171 if (breakCharacter && linBreakDetection.Value) 172 { 173 // We have to broadcast LIN break 174 BroadcastLINBreak?.Invoke(); 175 } 176 else if (transmitterEnabled.Value) 177 { 178 TransmitData((byte)val); 179 } 180 else if (txQueue.Count < txMaxBytes) 181 { 182 txQueue.Enqueue((byte)val); 183 184 UpdateFillLevels(); 185 } 186 else 187 { 188 transmitFifoOverflowInterrupt.Value = true; 189 this.Log(LogLevel.Warning, "Trying to write to a full Tx FIFO."); 190 } 191 UpdateGPIOOutputs(); 192 193 }) 194 .WithReservedBits(10, 1) 195 .WithTaggedFlag("IDLINE / Idle Line", 11) 196 .WithFlag(12, FieldMode.Read, valueProviderCallback: _ => BufferState == BufferState.Empty, name: "RXEMPT / Receive Buffer Empty") 197 .WithFlag(13, out transmitSpecialCharacter, name: "FRETSC / Frame Error / Transmit Special Character") 198 .WithFlag(14, FieldMode.Read, valueProviderCallback: _ => false, name: "PARITYE / PARITYE") 199 .WithFlag(15, FieldMode.Read, valueProviderCallback: _ => false, name: "NOISY / NOISY") 200 .WithReservedBits(16, 16) 201 .WithReadCallback((_, __) => 202 { 203 UpdateBufferState(); 204 UpdateInterrupt(); 205 }) 206 ); 207 208 registersMap.Add(CommonRegistersOffset + (long)CommonRegs.MatchAddress, new DoubleWordRegister(this) 209 .WithTag("MA1 / Match Address 1", 0, 10) 210 .WithReservedBits(10, 6) 211 .WithTag("MA2 / Match Address 2", 16, 10) 212 .WithReservedBits(26, 6) 213 ); 214 215 if (hasFifoRegisters) 216 { 217 registersMap.Add(FifoRegistersOffset + (long)FifoRegs.Fifo, new DoubleWordRegister(this) 218 .WithValueField(0, 3, FieldMode.Read, valueProviderCallback: _ => CalculateFIFODatawordsCount(rxFIFOCapacity), name: "RXFIFOSIZE / Receive FIFO Buffer Depth") 219 .WithFlag(3, out receiveFifoEnabled, name: "RXFE / Receive FIFO Enable", writeCallback: (current, val) => 220 { 221 if (current != val && (transmitterEnabled.Value || receiverEnabled.Value)) 222 { 223 this.Log(LogLevel.Warning, "Both CTRL[TE] and CTRL[RE] must be cleared prior to changing this field."); 224 return; 225 } 226 if (!val) 227 { 228 rxMaxBytes = 1; 229 // assuming that disabling fifo clears it 230 ClearBuffer(); 231 } 232 else 233 { 234 rxMaxBytes = (int)rxFIFOCapacity; 235 } 236 }) 237 .WithValueField(4, 3, FieldMode.Read, valueProviderCallback: _ => CalculateFIFODatawordsCount(txFIFOCapacity), name: "TXFIFOSIZE / Transmit FIFO Buffer Depth") 238 .WithFlag(7, out transmitFifoEnabled, name: "TXFE / Transmit FIFO Enable", writeCallback: (current, val) => 239 { 240 if (current != val && (transmitterEnabled.Value || receiverEnabled.Value)) 241 { 242 this.Log(LogLevel.Warning, "Both CTRL[TE] and CTRL[RE] must be cleared prior to changing this field."); 243 return; 244 } 245 if (!val) 246 { 247 txMaxBytes = 1; 248 // assuming that disabling fifo clears it 249 txQueue.Clear(); 250 } 251 else 252 { 253 txMaxBytes = (int)txFIFOCapacity; 254 } 255 }) 256 .WithFlag(8, out receiveFifoUnderflowEnabled, name: "RXUFE / Receive FIFO Underflow Interrupt Enable") 257 .WithFlag(9, out transmitFifoOverflowEnabled, name: "TXOFE / Transmit FIFO Overflow Interrupt Enable") 258 .WithTag("RXIDEN / Receiver Idle Empty Enable", 10, 3) 259 .WithReservedBits(13, 1) 260 .WithFlag(14, FieldMode.Write, name: "RXFLUSH / Receive FIFO/Buffer Flush", writeCallback: (_, val) => 261 { 262 if (val) 263 { 264 ClearBuffer(); 265 } 266 }) 267 .WithFlag(15, FieldMode.Write, name: "TXFLUSH / Transmit FIFO/Buffer Flush", writeCallback: (_, val) => 268 { 269 if (val) 270 { 271 txQueue.Clear(); 272 } 273 }) 274 .WithFlag(16, out receiveFifoUnderflowInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "RXUF / Receiver Buffer Underflow Flag") 275 .WithFlag(17, out transmitFifoOverflowInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "TXOF / Transmitter Buffer Overflow Flag") 276 .WithReservedBits(18, 4) 277 .WithFlag(22, FieldMode.Read, valueProviderCallback: _ => BufferState == BufferState.Empty, name: "RXEMPT / Receive Buffer Empty") 278 .WithFlag(23, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "TXEMPT / Transmit Buffer Empty") 279 .WithReservedBits(24, 8) 280 .WithWriteCallback((_, __) => UpdateGPIOOutputs()) 281 ); 282 283 registersMap.Add(FifoRegistersOffset + (long)FifoRegs.Watermark, new DoubleWordRegister(this) 284 .WithValueField(0, 2, writeCallback: (_, val) => { transmitWatermark = DecodeFifoCount(val); }, name: "TXWATER / Transmit Watermark") 285 .WithReservedBits(2, 6) 286 .WithValueField(8, 3, FieldMode.Read, valueProviderCallback: _ => (uint)txQueue.Count, name: "TXCOUNT / Transmit Counter") 287 .WithReservedBits(11, 5) 288 .WithValueField(16, 2, writeCallback: (_, val) => { receiveWatermark = (uint)val; }, name: "RXWATER / Receive Watermark") 289 .WithReservedBits(18, 6) 290 .WithValueField(24, 3, FieldMode.Read, valueProviderCallback: _ => 291 { 292 /* This value is not backed by the manual. 293 * Since the manual is vague in this regard it is impossible to tell if this should be encoded the same 294 * way as Fifo depth (FIFO_SIZE) or real count clipped at the maximum possible to express with just 3 bits. 295 * As the available drivers suggest the second approach - this is what we use here. 296 * But this should be adjusted if proven to not work or if the manual gets updated */ 297 return (uint)Math.Min(Count, 0b111); 298 }, name: "RXCOUNT / Receive Counter") 299 .WithReservedBits(27, 5) 300 .WithWriteCallback((_, __) => UpdateGPIOOutputs()) 301 ); 302 } 303 304 registers = new DoubleWordRegisterCollection(this, registersMap); 305 } 306 Reset()307 public override void Reset() 308 { 309 lock (locker) 310 { 311 base.Reset(); 312 registers.Reset(); 313 txQueue.Clear(); 314 latestBufferState = BufferState.Empty; 315 rxMaxBytes = 1; 316 txMaxBytes = 1; 317 UpdateGPIOOutputs(); 318 reset.Value = true; 319 } 320 } 321 ReadByte(long offset)322 public byte ReadByte(long offset) 323 { 324 lock (locker) 325 { 326 if (!IsDataRegister(offset)) 327 { 328 this.Log(LogLevel.Warning, "Trying to read byte from {0} (0x{0:X}), not supported", offset); 329 return 0; 330 } 331 332 return (byte)registers.Read(offset); 333 } 334 } 335 WriteByte(long offset, byte value)336 public void WriteByte(long offset, byte value) 337 { 338 lock (locker) 339 { 340 if (!IsDataRegister(offset)) 341 { 342 this.Log(LogLevel.Warning, "Trying to read byte from {0} (0x{0:X}), not supported", offset); 343 return; 344 } 345 346 registers.Write(offset, value); 347 } 348 } 349 ReadDoubleWord(long offset)350 public uint ReadDoubleWord(long offset) 351 { 352 lock (locker) 353 { 354 return registers.Read(offset); 355 } 356 } 357 WriteDoubleWord(long offset, uint value)358 public void WriteDoubleWord(long offset, uint value) 359 { 360 lock (locker) 361 { 362 registers.Write(offset, value); 363 } 364 } 365 WriteChar(byte data)366 public override void WriteChar(byte data) 367 { 368 lock (locker) 369 { 370 if (loopMode.Value) 371 { 372 if (receiverSource.Value && transmissionPinDirectionOutNotIn.Value) 373 { 374 this.Log(LogLevel.Warning, "Data ignored, uart operates in Single-Wire mode and txPin is set to output. (value: 0x{0:X})", data); 375 return; 376 } 377 378 if (!receiverSource.Value) 379 { 380 this.Log(LogLevel.Warning, "Data ignored, uart operates in Loop mode. (value: 0x{0:X})", data); 381 return; 382 } 383 } 384 385 if (receiverOverrun.Value) 386 { 387 this.Log(LogLevel.Info, "Data ignored, receiver has been overrun. (value: 0x{0:X})", data); 388 return; 389 } 390 391 if (Count >= rxMaxBytes) 392 { 393 this.Log(LogLevel.Info, "rxFIFO/Buffer is overflowing but we are buffering character", data, rxMaxBytes); 394 } 395 396 base.WriteChar(data); 397 UpdateBufferState(); 398 UpdateInterrupt(); 399 } 400 } 401 ReceiveLINBreak()402 public void ReceiveLINBreak() 403 { 404 linBreakDetect.Value |= linBreakDetection.Value; 405 UpdateGPIOOutputs(); 406 } 407 408 public event Action BroadcastLINBreak; 409 public event Action<BufferState> BufferStateChanged; 410 411 public BufferState BufferState { get; private set; } 412 413 public long Size => 0x30; 414 415 public override Bits StopBits => stopBitNumberSelect.Value ? Bits.Two : Bits.One; 416 417 public override Parity ParityBit => parityEnabled.Value ? Parity.None : parityType.Value ? Parity.Odd : Parity.Even; 418 419 public override uint BaudRate => (baudRateModuloDivisor.Value == 0) 420 ? 0 421 : (uint)(frequency / ((oversamplingRatio.Value == 0 ? 16 : (uint)(oversamplingRatio.Value + 1)) * (uint)baudRateModuloDivisor.Value)); 422 423 public GPIO IRQ { get; } 424 public GPIO SeparateRxIRQ { get; } 425 public GPIO DMA { get; } 426 UpdateBufferState()427 private void UpdateBufferState() 428 { 429 var count = Count; 430 if (count == 0) 431 { 432 BufferState = BufferState.Empty; 433 return; 434 } 435 436 if (receiveFifoEnabled.Value) 437 { 438 if ((ulong)count > receiveWatermark) 439 { 440 BufferState = BufferState.Ready; 441 return; 442 } 443 } 444 445 if (count >= rxMaxBytes) 446 { 447 BufferState = BufferState.Full; 448 } 449 BufferState = BufferState.Ready; 450 } 451 TransmitData(byte data)452 protected void TransmitData(byte data) 453 { 454 if (!loopMode.Value) 455 { 456 TransmitCharacter(data); 457 } 458 else if (receiverSource.Value) 459 { 460 if (!transmissionPinDirectionOutNotIn.Value) 461 { 462 this.Log(LogLevel.Warning, "Data not transmitted, uart operates in Single-Wire mode and txPin set to input. (value: 0x{0:X})", data); 463 return; 464 } 465 TransmitCharacter(data); 466 } 467 else 468 { 469 WriteChar(data); 470 } 471 } 472 CharWritten()473 protected override void CharWritten() 474 { 475 UpdateGPIOOutputs(); 476 } 477 QueueEmptied()478 protected override void QueueEmptied() 479 { 480 UpdateGPIOOutputs(); 481 } 482 483 private long CommonRegistersOffset => hasGlobalRegisters ? 0x10 : 0x0; 484 private long FifoRegistersOffset => 0x18 + CommonRegistersOffset; 485 UpdateGPIOOutputs()486 private void UpdateGPIOOutputs() 487 { 488 UpdateFillLevels(); 489 UpdateInterrupt(); 490 UpdateDMA(); 491 } 492 UpdateInterrupt()493 private void UpdateInterrupt() 494 { 495 var rxUnderflow = receiveFifoUnderflowEnabled.Value && receiveFifoUnderflowInterrupt.Value; 496 var rx = receiverInterruptEnabled.Value && BufferState == BufferState.Ready; // Watermark level exceeded 497 var linBreak = linBreakDetect.Value && linBreakDetectInterruptEnable.Value; 498 var rxRequest = rxUnderflow || rx || linBreak; 499 500 var txOverflow = transmitFifoOverflowEnabled.Value && transmitFifoOverflowInterrupt.Value; 501 var tx = transmitterInterruptEnabled.Value && transmitDataRegisterEmpty.Value; 502 var txComplete = transmissionCompleteInterruptEnabled.Value && (txQueue.Count == 0); 503 var txRequest = txOverflow || tx || txComplete; 504 505 if (separateIRQs) 506 { 507 SeparateRxIRQ.Set(rxRequest); 508 this.Log(LogLevel.Debug, "Setting SeparateRxIRQ to {0}; rxUnderflow {1}, rx {2}, linBreak {3}", rxRequest, rxUnderflow, rx, linBreak); 509 510 IRQ.Set(txRequest); 511 this.Log(LogLevel.Debug, "Setting IRQ to {0}; txOverflow {1}, tx {2}, txComplete {3}", txRequest, txOverflow, tx, txComplete); 512 } 513 else 514 { 515 var irqState = txRequest || rxRequest; 516 this.Log(LogLevel.Noisy, "Setting IRQ to {0}, rxUnderflow {1}, txOverflow {2}, tx {3}, rx {4}, txComplete {5}, linBreak {6}", irqState, rxUnderflow, txOverflow, tx, rx, txComplete, linBreak); 517 IRQ.Set(irqState); 518 } 519 } 520 UpdateDMA()521 private void UpdateDMA() 522 { 523 var drqState = false; 524 525 drqState |= transmitterDMAEnabled.Value && transmitDataRegisterEmpty.Value; 526 drqState |= receiverDMAEnabled.Value && BufferState == BufferState.Full; 527 528 DMA.Set(drqState); 529 this.Log(LogLevel.Noisy, "Setting DMA request to {0}", drqState); 530 } 531 UpdateFillLevels()532 private void UpdateFillLevels() 533 { 534 OnBufferStateChanged(); 535 if (transmitFifoEnabled.Value) 536 { 537 transmitDataRegisterEmpty.Value = txQueue.Count <= (int)transmitWatermark; 538 } 539 else 540 { 541 transmitDataRegisterEmpty.Value = txQueue.Count == 0; 542 } 543 } 544 OnBufferStateChanged()545 private void OnBufferStateChanged() 546 { 547 var state = BufferState; 548 if (latestBufferState != state) 549 { 550 latestBufferState = state; 551 BufferStateChanged?.Invoke(state); 552 } 553 } 554 IsDataRegister(long offset)555 private bool IsDataRegister(long offset) 556 { 557 return offset == CommonRegistersOffset + (long)CommonRegs.Data; 558 } 559 CalculateFIFODatawordsCount(uint capacity)560 private uint CalculateFIFODatawordsCount(uint capacity) 561 { 562 if (capacity == 1) 563 { 564 return 0; 565 } 566 return (uint)Misc.Logarithm2((int)capacity) - 1; 567 } 568 DecodeFifoCount(ulong encodedValue)569 private uint DecodeFifoCount(ulong encodedValue) 570 { 571 if (encodedValue == 0) 572 { 573 return 1; 574 } 575 return (uint)Math.Pow(2, encodedValue + 1); 576 } 577 578 private BufferState latestBufferState = BufferState.Empty; 579 private int rxMaxBytes = 1; 580 private int txMaxBytes = 1; 581 private readonly object locker; 582 private readonly Queue<byte> txQueue; 583 private readonly DoubleWordRegisterCollection registers; 584 private readonly IFlagRegisterField reset; 585 private readonly IFlagRegisterField stopBitNumberSelect; 586 private readonly IFlagRegisterField bothEdgeSampling; 587 private readonly IFlagRegisterField transmitterDMAEnabled; 588 private readonly IFlagRegisterField receiverDMAEnabled; 589 private readonly IFlagRegisterField receiverOverrun; 590 private readonly IFlagRegisterField transmitDataRegisterEmpty; 591 private readonly IFlagRegisterField parityType; 592 private readonly IFlagRegisterField parityEnabled; 593 private readonly IFlagRegisterField receiverSource; 594 private readonly IFlagRegisterField loopMode; 595 private readonly IFlagRegisterField receiverEnabled; 596 private readonly IFlagRegisterField transmitterEnabled; 597 private readonly IFlagRegisterField receiverInterruptEnabled; 598 private readonly IFlagRegisterField transmissionCompleteInterruptEnabled; 599 private readonly IFlagRegisterField transmitterInterruptEnabled; 600 private readonly IFlagRegisterField transmissionPinDirectionOutNotIn; 601 private readonly IFlagRegisterField receiveFifoEnabled; 602 private readonly IFlagRegisterField transmitFifoEnabled; 603 private readonly IFlagRegisterField receiveFifoUnderflowEnabled; 604 private readonly IFlagRegisterField transmitFifoOverflowEnabled; 605 private readonly IFlagRegisterField receiveFifoUnderflowInterrupt; 606 private readonly IFlagRegisterField transmitFifoOverflowInterrupt; 607 private readonly IFlagRegisterField linBreakDetectInterruptEnable; 608 private readonly IFlagRegisterField transmitSpecialCharacter; 609 private readonly IFlagRegisterField linBreakDetect; 610 private readonly IFlagRegisterField linBreakDetection; 611 private readonly IValueRegisterField baudRateModuloDivisor; 612 private readonly IValueRegisterField oversamplingRatio; 613 private readonly long frequency; 614 private readonly bool hasGlobalRegisters; 615 private readonly bool separateIRQs; 616 private readonly uint txFIFOCapacity; 617 private readonly uint rxFIFOCapacity; 618 private uint transmitWatermark; 619 private uint receiveWatermark; 620 621 private const uint DefaultFIFOSize = 256; 622 private const int DataSize = 8; 623 624 // enum belows intentionally do not contain `Register(s)` in the name 625 // to avoid using them when logging accesses (which might have been 626 // misleading depending on `hasGlobalRegisters` and `hasFifoRegisters` configuration) 627 private enum GlobalRegs 628 { 629 VersionID = 0x0, 630 Parameter = 0x4, 631 Global = 0x8, 632 PinConfiguration = 0xc, 633 } 634 635 private enum CommonRegs 636 { 637 BaudRate = 0x0, 638 Status = 0x4, 639 Control = 0x8, 640 Data = 0xc, 641 MatchAddress = 0x10, 642 ModemIrDA = 0x14, 643 } 644 645 private enum FifoRegs 646 { 647 Fifo = 0x0, 648 Watermark = 0x4, 649 } 650 } 651 } 652