1 //
2 // Copyright (c) 2010-2023 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.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 CC2538_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IKnownSize
18     {
CC2538_GPIO(IMachine machine)19         public CC2538_GPIO(IMachine machine) : base(machine, NumberOfGPIOs)
20         {
21             locker = new object();
22             IRQ = new GPIO();
23             irqManager = new GPIOInterruptManager(IRQ, State);
24 
25             PrepareRegisters();
26         }
27 
ReadDoubleWord(long offset)28         public uint ReadDoubleWord(long offset)
29         {
30             lock(locker)
31             {
32                 if(offset < 0x400)
33                 {
34                     var mask = BitHelper.GetBits((uint)(offset >> 2) & 0xFF);
35                     var bits = BitHelper.GetBits(registers.Read(0));
36                     var result = new bool[8];
37                     for(var i = 0; i < 8; i++)
38                     {
39                         if(mask[i])
40                         {
41                             result[i] = bits[i];
42                         }
43                     }
44 
45                     return BitHelper.GetValueFromBitsArray(result);
46                 }
47 
48                 return registers.Read(offset);
49             }
50         }
51 
WriteDoubleWord(long offset, uint value)52         public void WriteDoubleWord(long offset, uint value)
53         {
54             lock(locker)
55             {
56                 if(offset < 0x400)
57                 {
58                     var mask = BitHelper.GetBits((uint)(offset >> 2) & 0xFF);
59                     var bits = BitHelper.GetBits(value);
60                     for(var i = 0; i < 8; i++)
61                     {
62                         if(mask[i])
63                         {
64                             Connections[i].Set(bits[i]);
65                             State[i] = bits[i];
66                         }
67                     }
68                 }
69                 else
70                 {
71                     registers.Write(offset, value);
72                 }
73             }
74         }
75 
OnGPIO(int number, bool value)76         public override void OnGPIO(int number, bool value)
77         {
78             if(number < 0 || number >= NumberOfGPIOs)
79             {
80                 throw new ArgumentOutOfRangeException(string.Format("Gpio #{0} called, but only {1} lines are available", number, NumberOfGPIOs));
81             }
82 
83             lock(locker)
84             {
85                 base.OnGPIO(number, value);
86                 irqManager.RefreshInterrupts();
87             }
88         }
89 
Reset()90         public override void Reset()
91         {
92             lock(locker)
93             {
94                 base.Reset();
95                 irqManager.Reset();
96                 registers.Reset();
97                 IRQ.Unset();
98             }
99         }
100 
101         public GPIO IRQ { get; private set; }
102         public long Size => 0x1000;
103 
PrepareRegisters()104         private void PrepareRegisters()
105         {
106             registers = new DoubleWordRegisterCollection(this, new Dictionary<long, DoubleWordRegister>
107             {
108                 {(long)Registers.Data, new DoubleWordRegister(this)
109                     .WithValueField(0, 8,
110                         writeCallback: (_, val) =>
111                         {
112                             var bits = BitHelper.GetBits((uint)val);
113                             for(int i = 0; i < 8; i++)
114                             {
115                                 if(irqManager.PinDirection[i] == GPIOInterruptManager.Direction.Input)
116                                 {
117                                     Connections[i].Set(bits[i]);
118                                     State[i] = bits[i];
119                                 }
120                             }
121                         },
122                     valueProviderCallback: _ => { return BitHelper.GetValueFromBitsArray(State); })
123                 },
124                 {(long)Registers.DataDirection, new DoubleWordRegister(this)
125                     .WithValueField(0, 8, writeCallback: (_, val) =>
126                     {
127                         var bits = BitHelper.GetBits((uint)val);
128                         for(var i = 0; i < 8; i++)
129                         {
130                             irqManager.PinDirection[i] = bits[i] ? GPIOInterruptManager.Direction.Output : GPIOInterruptManager.Direction.Input;
131                         }
132                     },
133                     valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(irqManager.PinDirection.Select(x => x == GPIOInterruptManager.Direction.Output)))
134                 },
135                 {(long)Registers.InterruptSense, new DoubleWordRegister(this)
136                     .WithValueField(0, 8, out interruptSenseField, writeCallback: (_, val) => CalculateInterruptTypes())
137                 },
138                 {(long)Registers.InterruptBothEdges, new DoubleWordRegister(this)
139                     .WithValueField(0, 8, out interruptBothEdgeField, writeCallback: (_, val) => CalculateInterruptTypes())
140                 },
141                 {(long)Registers.InterruptEvent, new DoubleWordRegister(this)
142                     .WithValueField(0, 8, out interruptEventField, writeCallback: (_, val) => CalculateInterruptTypes())
143                 },
144                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
145                     .WithValueField(0, 8, writeCallback: (_, val) =>
146                     {
147                         var bits = BitHelper.GetBits((uint)val);
148                         for(var i = 0; i < 8; i++)
149                         {
150                             irqManager.InterruptEnable[i] = bits[i];
151                             irqManager.InterruptMask[i] = bits[i];
152                         }
153                         irqManager.RefreshInterrupts();
154                     },
155                     valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(irqManager.InterruptEnable))
156                 },
157                 {(long)Registers.RawInterruptStatus, new DoubleWordRegister(this)
158                     .WithValueField(0, 8, valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(irqManager.ActiveInterrupts))},
159                 {(long)Registers.MaskedInterruptStatus, new DoubleWordRegister(this)
160                     .WithValueField(0, 8, valueProviderCallback: _ => CalculateMaskedInterruptValue())},
161                 {(long)Registers.InterruptClear, new DoubleWordRegister(this)
162                                 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, val) =>
163                                 {
164                                     var bits = BitHelper.GetBits((uint)val);
165                                     for(var i = 0; i < 8; i++)
166                                     {
167                                         if(bits[i])
168                                         {
169                                             irqManager.ClearInterrupt(i);
170                                         }
171                                     }
172                                 })
173                 },
174                 {(long)Registers.ModeControlSelect, new DoubleWordRegister(this)
175                     .WithTag("AFSEL", 0, 32)
176                 },
177                 {(long)Registers.PortEdgeControl, new DoubleWordRegister(this)
178                     .WithTag("P_EDGE_CTRL", 0, 32)
179                 },
180                 {(long)Registers.PowerUpInterruptEnable, new DoubleWordRegister(this)
181                     .WithTag("PI_IEN", 0, 32)
182                 },
183                 {(long)Registers.IOPortsIRQDetectACK, new DoubleWordRegister(this)
184                     .WithTag("IRQ_DETECT_ACK", 0, 32)
185                 },
186                 {(long)Registers.MaskedIRQDetectACK, new DoubleWordRegister(this)
187                     .WithTag("IRQ_DETECT_UNMASK", 0, 32)
188                 }
189             });
190         }
191 
CalculateInterruptTypes()192         private void CalculateInterruptTypes()
193         {
194             lock(locker)
195             {
196                 var isBothEdgesSensitive = BitHelper.GetBits((uint)interruptBothEdgeField.Value);
197                 var isLevelSensitive = BitHelper.GetBits((uint)interruptSenseField.Value);
198                 var isActiveHighOrRisingEdge = BitHelper.GetBits((uint)interruptEventField.Value);
199 
200                 for(int i = 0; i < 8; i++)
201                 {
202                     if(isLevelSensitive[i])
203                     {
204                         irqManager.InterruptType[i] = isActiveHighOrRisingEdge[i]
205                                 ? GPIOInterruptManager.InterruptTrigger.ActiveHigh
206                                 : GPIOInterruptManager.InterruptTrigger.ActiveLow;
207                     }
208                     else
209                     {
210                         if(isBothEdgesSensitive[i])
211                         {
212                             irqManager.InterruptType[i] = GPIOInterruptManager.InterruptTrigger.BothEdges;
213                         }
214                         else
215                         {
216                             irqManager.InterruptType[i] = isActiveHighOrRisingEdge[i]
217                                 ? GPIOInterruptManager.InterruptTrigger.RisingEdge
218                                 : GPIOInterruptManager.InterruptTrigger.FallingEdge;
219                         }
220                     }
221                 }
222                 irqManager.RefreshInterrupts();
223             }
224         }
225 
CalculateMaskedInterruptValue()226         private uint CalculateMaskedInterruptValue()
227         {
228             var result = new bool[8];
229             for(var i = 0; i < 8; i++)
230             {
231                 result[i] = irqManager.ActiveInterrupts.ElementAt(i) && irqManager.InterruptMask[i];
232             }
233             return BitHelper.GetValueFromBitsArray(result);
234         }
235 
236         private DoubleWordRegisterCollection registers;
237         private readonly GPIOInterruptManager irqManager;
238         private readonly object locker;
239 
240         private IValueRegisterField interruptSenseField;
241         private IValueRegisterField interruptBothEdgeField;
242         private IValueRegisterField interruptEventField;
243 
244         private const int NumberOfGPIOs = 8;
245 
246         private enum Registers
247         {
248             Data = 0x0,
249             DataDirection = 0x400,
250             InterruptSense = 0x404,
251             InterruptBothEdges = 0x408,
252             InterruptEvent = 0x40C,
253             InterruptEnable = 0x410,
254             RawInterruptStatus = 0x414,
255             MaskedInterruptStatus = 0x418,
256             InterruptClear = 0x41C,
257             ModeControlSelect = 0x420,
258             GPIOCommitUnlock = 0x520,
259             GPIOCommit = 0x524,
260             PMUX = 0x700,
261             PortEdgeControl = 0x704,
262             USBInputPowerUpEdgeControl = 0x708,
263             PowerUpInterruptEnable = 0x710,
264             IOPortsIRQDetectACK = 0x718,
265             USBIRQDetectACK = 0x71C,
266             MaskedIRQDetectACK = 0x720
267         }
268     }
269 }
270