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