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