1 // 2 // Copyright (c) 2010-2024 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 System; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Utilities; 13 using System.Collections.Generic; 14 using System.Linq; 15 16 namespace Antmicro.Renode.Peripherals.IRQControllers 17 { 18 public class GaislerMIC: IDoubleWordPeripheral, INumberedGPIOOutput, IIRQController, IGaislerAPB 19 { GaislerMIC(IMachine machine, uint totalNumberCPUs = 1)20 public GaislerMIC(IMachine machine, uint totalNumberCPUs = 1) 21 { 22 this.numberOfProcessors = totalNumberCPUs; 23 if(totalNumberCPUs > maxNumberOfProcessors) 24 { 25 this.Log(LogLevel.Warning, "Registration with unsupported number of CPUs, defaulting to maximum {0:X]", maxNumberOfProcessors); 26 this.numberOfProcessors = maxNumberOfProcessors; 27 } 28 registers = new deviceRegisters(); 29 registers.MultiprocessorStatus |= (((numberOfProcessors-1) << 28) & 0xF0000000); 30 // Set Broadcast Available bit in MultiprocessorStatus register if ncpu > 1 31 if(this.numberOfProcessors > 1) 32 { 33 registers.MultiprocessorStatus |= (1u << 27); 34 } 35 irqs = new GPIO[numberOfProcessors]; 36 resets = new GPIO[numberOfProcessors]; 37 runs = new GPIO[numberOfProcessors]; 38 set_nmi_interrupt = new bool[numberOfProcessors]; 39 for(var i = 0; i < numberOfProcessors; i++) 40 { 41 irqs[i] = new GPIO(); 42 resets[i] = new GPIO(); 43 runs[i] = new GPIO(); 44 interrupts[i] = new Dictionary<int, int>(); 45 set_nmi_interrupt[i] = false; 46 } 47 48 Connections = new IGPIORedirector((int)numberOfProcessors, HandleIRQConnect); 49 Reset(); 50 } 51 52 public IReadOnlyDictionary<int, IGPIO> Connections { get; private set; } 53 HandleIRQConnect(int src, IGPIOReceiver receiver, int dst)54 private void HandleIRQConnect(int src, IGPIOReceiver receiver, int dst) 55 { 56 switch(dst) 57 { 58 case 0: 59 irqs[src].Connect(receiver, dst); 60 break; 61 case 1: 62 resets[src].Connect(receiver, dst); 63 break; 64 case 2: 65 runs[src].Connect(receiver, dst); 66 break; 67 default: 68 this.Log(LogLevel.Warning, "Destination index value is undefined {0:X}", dst); 69 break; 70 } 71 } 72 73 #region IDoubleWordPeripheral implementation ReadDoubleWord(long offset)74 public uint ReadDoubleWord (long offset) 75 { 76 if(offset < (int)(registerOffset.ProcessorInterruptMaskBase)) 77 { 78 switch((registerOffset)offset) 79 { 80 case registerOffset.InterruptLevel: 81 return registers.InterruptLevel; 82 case registerOffset.InterruptPending: 83 return registers.InterruptPending; 84 case registerOffset.InterruptForce: 85 return 0; 86 case registerOffset.InterruptClear: 87 return 0; 88 case registerOffset.MultiprocessorStatus: 89 return registers.MultiprocessorStatus; 90 case registerOffset.Broadcast: 91 if(isBroadcastEnabled()) 92 { 93 return registers.Broadcast; 94 } 95 else 96 { 97 this.LogUnhandledRead(offset); 98 return 0; 99 } 100 default: 101 this.LogUnhandledRead(offset); 102 return 0; 103 } 104 } 105 else if(offset < (int)(registerOffset.ProcessorInterruptForceBase)) 106 { 107 for(var i = 0; i < numberOfProcessors; i++) 108 { 109 if(offset == (int)(registerOffset.ProcessorInterruptMaskBase) + 4 * i) 110 { 111 return registers.ProcessorInterruptMask[i]; 112 } 113 } 114 this.LogUnhandledRead(offset); 115 return 0; 116 } 117 else if(offset < (int)(registerOffset.ProcessorExtendedInterruptAcknowledgeBase)) 118 { 119 for(var i = 0; i < numberOfProcessors; i++) 120 { 121 if(offset == (int)(registerOffset.ProcessorInterruptForceBase) + 4 * i) 122 { 123 return registers.ProcessorInterruptForce[i]; 124 } 125 } 126 this.LogUnhandledRead(offset); 127 return 0; 128 } 129 else if(offset < (int)(registerOffset.ProcessorExtendedInterruptAcknowledgeBase) + 4 * maxNumberOfProcessors) 130 { 131 for(var i = 0; i < numberOfProcessors; i++) 132 { 133 if(offset == (int)(registerOffset.ProcessorExtendedInterruptAcknowledgeBase) + 4 * i) 134 { 135 return registers.ProcessorExtendedInterruptAcknowledge[i]; 136 } 137 } 138 this.LogUnhandledRead(offset); 139 return 0; 140 } 141 else 142 { 143 this.LogUnhandledRead(offset); 144 return 0; 145 } 146 } 147 WriteDoubleWord(long offset, uint value)148 public void WriteDoubleWord (long offset, uint value) 149 { 150 if(offset < (int)(registerOffset.ProcessorInterruptMaskBase)) 151 { 152 switch((registerOffset)offset) 153 { 154 case registerOffset.InterruptLevel: 155 // Each interrupt can be assigned to one of two levels (0 or 1) as programmed in 156 // the interrupt level register - bit 1-15. Level 1 has higher priority than level 0. 157 if(value < 0xFFFF) 158 { 159 registers.InterruptLevel = value; 160 } 161 else 162 { 163 this.Log(LogLevel.Warning, "Write of unsupported interrupt level value {0:X}", value); 164 } 165 break; 166 case registerOffset.InterruptPending: 167 // read-only register 168 this.Log(LogLevel.Warning, "Write to read-only register (InterruptPending) value {0:X}", value); 169 break; 170 case registerOffset.InterruptForce: 171 if(currentNumberCpus() == 1) 172 { 173 registers.InterruptPending |= (value & registers.ProcessorInterruptMask[0]); 174 } 175 else 176 { 177 this.LogUnhandledWrite(offset, value); 178 } 179 break; 180 case registerOffset.InterruptClear: 181 // Don't clear interrupts whose input is set 182 registers.InterruptPending &= ~(value & ~pirqState); 183 break; 184 case registerOffset.MultiprocessorStatus: 185 // A halted processor can be reset and restarted by writing a ‘1’ to its status field. Bit field = [15:0] 186 if((value & 0xF) != 0) 187 { 188 for(var i = 0; i < numberOfProcessors; i++) 189 { 190 // Check if CPU is halted and then if it is requested to reset 191 if((( ~(registers.MultiprocessorStatus >> i) & 0x1) == 0x1) 192 && (((value >> i) & 0x1) == 0x1)) 193 { 194 resets[i].Set(); 195 runs[i].Set(); 196 } 197 } 198 } 199 // Make setting a bit sticky 200 registers.MultiprocessorStatus |= value; 201 break; 202 case registerOffset.Broadcast: 203 if(isBroadcastEnabled()) 204 { 205 registers.Broadcast = value; 206 } 207 break; 208 default: 209 this.LogUnhandledWrite(offset, value); 210 break; 211 } 212 } 213 else if(offset < (int)(registerOffset.ProcessorInterruptForceBase)) 214 { 215 for(var i = 0; i < numberOfProcessors; i++) 216 { 217 // TODO: Interrupt 15 cannot be masked, should be handled here 218 if(offset == (int)(registerOffset.ProcessorInterruptMaskBase) + 4 * i) 219 { 220 registers.ProcessorInterruptMask[i] = value; 221 } 222 } 223 } 224 else if(offset < (int)(registerOffset.ProcessorExtendedInterruptAcknowledgeBase)) 225 { 226 int cpuid = (int)(offset - (int)(registerOffset.ProcessorInterruptForceBase))/4; 227 228 // Loop over the external interrupts in 'value' and if set insert them into the 229 // cpu's interrupt force register and the cpu's pending interrupt list. Extended 230 // interrupts (see VHDL generic eirq in the GRLIB IP Core Manual) are not dealt 231 // with at the moment. 232 for (int interrupt = 1; interrupt < maxNumberOfExternalInterrupts; interrupt++) 233 { 234 uint interrupt_mask = (1u << interrupt); 235 if ((value & interrupt_mask) != 0x0) { 236 if((interrupt_mask & registers.ProcessorInterruptMask[cpuid]) != 0) 237 { 238 lock(interrupts[cpuid]) 239 { 240 registers.ProcessorInterruptForce[cpuid] |= interrupt_mask; 241 addPendingInterrupt(cpuid, interrupt); 242 if (interrupt == NMI_IRQ) 243 { 244 set_nmi_interrupt[cpuid] = true; 245 } 246 } 247 } 248 } 249 } 250 } 251 else if(offset < (int)(registerOffset.ProcessorExtendedInterruptAcknowledgeBase) + 4 * maxNumberOfProcessors) 252 { 253 this.Log(LogLevel.Warning, "Write to read-only register (ProcessorExtendedInterruptAcknowledge) value {0:X}", value); 254 } 255 else 256 { 257 this.LogUnhandledWrite(offset, value); 258 } 259 this.forwardInterrupt(); 260 } 261 #endregion 262 263 #region IPeripheral implementation Reset()264 public void Reset () 265 { 266 for(var i = 0; i < numberOfProcessors; i++) 267 { 268 registers.ProcessorInterruptMask[i] = 0; 269 registers.ProcessorInterruptForce[i] = 0; 270 } 271 pirqState = 0; 272 } 273 #endregion 274 275 #region IGPIOReceiver implementation OnGPIO(int number, bool value)276 public void OnGPIO(int number, bool value) 277 { 278 int i; 279 uint pendingInterrupts = 0; 280 uint processorPendingInterrupts = 0; 281 282 if(value) 283 { 284 pirqState |= (1u << number); 285 pendingInterrupts |= (1u << number); 286 // If interrupt is enabled in Broadcast register use cpu Force registers instead of global Pending 287 if(isBroadcastEnabled() && ((registers.Broadcast & pendingInterrupts) != 0)) 288 { 289 for(i = 0; i < numberOfProcessors; i++) 290 { 291 processorPendingInterrupts = pendingInterrupts & registers.ProcessorInterruptMask[i]; 292 if(processorPendingInterrupts != 0) 293 { 294 lock(interrupts[i]) 295 { 296 registers.ProcessorInterruptForce[i] |= processorPendingInterrupts; 297 addPendingInterrupt(i, number); 298 if (number == NMI_IRQ) 299 { 300 set_nmi_interrupt[i] = true; 301 } 302 } 303 } 304 } 305 } 306 else 307 { 308 for(i = 0; i < numberOfProcessors; i++) 309 { 310 processorPendingInterrupts = pendingInterrupts & registers.ProcessorInterruptMask[i]; 311 if(processorPendingInterrupts != 0) 312 { 313 lock(interrupts[i]) 314 { 315 registers.InterruptPending |= processorPendingInterrupts; 316 addPendingInterrupt(i, number); 317 if (number == NMI_IRQ) 318 { 319 set_nmi_interrupt[i] = true; 320 } 321 } 322 } 323 } 324 } 325 } 326 else 327 { 328 pirqState &= ~(1u << number); 329 } 330 331 this.forwardInterrupt(); 332 } 333 #endregion 334 335 #region IGaislerAPB implementation GetVendorID()336 public uint GetVendorID () 337 { 338 return vendorID; 339 } 340 GetDeviceID()341 public uint GetDeviceID () 342 { 343 return deviceID; 344 } 345 GetSpaceType()346 public GaislerAPBPlugAndPlayRecord.SpaceType GetSpaceType () 347 { 348 return spaceType; 349 } 350 GetInterruptNumber()351 public uint GetInterruptNumber() 352 { 353 return this.GetCpuInterruptNumber(irqs[0]); 354 } 355 #endregion 356 GetNumberOfProcessors()357 public uint GetNumberOfProcessors() 358 { 359 return this.numberOfProcessors; 360 } 361 GetCurrentCpuIrq(int index)362 public GPIO GetCurrentCpuIrq (int index) 363 { 364 GPIO currentCpuIrq = null; 365 if(index < numberOfProcessors) 366 { 367 currentCpuIrq = irqs[index]; 368 } 369 else 370 { 371 this.NoisyLog("Current IRQ array index is out of range {0:X}.", index); 372 } 373 return currentCpuIrq; 374 } 375 forwardInterrupt()376 private void forwardInterrupt() 377 { 378 for(var i = 0; i < numberOfProcessors; i++) 379 { 380 lock(interrupts[i]) 381 { 382 // If broadcast is set for an irq send this to each CPU 383 if(isBroadcastEnabled()) 384 { 385 if((!irqs[i].IsSet) && (registers.ProcessorInterruptForce[i] != 0)) 386 { 387 irqs[i].Set(); 388 } 389 } 390 if((!irqs[i].IsSet) && (registers.InterruptPending & registers.ProcessorInterruptMask[i]) != 0) 391 { 392 irqs[i].Set(); 393 } 394 395 // Always forward the NMI interrupt, even if the cpu is already servicing 396 // another interrupt. Not doing this when running an SMP Linux kernel will 397 // result in a deadlock in the kernels cpu cross call mechanism. 398 if(set_nmi_interrupt[i]) 399 { 400 irqs[i].Unset(); 401 irqs[i].Set(); 402 set_nmi_interrupt[i] = false; 403 } 404 } 405 } 406 } 407 408 // Needs to be (interrupts[i]) locked from caller forwardInterruptSingleCPU(int cpuid)409 private void forwardInterruptSingleCPU(int cpuid) 410 { 411 // If broadcast is set for an irq send this to each CPU 412 if(isBroadcastEnabled()) 413 { 414 if((!irqs[cpuid].IsSet) && (registers.ProcessorInterruptForce[cpuid] != 0)) 415 { 416 irqs[cpuid].Set(); 417 } 418 } 419 if((!irqs[cpuid].IsSet) && (registers.InterruptPending & registers.ProcessorInterruptMask[cpuid]) != 0) 420 { 421 irqs[cpuid].Set(); 422 } 423 } 424 CPUGetInterrupt(int cpuid)425 public int CPUGetInterrupt(int cpuid) 426 { 427 lock(interrupts[cpuid]) 428 { 429 if(interrupts[cpuid].Any()) 430 { 431 // Find interrupt with highest priority for this CPU 432 var interrupt = interrupts[cpuid].OrderByDescending(x => x.Value).First().Key; 433 // Treat all extended interrupts as interrupt #1 434 if(IsExtendedInterruptNumber(interrupt)) 435 { 436 interrupt = 1; 437 } 438 // As the irq no is external, we have to add 0x10 439 var intNo = interrupt + 0x10; 440 return intNo; 441 } 442 } 443 return 0; 444 } 445 446 // When a processor acknowledges the interrupt, the corresponding pending bit will automatically be 447 // cleared. Interrupt can also be forced by setting a bit in the interrupt force register. 448 // In this case, the processor acknowledgement will clear the force bit rather than the pending bit. CPUAckInterrupt(int cpuid, int interruptNumber)449 public void CPUAckInterrupt(int cpuid, int interruptNumber) 450 { 451 // Have to subtract 0x10 as the irq is external 452 var realInterruptNumber = interruptNumber - 0x10; 453 454 lock(interrupts[cpuid]) 455 { 456 // Handle extended interrupts, which are all mapped to IRQ 1 457 if(realInterruptNumber == 1) 458 { 459 // Extended interrupts have no prioritization between individual interrupts 460 var extendedInt = interrupts[cpuid].Keys.FirstOrDefault(IsExtendedInterruptNumber); 461 if(extendedInt == 0) 462 { 463 // This is unusual, but supported by the documentation 464 this.DebugLog("Interrupt #1 acknowledged without a pending extended interrupt."); 465 registers.ProcessorExtendedInterruptAcknowledge[cpuid] = 0; // Clear PEXTACK register 466 } 467 else 468 { 469 realInterruptNumber = extendedInt; 470 registers.ProcessorExtendedInterruptAcknowledge[cpuid] = (uint)extendedInt; 471 } 472 } 473 474 // Check the irq is forced 475 var interruptMask = 1u << realInterruptNumber; 476 if((registers.ProcessorInterruptForce[cpuid] & interruptMask) != 0) 477 { 478 registers.ProcessorInterruptForce[cpuid] &= ~interruptMask; 479 interrupts[cpuid].Remove(realInterruptNumber); 480 if(irqs[cpuid].IsSet) 481 { 482 irqs[cpuid].Unset(); 483 } 484 } 485 else 486 { 487 // Check if the interrupt is still pending, needs an ACK and the input is not set 488 if((registers.InterruptPending & interruptMask) != 0 && (pirqState & interruptMask) == 0) 489 { 490 // Remove the global pending interrupt 491 registers.InterruptPending &= ~interruptMask; 492 interrupts[cpuid].Remove(realInterruptNumber); 493 if(irqs[cpuid].IsSet) 494 { 495 irqs[cpuid].Unset(); 496 } 497 } 498 } 499 this.forwardInterruptSingleCPU(cpuid); 500 } 501 } 502 addPendingInterrupt(int cpuid, int number)503 private void addPendingInterrupt(int cpuid, int number) 504 { 505 // Interrupts are added per CPU and have been checked against processor irq mask 506 // in OnGPIO function before call - only handle priority here 507 // Interrupt Level is either high (1) or low (0) - irq is prioritized per level, with 15 as highest 508 // Extended interrupts have no prioritization between individual interrupts 509 510 int interruptPriority; 511 if(IsExtendedInterruptNumber(number)) 512 { 513 interruptPriority = 1; 514 } 515 else 516 { 517 interruptPriority = number + (((registers.InterruptLevel & 1u<<number) != 0) ? 16 : 0); 518 } 519 520 // Safe as this is only called under the interrupts[cpuid] lock 521 if(!interrupts[cpuid].ContainsKey(number)) 522 { 523 interrupts[cpuid].Add(number, interruptPriority); 524 } 525 } 526 currentNumberCpus()527 private int currentNumberCpus () 528 { 529 return (int)((registers.MultiprocessorStatus >> 28) & 0xF); 530 } 531 isBroadcastEnabled()532 private bool isBroadcastEnabled () 533 { 534 if(((registers.MultiprocessorStatus >> 27) & 0x1) == 0x1) 535 { 536 return true; 537 } 538 else 539 { 540 return false; 541 } 542 } 543 IsExtendedInterruptNumber(int irq)544 private static bool IsExtendedInterruptNumber(int irq) 545 { 546 return irq >= 16 && irq <= 32; 547 } 548 549 private readonly bool[] set_nmi_interrupt; 550 private readonly uint numberOfProcessors; 551 private readonly uint vendorID = 0x01; // Aeroflex Gaisler 552 private readonly uint deviceID = 0x00d; // GRLIB IRQMP 553 private static uint maxNumberOfProcessors = 16; 554 private readonly GaislerAPBPlugAndPlayRecord.SpaceType spaceType = GaislerAPBPlugAndPlayRecord.SpaceType.APBIOSpace; 555 private deviceRegisters registers; 556 private uint pirqState; 557 private readonly GPIO[] irqs; 558 private readonly GPIO[] resets; 559 private readonly GPIO[] runs; 560 private Dictionary<int, int>[] interrupts = new Dictionary<int, int>[maxNumberOfProcessors]; 561 562 private enum registerOffset : uint 563 { 564 InterruptLevel = 0x00, 565 InterruptPending = 0x04, 566 InterruptForce = 0x08, 567 InterruptClear = 0x0C, 568 MultiprocessorStatus = 0x10, 569 Broadcast = 0x14, 570 ProcessorInterruptMaskBase = 0x40, 571 ProcessorInterruptForceBase = 0x80, 572 ProcessorExtendedInterruptAcknowledgeBase = 0xC0 573 } 574 575 private class deviceRegisters 576 { 577 public uint InterruptLevel; 578 public uint InterruptPending; 579 public uint MultiprocessorStatus = 0x01 | (1 << 16); // 1 - interrupt number used for extended IRQs 580 public uint Broadcast; 581 public uint[] ProcessorInterruptMask; 582 public uint[] ProcessorInterruptForce; 583 public uint[] ProcessorExtendedInterruptAcknowledge; 584 deviceRegisters()585 public deviceRegisters() 586 { 587 ProcessorInterruptMask = new uint[maxNumberOfProcessors]; 588 ProcessorInterruptForce = new uint[maxNumberOfProcessors]; 589 ProcessorExtendedInterruptAcknowledge = new uint[maxNumberOfProcessors]; 590 } 591 } 592 593 public const int maxNumberOfExternalInterrupts = 16; 594 public const int NMI_IRQ = 15; 595 } 596 } 597 598