1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Peripherals.Bus;
8 using Antmicro.Renode.Core;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Utilities;
13 using System;
14 
15 namespace Antmicro.Renode.Peripherals.UART
16 {
17     public class KB1200_UART : UARTBase, IDoubleWordPeripheral, IKnownSize
18     {
KB1200_UART(IMachine machine)19         public KB1200_UART(IMachine machine) : base(machine)
20         {
21             var registersMap = new Dictionary<long, DoubleWordRegister>();
22 
23             registersMap.Add((long)Registers.Configuration, new DoubleWordRegister(this)
24                 .WithTaggedFlag("SERIE_RX_ENABLE", 0)
25                 .WithFlag(1, out serieTxEnable, name: "SERIE_TX_ENABLE")
26                 .WithTag("Parity", 2, 2)
27                 .WithReservedBits(6, 10)
28                 .WithTag("Baud Rate", 16, 16)
29             );
30 
31             registersMap.Add((long)Registers.InterruptEnable, new DoubleWordRegister(this)
32                 .WithFlag(0, out serieIrqRxEnable, name: "SERIE_IRQ_RX_ENABLE")
33                 .WithFlag(1, out serieIrqTxEnable, name: "SERIE_IRQ_TX_ENABLE")
34                 .WithTaggedFlag("SERIE_IRQ_RX_ERROR", 2)
35                 .WithReservedBits(3, 29)
36                 .WithWriteCallback((_, __) => UpdateInterrupts())
37             );
38 
39             registersMap.Add((long)Registers.PendingFlag, new DoubleWordRegister(this)
40                 .WithFlag(0, out serpfRxCntFull,
41                     FieldMode.Read | FieldMode.WriteOneToClear,
42                     name: "SERPF_RX_CNT_FULL")
43                 // In Renode, the TX happens instantly
44                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => true, name: "SEPRF_TX_EMPTY")
45                 .WithTaggedFlag("SERPF_RX_ERROR", 2)
46                 .WithReservedBits(4, 28)
47                 .WithWriteCallback((_, __) => UpdateInterrupts())
48             );
49 
50             registersMap.Add((long)Registers.Status, new DoubleWordRegister(this)
51                 .WithTaggedFlag("TX_FULL", 0)
52                 .WithTaggedFlag("TX_OVERRUN", 1)
53                 .WithTaggedFlag("TX_BUSY", 2)
54                 .WithReservedBits(3, 1)
55                 .WithFlag(4, FieldMode.Read, name: "RX_EMPTY",
56                     valueProviderCallback: _ => receiveQueue.Count == 0)
57                 .WithTaggedFlag("RX_OVERRUN", 5)
58                 .WithTaggedFlag("RX_BUSY", 6)
59                 .WithTaggedFlag("RX_TIMEOUT", 7)
60                 .WithTaggedFlag("PARITY_ERROR", 8)
61                 .WithTaggedFlag("FRAME_ERROR", 9)
62                 .WithReservedBits(10, 22)
63             );
64 
65             registersMap.Add((long)Registers.RxDataBuffer, new DoubleWordRegister(this)
66                 .WithValueField(0, 8,
67                     FieldMode.Read,
68                     name: "SERTBUF",
69                     valueProviderCallback: _ => HandleReceiveData())
70                 .WithReservedBits(8, 24)
71             );
72 
73             registersMap.Add((long)Registers.TxDataBuffer, new DoubleWordRegister(this)
74                 .WithValueField(0, 8,
75                     FieldMode.Write,
76                     name: "SERRBUF",
77                     writeCallback: (_, v) => HandleTransmitData((uint)v))
78                 .WithReservedBits(8, 24)
79             );
80 
81             registersMap.Add((long)Registers.Control, new DoubleWordRegister(this)
82                 .WithTag("SERCTRL", 0, 3)
83                 .WithReservedBits(3, 29)
84             );
85 
86             registers = new DoubleWordRegisterCollection(this, registersMap);
87         }
88 
WriteChar(byte value)89         public override void WriteChar(byte value)
90         {
91             if(!IsReceiveEnabled)
92             {
93                 this.Log(LogLevel.Warning, "Char was received, but the receiver (or the whole USART) is not enabled. Ignoring.");
94                 return;
95             }
96             // We assume FIFO size is 1
97             serpfRxCntFull.Value = true;
98             receiveQueue.Enqueue(value);
99             UpdateInterrupts();
100         }
101 
UpdateInterrupts()102         public void UpdateInterrupts()
103         {
104             bool irqPending = (serieIrqRxEnable.Value && serpfRxCntFull.Value)
105                             || (serieIrqTxEnable.Value);
106             this.Log(LogLevel.Noisy, "Setting IRQ: {0}", irqPending);
107             IRQ.Set(irqPending);
108         }
109 
Reset()110         public override void Reset()
111         {
112             base.Reset();
113             registers.Reset();
114             receiveQueue.Clear();
115             IRQ.Set(false);
116         }
117 
ReadDoubleWord(long offset)118         public uint ReadDoubleWord(long offset)
119         {
120             return registers.Read(offset);
121         }
122 
WriteDoubleWord(long offset, uint val)123         public void WriteDoubleWord(long offset, uint val)
124         {
125             registers.Write(offset, val);
126         }
127 
128         public GPIO IRQ { get; } = new GPIO();
129 
130         public override Bits StopBits { get; }
131 
132         public override Parity ParityBit { get; }
133 
134         public override uint BaudRate => 115200;
135 
136         public long Size => 0x1C;
137 
CharWritten()138         protected override void CharWritten()
139         {
140             // intentionally left blank
141         }
142 
QueueEmptied()143         protected override void QueueEmptied()
144         {
145             // intentionally left blank
146         }
147 
HandleReceiveData()148         private uint HandleReceiveData()
149         {
150             if(receiveQueue.TryDequeue(out var result))
151             {
152                 UpdateInterrupts();
153             }
154             return result;
155         }
156 
HandleTransmitData(uint value)157         private void HandleTransmitData(uint value)
158         {
159             if(!serieTxEnable.Value)
160             {
161                 this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring.");
162                 return;
163             }
164             TransmitCharacter((byte)value);
165         }
166 
167         private readonly IFlagRegisterField serieIrqRxEnable;
168         private readonly IFlagRegisterField serieTxEnable;
169         private readonly IFlagRegisterField serieIrqTxEnable;
170         private readonly IFlagRegisterField serpfRxCntFull;
171 
172         private readonly Queue<byte> receiveQueue = new Queue<byte>();
173 
174         private readonly DoubleWordRegisterCollection registers;
175 
176         private enum Registers
177         {
178             Configuration = 0x00,
179             InterruptEnable = 0x04,
180             PendingFlag = 0x08,
181             Status = 0x0C,
182             RxDataBuffer = 0x10,
183             TxDataBuffer = 0x14,
184             Control = 0x18
185         }
186     }
187 }
188