1 //
2 // Copyright (c) 2010-2023 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;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 
15 namespace Antmicro.Renode.Peripherals.UART
16 {
17     public class CMSDK_APB_UART : UARTBase, IDoubleWordPeripheral, IKnownSize
18     {
CMSDK_APB_UART(IMachine machine, uint frequency = 24000000)19         public CMSDK_APB_UART(IMachine machine, uint frequency = 24000000) : base(machine)
20         {
21             this.frequency = frequency;
22             var registersMap = new Dictionary<long, DoubleWordRegister>
23             {
24                 {(long)Registers.Data, new DoubleWordRegister(this)
25                     .WithValueField(0, 8,
26                         writeCallback: (_, value) =>
27                         {
28                             if(!txEnabled.Value)
29                             {
30                                 this.Log(LogLevel.Warning, "Data Register Write Error: Transmitter not enabled");
31                                 return;
32                             }
33                             this.TransmitCharacter((byte)value);
34                             if(txInterruptEnabled.Value)
35                             {
36                                 txInterruptPending.Value = true;
37                                 UpdateInterrupts();
38                             }
39                         },
40                         valueProviderCallback: _ =>
41                         {
42                             if(!rxEnabled.Value)
43                             {
44                                 this.Log(LogLevel.Warning, "Data Register Read Error: Receiver not enabled");
45                                 return 0;
46                             }
47                             if(!TryGetCharacter(out var character))
48                             {
49                                 this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO.");
50                             }
51                             return character;
52                         })
53                     .WithReservedBits(8, 24)
54                 },
55                 {(long)Registers.Status, new DoubleWordRegister(this)
56                     .WithFlag(0, FieldMode.Read, name: "TxBufferFull", valueProviderCallback: _ => false)
57                     .WithFlag(1, out rxBufferFull, FieldMode.Read, name: "RxBufferFull")
58                     .WithTaggedFlag("TxBufferOverrun", 2)
59                     .WithTaggedFlag("RxBufferOverrun", 3)
60                     .WithReservedBits(4, 28)
61                 },
62                 {(long)Registers.Control, new DoubleWordRegister(this)
63                     .WithFlag(0, out txEnabled, name: "TxEnabled")
64                     .WithFlag(1, out rxEnabled, name: "RxEnabled")
65                     .WithFlag(2, out txInterruptEnabled, name: "TxInterruptEnable", writeCallback: (_, __) => UpdateInterrupts())
66                     .WithFlag(3, out rxInterruptEnabled, name: "RxInterruptEnable", writeCallback: (_, __) => UpdateInterrupts())
67                     .WithTaggedFlag("TxOverrunInterruptEnable", 4)
68                     .WithTaggedFlag("RxOverrunInterruptEnable", 5)
69                     .WithTaggedFlag("HighSpeedTestModeTx", 6)
70                     .WithReservedBits(7, 25)
71                 },
72                 {(long)Registers.Interrupts, new DoubleWordRegister(this)
73                     .WithFlag(0, out txInterruptPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "TxInterrupt", writeCallback: (_, __) => UpdateInterrupts())
74                     .WithFlag(1, out rxInterruptPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "RxInterrupt", writeCallback: (_, __) => UpdateInterrupts())
75                     .WithTaggedFlag("TxOverrunInterrupt", 2)
76                     .WithTaggedFlag("RxOverrunInterrupt", 3)
77                     .WithReservedBits(4, 28)
78                 },
79                 {(long)Registers.BaudRateDiv, new DoubleWordRegister(this)
80                     .WithValueField(0, 8, out baudRateDivValue)
81                     .WithReservedBits(8, 24)
82                 },
83             };
84 
85             TxInterrupt = new GPIO();
86             RxInterrupt = new GPIO();
87             registers = new DoubleWordRegisterCollection(this, registersMap);
88         }
89 
ReadDoubleWord(long offset)90         public uint ReadDoubleWord(long offset)
91         {
92             return registers.Read(offset);
93         }
94 
WriteDoubleWord(long offset, uint value)95         public void WriteDoubleWord(long offset, uint value)
96         {
97             registers.Write(offset, value);
98         }
99 
CharWritten()100         protected override void CharWritten()
101         {
102             // We're assuming that the size of rx buffer equals 1, so we set rxBufferFull flag when a char is read by uart.
103             rxBufferFull.Value = true;
104             rxInterruptPending.Value = true;
105             UpdateInterrupts();
106         }
107 
QueueEmptied()108         protected override void QueueEmptied()
109         {
110             rxBufferFull.Value = false;
111         }
112 
UpdateInterrupts()113         private void UpdateInterrupts()
114         {
115             bool txInterrupt = txInterruptEnabled.Value && txInterruptPending.Value;
116             bool rxInterrupt = rxInterruptEnabled.Value && rxInterruptPending.Value;
117             TxInterrupt.Set(txInterrupt);
118             RxInterrupt.Set(rxInterrupt);
119         }
120 
121         public long Size => 0x1000;
122         public GPIO TxInterrupt { get; }
123         public GPIO RxInterrupt { get; }
124 
125         public override uint BaudRate => (baudRateDivValue.Value == 0) ? 0 : (uint)(frequency / baudRateDivValue.Value);
126         public override Bits StopBits => Bits.None;
127         public override Parity ParityBit => Parity.None;
128 
129         private IFlagRegisterField rxBufferFull;
130         private IFlagRegisterField txEnabled;
131         private IFlagRegisterField rxEnabled;
132         private IFlagRegisterField txInterruptEnabled;
133         private IFlagRegisterField rxInterruptEnabled;
134         private IFlagRegisterField txInterruptPending;
135         private IFlagRegisterField rxInterruptPending;
136         private IValueRegisterField baudRateDivValue;
137 
138         private readonly DoubleWordRegisterCollection registers;
139         private readonly ulong frequency;
140 
141         private enum Registers
142         {
143             Data = 0x00,
144             Status = 0x04,
145             Control = 0x08,
146             Interrupts = 0x0c,
147             BaudRateDiv = 0x10
148         }
149     }
150 }
151