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 System;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Utilities;
13 using Antmicro.Renode.Utilities.Collections;
14 using Antmicro.Renode.Logging;
15 
16 namespace Antmicro.Renode.Peripherals.UART
17 {
18     public class NPCX_UART : UARTBase, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize
19     {
NPCX_UART(Machine machine)20         public NPCX_UART(Machine machine) : base(machine)
21         {
22             IRQ = new GPIO();
23             DMAReceive = new GPIO();
24 
25             RegistersCollection = new ByteRegisterCollection(this, BuildRegisterMap());
26 
27             Reset();
28         }
29 
ReadByte(long offset)30         public byte ReadByte(long offset)
31         {
32             return RegistersCollection.Read(offset);
33         }
34 
Reset()35         public override void Reset()
36         {
37             stopBits = false;
38             parityEnable = false;
39             parityMode = ParityMode.Odd;
40             divisor = 1;
41             rxFullLevelSelect = 1;
42 
43             base.Reset();
44             RegistersCollection.Reset();
45             IRQ.Unset();
46         }
47 
WriteByte(long offset, byte value)48         public void WriteByte(long offset, byte value)
49         {
50             RegistersCollection.Write(offset, value);
51         }
52 
53         public long Size => 0x2D;
54         public GPIO IRQ { get; }
55         public GPIO DMAReceive { get; }
56 
57         public ByteRegisterCollection RegistersCollection { get; }
58 
59         public override Bits StopBits => stopBits ? Bits.Two : Bits.One;
60 
61         public override Parity ParityBit
62         {
63             get
64             {
65                 if(!parityEnable)
66                 {
67                     return Parity.None;
68                 }
69 
70                 switch(parityMode)
71                 {
72                     case ParityMode.Odd:
73                         return Parity.Odd;
74                     case ParityMode.Even:
75                         return Parity.Even;
76                     case ParityMode.Mark:
77                         return Parity.Forced1;
78                     case ParityMode.Space:
79                         return Parity.Forced0;
80                 }
81 
82                 throw new Exception("Unreachable");
83             }
84         }
85 
86         // It's supposed to be APB4_CLK / (16 * DIV * P), where:
87         //     APB4_CLK is the APB4 clock frequency
88         //     DIV = UDIV10-0 + 1
89         //     P is the "Prescaler Factor" selected by UPSC field
90         public override uint BaudRate => 115200;
91 
CharWritten()92         protected override void CharWritten()
93         {
94             UpdateInterrupts();
95             if(receiveDMAEnabled.Value)
96             {
97                 // This blink is used to signal the DMA that it should perform the peripheral -> memory transaction now.
98                 // Without this signal DMA will never move data from the receive FIFO to memory.
99                 // See NPCX_MDMA:OnGPIO
100                 DMAReceive.Blink();
101             }
102         }
103 
QueueEmptied()104         protected override void QueueEmptied()
105         {
106             // intentionally left blank
107         }
108 
UpdateInterrupts()109         private void UpdateInterrupts()
110         {
111             var rxNonEmpty = rxNonEmptyInterruptEnable.Value && Count != 0;
112             var rxFullLevel = rxFullLevelInterruptEnable.Value && RxFullLevelStatus;
113 
114             var status = rxNonEmpty || rxFullLevel || transmitFifoEmptyInterruptEnable.Value || noTransmitInProgressInterruptEnable.Value;
115             this.Log(LogLevel.Noisy, "IRQ set to {0}", status);
116             IRQ.Set(status);
117         }
118 
BuildRegisterMap()119         private Dictionary<long, ByteRegister> BuildRegisterMap()
120         {
121             var registerMap = new Dictionary<long, ByteRegister>
122             {
123                 {(long)Registers.TransmitBuffer, new ByteRegister(this)
124                     .WithValueField(0, 8, FieldMode.Write, name: "UTBUF",
125                         writeCallback: (_, value) => this.TransmitCharacter((byte)value)
126                     )
127                     .WithWriteCallback((_, __) => UpdateInterrupts())
128                 },
129                 {(long)Registers.ReceiveBuffer, new ByteRegister(this)
130                     .WithValueField(0, 8, FieldMode.Read, name: "URBUF",
131                         valueProviderCallback: _ =>
132                         {
133                             if(!TryGetCharacter(out var character))
134                             {
135                                 return 0xFF;
136                             }
137                             return character;
138                         }
139                     )
140                     .WithReadCallback((_, __) => UpdateInterrupts())
141                 },
142                 {(long)Registers.Status, new ByteRegister(this)
143                     .WithReservedBits(5, 3)
144                     .WithTaggedFlag("BKD (Break Detect)", 4)
145                     .WithReservedBits(3, 1)
146                     .WithTaggedFlag("DOE (Data Overrun Error)", 2)
147                     .WithTaggedFlag("FE (Framing Error)", 1)
148                     .WithTaggedFlag("PE (Parity Error)", 0)
149                 },
150                 {(long)Registers.FrameSelect, new ByteRegister(this)
151                     .WithReservedBits(7, 1)
152                     .WithFlag(6, name: "PEN (Parity Enable)",
153                         valueProviderCallback: _ => parityEnable,
154                         writeCallback: (_, val) => parityEnable = val
155                     )
156                     .WithEnumField<ByteRegister, ParityMode>(4, 2, name: "PSEL (Parity Select)",
157                         valueProviderCallback: _ => parityMode,
158                         writeCallback: (_, val) => parityMode = val
159                     )
160                     .WithReservedBits(3, 1)
161                     .WithFlag(2, name: "STP (Stop Bits)",
162                         valueProviderCallback: _ => stopBits,
163                         writeCallback: (_, val) => stopBits = val
164                     )
165                     .WithReservedBits(0, 2)
166                 },
167                 {(long)Registers.ModeSelect, new ByteRegister(this)
168                     .WithReservedBits(6, 2)
169                     .WithFlag(5, out receiveDMAEnabled, name: "ERD (Enable Receive DMA)")
170                     .WithTaggedFlag("ETD (Enable Transmit DMA)", 4)
171                     .WithReservedBits(3, 1)
172                     .WithTaggedFlag("BRK (Break Transmit)", 2)
173                     .WithReservedBits(0, 2)
174                 },
175                 {(long)Registers.BaudRateDivisor, new ByteRegister(this)
176                     .WithValueField(0, 8, name: "UDIV7-0 (UART Divisor Bits 7-0)",
177                         valueProviderCallback: _ => divisor,
178                         writeCallback: (_, val) => divisor = (divisor & 0x700) | (uint)val
179                     )
180                 },
181                 {(long)Registers.BaudRatePrescaler, new ByteRegister(this)
182                     .WithTag("UPSC (Prescaler Select)", 3, 5)
183                     .WithValueField(0, 3, name: "UDIV10-8 (UART Divisor Bits 10-8)",
184                         valueProviderCallback: _ => divisor >> 8,
185                         writeCallback: (_, val) => divisor = (divisor & 0xff) | ((uint)val << 8)
186                     )
187                 },
188                 {(long)Registers.TransmitStatus, new ByteRegister(this)
189                     .WithFlag(7, FieldMode.Read, name: "XMIP (No Transmit in Progress)",
190                         // 0: CR_UART is transmitting.
191                         // 1: CR_UART is not transmitting (default).
192                         valueProviderCallback: _ => true
193                     )
194                     .WithFlag(6, FieldMode.Read, name: "TFIFO_EMPTY_STS (Transmit FIFO Empty Status)",
195                         valueProviderCallback: _ => true
196                     )
197                     .WithTaggedFlag("TEMPTY_LEVEL_STS (Transmit FIFO Empty Level Status)", 5)
198                     .WithValueField(0, 5, FieldMode.Read, name: "TEMPTY_LEVEL (Transmit FIFO Empty Level)",
199                         valueProviderCallback: _ => (ulong)MaxQueueCount
200                     )
201                 },
202                 {(long)Registers.ReceiveStatus, new ByteRegister(this)
203                     .WithTaggedFlag("ERR (Receive Error)", 7)
204                     .WithFlag(6, FieldMode.Read, name: "RFIFO_NEMPTY_STS (Receive FIFO Not Empty Status)",
205                         valueProviderCallback: _ => Count != 0
206                     )
207                     .WithFlag(5, FieldMode.Read, name: "RFULL_LEVEL_STS (Receive FIFO Full Level Status)",
208                         valueProviderCallback: _ => RxFullLevelStatus
209                     )
210                     .WithValueField(0, 5, FieldMode.Read, name: "RFULL_LEVEL (Receive FIFO Full Level)",
211                         valueProviderCallback: _ => (ulong)(Count >= MaxQueueCount ? MaxQueueCount : Count)
212                     )
213                 },
214                 {(long)Registers.TransmitControl, new ByteRegister(this)
215                     .WithFlag(7, out noTransmitInProgressInterruptEnable, name: "XMIP_EN (No Transmit in Progress Interrupt Enable)")
216                     .WithFlag(6, out transmitFifoEmptyInterruptEnable, name: "TFIFO_EMPTY_EN (Transmit FIFO Empty Interrupt Enable)")
217                     .WithTaggedFlag("TEMPTY_LEVEL_EN (Transmit FIFO Empty Level Interrupt Enable)", 5)
218                     .WithTag("TEMPTY_LEVEL_SEL (Transmit FIFO Empty Level Select)", 0, 5)
219                     .WithWriteCallback((_, __) => UpdateInterrupts())
220                 },
221                 {(long)Registers.ReceiveControl, new ByteRegister(this)
222                     .WithTaggedFlag("ERR_EN (Receive Error Interrupt Enable)", 7)
223                     .WithFlag(6, out rxNonEmptyInterruptEnable, name: "RFIFO_NEMPTY_EN (Receive FIFO Not Empty Status Interrupt Enable)")
224                     .WithFlag(5, out rxFullLevelInterruptEnable, name: "RFULL_LEVEL_EN (Receive FIFO Full Level Status Interrupt Enable)")
225                     .WithValueField(0, 5, name: "RFULL_LEVEL_SEL (Receive FIFO Full Level Select)",
226                         valueProviderCallback: _ => (ulong)rxFullLevelSelect,
227                         writeCallback: (_, val) => rxFullLevelSelect = (int)val
228                     )
229                     .WithWriteCallback((_, __) => UpdateInterrupts())
230                 },
231                 {(long)Registers.Control, new ByteRegister(this)
232                     .WithReservedBits(7, 1)
233                     .WithTaggedFlag("COM_FDBK_EN (Common Mode Feedback Enable)", 6)
234                     .WithTaggedFlag("CR_SOUT_PP (CR_SOUT Common Push-Pull Select)", 5)
235                     .WithTaggedFlag("CR_SOUT_COM (CR_SOUT Common Mode Select)", 4)
236                     .WithTaggedFlag("CR_SIN_PP (CR_SIN Common Push-Pull Select)", 3)
237                     .WithTaggedFlag("CR_SIN_COM (CR_SIN Common Mode Select)", 2)
238                     .WithTaggedFlag("CR_SOUT_INV (CR_SOUT Signal Invert)", 1)
239                     .WithTaggedFlag("CR_SIN_INV (CR_SIN Signal Invert)", 0)
240                     .WithWriteCallback((_, __) => UpdateInterrupts())
241                 },
242             };
243 
244             return registerMap;
245         }
246 
247         private bool RxFullLevelStatus => Count >= rxFullLevelSelect;
248 
249         private IFlagRegisterField receiveDMAEnabled;
250 
251         private bool stopBits;
252         private bool parityEnable;
253         private ParityMode parityMode;
254         private uint divisor;
255         private int rxFullLevelSelect;
256 
257         private IFlagRegisterField rxNonEmptyInterruptEnable;
258         private IFlagRegisterField rxFullLevelInterruptEnable;
259         private IFlagRegisterField noTransmitInProgressInterruptEnable;
260         private IFlagRegisterField transmitFifoEmptyInterruptEnable;
261 
262         private const int MaxQueueCount = 16;
263 
264         private enum ParityMode
265         {
266             Odd   = 0b00,
267             Even  = 0b01,
268             Mark  = 0b10,
269             Space = 0b11,
270         }
271 
272         private enum Registers : long
273         {
274             TransmitBuffer    = 0x00, // UTBUF
275             ReceiveBuffer     = 0x02, // URBUF
276             Status            = 0x06, // USTAT
277             FrameSelect       = 0x08, // UFRS
278             ModeSelect        = 0x0A, // UMDSL
279             BaudRateDivisor   = 0x0C, // UBAUD
280             BaudRatePrescaler = 0x0E, // UPSR
281             TransmitStatus    = 0x20, // UFTSTS
282             ReceiveStatus     = 0x22, // UFRSTS
283             TransmitControl   = 0x24, // UFTCTL
284             ReceiveControl    = 0x26, // UFRCTL
285             Control           = 0x2C, // UCNTL
286         }
287     }
288 }
289