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