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 Antmicro.Renode.Peripherals.Bus; 8 using Antmicro.Renode.Core; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Utilities; 13 using System; 14 15 namespace Antmicro.Renode.Peripherals.UART 16 { 17 public class KB1200_UART : UARTBase, IDoubleWordPeripheral, IKnownSize 18 { KB1200_UART(IMachine machine)19 public KB1200_UART(IMachine machine) : base(machine) 20 { 21 var registersMap = new Dictionary<long, DoubleWordRegister>(); 22 23 registersMap.Add((long)Registers.Configuration, new DoubleWordRegister(this) 24 .WithTaggedFlag("SERIE_RX_ENABLE", 0) 25 .WithFlag(1, out serieTxEnable, name: "SERIE_TX_ENABLE") 26 .WithTag("Parity", 2, 2) 27 .WithReservedBits(6, 10) 28 .WithTag("Baud Rate", 16, 16) 29 ); 30 31 registersMap.Add((long)Registers.InterruptEnable, new DoubleWordRegister(this) 32 .WithFlag(0, out serieIrqRxEnable, name: "SERIE_IRQ_RX_ENABLE") 33 .WithFlag(1, out serieIrqTxEnable, name: "SERIE_IRQ_TX_ENABLE") 34 .WithTaggedFlag("SERIE_IRQ_RX_ERROR", 2) 35 .WithReservedBits(3, 29) 36 .WithWriteCallback((_, __) => UpdateInterrupts()) 37 ); 38 39 registersMap.Add((long)Registers.PendingFlag, new DoubleWordRegister(this) 40 .WithFlag(0, out serpfRxCntFull, 41 FieldMode.Read | FieldMode.WriteOneToClear, 42 name: "SERPF_RX_CNT_FULL") 43 // In Renode, the TX happens instantly 44 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => true, name: "SEPRF_TX_EMPTY") 45 .WithTaggedFlag("SERPF_RX_ERROR", 2) 46 .WithReservedBits(4, 28) 47 .WithWriteCallback((_, __) => UpdateInterrupts()) 48 ); 49 50 registersMap.Add((long)Registers.Status, new DoubleWordRegister(this) 51 .WithTaggedFlag("TX_FULL", 0) 52 .WithTaggedFlag("TX_OVERRUN", 1) 53 .WithTaggedFlag("TX_BUSY", 2) 54 .WithReservedBits(3, 1) 55 .WithFlag(4, FieldMode.Read, name: "RX_EMPTY", 56 valueProviderCallback: _ => receiveQueue.Count == 0) 57 .WithTaggedFlag("RX_OVERRUN", 5) 58 .WithTaggedFlag("RX_BUSY", 6) 59 .WithTaggedFlag("RX_TIMEOUT", 7) 60 .WithTaggedFlag("PARITY_ERROR", 8) 61 .WithTaggedFlag("FRAME_ERROR", 9) 62 .WithReservedBits(10, 22) 63 ); 64 65 registersMap.Add((long)Registers.RxDataBuffer, new DoubleWordRegister(this) 66 .WithValueField(0, 8, 67 FieldMode.Read, 68 name: "SERTBUF", 69 valueProviderCallback: _ => HandleReceiveData()) 70 .WithReservedBits(8, 24) 71 ); 72 73 registersMap.Add((long)Registers.TxDataBuffer, new DoubleWordRegister(this) 74 .WithValueField(0, 8, 75 FieldMode.Write, 76 name: "SERRBUF", 77 writeCallback: (_, v) => HandleTransmitData((uint)v)) 78 .WithReservedBits(8, 24) 79 ); 80 81 registersMap.Add((long)Registers.Control, new DoubleWordRegister(this) 82 .WithTag("SERCTRL", 0, 3) 83 .WithReservedBits(3, 29) 84 ); 85 86 registers = new DoubleWordRegisterCollection(this, registersMap); 87 } 88 WriteChar(byte value)89 public override void WriteChar(byte value) 90 { 91 if(!IsReceiveEnabled) 92 { 93 this.Log(LogLevel.Warning, "Char was received, but the receiver (or the whole USART) is not enabled. Ignoring."); 94 return; 95 } 96 // We assume FIFO size is 1 97 serpfRxCntFull.Value = true; 98 receiveQueue.Enqueue(value); 99 UpdateInterrupts(); 100 } 101 UpdateInterrupts()102 public void UpdateInterrupts() 103 { 104 bool irqPending = (serieIrqRxEnable.Value && serpfRxCntFull.Value) 105 || (serieIrqTxEnable.Value); 106 this.Log(LogLevel.Noisy, "Setting IRQ: {0}", irqPending); 107 IRQ.Set(irqPending); 108 } 109 Reset()110 public override void Reset() 111 { 112 base.Reset(); 113 registers.Reset(); 114 receiveQueue.Clear(); 115 IRQ.Set(false); 116 } 117 ReadDoubleWord(long offset)118 public uint ReadDoubleWord(long offset) 119 { 120 return registers.Read(offset); 121 } 122 WriteDoubleWord(long offset, uint val)123 public void WriteDoubleWord(long offset, uint val) 124 { 125 registers.Write(offset, val); 126 } 127 128 public GPIO IRQ { get; } = new GPIO(); 129 130 public override Bits StopBits { get; } 131 132 public override Parity ParityBit { get; } 133 134 public override uint BaudRate => 115200; 135 136 public long Size => 0x1C; 137 CharWritten()138 protected override void CharWritten() 139 { 140 // intentionally left blank 141 } 142 QueueEmptied()143 protected override void QueueEmptied() 144 { 145 // intentionally left blank 146 } 147 HandleReceiveData()148 private uint HandleReceiveData() 149 { 150 if(receiveQueue.TryDequeue(out var result)) 151 { 152 UpdateInterrupts(); 153 } 154 return result; 155 } 156 HandleTransmitData(uint value)157 private void HandleTransmitData(uint value) 158 { 159 if(!serieTxEnable.Value) 160 { 161 this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring."); 162 return; 163 } 164 TransmitCharacter((byte)value); 165 } 166 167 private readonly IFlagRegisterField serieIrqRxEnable; 168 private readonly IFlagRegisterField serieTxEnable; 169 private readonly IFlagRegisterField serieIrqTxEnable; 170 private readonly IFlagRegisterField serpfRxCntFull; 171 172 private readonly Queue<byte> receiveQueue = new Queue<byte>(); 173 174 private readonly DoubleWordRegisterCollection registers; 175 176 private enum Registers 177 { 178 Configuration = 0x00, 179 InterruptEnable = 0x04, 180 PendingFlag = 0x08, 181 Status = 0x0C, 182 RxDataBuffer = 0x10, 183 TxDataBuffer = 0x14, 184 Control = 0x18 185 } 186 } 187 } 188