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.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Exceptions;
12 using Antmicro.Renode.Core.Extensions;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Peripherals.Bus;
16 using Antmicro.Renode.Peripherals.GPIOPort;
17 using Antmicro.Renode.Utilities;
18 
19 using Endianness = ELFSharp.ELF.Endianess;
20 
21 namespace Antmicro.Renode.Peripherals.Miscellaneous
22 {
23     public class S32K3XX_SystemIntegrationUnitLite2 : BaseGPIOPort, IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, IKnownSize,
24         IProvidesRegisterCollection<DoubleWordRegisterCollection>, IProvidesRegisterCollection<ByteRegisterCollection>
25     {
S32K3XX_SystemIntegrationUnitLite2(IMachine machine)26         public S32K3XX_SystemIntegrationUnitLite2(IMachine machine) : base(machine, MaximumValidPadIndex + 1)
27         {
28             IRQ1 = new GPIO();
29             IRQ2 = new GPIO();
30             IRQ3 = new GPIO();
31             IRQ4 = new GPIO();
32 
33             interruptType = new InterruptType[ExternalInterruptCount];
34             interruptPending = new IFlagRegisterField[ExternalInterruptCount];
35             interruptEnabled = new IFlagRegisterField[ExternalInterruptCount];
36 
37             doubleWordRegisterCollection = new DoubleWordRegisterCollection(this);
38             byteRegisterCollection = new ByteRegisterCollection(this);
39 
40             DefineRegisters();
41         }
42 
ReadDoubleWord(long offset)43         public uint ReadDoubleWord(long offset)
44         {
45             if(!doubleWordRegisterCollection.TryRead(offset, out var value))
46             {
47                 return this.ReadDoubleWordUsingByte(offset);
48             }
49             return value;
50         }
51 
WriteDoubleWord(long offset, uint value)52         public void WriteDoubleWord(long offset, uint value)
53         {
54             if(!doubleWordRegisterCollection.TryWrite(offset, value))
55             {
56                 this.WriteDoubleWordUsingByte(offset, value);
57             }
58         }
59 
ReadWord(long offset)60         public ushort ReadWord(long offset)
61         {
62             return this.ReadWordUsingByte(offset);
63         }
64 
WriteWord(long offset, ushort value)65         public void WriteWord(long offset, ushort value)
66         {
67             this.WriteWordUsingByte(offset, value);
68         }
69 
ReadByte(long offset)70         public byte ReadByte(long offset)
71         {
72             return byteRegisterCollection.Read(offset);
73         }
74 
WriteByte(long offset, byte value)75         public void WriteByte(long offset, byte value)
76         {
77             byteRegisterCollection.Write(offset, value);
78         }
79 
Reset()80         public override void Reset()
81         {
82             base.Reset();
83             doubleWordRegisterCollection.Reset();
84             byteRegisterCollection.Reset();
85         }
86 
OnGPIO(int number, bool value)87         public override void OnGPIO(int number, bool value)
88         {
89             if(!validPadIndexes.Contains(number))
90             {
91                 this.Log(LogLevel.Warning, "Tried to set {0} to pad#{1} is not an valid pad index", value, number);
92                 return;
93             }
94 
95             var previousState = State[number];
96             base.OnGPIO(number, value);
97 
98             if(previousState == value)
99             {
100                 return;
101             }
102 
103             var mapping = eirqToPadMapping
104                 .Select((Pads, Index) => new { Pads, Index })
105                 .Where(item => item.Pads.Contains(number))
106                 .FirstOrDefault();
107 
108             if(mapping == null)
109             {
110                 return;
111             }
112 
113             var externalIRQ = mapping.Index;
114             if(interruptType[externalIRQ].HasFlag(InterruptType.RisingEdge) && !previousState)
115             {
116                 interruptPending[externalIRQ].Value = true;
117             }
118             if(interruptType[externalIRQ].HasFlag(InterruptType.FallingEdge) && previousState)
119             {
120                 interruptPending[externalIRQ].Value = true;
121             }
122 
123             UpdateInterrupts();
124         }
125 
TranslatePinName(string pinName)126         public int TranslatePinName(string pinName)
127         {
128             var normalizedPinName = pinName.ToUpper();
129 
130             // Pin name is in format PTxy, where x is between A and H, and y can be between 0 and 31
131             if(normalizedPinName.Length < 4 || !normalizedPinName.StartsWith("PT"))
132             {
133                 throw new RecoverableException($"{pinName} is invalid pin name. Correct pin names are in format PTxyy");
134             }
135 
136             var portIndexChar = normalizedPinName[2];
137             if(portIndexChar > 'H' || portIndexChar < 'A')
138             {
139                 throw new RecoverableException("Pin name should be in range PTAxx to PTHxx");
140             }
141             var portIndex = portIndexChar - 'A';
142 
143             var pinIndexString = normalizedPinName.Substring(3);
144             if(!Int32.TryParse(pinIndexString, out var pinIndex) || pinIndex < 0 || pinIndex > 31)
145             {
146                 throw new RecoverableException("Pin name should be in range PTx00 to PTx31");
147             }
148 
149             var padIndex = portIndex * 32 + pinIndex;
150             if(!validPadIndexes.Contains(padIndex))
151             {
152                 throw new RecoverableException("This pin is unavailable for GPIO");
153             }
154 
155             return padIndex;
156         }
157 
158         public long Size => 0x4000;
159         public GPIO IRQ1 { get; }
160         public GPIO IRQ2 { get; }
161         public GPIO IRQ3 { get; }
162         public GPIO IRQ4 { get; }
163 
164         DoubleWordRegisterCollection IProvidesRegisterCollection<DoubleWordRegisterCollection>.RegistersCollection => doubleWordRegisterCollection;
165         ByteRegisterCollection IProvidesRegisterCollection<ByteRegisterCollection>.RegistersCollection => byteRegisterCollection;
166 
UpdateInterrupts()167         private void UpdateInterrupts()
168         {
169             IRQ1.Set(Enumerable.Range(0, 8).Any(irq => interruptEnabled[irq].Value && interruptPending[irq].Value));
170             IRQ2.Set(Enumerable.Range(8, 8).Any(irq => interruptEnabled[irq].Value && interruptPending[irq].Value));
171             IRQ3.Set(Enumerable.Range(16, 8).Any(irq => interruptEnabled[irq].Value && interruptPending[irq].Value));
172             IRQ4.Set(Enumerable.Range(24, 8).Any(irq => interruptEnabled[irq].Value && interruptPending[irq].Value));
173         }
174 
DefineRegisters()175         private void DefineRegisters()
176         {
177             IProvidesRegisterCollection<DoubleWordRegisterCollection> asDoubleWordCollection = this;
178 
179             Registers.MCUIDRegister1.Define(asDoubleWordCollection)
180                 .WithTag("MinorMaskRevision", 0, 4)
181                 .WithTag("MajorMaskRevision", 4, 4)
182                 .WithReservedBits(8, 8)
183                 .WithTag("MCUPartNumber", 16, 10)
184                 .WithTag("ProductLineLetter", 26, 6)
185             ;
186 
187             Registers.MCUIDRegister2.Define(asDoubleWordCollection)
188                 .WithTag("FlashSizeCode0", 0, 7)
189                 .WithTag("FlashSizeData0", 8, 4)
190                 .WithTag("FlashData0", 12, 2)
191                 .WithTag("FlashCode0", 14, 2)
192                 .WithTag("Frequency0", 16, 4)
193                 .WithTag("Package0", 20, 6)
194                 .WithTag("Temperature0", 26, 3)
195                 .WithTag("Technology0", 29, 3)
196             ;
197 
198             var interruptStatusFlag = Registers.DMAInterruptStatusFlag0.Define(asDoubleWordCollection);
199             var interruptRequestEnable = Registers.DMAInterruptRequestEnable0.Define(asDoubleWordCollection);
200             var interruptRequestSelect = Registers.DMAInterruptRequestSelect0.Define(asDoubleWordCollection);
201             var interruptRisingEdgeEventEnable = Registers.InterruptRisingEdgeEventEnable0.Define(asDoubleWordCollection);
202             var interruptFallingEdgeEventEnable = Registers.InterruptFallingEdgeEventEnable0.Define(asDoubleWordCollection);
203             var interruptFilterEnable = Registers.InterruptFilterEnable0.Define(asDoubleWordCollection);
204 
205             for(var i = 0; i < ExternalInterruptCount; ++i)
206             {
207                 var irq = i;
208 
209                 interruptStatusFlag.WithFlag(irq, out interruptPending[irq], FieldMode.Read | FieldMode.WriteOneToClear, name: $"ExternalInterruptStatusFlag{irq}");
210                 interruptRequestEnable.WithFlag(irq, out interruptEnabled[irq], name: $"ExternalRequestEnable{irq}");
211                 interruptRequestSelect.WithTaggedFlag($"RequestSelect{irq}", irq);
212                 interruptRisingEdgeEventEnable.WithFlag(irq, name: $"EnableRisingEdgeEventsToSetDISR0[{irq}]",
213                     valueProviderCallback: _ => interruptType[irq].HasFlag(InterruptType.RisingEdge),
214                     changeCallback: (_, value) => interruptType[irq] = value ? (interruptType[irq] | InterruptType.RisingEdge) : (interruptType[irq] & ~InterruptType.RisingEdge)
215                 );
216                 interruptFallingEdgeEventEnable.WithFlag(irq, name: $"EnableFallingEdgeEventsToSetDISR0[{irq}]",
217                     valueProviderCallback: _ => interruptType[irq].HasFlag(InterruptType.FallingEdge),
218                     changeCallback: (_, value) => interruptType[irq] = value ? (interruptType[irq] | InterruptType.FallingEdge) : (interruptType[irq] & ~InterruptType.FallingEdge)
219                 );
220                 interruptFilterEnable.WithTaggedFlag($"EnableFilterOnInterruptPad{irq}", irq);
221             }
222 
223             interruptStatusFlag.WithChangeCallback((_, __) => UpdateInterrupts());
224             interruptRequestEnable.WithChangeCallback((_, __) => UpdateInterrupts());
225             interruptRisingEdgeEventEnable.WithChangeCallback((_, __) => UpdateInterrupts());
226             interruptFallingEdgeEventEnable.WithChangeCallback((_, __) => UpdateInterrupts());
227 
228             Registers.InterruptFilterMaximumCounter0.DefineMany(asDoubleWordCollection, ExternalInterruptCount, (register, registerIndex) =>
229             {
230                 register
231                     .WithTag("MaximumInterruptFilterCounter", 0, 4)
232                     .WithReservedBits(4, 28)
233                 ;
234             });
235 
236             Registers.InterruptFilterClockPrescaler.Define(asDoubleWordCollection)
237                 .WithTag("InterruptFilterClockPrescaler", 0, 4)
238                 .WithReservedBits(4, 28)
239             ;
240 
241             Registers.MUX0EMIOSEnable1.DefineMany(asDoubleWordCollection, MuxCount, (register, registerIndex) =>
242             {
243                 var lowerFlags = Enumerable.Range(0, 8).ToDictionary(x => x, x => x + 16);
244                 var upperFlags = Enumerable.Range(16, 16).ToDictionary(x => x, x => x - 16);
245 
246                 foreach(var flag in upperFlags.Concat(lowerFlags))
247                 {
248                     register.WithTaggedFlag($"EMIOS0OutputFlag{flag.Value}MonitorEnable", flag.Key);
249                 }
250                 register.WithReservedBits(8, 8);
251             }, stepInBytes: Registers.MUX1EMIOSEnable - Registers.MUX0EMIOSEnable1);
252 
253             Registers.MCUIDRegister3.Define(asDoubleWordCollection)
254                 .WithTag("SystemRAMSize", 0, 6)
255                 .WithReservedBits(6, 4)
256                 .WithTag("PartNumberSuffix", 10, 6)
257                 .WithTag("ProductFamilyNumber", 16, 10)
258                 .WithTag("ProductFamilyLetter", 26, 6)
259             ;
260 
261             Registers.MCUIDRegister4.Define(asDoubleWordCollection)
262                 .WithTag("CorePlatformOptionsFeature", 0, 3)
263                 .WithTag("EthernetFeature", 3, 2)
264                 .WithTag("SecurityFeature", 5, 2)
265                 .WithReservedBits(7, 7)
266                 .WithTag("CorePlatformOptionsFeature", 14, 2)
267                 .WithReservedBits(16, 16)
268             ;
269 
270             var multiplexedSignalConfigurationIndexes = Enumerable.Empty<int>()
271                 .ConcatRangeFromTo(0, 37)
272                 .ConcatRangeFromTo(40, 140)
273                 .ConcatRangeFromTo(142, 236);
274 
275             var multiplexedSignalConfigurationResets = new Dictionary<int, uint>
276             {
277                 {4, 0x82827},
278                 {10, 0x127},
279                 {12, 0x3},
280                 {68, 0x82000},
281                 {69, 0x82800},
282                 {76, 0x4000},
283                 {80, 0x4000},
284                 {66, 0x4000},
285                 {67, 0x4000},
286                 {101, 0x4000},
287                 {102, 0x4000},
288                 {103, 0x4000},
289                 {106, 0x4000},
290                 {107, 0x4000},
291                 {108, 0x4000},
292                 {136, 0x4000},
293             };
294 
295             foreach(var index in multiplexedSignalConfigurationIndexes)
296             {
297                 var offset = Registers.MultiplexedSignalConfiguration0 + index * 4;
298                 if(!multiplexedSignalConfigurationResets.TryGetValue(index, out var resetValue))
299                 {
300                     resetValue = 0;
301                 }
302 
303                 offset.Define(asDoubleWordCollection, resetValue, name: $"MSCR{index}")
304                     .WithTag("SourceSignalSelect", 0, 4)
305                     .WithReservedBits(4, 1)
306                     .WithTaggedFlag("SafeModeControl", 5)
307                     .WithTaggedFlag("InputFilterEnable", 6)
308                     .WithReservedBits(7, 1)
309                     .WithTaggedFlag("DriveStrengthEnable", 8)
310                     .WithReservedBits(9, 2)
311                     .WithTaggedFlag("PullSelect", 11)
312                     .WithReservedBits(12, 1)
313                     .WithTaggedFlag("PullEnable", 13)
314                     .WithTaggedFlag("SlewRateControl", 14)
315                     .WithReservedBits(15, 1)
316                     .WithTaggedFlag("PadKeepingEnable", 16)
317                     .WithTaggedFlag("Invert", 17)
318                     .WithReservedBits(18, 1)
319                     .WithTaggedFlag("InputBufferEnable", 19)
320                     .WithReservedBits(20, 1)
321                     .WithTaggedFlag("GPIOOutputBufferEnable", 21)
322                     .WithReservedBits(22, 10)
323                 ;
324             }
325 
326             var inputMultiplexedSignalConfigurationRanges = Enumerable.Empty<int>()
327                 .ConcatRangeFromTo(0, 5)
328                 .ConcatRangeFromTo(16, 71)
329                 .ConcatRangeFromTo(80, 103)
330                 .ConcatRangeFromTo(112, 135)
331                 .ConcatRangeFromTo(144, 149)
332                 .ConcatRangeFromTo(152, 202)
333                 .ConcatRangeFromTo(211, 268)
334                 .ConcatRangeFromTo(289, 309)
335                 .ConcatRangeFromTo(315, 325)
336                 .ConcatRangeFromTo(343, 370)
337                 .ConcatRangeFromTo(373, 378)
338                 .ConcatRangeFromTo(389, 389)
339                 .ConcatRangeFromTo(398, 399)
340                 .ConcatRangeFromTo(409, 418)
341                 .ConcatRangeFromTo(440, 440)
342                 .ConcatRangeFromTo(448, 469);
343 
344             foreach(var index in inputMultiplexedSignalConfigurationRanges)
345             {
346                 var offset = Registers.InputMultiplexedSignalConfiguration0 + index * 4;
347                 offset.Define(asDoubleWordCollection, name: $"IMCR{index}")
348                     .WithTag($"SourceSignalSelect{index}", 0, 4)
349                     .WithReservedBits(4, 28)
350                 ;
351             }
352 
353             IProvidesRegisterCollection<ByteRegisterCollection> asByteCollection = this;
354 
355             foreach(var i in validPadIndexes.OrderBy(item => item))
356             {
357                 var index = i;
358                 var registerOffset = index + 3 - 2 * (index % 4);
359                 var outputOffset = Registers.GPIOPadDataOutput3 + registerOffset;
360                 outputOffset.Define(asByteCollection, name: $"GPDO{index}")
361                     .WithFlag(0, name: $"PadDataOut{index}",
362                         valueProviderCallback: _ => Connections[index].IsSet,
363                         changeCallback: (_, value) => Connections[index].Set(value))
364                     .WithReservedBits(1, 7)
365                 ;
366 
367                 var inputOffset = Registers.GPIOPadDataInput3 + registerOffset;
368                 inputOffset.Define(asByteCollection, name: $"GPDI{index}")
369                     .WithFlag(0, FieldMode.Read, name: $"PadDataInput{index}",
370                         valueProviderCallback: _ => State[index])
371                     .WithReservedBits(1, 7)
372                 ;
373             }
374 
375             // NOTE: As we are managing address translation manually in this peripheral,
376             // we have to carefully calculate bit-offsets for 16-bit registers...
377             var peripheralEndianness = this.GetEndianness(machine.SystemBus.Endianess);
378             Func<int, int, int> getStartPadIndex = (int registerIndex, int byteIndex) =>
379             {
380                 // Registers are 16-bit wide
381                 var startPadIndex = registerIndex * 16;
382                 // Bits are in reversed order
383                 switch(peripheralEndianness)
384                 {
385                     case Endianness.LittleEndian:
386                         startPadIndex += (1 - byteIndex) * 8;
387                         break;
388                     case Endianness.BigEndian:
389                         startPadIndex += byteIndex * 8;
390                         break;
391                 }
392 
393                 return startPadIndex;
394             };
395 
396             // While the register addresses are one after another...
397             for(var registerOffset = 0; registerOffset < PadDataCount; ++registerOffset)
398             {
399                 // ...the register indexes are in reversed order pair-wise, so 1, 0, 3, 2, 5, 4, etc.
400                 var registerIndex = registerOffset ^ 1;
401                 var outputOffset = Registers.ParallelGPIOPadDataOut0 + registerOffset * 2;
402                 var inputOffset = Registers.ParallelGPIOPadDataIn0 + registerOffset * 2;
403 
404                 for(var byteIndex = 0; byteIndex < 2; ++byteIndex)
405                 {
406                     var startPadIndex = getStartPadIndex(registerIndex, byteIndex);
407                     var padRange = Enumerable.Range(startPadIndex, 8).Reverse();
408 
409                     (outputOffset + byteIndex).Define(asByteCollection)
410                         .WithValueField(0, 8, name: $"ParallelPadDataOutput{registerIndex}.{byteIndex}",
411                             valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(padRange.Select(pinIndex => Connections[pinIndex].IsSet)),
412                             changeCallback: (previousValue, currentValue) =>
413                             {
414                                 var difference = previousValue ^ currentValue;
415                                 foreach(var padIndex in BitHelper.GetSetBits(difference).Select(index => 7 - index))
416                                 {
417                                     if(validPadIndexes.Contains(startPadIndex + padIndex))
418                                     {
419                                         Connections[startPadIndex + padIndex].Toggle();
420                                     }
421                                 }
422                             })
423                     ;
424 
425                     (inputOffset + byteIndex).Define(asByteCollection)
426                         .WithValueField(0, 8, FieldMode.Read, name: $"ParallelPadDataInput{registerIndex}.{byteIndex}",
427                             valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(padRange.Select(pinIndex => State[pinIndex])))
428                     ;
429                 }
430             }
431 
432             // Parallel GPIO Pad Data is implemented as two byte registers, instead of a single word register, to simplify implementation.
433             // Those registers are accessible using all widths same as Pad Data registers (non-parallel).
434             var parallelPadDataReservedFlags = new Dictionary<int, int[]>
435             {
436                 {2, new int [] {8, 9}},
437                 {8, new int [] {2}},
438                 {14, new int [] {0, 1, 2}}
439             };
440 
441             Registers.MaskedParallelGPIOPadDataOut0.DefineMany(asDoubleWordCollection, PadDataCount, (register, registerIndex) =>
442             {
443                 for(var flagIndex = 0; flagIndex < 16; ++flagIndex)
444                 {
445                     var maskFlagIndex = 16 + flagIndex;
446                     if(parallelPadDataReservedFlags.TryGetValue(registerIndex, out var reservedFlagIndexes)
447                         && reservedFlagIndexes.Contains(flagIndex))
448                     {
449                         register.WithReservedBits(maskFlagIndex, 1);
450                         register.WithReservedBits(flagIndex, 1);
451                         continue;
452                     }
453                     register.WithTaggedFlag($"MaskField{flagIndex}", maskFlagIndex);
454                     register.WithTaggedFlag($"MaskedParallelPadDataOut{flagIndex}", flagIndex);
455                 }
456             });
457         }
458 
459         private readonly HashSet<int> validPadIndexes =
460             new HashSet<int>(Enumerable.Empty<int>()
461                 .ConcatRangeFromTo(0, 37)
462                 .ConcatRangeFromTo(40, 140)
463                 .ConcatRangeFromTo(142, 236));
464 
465         private readonly List<int[]> eirqToPadMapping = new List<int[]> {
466             /* EIRQ00 */ new[] { 0, 18, 64, 128, 160 },
467             /* EIRQ01 */ new[] { 1, 19, 65, 129, 161 },
468             /* EIRQ02 */ new[] { 2, 20, 66, 130, 162 },
469             /* EIRQ03 */ new[] { 3, 21, 67, 131, 163 },
470             /* EIRQ04 */ new[] { 4, 16, 68, 132, 164 },
471             /* EIRQ05 */ new[] { 5, 69, 133, 165 },
472             /* EIRQ06 */ new[] { 6, 28, 70, 134, 166 },
473             /* EIRQ07 */ new[] { 7, 30, 71, 136, 167 },
474             /* EIRQ08 */ new[] { 32, 53, 96, 137, 192 },
475             /* EIRQ09 */ new[] { 33, 54, 97, 138, 193 },
476             /* EIRQ10 */ new[] { 34, 55, 98, 139, 194 },
477             /* EIRQ11 */ new[] { 35, 56, 99, 140, 195 },
478             /* EIRQ12 */ new[] { 36, 57, 100, 196 },
479             /* EIRQ13 */ new[] { 37, 58, 101, 142, 197 },
480             /* EIRQ14 */ new[] { 40, 60, 102, 143, 198 },
481             /* EIRQ15 */ new[] { 41, 63, 103, 144, 199 },
482             /* EIRQ16 */ new[] { 8, 72, 84, 168, 224 },
483             /* EIRQ17 */ new[] { 9, 73, 85, 169, 225 },
484             /* EIRQ18 */ new[] { 10, 74, 87, 170, 226 },
485             /* EIRQ19 */ new[] { 11, 75, 88, 171, 227 },
486             /* EIRQ20 */ new[] { 12, 76, 89, 172, 228 },
487             /* EIRQ21 */ new[] { 13, 77, 90, 173, 229 },
488             /* EIRQ22 */ new[] { 14, 78, 91, 174, 230 },
489             /* EIRQ23 */ new[] { 15, 79, 93, 175, 231 },
490             /* EIRQ24 */ new[] { 42, 104, 113, 200, 232 },
491             /* EIRQ25 */ new[] { 43, 105, 116, 201, 233 },
492             /* EIRQ26 */ new[] { 44, 106, 117, 202, 234 },
493             /* EIRQ27 */ new[] { 45, 107, 118, 203, 235 },
494             /* EIRQ28 */ new[] { 46, 108, 119, 204, 236 },
495             /* EIRQ29 */ new[] { 47, 109, 120, 205, 221 },
496             /* EIRQ30 */ new[] { 48, 110, 123, 206, 222 },
497             /* EIRQ31 */ new[] { 49, 111, 124, 207, 223 },
498         };
499 
500         private readonly DoubleWordRegisterCollection doubleWordRegisterCollection;
501         private readonly ByteRegisterCollection byteRegisterCollection;
502         private readonly IFlagRegisterField[] interruptPending;
503         private readonly IFlagRegisterField[] interruptEnabled;
504 
505         private const int MaximumValidPadIndex = 236;
506         private const uint ExternalInterruptCount = 32;
507         private const uint MuxCount = 3;
508         private const int PadDataCount = 15;
509 
510         private readonly InterruptType[] interruptType;
511 
512         [Flags]
513         private enum InterruptType
514         {
515             Disabled,
516             RisingEdge,
517             FallingEdge,
518         }
519 
520         private enum Registers
521         {
522             MCUIDRegister1 = 0x4, // MIDR1
523             MCUIDRegister2 = 0x8, // MIDR2
524             DMAInterruptStatusFlag0 = 0x10, // DISR0
525             DMAInterruptRequestEnable0 = 0x18, // DIRER0
526             DMAInterruptRequestSelect0 = 0x20, // DIRSR0
527             InterruptRisingEdgeEventEnable0 = 0x28, // IREER0
528             InterruptFallingEdgeEventEnable0 = 0x30, // IFEER0
529             InterruptFilterEnable0 = 0x38, // IFER0
530             InterruptFilterMaximumCounter0 = 0x40, // IFMCR0
531             InterruptFilterMaximumCounter31 = 0xBC, // IFMCR31
532             InterruptFilterClockPrescaler = 0xC0, // IFCPR
533             MUX0EMIOSEnable1 = 0x100, // MUX0_EMIOS_EN1
534             MUX0MISCEnable = 0x104, // MUX0_MISC_EN
535             MUX1EMIOSEnable = 0x108, // MUX1_EMIOS_EN
536             MUX1MISCEnable = 0x10C, // MUX1_MISC_EN
537             MUX2EMIOSEnable = 0x110, // MUX2_EMIOS_EN
538             MUX2MISCEnable = 0x114, // MUX2_MISC_EN
539             MCUIDRegister3 = 0x200, // MIDR3
540             MCUIDRegister4 = 0x204, // MIDR4
541             MultiplexedSignalConfiguration0 = 0x240, // MSCR0
542             MultiplexedSignalConfiguration236 = 0x5F0, // MSCR236
543             InputMultiplexedSignalConfiguration0 = 0xA40, // IMCR0
544             InputMultiplexedSignalConfiguration469 = 0x1194, // IMCR469
545             GPIOPadDataOutput3 = 0x1300, // GPDO3
546             GPIOPadDataOutput236 = 0x13EF, // GPDO236
547             GPIOPadDataInput3 = 0x1500, // GPDI3
548             GPIOPadDataInput236 = 0x15EF, // GPDI236
549             ParallelGPIOPadDataOut0 = 0x1700, // PGPDO0
550             ParallelGPIOPadDataOut14 = 0x171E, // PGPDO14
551             ParallelGPIOPadDataIn0 = 0x1740, // PGPDI0
552             ParallelGPIOPadDataIn14 = 0x175E, // PGPDI14
553             MaskedParallelGPIOPadDataOut0 = 0x1780, // MPGPDO0
554             MaskedParallelGPIOPadDataOut14 = 0x17B8 // MPGPDO14
555         }
556     }
557 }
558