1 // 2 // Copyright (c) 2010-2020 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 // this is a model of LiteX UART with register layout to simulate 64 bit bus read/write access 16 public class LiteX_UART64 : UARTBase, IDoubleWordPeripheral, IBytePeripheral, IKnownSize 17 { LiteX_UART64(IMachine machine)18 public LiteX_UART64(IMachine machine) : base(machine) 19 { 20 IRQ = new GPIO(); 21 var registersMap = new Dictionary<long, DoubleWordRegister> 22 { 23 {(long)Registers.RxTx, new DoubleWordRegister(this) 24 .WithValueField(0, 8, writeCallback: (_, value) => this.TransmitCharacter((byte)value), 25 valueProviderCallback: _ => { 26 if(!TryGetCharacter(out var character)) 27 { 28 this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO."); 29 } 30 return character; 31 }) 32 }, 33 {(long)Registers.RxTxHi, new DoubleWordRegister(this) 34 .WithReservedBits(0, 32) // simulating an upper half of a 64bit register, never used bits 35 }, 36 {(long)Registers.TxFull, new DoubleWordRegister(this) 37 .WithFlag(0, FieldMode.Read) //tx is never full 38 }, 39 {(long)Registers.TxFullHi, new DoubleWordRegister(this) 40 .WithReservedBits(0, 32) // simulating an upper half of a 64bit register, never used bits 41 }, 42 {(long)Registers.RxEmpty, new DoubleWordRegister(this) 43 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => Count == 0) 44 }, 45 {(long)Registers.RxEmptyHi, new DoubleWordRegister(this) 46 .WithReservedBits(0, 32) // simulating an upper half of a 64bit register, never used bits 47 }, 48 {(long)Registers.EventPending, new DoubleWordRegister(this) 49 // `txEventPending` implements `WriteOneToClear` semantics to avoid fake warnings 50 // `txEventPending` is generated on the falling edge of TxFull; in our case it means never 51 .WithFlag(0, FieldMode.Read | FieldMode.WriteOneToClear, valueProviderCallback: _ => false, name: "txEventPending") 52 .WithFlag(1, out rxEventPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "rxEventPending") 53 .WithWriteCallback((_, __) => UpdateInterrupts()) 54 }, 55 {(long)Registers.EventPendingHi, new DoubleWordRegister(this) 56 .WithReservedBits(0, 32) // simulating an upper half of a 64bit register, never used bits 57 }, 58 {(long)Registers.EventEnable, new DoubleWordRegister(this) 59 .WithFlag(0, name: "txEventEnabled") 60 .WithFlag(1, out rxEventEnabled) 61 .WithWriteCallback((_, __) => UpdateInterrupts()) 62 }, 63 {(long)Registers.EventEnableHi, new DoubleWordRegister(this) 64 .WithReservedBits(0, 32) // simulating an upper half of a 64bit register, never used bits 65 }, 66 }; 67 68 registers = new DoubleWordRegisterCollection(this, registersMap); 69 } 70 ReadDoubleWord(long offset)71 public uint ReadDoubleWord(long offset) 72 { 73 return registers.Read(offset); 74 } 75 ReadByte(long offset)76 public byte ReadByte(long offset) 77 { 78 if(offset % 8 != 0) 79 { 80 // in the current configuration, only the lowest byte 81 // contains a meaningful data 82 return 0; 83 } 84 return (byte)ReadDoubleWord(offset); 85 } 86 Reset()87 public override void Reset() 88 { 89 base.Reset(); 90 registers.Reset(); 91 92 UpdateInterrupts(); 93 } 94 WriteDoubleWord(long offset, uint value)95 public void WriteDoubleWord(long offset, uint value) 96 { 97 registers.Write(offset, value); 98 } 99 WriteByte(long offset, byte value)100 public void WriteByte(long offset, byte value) 101 { 102 if(offset % 8 != 0) 103 { 104 // in the current configuration, only the lowest byte 105 // contains a meaningful data 106 return; 107 } 108 109 WriteDoubleWord(offset, value); 110 } 111 112 public long Size => 0x100; 113 114 public GPIO IRQ { get; private set; } 115 116 public override Bits StopBits => Bits.One; 117 118 public override Parity ParityBit => Parity.None; 119 120 public override uint BaudRate => 115200; 121 CharWritten()122 protected override void CharWritten() 123 { 124 UpdateInterrupts(); 125 } 126 QueueEmptied()127 protected override void QueueEmptied() 128 { 129 UpdateInterrupts(); 130 } 131 UpdateInterrupts()132 private void UpdateInterrupts() 133 { 134 // rxEventPending is latched 135 rxEventPending.Value = (Count != 0); 136 137 // tx fifo is never full, so `txEventPending` is always false 138 var eventPending = (rxEventEnabled.Value && rxEventPending.Value); 139 IRQ.Set(eventPending); 140 } 141 142 private IFlagRegisterField rxEventEnabled; 143 private IFlagRegisterField rxEventPending; 144 private readonly DoubleWordRegisterCollection registers; 145 146 private enum Registers : long 147 { 148 RxTx = 0x0, 149 RxTxHi = 0x04, 150 TxFull = 0x08, 151 TxFullHi = 0x0C, 152 RxEmpty = 0x10, 153 RxEmptyHi = 0x14, 154 EventStatus = 0x18, 155 EventStatusHi = 0x1C, 156 EventPending = 0x20, 157 EventPendingHi = 0x24, 158 EventEnable = 0x28, 159 EventEnableHi = 0x3C 160 } 161 } 162 } 163