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