1 // 2 // Copyright (c) 2020 LabMICRO FACET UNT 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.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.Peripherals.GPIOPort 16 { 17 public class LPC43xx_GPIO : BaseGPIOPort, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize 18 { LPC43xx_GPIO(IMachine machine)19 public LPC43xx_GPIO(IMachine machine) : base(machine, PinsPerPort * NumberOfPorts) 20 { 21 RegistersCollection = new DoubleWordRegisterCollection(this); 22 23 ports = new Port[NumberOfPorts]; 24 for(var portNumber = 0; portNumber < ports.Length; portNumber++) 25 { 26 ports[portNumber] = new Port(portNumber, this); 27 } 28 29 Reset(); 30 } 31 ReadDoubleWord(long offset)32 public uint ReadDoubleWord(long offset) 33 { 34 return RegistersCollection.Read(offset); 35 } 36 WriteDoubleWord(long offset, uint value)37 public void WriteDoubleWord(long offset, uint value) 38 { 39 RegistersCollection.Write(offset, value); 40 } 41 Reset()42 public override void Reset() 43 { 44 base.Reset(); 45 RegistersCollection.Reset(); 46 } 47 48 public long Size => 0x2380; 49 50 public DoubleWordRegisterCollection RegistersCollection { get; } 51 52 private readonly Port[] ports; 53 54 private const int NumberOfPorts = 8; 55 private const int PinsPerPort = 32; 56 57 private class Port 58 { Port(int portNumber, LPC43xx_GPIO parent)59 public Port(int portNumber, LPC43xx_GPIO parent) 60 { 61 this.portNumber = portNumber; 62 this.parent = parent; 63 64 parent.RegistersCollection.DefineRegister((uint)Registers.Direction + 4 * portNumber) 65 .WithValueField(0, PinsPerPort, out direction, name: $"GPIO_DIR{portNumber}", 66 writeCallback: (_, value) => RefreshConnectionsState()); 67 68 parent.RegistersCollection.DefineRegister((uint)Registers.Mask + 4 * portNumber) 69 .WithValueField(0, PinsPerPort, out mask, name: $"GPIO_MASK{portNumber}"); 70 71 parent.RegistersCollection.DefineRegister((uint)Registers.Pin + 4 * portNumber) 72 .WithValueField(0, PinsPerPort, out state, name: $"GPIO_PIN{portNumber}", 73 writeCallback: (_, value) => RefreshConnectionsState(), 74 valueProviderCallback: _ => GetStateValue()); 75 76 parent.RegistersCollection.DefineRegister((uint)Registers.MaskedPin + 4 * portNumber) 77 .WithValueField(0, PinsPerPort, name: $"GPIO_MPIN{portNumber}", 78 writeCallback: (_, value) => SetStateValue((uint)(state.Value & mask.Value | value & ~mask.Value)), 79 valueProviderCallback: _ => GetStateValue() & ~mask.Value); 80 81 parent.RegistersCollection.DefineRegister((uint)Registers.SetPin + 4 * portNumber) 82 .WithValueField(0, PinsPerPort, name: $"GPIO_SET{portNumber}", 83 writeCallback: (_, value) => SetStateValue((uint)(state.Value | value)), 84 valueProviderCallback: _ => GetStateValue()); 85 86 parent.RegistersCollection.DefineRegister((uint)Registers.ClearPin + 4 * portNumber) 87 .WithValueField(0, PinsPerPort, FieldMode.Write, name: $"GPIO_CLR{portNumber}", 88 writeCallback: (_, value) => SetStateValue((uint)(state.Value & ~value))); 89 90 parent.RegistersCollection.DefineRegister((uint)Registers.NegatePin + 4 * portNumber) 91 .WithValueField(0, PinsPerPort, FieldMode.Write, name: $"GPIO_NOT{portNumber}", 92 writeCallback: (_, value) => SetStateValue((uint)(state.Value ^ value))); 93 } 94 GetStateValue()95 private UInt32 GetStateValue() 96 { 97 UInt32 result = 0; 98 99 for(byte bitIndex = 0; bitIndex < PinsPerPort; bitIndex++) 100 { 101 var idx = PinsPerPort * portNumber + bitIndex; 102 var isOutputPin = BitHelper.IsBitSet(direction.Value, bitIndex); 103 104 BitHelper.SetBit(ref result, bitIndex, isOutputPin 105 ? parent.Connections[idx].IsSet 106 : parent.State[idx]); 107 } 108 109 return result; 110 } 111 SetStateValue(UInt32 value)112 private void SetStateValue(UInt32 value) 113 { 114 state.Value = value; 115 RefreshConnectionsState(); 116 } 117 RefreshConnectionsState()118 private void RefreshConnectionsState() 119 { 120 for(byte bitIndex = 0; bitIndex < PinsPerPort; bitIndex++) 121 { 122 if(BitHelper.IsBitSet(direction.Value, bitIndex)) 123 { 124 var connection = parent.Connections[PinsPerPort * portNumber + bitIndex]; 125 var pinState = BitHelper.IsBitSet(state.Value, bitIndex); 126 127 connection.Set(pinState); 128 } 129 } 130 } 131 132 private readonly int portNumber; 133 private readonly IValueRegisterField direction; 134 private readonly IValueRegisterField mask; 135 private readonly IValueRegisterField state; 136 137 private readonly LPC43xx_GPIO parent; 138 } 139 140 private enum Registers 141 { 142 Direction = 0x2000, 143 Mask = 0x2080, 144 Pin = 0x2100, 145 MaskedPin = 0x2180, 146 SetPin = 0x2200, 147 ClearPin = 0x2280, 148 NegatePin = 0x2300, 149 } 150 } 151 } 152