1 // 2 // Copyright (c) 2010-2018 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.Collections.Generic; 8 using Antmicro.Renode.Peripherals.Bus; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Logging; 12 13 namespace Antmicro.Renode.Peripherals.UART 14 { 15 public class LiteX_UART : UARTBase, IDoubleWordPeripheral, IBytePeripheral, IKnownSize 16 { LiteX_UART(IMachine machine)17 public LiteX_UART(IMachine machine) : base(machine) 18 { 19 IRQ = new GPIO(); 20 var registersMap = new Dictionary<long, DoubleWordRegister> 21 { 22 {(long)Registers.RxTx, new DoubleWordRegister(this) 23 .WithValueField(0, 8, writeCallback: (_, value) => this.TransmitCharacter((byte)value), 24 valueProviderCallback: _ => { 25 if(!TryGetCharacter(out var character)) 26 { 27 this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO."); 28 } 29 return character; 30 }) 31 }, 32 {(long)Registers.TxFull, new DoubleWordRegister(this) 33 .WithFlag(0, FieldMode.Read) //tx is never full 34 }, 35 {(long)Registers.RxEmpty, new DoubleWordRegister(this) 36 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => Count == 0) 37 }, 38 {(long)Registers.EventPending, new DoubleWordRegister(this) 39 // `txEventPending` implements `WriteOneToClear` semantics to avoid fake warnings 40 // `txEventPending` is generated on the falling edge of TxFull; in our case it means never 41 .WithFlag(0, FieldMode.Read | FieldMode.WriteOneToClear, valueProviderCallback: _ => false, name: "txEventPending") 42 .WithFlag(1, out rxEventPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "rxEventPending") 43 .WithWriteCallback((_, __) => UpdateInterrupts()) 44 }, 45 {(long)Registers.EventEnable, new DoubleWordRegister(this) 46 .WithFlag(0, name: "txEventEnabled") 47 .WithFlag(1, out rxEventEnabled) 48 .WithWriteCallback((_, __) => UpdateInterrupts()) 49 }, 50 }; 51 52 registers = new DoubleWordRegisterCollection(this, registersMap); 53 } 54 ReadDoubleWord(long offset)55 public uint ReadDoubleWord(long offset) 56 { 57 return registers.Read(offset); 58 } 59 ReadByte(long offset)60 public byte ReadByte(long offset) 61 { 62 if(offset % 4 != 0) 63 { 64 // in the current configuration, only the lowest byte 65 // contains a meaningful data 66 return 0; 67 } 68 return (byte)ReadDoubleWord(offset); 69 } 70 Reset()71 public override void Reset() 72 { 73 base.Reset(); 74 registers.Reset(); 75 76 UpdateInterrupts(); 77 } 78 WriteDoubleWord(long offset, uint value)79 public void WriteDoubleWord(long offset, uint value) 80 { 81 registers.Write(offset, value); 82 } 83 WriteByte(long offset, byte value)84 public void WriteByte(long offset, byte value) 85 { 86 if(offset % 4 != 0) 87 { 88 // in the current configuration, only the lowest byte 89 // contains a meaningful data 90 return; 91 } 92 93 WriteDoubleWord(offset, value); 94 } 95 96 public long Size => 0x100; 97 98 public GPIO IRQ { get; private set; } 99 100 public override Bits StopBits => Bits.One; 101 102 public override Parity ParityBit => Parity.None; 103 104 public override uint BaudRate => 115200; 105 CharWritten()106 protected override void CharWritten() 107 { 108 UpdateInterrupts(); 109 } 110 QueueEmptied()111 protected override void QueueEmptied() 112 { 113 UpdateInterrupts(); 114 } 115 UpdateInterrupts()116 private void UpdateInterrupts() 117 { 118 // rxEventPending is latched 119 rxEventPending.Value = (Count != 0); 120 121 // tx fifo is never full, so `txEventPending` is always false 122 var eventPending = (rxEventEnabled.Value && rxEventPending.Value); 123 IRQ.Set(eventPending); 124 } 125 126 private IFlagRegisterField rxEventEnabled; 127 private IFlagRegisterField rxEventPending; 128 private readonly DoubleWordRegisterCollection registers; 129 130 private enum Registers : long 131 { 132 RxTx = 0x0, 133 TxFull = 0x04, 134 RxEmpty = 0x08, 135 EventStatus = 0x0c, 136 EventPending = 0x10, 137 EventEnable = 0x14, 138 } 139 } 140 } 141