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.Collections.Generic; 8 using Antmicro.Renode.Peripherals.Bus; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Core; 11 12 namespace Antmicro.Renode.Peripherals.UART 13 { 14 // This peripheral only has byte-wide registers, but we define it as a double-word peripheral and 15 // translate byte->dword instead of dword->byte to avoid unhandled read warnings on dword access. 16 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)] 17 public class MiV_CoreUART : UARTBase, IDoubleWordPeripheral, IKnownSize 18 { MiV_CoreUART(IMachine machine, ulong clockFrequency)19 public MiV_CoreUART(IMachine machine, ulong clockFrequency) : base(machine) 20 { 21 this.clockFrequency = clockFrequency; 22 var registersMap = new Dictionary<long, ByteRegister> 23 { 24 {(long)Registers.TransmitData, new ByteRegister(this) 25 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, b) => { 26 this.TransmitCharacter((byte)b); 27 })}, 28 29 {(long)Registers.ReceiveData, new ByteRegister(this) 30 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => { 31 this.TryGetCharacter(out var character); 32 return character; 33 })}, 34 35 {(long)Registers.Control1, new ByteRegister(this) 36 .WithValueField(0, 8, out baudValue0to7, name: "BAUD_VALUE_0_7")}, 37 38 {(long)Registers.Control2, new ByteRegister(this) 39 .WithFlag(0, name: "BIT8") // The register only provides a read-back function 40 .WithFlag(1, out parityFlagField, name: "PARITY_EN") 41 .WithFlag(2, out oddNEventFlagField, name: "ODD_N_EVEN") 42 .WithValueField(3, 5, out baudValue8to12, name: "BAUD_VALUE_8_12")}, 43 44 {(long)Registers.Control3, new ByteRegister(this) 45 .WithValueField(0, 3, out baudValueFractionField, name: "BAUD_VAL_FRACTION") 46 // bits 7:3 not mentioned in the documentation 47 }, 48 49 {(long)Registers.Status, new ByteRegister(this) 50 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true, name: "TXRDY") 51 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => Count > 0, name: "RXRDY") 52 .WithFlag(2, FieldMode.Read, name: "PARITY_ERR") 53 .WithFlag(3, FieldMode.Read, name: "OVERFLOW") 54 .WithFlag(4, FieldMode.Read, name: "FRAMING_ERROR")} 55 // bits 7:5 not used according to the documentation 56 }; 57 58 registers = new ByteRegisterCollection(this, registersMap); 59 } 60 Reset()61 public override void Reset() 62 { 63 base.Reset(); 64 registers.Reset(); 65 } 66 ReadDoubleWord(long offset)67 public uint ReadDoubleWord(long offset) 68 { 69 return registers.Read(offset); 70 } 71 WriteDoubleWord(long offset, uint value)72 public void WriteDoubleWord(long offset, uint value) 73 { 74 registers.Write(offset, (byte)value); 75 } 76 77 public long Size => 0x18; 78 79 public override Bits StopBits => Bits.One; 80 81 public override Parity ParityBit => parityFlagField.Value ? (oddNEventFlagField.Value ? Parity.Odd : Parity.Even) : Parity.None; 82 83 public override uint BaudRate => (uint)((clockFrequency / (16 * ((baudValue8to12.Value << 8) + baudValue0to7.Value + 1))) + baudValueFractionField.Value * 0.125); 84 CharWritten()85 protected override void CharWritten() 86 { 87 // intentionally left blank 88 } 89 QueueEmptied()90 protected override void QueueEmptied() 91 { 92 // intentionally left blank 93 } 94 95 private readonly IValueRegisterField baudValue0to7; 96 private readonly IFlagRegisterField parityFlagField; 97 private readonly IFlagRegisterField oddNEventFlagField; 98 private readonly IValueRegisterField baudValue8to12; 99 private readonly IValueRegisterField baudValueFractionField; 100 private readonly ByteRegisterCollection registers; 101 private readonly ulong clockFrequency; 102 103 private enum Registers : long 104 { 105 TransmitData = 0x0, 106 ReceiveData = 0x04, 107 Control1 = 0x08, 108 Control2 = 0x0C, 109 Status = 0x10, 110 Control3 = 0x14 111 } 112 } 113 } 114