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;
8 using System.Linq;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 
15 namespace Antmicro.Renode.Peripherals.GPIOPort
16 {
17     public class ARM_AHB_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
18     {
ARM_AHB_GPIO(IMachine machine, uint alternateFunctionResetValue = 0, bool hasDedicatedIRQs = false)19         public ARM_AHB_GPIO(IMachine machine, uint alternateFunctionResetValue = 0, bool hasDedicatedIRQs = false) : base(machine, NumberOfGPIOs)
20         {
21             this.alternateFunctionResetValue = alternateFunctionResetValue;
22             this.hasDedicatedIRQs = hasDedicatedIRQs;
23             RegistersCollection = new DoubleWordRegisterCollection(this);
24 
25             if(hasDedicatedIRQs)
26             {
27                 DedicatedIRQs = new GPIO[NumberOfDedicatedIRQs];
28                 DedicatedIRQs[0] = DedicatedIRQ0;
29                 DedicatedIRQs[1] = DedicatedIRQ1;
30                 DedicatedIRQs[2] = DedicatedIRQ2;
31                 DedicatedIRQs[3] = DedicatedIRQ3;
32                 DedicatedIRQs[4] = DedicatedIRQ4;
33                 DedicatedIRQs[5] = DedicatedIRQ5;
34                 DedicatedIRQs[6] = DedicatedIRQ6;
35                 DedicatedIRQs[7] = DedicatedIRQ7;
36             }
37 
38             DefineRegisters();
39             Reset();
40         }
41 
ReadDoubleWord(long offset)42         public uint ReadDoubleWord(long offset)
43         {
44             return RegistersCollection.Read(offset);
45         }
46 
WriteDoubleWord(long offset, uint value)47         public void WriteDoubleWord(long offset, uint value)
48         {
49             RegistersCollection.Write(offset, value);
50         }
51 
OnGPIO(int number, bool value)52         public override void OnGPIO(int number, bool value)
53         {
54             var previousValue = State[number];
55             base.OnGPIO(number, value);
56             OnPinStateChanged(number, previousValue, value);
57         }
58 
Reset()59         public override void Reset()
60         {
61             bool[] cachedState = new bool[NumberOfGPIOs];
62 
63             Array.Copy(State, cachedState, State.Length);
64             base.Reset();
65             RegistersCollection.Reset();
66             UpdateInterrupts();
67 
68             for(byte i = 0; i < NumberOfGPIOs; i++)
69             {
70                 if(!softReset.Value)
71                 {
72                     pinAlternateFunctionEnabled[i] = BitHelper.IsBitSet(alternateFunctionResetValue, i);
73                     pinOutputEnabled[i] = false;
74                     pullEnable[i].Value = false;
75                     pullUpDown[i].Value = false;
76                     interruptEnabled[i] = false;
77                     interruptStatus[i] = false;
78                 }
79                 else
80                 {
81                     State[i] = cachedState[i];
82                 }
83             }
84         }
85 
86         public long Size => 0x1000;
87 
88         // Combined IRQ is a standard ARM AHB GPIO IRQ which is asserted when any of the pins for which IRQ is enabled is triggered
89         [DefaultInterrupt]
90         public GPIO CombinedIRQ { get; } = new GPIO();
91 
92         // In UT32 variant, a GPIO ports can optionally feature dedicated per-pin IRQs for first eight pins. For those pins the dedicated IRQ is asserted instead of the combined IRQ
93         public GPIO DedicatedIRQ0 { get; } = new GPIO();
94         public GPIO DedicatedIRQ1 { get; } = new GPIO();
95         public GPIO DedicatedIRQ2 { get; } = new GPIO();
96         public GPIO DedicatedIRQ3 { get; } = new GPIO();
97         public GPIO DedicatedIRQ4 { get; } = new GPIO();
98         public GPIO DedicatedIRQ5 { get; } = new GPIO();
99         public GPIO DedicatedIRQ6 { get; } = new GPIO();
100         public GPIO DedicatedIRQ7 { get; } = new GPIO();
101 
102         public DoubleWordRegisterCollection RegistersCollection { get; }
103 
UpdatePinOutput(int idx, bool value)104         private void UpdatePinOutput(int idx, bool value)
105         {
106             if(!pinOutputEnabled[idx])
107             {
108                 this.Log(LogLevel.Noisy, "Attempted to set pin{0} to {1}, but it's not configured as output; ignoring", idx, value);
109                 return;
110             }
111 
112             if(State[idx] == value)
113             {
114                 return;
115             }
116 
117             Connections[idx].Set(value);
118             State[idx] = value;
119         }
120 
OnPinStateChanged(int idx, bool previous, bool current)121         private void OnPinStateChanged(int idx, bool previous, bool current)
122         {
123             var interruptPending = false;
124             switch(interruptPolarity[idx])
125             {
126                 case InterruptPolarity.LowFalling:
127                     if(interruptType[idx] == InterruptType.EdgeTriggered)
128                     {
129                         interruptPending = !current && (previous != current);
130                     }
131                     if(interruptType[idx] == InterruptType.LevelTriggered)
132                     {
133                         interruptPending = !current;
134                     }
135                     break;
136                 case InterruptPolarity.HighRising:
137                     if(interruptType[idx] == InterruptType.EdgeTriggered)
138                     {
139                         interruptPending = current && (previous != current);
140                     }
141                     if(interruptType[idx] == InterruptType.LevelTriggered)
142                     {
143                         interruptPending = current;
144                     }
145                     break;
146                 default:
147                     throw new Exception("Should not reach here.");
148             }
149 
150             interruptStatus[idx] |= interruptPending;
151             UpdateInterrupts();
152         }
153 
UpdateInterrupts()154         private void UpdateInterrupts()
155         {
156             var pendingCombinedInterrupt = false;
157             for(var i = 0; i < NumberOfConnections; ++i)
158             {
159                 var pendingInterrupt = interruptEnabled[i] && interruptStatus[i];
160                 if(hasDedicatedIRQs && i < NumberOfDedicatedIRQs)
161                 {
162                     DedicatedIRQs[i].Set(pendingInterrupt);
163                 }
164                 else
165                 {
166                     pendingCombinedInterrupt |= pendingInterrupt;
167                 }
168             }
169             CombinedIRQ.Set(pendingCombinedInterrupt);
170         }
171 
DefineRegisters()172         private void DefineRegisters()
173         {
174             Registers.Data.Define(this)
175                 .WithFlags(0, 16, name: "DATA",
176                     valueProviderCallback: (i, _) =>
177                     {
178                         if(pinOutputEnabled[i])
179                         {
180                             this.Log(LogLevel.Noisy, "Trying to get value from pin {0} which is configured as output");
181                             return false;
182                         }
183                         return State[i];
184                     },
185                     writeCallback: (i, _, val) => UpdatePinOutput(i, val))
186                 .WithReservedBits(16, 16);
187             ;
188             Registers.DataOutput.Define(this)
189                 .WithFlags(0, 16, name: "DATAOUT",
190                     valueProviderCallback: (i, _) => State[i] && pinOutputEnabled[i],
191                     writeCallback: (i, _, val) => UpdatePinOutput(i, val))
192                 .WithReservedBits(16, 16);
193             ;
194             Registers.OutputEnableSet.Define(this)
195                 .WithFlags(0, 16, name: "OUTENSET",
196                     valueProviderCallback: (i, _) => pinOutputEnabled[i],
197                     writeCallback: (i, _, val) => { if(val) pinOutputEnabled[i] = true; })
198                 .WithReservedBits(16, 16);
199             ;
200             Registers.OutputEnableClear.Define(this)
201                 .WithFlags(0, 16, name: "OUTENCLR",
202                     valueProviderCallback: (i, _) => pinOutputEnabled[i],
203                     writeCallback: (i, _, val) => { if(val) pinOutputEnabled[i] = false; })
204                 .WithReservedBits(16, 16);
205             ;
206             Registers.AlternateFunctionSet.Define(this)
207                 .WithFlags(0, 16, name: "ALTFUNCSET",
208                     valueProviderCallback: (i, _) => pinAlternateFunctionEnabled[i],
209                     writeCallback: (i, _, val) => { if(val) pinAlternateFunctionEnabled[i] = true; })
210                 .WithReservedBits(16, 16);
211             ;
212             Registers.AlternateFunctionClear.Define(this)
213                 .WithFlags(0, 16, name: "ALTFUNCCLR",
214                     valueProviderCallback: (i, _) => pinAlternateFunctionEnabled[i],
215                     writeCallback: (i, _, val) => { if(val) pinAlternateFunctionEnabled[i] = false; })
216                 .WithReservedBits(16, 16);
217             ;
218             Registers.InterruptEnableSet.Define(this)
219                 .WithFlags(0, 16, name: "INTENSET",
220                     valueProviderCallback: (i, _) => interruptEnabled[i],
221                     writeCallback: (i, _, val) => { if(val) interruptEnabled[i] = true; })
222                 .WithReservedBits(16, 16)
223                 .WithWriteCallback((_, __) => UpdateInterrupts());
224             ;
225             Registers.InterruptEnableClear.Define(this)
226                 .WithFlags(0, 16, name: "INTENCLR",
227                     valueProviderCallback: (i, _) => interruptEnabled[i],
228                     writeCallback: (i, _, val) => { if(val) interruptEnabled[i] = false; })
229                 .WithReservedBits(16, 16)
230                 .WithWriteCallback((_, __) => UpdateInterrupts());
231             ;
232             Registers.InterruptTypeSet.Define(this)
233                 .WithFlags(0, 16, name: "INTTYPESET",
234                     valueProviderCallback: (i, _) => interruptType[i] == InterruptType.LevelTriggered ? false : true,
235                     writeCallback: (i, _, val) => { if(val) interruptType[i] = InterruptType.EdgeTriggered; })
236                 .WithReservedBits(16, 16);
237             ;
238             Registers.InterruptTypeClear.Define(this)
239                 .WithFlags(0, 16, name: "INTTYPECLR",
240                     valueProviderCallback: (i, _) => interruptType[i] == InterruptType.LevelTriggered ? false : true,
241                     writeCallback: (i, _, val) => { if(val) interruptType[i] = InterruptType.LevelTriggered; })
242                 .WithReservedBits(16, 16)
243                 .WithWriteCallback((_, __) => UpdateInterrupts());
244             ;
245             Registers.InterruptPolaritySet.Define(this)
246                 .WithFlags(0, 16, name: "INTPOLSET",
247                     valueProviderCallback: (i, _) => interruptPolarity[i] == InterruptPolarity.LowFalling ? false : true,
248                     writeCallback: (i, _, val) => { if(val) interruptPolarity[i] = InterruptPolarity.HighRising; })
249                 .WithReservedBits(16, 16)
250                 .WithWriteCallback((_, __) => UpdateInterrupts());
251             ;
252             Registers.InterruptPolarityClear.Define(this)
253                 .WithFlags(0, 16, name: "INTPOLCLR",
254                     valueProviderCallback: (i, _) => interruptPolarity[i] == InterruptPolarity.LowFalling ? false : true,
255                     writeCallback: (i, _, val) => { if(val) interruptPolarity[i] = InterruptPolarity.LowFalling; })
256                 .WithReservedBits(16, 16)
257                 .WithWriteCallback((_, __) => UpdateInterrupts());
258             ;
259             Registers.InterruptStatus_InterruptClear.Define(this)
260                 .WithFlags(0, 16, name: "INTSTATUS_INTCLEAR",
261                     valueProviderCallback: (i, _) => interruptStatus[i],
262                     writeCallback: (i, _, value) =>
263                     {
264                         if(value)
265                         {
266                             interruptStatus[i] = false;
267                         }
268                     })
269                 .WithReservedBits(16, 16)
270                 .WithWriteCallback((_, __) => UpdateInterrupts())
271             ;
272             Registers.SoftReset.Define(this)
273                 .WithFlag(0, out softReset, name: "SOFTRESET")
274                 .WithReservedBits(1, 31);
275             ;
276             Registers.PullEnable.Define(this)
277                 .WithFlags(0, 16, out pullEnable, name: "PULL_ENABLE")
278                 .WithReservedBits(16, 16);
279             ;
280 
281             Registers.PullUpDown.Define(this)
282                 .WithFlags(0, 16, out pullUpDown, name: "PULL_UP_DOWN")
283                 .WithReservedBits(16, 16);
284             ;
285 
286             Registers.MaskLowByte0.DefineMany(this, 256, (register, idx) =>
287             {
288                 register
289                     .WithTag("MASKLOWBYTE", 0, 8)
290                     .WithReservedBits(8, 24);
291             });
292 
293             Registers.MaskHighByte0.DefineMany(this, 256, (register, idx) =>
294             {
295                 register
296                     .WithTag("MASKHIGHBYTE", 0, 8)
297                     .WithReservedBits(8, 24);
298             });
299         }
300 
301         private IFlagRegisterField softReset;
302         private IFlagRegisterField[] pullEnable;
303         private IFlagRegisterField[] pullUpDown;
304         private GPIO[] DedicatedIRQs { get; }
305 
306         private readonly bool[] pinOutputEnabled = new bool[NumberOfGPIOs];
307         private readonly bool[] pinAlternateFunctionEnabled = new bool[NumberOfGPIOs];
308         private readonly bool[] interruptEnabled = new bool[NumberOfGPIOs];
309         private readonly bool[] interruptStatus = new bool[NumberOfGPIOs];
310         private readonly uint alternateFunctionResetValue;
311         private readonly bool hasDedicatedIRQs;
312         private readonly InterruptType[] interruptType = new InterruptType[NumberOfGPIOs];
313         private readonly InterruptPolarity[] interruptPolarity = new InterruptPolarity[NumberOfGPIOs];
314 
315         private const int NumberOfGPIOs = 16;
316         private const int NumberOfDedicatedIRQs = 8;
317 
318         private enum InterruptType
319         {
320             LevelTriggered = 0,
321             EdgeTriggered,
322         }
323 
324         private enum InterruptPolarity
325         {
326             LowFalling = 0,
327             HighRising,
328         }
329 
330         private enum Registers
331         {
332             Data = 0x000,
333             DataOutput = 0x004,
334             OutputEnableSet = 0x010,
335             OutputEnableClear = 0x014,
336             AlternateFunctionSet = 0x018,
337             AlternateFunctionClear = 0x01c,
338             InterruptEnableSet = 0x020,
339             InterruptEnableClear = 0x024,
340             InterruptTypeSet = 0x028,
341             InterruptTypeClear = 0x02c,
342             InterruptPolaritySet = 0x030,
343             InterruptPolarityClear = 0x034,
344             InterruptStatus_InterruptClear = 0x038,
345             SoftReset = 0x03c,  // UT32 specific
346             PullEnable = 0x040, // UT32 specific
347             PullUpDown = 0x044, // UT32 specific
348             MaskLowByte0 = 0x400,  // 256 MaskLowByte registers, 0x400-0x7fc
349             MaskHighByte0 = 0x800, // 256 MaskHighByte registers, 0x800-0xbfc
350         }
351     }
352 }
353