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