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