1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using System.Collections.Generic;
13 using System;
14 
15 namespace Antmicro.Renode.Peripherals.IRQControllers
16 {
17     public class AINTC : IDoubleWordPeripheral, IIRQController, IKnownSize
18     {
AINTC()19         public AINTC()
20         {
21             IRQ = new GPIO();
22             FIQ = new GPIO();
23             interrupts = new InterruptStatus[64];
24             SetupRegisters();
25             Reset();
26         }
27 
ReadDoubleWord(long offset)28         public uint ReadDoubleWord(long offset)
29         {
30             switch((Registers)offset)
31             {
32             case Registers.FastInterruptRequestStatus0:
33                 return ReadStatusRegister(0, InterruptType.FIQ);
34             case Registers.FastInterruptRequestStatus1:
35                 return ReadStatusRegister(1, InterruptType.FIQ);
36             case Registers.InterruptRequestStatus0:
37                 return ReadStatusRegister(0, InterruptType.IRQ);
38             case Registers.InterruptRequestStatus1:
39                 return ReadStatusRegister(1, InterruptType.IRQ);
40             case Registers.InterruptEnable0:
41                 return ReadInterruptEnableRegister(0);
42             case Registers.InterruptEnable1:
43                 return ReadInterruptEnableRegister(1);
44             case Registers.InterruptRequestEntryAddress:
45                 return (uint)(entryTableBaseAddress + (bestIrq + 1) * 4);
46             case Registers.FastInterruptRequestEntryAddress:
47                 return (uint)(entryTableBaseAddress + (bestFiq + 1) * 4);
48             case Registers.EntryTableBaseAddress:
49                 return entryTableBaseAddress;
50             case Registers.InterruptOperationControl:
51                 return interruptOperationControl.Read();
52             default:
53                 return interruptPriorityRegisterCollection.Read(offset);
54             }
55         }
56 
WriteDoubleWord(long offset, uint value)57         public void WriteDoubleWord(long offset, uint value)
58         {
59             switch((Registers)offset)
60             {
61             case Registers.FastInterruptRequestStatus0:
62             case Registers.InterruptRequestStatus0:
63                 WriteStatusRegister(0, value);
64                 break;
65             case Registers.InterruptRequestStatus1:
66             case Registers.FastInterruptRequestStatus1:
67                 WriteStatusRegister(1, value);
68                 break;
69             case Registers.InterruptEnable0:
70                 WriteEnableRegister(0, value);
71                 break;
72             case Registers.InterruptEnable1:
73                 WriteEnableRegister(1, value);
74                 break;
75             case Registers.InterruptOperationControl:
76                 interruptOperationControl.Write(offset, value);
77                 break;
78             case Registers.EntryTableBaseAddress:
79                 entryTableBaseAddress = value;
80                 break;
81             default:
82                 interruptPriorityRegisterCollection.Write(offset, value);
83                 break;
84             }
85         }
86 
Reset()87         public void Reset()
88         {
89             Array.Clear(interrupts, 0, interrupts.Length);
90             interruptPriorityRegisterCollection.Reset();
91             interruptOperationControl.Reset();
92             entryTableBaseAddress = 0;
93         }
94 
OnGPIO(int number, bool value)95         public void OnGPIO(int number, bool value)
96         {
97             this.NoisyLog("Received interrupt! Number {0} value {1}", number, value);
98             lock(interrupts)
99             {
100                 if(value)
101                 {
102                     interrupts[number] |= InterruptStatus.Running;
103                     interrupts[number] |= InterruptStatus.Pending;
104                 }
105                 else
106                 {
107                     interrupts[number] &= ~InterruptStatus.Running;
108                 }
109                 Update();
110             }
111         }
112 
113         public long Size
114         {
115             get
116             {
117                 return 0x400;
118             }
119         }
120 
121         public GPIO IRQ
122         {
123             get;
124             private set;
125         }
126 
127         public GPIO FIQ
128         {
129             get;
130             private set;
131         }
132 
Update()133         private void Update()
134         {
135             var bestFiqPriority = 3u;
136             var bestIrqPriority = 8u;
137             bestFiq = -1;
138             bestIrq = -1;
139 
140             for(var i = 0; i < interrupts.Length; i++)
141             {
142                 if(IsCandidate(i))
143                 {
144                     var type = GetInterruptType(i);
145                     if(type == InterruptType.FIQ)
146                     {
147                         if(priorities[i].Value < bestFiqPriority)
148                         {
149                             bestFiqPriority = (uint)priorities[i].Value;
150                             bestFiq = i;
151                         }
152                     }
153                     else
154                     {
155                         if(priorities[i].Value < bestIrqPriority)
156                         {
157                             bestIrqPriority = (uint)priorities[i].Value;
158                             bestIrq = i;
159                         }
160                     }
161                 }
162             }
163             IRQ.Set(bestIrq != -1);
164             FIQ.Set(bestFiq != -1);
165         }
166 
ReadStatusRegister(int number, InterruptType type)167         private uint ReadStatusRegister(int number, InterruptType type)
168         {
169             var value = 0u;
170             lock(interrupts)
171             {
172                 for(var i = 0; i < 32; ++i)
173                 {
174                     var status = interrupts[32 * number + i];
175                     if((status & InterruptStatus.Running) != 0 && GetInterruptType(i) == type)
176                     {
177                         value |= (1u << i);
178                     }
179                 }
180             }
181             return value;
182         }
183 
WriteStatusRegister(int number, uint value)184         private void WriteStatusRegister(int number, uint value)
185         {
186             lock(interrupts)
187             {
188                 for(var i = 0; i < 32; ++i)
189                 {
190                     var offset = i + 32 * number;
191                     if((value & (1 << i)) != 0)
192                     {
193                         if((interrupts[offset] & InterruptStatus.Running) != 0)
194                         {
195                             interrupts[offset] |= InterruptStatus.Pending;
196                         }
197                         else
198                         {
199                             interrupts[offset] &= ~InterruptStatus.Pending;
200                         }
201                     }
202                 }
203                 Update();
204             }
205         }
206 
ReadInterruptEnableRegister(int number)207         private uint ReadInterruptEnableRegister(int number)
208         {
209             var value = 0u;
210             lock(interrupts)
211             {
212                 for(var i = 0; i < 32; ++i)
213                 {
214                     if((interrupts[32 * number + i] & InterruptStatus.Enabled) != 0)
215                     {
216                         value |= (1u << i);
217                     }
218                 }
219             }
220             return value;
221         }
222 
WriteEnableRegister(int number, uint value)223         private void WriteEnableRegister(int number, uint value)
224         {
225             lock(interrupts)
226             {
227                 for(var i = 0; i < 32; ++i)
228                 {
229                     interrupts[32 * number + i] = (value & (1 << i)) != 0 ? InterruptStatus.Enabled : 0;
230                 }
231                 Update();
232             }
233         }
234 
IsCandidate(int number)235         private bool IsCandidate(int number)
236         {
237             var status = interrupts[number];
238             var type = GetInterruptType(number);
239             var isEnabled = (status & InterruptStatus.Enabled) != 0 || (reflectMaskedFiq.Value && type == InterruptType.FIQ) || (reflectMaskedIrq.Value && type == InterruptType.IRQ);
240             return (status & InterruptStatus.Pending) != 0 && isEnabled;
241         }
242 
SetupRegisters()243         private void SetupRegisters()
244         {
245             var interruptPriorityRegisters = new Dictionary<long, DoubleWordRegister>();
246             priorities = new IValueRegisterField[64];
247 
248             for(var i = 0; i < 8; i++)
249             {
250                 var registerKey = (long)Registers.InterruptPriority0 + 4 * i;
251                 interruptPriorityRegisters.Add(registerKey, new DoubleWordRegister(this, 0x77777777));
252                 for(var j = 0; j < 8; j++)
253                 {
254                     priorities[i * 8 + j] = interruptPriorityRegisters[registerKey].DefineValueField(4 * j, 3, writeCallback: (oldValue, newValue) => Update());
255                 }
256             }
257 
258             interruptPriorityRegisterCollection = new DoubleWordRegisterCollection(this, interruptPriorityRegisters);
259 
260             interruptOperationControl = new DoubleWordRegister(this);
261             reflectMaskedFiq = interruptOperationControl.DefineFlagField(0, writeCallback: (oldValue, newValue) => Update());
262             reflectMaskedIrq = interruptOperationControl.DefineFlagField(1, writeCallback: (oldValue, newValue) => Update());
263             interruptOperationControl.DefineFlagField(2, changeCallback: (oldValue, newValue) => {
264                 if(newValue)
265                 {
266                     this.Log(LogLevel.Warning, "Unsupported delayed interrupt enable/disable mode was set.");
267                 }
268             });
269         }
270 
GetInterruptType(int number)271         private InterruptType GetInterruptType(int number)
272         {
273             return priorities[number].Value < 2 ? InterruptType.FIQ : InterruptType.IRQ;
274         }
275 
276         private IValueRegisterField[] priorities;
277         private IFlagRegisterField reflectMaskedIrq, reflectMaskedFiq;
278         private InterruptStatus[] interrupts;
279         private DoubleWordRegisterCollection interruptPriorityRegisterCollection;
280         private DoubleWordRegister interruptOperationControl;
281         private uint entryTableBaseAddress;
282         private int bestIrq = -1, bestFiq = -1;
283 
284         private enum Registers
285         {
286             FastInterruptRequestStatus0 = 0x0,
287             FastInterruptRequestStatus1 = 0x4,
288             InterruptRequestStatus0 = 0x8,
289             InterruptRequestStatus1 = 0xc,
290             FastInterruptRequestEntryAddress = 0x10,
291             InterruptRequestEntryAddress = 0x14,
292             InterruptEnable0 = 0x18,
293             InterruptEnable1 = 0x1c,
294             InterruptOperationControl = 0x20,
295             EntryTableBaseAddress = 0x24,
296             InterruptPriority0 = 0x30,
297             InterruptPriority1 = 0x34,
298             InterruptPriority2 = 0x38,
299             InterruptPriority3 = 0x3c,
300             InterruptPriority4 = 0x40,
301             InterruptPriority5 = 0x44,
302             InterruptPriority6 = 0x48,
303             InterruptPriority7 = 0x4c,
304         }
305 
306         [Flags]
307         private enum InterruptStatus
308         {
309             Enabled = 1,
310             Running = 2,
311             Pending = 4
312         }
313 
314         private enum InterruptType
315         {
316             FIQ,
317             IRQ
318         }
319     }
320 }
321