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