1 // 2 // Copyright (c) 2010-2019 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 14 namespace Antmicro.Renode.Peripherals.UART 15 { 16 public class Murax_UART : UARTBase, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 17 { Murax_UART(IMachine machine)18 public Murax_UART(IMachine machine) : base(machine) 19 { 20 RegistersCollection = new DoubleWordRegisterCollection(this); 21 DefineRegisters(); 22 } 23 ReadDoubleWord(long offset)24 public uint ReadDoubleWord(long offset) 25 { 26 return RegistersCollection.Read(offset); 27 } 28 WriteDoubleWord(long offset, uint value)29 public void WriteDoubleWord(long offset, uint value) 30 { 31 RegistersCollection.Write(offset, value); 32 } 33 Reset()34 public override void Reset() 35 { 36 base.Reset(); 37 RegistersCollection.Reset(); 38 UpdateInterrupts(); 39 } 40 41 public long Size => 0x10; 42 43 public override Bits StopBits => stopBits; 44 45 public override Parity ParityBit => parity; 46 47 public override uint BaudRate => 0; 48 49 public GPIO IRQ { get; } = new GPIO(); 50 51 public DoubleWordRegisterCollection RegistersCollection { get; private set; } 52 CharWritten()53 protected override void CharWritten() 54 { 55 UpdateInterrupts(); 56 } 57 QueueEmptied()58 protected override void QueueEmptied() 59 { 60 UpdateInterrupts(); 61 } 62 DefineRegisters()63 private void DefineRegisters() 64 { 65 Registers.Data.Define(this) 66 .WithValueField(0, 8, writeCallback: (_, value) => this.TransmitCharacter((byte)value), 67 valueProviderCallback: _ => { 68 if(!TryGetCharacter(out var character)) 69 { 70 this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO."); 71 } 72 return character; 73 }) 74 ; 75 76 Registers.Status.Define(this) 77 .WithTag("txInterruptEnabled", 0, 1) 78 .WithFlag(1, out rxInterruptEnabled) 79 .WithReservedBits(2, 6) 80 .WithTag("txInterruptActive", 8, 1) 81 .WithFlag(9, FieldMode.Read, name: "rxInterruptActive", valueProviderCallback: _ => Count != 0) 82 .WithReservedBits(10, 6) 83 .WithTag("txFifoOccupancy", 16, 8) 84 .WithTag("rxFifoOccupancy", 24, 8) 85 .WithWriteCallback((_, __) => UpdateInterrupts()) 86 ; 87 88 Registers.FrameConfig.Define(this) 89 .WithTag("frameDataLength", 0, 8) 90 .WithEnumField<DoubleWordRegister, InnerParity>(8, 2, name: "parity", 91 writeCallback: (_, val) => 92 { 93 switch(val) 94 { 95 case InnerParity.None: 96 parity = Parity.None; 97 break; 98 case InnerParity.Even: 99 parity = Parity.Even; 100 break; 101 case InnerParity.Odd: 102 parity = Parity.Odd; 103 break; 104 default: 105 this.Log(LogLevel.Warning, "Unexpected parity value: {0}", val); 106 break; 107 } 108 }) 109 .WithEnumField<DoubleWordRegister, InnerStopBits>(16, 1, name: "stopBits", 110 writeCallback: (_, val) => 111 { 112 switch(val) 113 { 114 case InnerStopBits.One: 115 stopBits = Bits.One; 116 break; 117 case InnerStopBits.Two: 118 stopBits = Bits.Two; 119 break; 120 } 121 }); 122 ; 123 } 124 UpdateInterrupts()125 private void UpdateInterrupts() 126 { 127 var eventPending = (rxInterruptEnabled.Value && Count != 0); 128 this.Log(LogLevel.Info, "Setting interrupt to: {0}", eventPending); 129 IRQ.Set(eventPending); 130 } 131 132 private IFlagRegisterField rxInterruptEnabled; 133 private Bits stopBits; 134 private Parity parity; 135 136 private enum Registers 137 { 138 Data = 0x0, 139 Status = 0x4, 140 ClockDivider = 0x8, 141 FrameConfig = 0xC 142 } 143 144 private enum InnerParity 145 { 146 None, 147 Even, 148 Odd 149 } 150 151 private enum InnerStopBits 152 { 153 One, 154 Two 155 } 156 } 157 } 158