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