1 //
2 // Copyright (c) 2010-2018 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 
9 using System;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 using System.Collections.Generic;
15 
16 namespace Antmicro.Renode.Peripherals.IRQControllers
17 {
18     public class AIC : IDoubleWordPeripheral, IIRQController, IKnownSize
19     {
AIC()20         public AIC()
21         {
22             IRQ = new GPIO();
23             FIQ = new GPIO();
24         }
25 
26         public GPIO IRQ { get; set; }
27         public GPIO FIQ { get; set; }
28 
29         #region IGPIOReceiver implementation
30 
OnGPIO(int number, bool value)31         public void OnGPIO(int number, bool value)
32         {
33             lock (localLock)
34             {
35             this.Log(LogLevel.Noisy, "GPIO IRQ{0} set to {1}", number, value);
36 
37             if ((IsInternalHighlevelSensitive(number) && value) || (IsInternalPositiveEdgeTriggered(number) && !level[number] && value))
38             {
39                 BitHelper.SetBit(ref interruptPendingRegister, (byte)number, false);
40                 if (IsIRQEnabled(number))
41                 {
42                     if (CurrentIRQ.HasValue && CurrentIRQ.Value != -1 && GetPriority(number) > GetPriority(CurrentIRQ.Value))
43                     {
44                         IRQ.Set(false);
45                     }
46 
47                     IRQ.Set();
48                 }
49             }
50 
51                level[number] = value;
52             }
53         }
54 
55         #endregion
56 
57         #region IDoubleWordPeripheral implementation
58 
ReadDoubleWord(long offset)59         public uint ReadDoubleWord(long offset)
60         {
61             lock(localLock)
62             {
63                 switch ((Register)offset)
64                 {
65                 case Register.InterruptVectorRegister:
66                     if (CurrentIRQ.HasValue)
67                     {
68                         nestedInterruptStack.Push(Tuple.Create(CurrentIRQ.Value, (int)GetPriority(CurrentIRQ.Value)));
69                         BitHelper.SetBit(ref interruptPendingRegister, (byte)CurrentIRQ.Value, true);
70                     }
71 
72                     uint result;
73                     var irq = CalculateCurrentInterrupt();
74                     if (irq.HasValue)
75                     {
76                         BitHelper.SetBit(ref interruptPendingRegister, (byte)irq.Value, false); // clears the interrupt
77                         CurrentIRQ = irq.Value;
78                         result = sourceVectorRegisters[irq.Value];
79                     }
80                     else
81                     {
82                         CurrentIRQ = -1; // hack - there is no irq, but spourius irq handler is called
83                         result = spouriousInterruptVectorRegister;
84                     }
85 
86                     IRQ.Unset(); // de-asserts nIRQ to processor
87                     return result;
88 
89                 case Register.InterruptStatusRegister:
90                     if (CurrentIRQ.HasValue && CurrentIRQ > -1)
91                     {
92                         return (uint)CurrentIRQ.Value;
93                     }
94                     else
95                     {
96                         this.Log(LogLevel.Warning, "Spourious !!! level is: {0}", level[1]);
97                         // When there is no interrupt or we have a spourious one return 0
98                         return 0u;
99                     }
100 
101                 default:
102                     this.LogUnhandledRead(offset);
103                     return 0u;
104                 }
105             }
106         }
107 
WriteDoubleWord(long offset, uint value)108         public void WriteDoubleWord(long offset, uint value)
109         {
110             lock (localLock)
111         {
112             var val = -1;
113             if ((val = IsOffsetInRange((uint)offset, (uint)Register.SourceModeRegister0, 0x04, 32)) != -1)
114             {
115                 this.Log(LogLevel.Noisy, "This was write to Source Mode Register {0}", val);
116                 sourceModeRegisters[val] = value;
117                 return;
118             }
119 
120             if ((val = IsOffsetInRange((uint)offset, (uint)Register.SourceVectorRegister0, 0x04, 32)) != -1)
121             {
122                 this.Log(LogLevel.Noisy, "This was write to Source Vector Register {0}", val);
123                 sourceVectorRegisters[val] = value;
124                 return;
125             }
126 
127             switch ((Register)offset)
128             {
129             case Register.EndofInterruptCommandRegister:
130 
131                 if (nestedInterruptStack.Count > 0)
132                 {
133                     var irq = nestedInterruptStack.Pop();
134                     //CurrentIRQ = irq.Item1;
135                     BitHelper.SetBit(ref interruptPendingRegister, (byte)irq.Item1, true);
136                 }
137                 else
138                 {
139                     if (CurrentIRQ.HasValue)
140                     {
141                         BitHelper.SetBit(ref interruptPendingRegister, (byte)CurrentIRQ, false);
142                     }
143                     this.Log(LogLevel.Noisy, "IRQ set to false");
144                     IRQ.Set(false);
145                 }
146 
147                 CurrentIRQ = null;
148 
149                 // save to this register indicates the end of the interrupt handling
150                 break;
151 
152             case Register.InterruptEnableCommandRegister:
153                 interruptMaskRegister |= value;
154                 break;
155 
156             case Register.SpuriousInterruptVectorRegister:
157                 spouriousInterruptVectorRegister = value;
158                 break;
159 
160             //case Register.DebugControlRegister:
161                 //debugControlRegister = value;
162             //    break;
163 
164             case Register.InterruptClearCommandRegister:
165 
166                 foreach(var irq in BitHelper.GetSetBits(value))
167                 {
168                     if (IsInternalPositiveEdgeTriggered(irq))
169                     {
170                         BitHelper.SetBit(ref interruptPendingRegister, (byte)irq, false);
171                     }
172                 }
173 
174                 break;
175 
176             case Register.InterruptDisableCommandRegister:
177                 interruptMaskRegister &= ~value;
178                 //interruptPendingRegister &= ~value;
179                 break;
180 
181             default:
182                 this.LogUnhandledWrite(offset, value);
183                 return;
184             }
185         }
186         }
187 
188         #endregion
189 
190         #region IPeripheral implementation
191 
Reset()192         public void Reset()
193         {
194 
195         }
196 
197         #endregion
198 
199         #region IKnownSize implementation
200 
201         public long Size {
202             get {
203                 return 512;
204             }
205         }
206 
207         #endregion
208 
209         #region Helper methods
210 
CalculateCurrentInterrupt()211         private int? CalculateCurrentInterrupt()
212         {
213             var result = (int?)null;
214             for (int i = 0; i < level.Length; i++)
215             {
216                 if (level[i])
217                 {
218                     if (result == null || GetPriority(i) > GetPriority(result.Value))
219                     {
220                         result = i;
221                     }
222                 }
223             }
224 
225             return result;
226         }
227 
IsOffsetInRange(uint offset, uint start, uint step, byte count)228         private int IsOffsetInRange(uint offset, uint start, uint step, byte count)
229         {
230             var position  = start;
231             var counter = 0;
232             do
233             {
234                 if (position == offset)
235                 {
236                     return counter;
237                 }
238                 position += step;
239                 counter++;
240             } while (counter < count);
241 
242             return -1;
243         }
244 
GetPriority(int irq)245         private uint GetPriority(int irq)
246         {
247             return sourceModeRegisters[irq] & 7u;
248         }
249 
IsIRQEnabled(int irq)250         private bool IsIRQEnabled(int irq)
251         {
252             return BitHelper.IsBitSet(interruptMaskRegister, (byte)irq);
253         }
254 
IsInternalHighlevelSensitive(int irq)255         private bool IsInternalHighlevelSensitive(int irq)
256         {
257             var val = ((sourceModeRegisters[irq] >> 5) & 3u);
258             return val == 0 || val == 2;
259         }
260 
IsInternalPositiveEdgeTriggered(int irq)261         private bool IsInternalPositiveEdgeTriggered(int irq)
262         {
263             var val = ((sourceModeRegisters[irq] >> 5) & 3u);
264             return val == 1 || val == 3;
265         }
266 
267         private int? CurrentIRQ;
268 
269         #endregion
270 
271         private bool[] level = new bool[32];
272 
273         private uint[] sourceModeRegisters = new uint[32];
274         private uint[] sourceVectorRegisters = new uint[32];
275         private uint interruptMaskRegister;
276         private uint interruptPendingRegister;
277         private uint spouriousInterruptVectorRegister;
278         //private uint debugControlRegister; // TODO: use only two bits
279 
280         private Stack<Tuple<int, int>> nestedInterruptStack = new Stack<Tuple<int, int>>();
281 
282         private object localLock = new object();
283 
284         private enum Register : uint
285         {
286             SourceModeRegister0             = 0x000,   // SMR0
287             SourceVectorRegister0           = 0x080,   // SVR0
288             InterruptVectorRegister         = 0x100,   // IVR
289             InterruptStatusRegister         = 0x108,   // ISR
290             InterruptPendingRegister        = 0x10C,   // IPR
291             InterruptEnableCommandRegister  = 0x120,   // IECR
292             InterruptDisableCommandRegister = 0x124,   // IDCR
293             InterruptClearCommandRegister   = 0x128,   // ICCR
294             EndofInterruptCommandRegister   = 0x130,   // EICR
295             SpuriousInterruptVectorRegister = 0x134,   // SIVR
296             DebugControlRegister            = 0x138    // DCR
297         }
298     }
299 }
300 
301