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 Antmicro.Renode.Logging;
9 using Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 
13 namespace Antmicro.Renode.Peripherals.UART
14 {
15     [AllowedTranslations(AllowedTranslation.DoubleWordToByte | AllowedTranslation.WordToByte)]
16     public class SAMD5_UART : UARTBase, IBytePeripheral, IKnownSize, IProvidesRegisterCollection<ByteRegisterCollection>
17     {
SAMD5_UART(IMachine machine)18         public SAMD5_UART(IMachine machine) : base(machine)
19         {
20             RegistersCollection = new ByteRegisterCollection(this);
21             IRQ = new GPIO();
22             DefineRegisters();
23             Reset();
24         }
25 
ReadByte(long offset)26         public byte ReadByte(long offset)
27         {
28             return RegistersCollection.Read(offset);
29         }
30 
WriteByte(long offset, byte value)31         public void WriteByte(long offset, byte value)
32         {
33             RegistersCollection.Write(offset, value);
34         }
35 
Reset()36         public override void Reset()
37         {
38             base.Reset();
39             RegistersCollection.Reset();
40         }
41 
42         public GPIO IRQ { get; }
43 
44         public ByteRegisterCollection RegistersCollection { get; }
45 
46         public long Size => 0x100;
47 
48         public override Bits StopBits => Bits.None;
49 
50         public override Parity ParityBit => Parity.None;
51 
52         public override uint BaudRate => 0;
53 
CharWritten()54         protected override void CharWritten()
55         {
56             receiveStart.Value = true;
57             receiveComplete.Value = true;
58             UpdateInterrupt();
59         }
60 
QueueEmptied()61         protected override void QueueEmptied()
62         {
63             receiveStart.Value = false;
64             receiveComplete.Value = false;
65             UpdateInterrupt();
66         }
67 
DefineRegisters()68         private void DefineRegisters()
69         {
70             Registers.DataRegister0.Define(this)
71                 .WithValueField(0, 8, name: "DATA",
72                     valueProviderCallback: _ =>
73                     {
74                         if(TryGetCharacter(out var b))
75                         {
76                             return b;
77                         }
78 
79                         this.Log(LogLevel.Warning, "Tried to read DATA, but there is nothing in the queue");
80                         return 0;
81                     },
82                     writeCallback: (_, val) =>
83                     {
84                         TransmitCharacter((byte)val);
85                         transmitComplete.Value = true;
86                         UpdateInterrupt();
87                     })
88             ;
89 
90             Registers.InterruptFlag.Define(this)
91                 .WithFlag(0, FieldMode.Read, name: "DRE - Data Register Empty", valueProviderCallback: _ => Count == 0)
92                 .WithFlag(1, out transmitComplete, FieldMode.Read | FieldMode.WriteOneToClear, name: "TXC - Transmit Complete")
93                 .WithFlag(2, out receiveComplete, FieldMode.Read, name: "RXC - Receive Complete")
94                 .WithFlag(3, out receiveStart, FieldMode.Read | FieldMode.WriteOneToClear, name: "RXS - Receive Start")
95                 .WithTaggedFlag("CTSIC - Clear To Send Input Change", 4)
96                 .WithTaggedFlag("RXBRK - Receive Break", 5)
97                 .WithReservedBits(6, 1)
98                 .WithTaggedFlag("ERROR", 7)
99                 .WithWriteCallback((_, __) => UpdateInterrupt())
100             ;
101 
102             Registers.InterruptEnableClear.Define(this)
103                 .WithFlag(0, out dataRegisterEmptyInterruptEnable, FieldMode.Read | FieldMode.WriteOneToClear, name: "DRE - Data Register Empty Interrupt Enable")
104                 .WithFlag(1, out transmitCompleteInterruptEnable, FieldMode.Read | FieldMode.WriteOneToClear, name: "TXC - Transmit Complete Interrupt Enable")
105                 .WithFlag(2, out receiveCompleteInterruptEnable, FieldMode.Read | FieldMode.WriteOneToClear, name: "RXC - Receive Complete Interrupt Enable")
106                 .WithFlag(3, out receiveStartInterruptEnable, FieldMode.Read | FieldMode.WriteOneToClear, name: "RXS - Receive Start Interrupt Enable")
107                 .WithTaggedFlag("CTSIC - Clear To Send Input Change Interrupt Enable", 4)
108                 .WithTaggedFlag("RXBRK - Receive Break Interrupt Enable", 5)
109                 .WithReservedBits(6, 1)
110                 .WithTaggedFlag("ERROR Interrupt Enable", 7)
111                 .WithWriteCallback((_, __) => UpdateInterrupt())
112             ;
113 
114             Registers.InterruptEnableSet.Define(this)
115                 .WithFlag(0, name: "DRE - Data Register Empty Interrupt Enable", valueProviderCallback: _ => dataRegisterEmptyInterruptEnable.Value, writeCallback: (_, val) => { dataRegisterEmptyInterruptEnable.Value |= val; })
116                 .WithFlag(1, name: "TXC - Transmit Complete Interrupt Enable", valueProviderCallback: _ => transmitCompleteInterruptEnable.Value, writeCallback: (_, val) => { transmitCompleteInterruptEnable.Value |= val; })
117                 .WithFlag(2, name: "RXC - Receive Complete Interrupt Enable", valueProviderCallback: _ => receiveCompleteInterruptEnable.Value, writeCallback: (_, val) => { receiveCompleteInterruptEnable.Value |= val; })
118                 .WithFlag(3, name: "RXS - Receive Start Interrupt Enable", valueProviderCallback: _ => receiveStartInterruptEnable.Value, writeCallback: (_, val) => { receiveStartInterruptEnable.Value |= val; })
119                 .WithTaggedFlag("CTSIC - Clear To Send Input Change Interrupt Enable", 4)
120                 .WithTaggedFlag("RXBRK - Receive Break Interrupt Enable", 5)
121                 .WithReservedBits(6, 1)
122                 .WithTaggedFlag("ERROR Interrupt Enable", 7)
123                 .WithWriteCallback((_, __) => UpdateInterrupt())
124             ;
125         }
126 
UpdateInterrupt()127         private void UpdateInterrupt()
128         {
129             var flag = (dataRegisterEmptyInterruptEnable.Value && Count == 0)
130                 || (transmitCompleteInterruptEnable.Value && transmitComplete.Value)
131                 || (receiveCompleteInterruptEnable.Value && receiveComplete.Value)
132                 || (receiveStartInterruptEnable.Value && receiveStart.Value);
133 
134             this.Log(LogLevel.Debug, "IRQ set to: {0}", flag);
135             IRQ.Set(flag);
136         }
137 
138         private IFlagRegisterField transmitComplete;
139         private IFlagRegisterField receiveComplete;
140         private IFlagRegisterField receiveStart;
141 
142         private IFlagRegisterField dataRegisterEmptyInterruptEnable;
143         private IFlagRegisterField transmitCompleteInterruptEnable;
144         private IFlagRegisterField receiveCompleteInterruptEnable;
145         private IFlagRegisterField receiveStartInterruptEnable;
146 
147         private enum Registers : long
148         {
149             ControlA0 = 0x0,
150             ControlA1 = 0x1,
151             ControlA2 = 0x2,
152             ControlA3 = 0x3,
153             ControlB0 = 0x4,
154             ControlB1 = 0x5,
155             ControlB2 = 0x6,
156             ControlB3 = 0x7,
157             ControlC0 = 0x8,
158             ControlC1 = 0x9,
159             ControlC2 = 0xA,
160             ControlC3 = 0xB,
161             Baud0 = 0xC,
162             Baud1 = 0xD,
163             ReceivePulseLength = 0xE,
164             InterruptEnableClear = 0x14,
165             InterruptEnableSet = 0x16,
166             InterruptFlag = 0x18,
167             Status0 = 0x1A,
168             Status1 = 0x1B,
169             SynchronizationBusy0 = 0x1C,
170             SynchronizationBusy1 = 0x1D,
171             SynchronizationBusy2 = 0x1E,
172             SynchronizationBusy3 = 0x1F,
173             ReceiveErrorCount = 0x20,
174             Length0 = 0x22,
175             Length1 = 0x23,
176             DataRegister0 = 0x28,
177             DataRegister1 = 0x29,
178             DataRegister2 = 0x2A,
179             DataRegister3 = 0x2B,
180             DebugControl = 0x30
181         }
182     }
183 }
184 
185