1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System.Collections.Generic; 8 using System.Collections.ObjectModel; 9 using System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 14 using Collections = Antmicro.Renode.Utilities.Collections; 15 16 namespace Antmicro.Renode.Peripherals.IRQControllers 17 { 18 public class PL190_VIC : BasicDoubleWordPeripheral, IIRQController, IKnownSize 19 { PL190_VIC(IMachine machine)20 public PL190_VIC(IMachine machine) : base(machine) 21 { 22 IRQ = new GPIO(); 23 FIQ = new GPIO(); 24 interrupts = new Interrupt[NumberOfInputLines]; 25 for(var i = 0; i < interrupts.Length; i++) 26 { 27 interrupts[i] = new Interrupt(i); 28 } 29 30 activeInterrupts = new Collections.PriorityQueue<Interrupt, int>(); 31 servicedInterrupts = new Stack<Interrupt>(); 32 33 DefineRegisters(); 34 Reset(); 35 } 36 Reset()37 public override void Reset() 38 { 39 activeInterrupts.Clear(); 40 servicedInterrupts.Clear(); 41 IRQ.Set(false); 42 FIQ.Set(false); 43 foreach(var interrupt in interrupts) 44 { 45 interrupt.Reset(); 46 } 47 base.Reset(); 48 } 49 OnGPIO(int id, bool state)50 public void OnGPIO(int id, bool state) 51 { 52 if(id < 0 || id >= NumberOfInputLines) 53 { 54 this.Log(LogLevel.Error, "GPIO number {0} is out of range [0; {1})", id, NumberOfInputLines); 55 return; 56 } 57 58 this.Log(LogLevel.Debug, "GPIO #{0} state changed to {1}", id, state); 59 interrupts[id].PinState = state; 60 UpdateInterrupts(id); 61 } 62 63 public GPIO IRQ { get; } 64 public GPIO FIQ { get; } 65 66 public long Size => 0x1000; 67 FinishCurrentInterrupt()68 private Interrupt FinishCurrentInterrupt() 69 { 70 var result = servicedInterrupts.Pop(); 71 ClearInactiveInterrupts(); 72 return result; 73 } 74 ClearInactiveInterrupts()75 private void ClearInactiveInterrupts() 76 { 77 // clear all inactive interrupts (might have been disabled in the meantime) 78 while(activeInterrupts.Count > 0 && !activeInterrupts.Peek().IsActive) 79 { 80 activeInterrupts.Dequeue(); 81 } 82 while(servicedInterrupts.Count > 0 && !servicedInterrupts.Peek().IsActive) 83 { 84 servicedInterrupts.Pop(); 85 } 86 } 87 UpdateInterrupts(int id)88 private void UpdateInterrupts(int id) 89 { 90 lock(activeInterrupts) 91 { 92 var lineStatus = interrupts[id].IsActive; 93 94 // IRQ line deactivated 95 if(lineStatus == false) 96 { 97 ClearInactiveInterrupts(); 98 RefreshIrqFiqState(); 99 } 100 else 101 { 102 // FIQ is handled separately, the vector address register is not used 103 if(interrupts[id].IsIrq) 104 { 105 activeInterrupts.Enqueue(interrupts[id], interrupts[id].Priority); 106 } 107 RefreshIrqFiqState(); 108 } 109 } 110 } 111 RefreshIrqFiqState()112 private void RefreshIrqFiqState() 113 { 114 var irq = activeInterrupts.TryPeek(out var interrupt, out _) && interrupt.IsActive; 115 var fiq = interrupts.Any(intr => intr.IsFiq && intr.IsActive); 116 this.Log(LogLevel.Noisy, "Setting outputs: IRQ={0}, FIQ={1}", irq, fiq); 117 IRQ.Set(irq); 118 FIQ.Set(fiq); 119 } 120 DefineRegisters()121 private void DefineRegisters() 122 { 123 Registers.IrqStatus.Define(this) 124 .WithFlags(0, 32, FieldMode.Read, valueProviderCallback: (idx, _) => interrupts[idx].IsActive && interrupts[idx].IsIrq); 125 126 Registers.FiqStatus.Define(this) 127 .WithFlags(0, 32, FieldMode.Read, valueProviderCallback: (idx, _) => interrupts[idx].IsActive && interrupts[idx].IsFiq); 128 129 Registers.InterruptSelect.Define(this) 130 .WithFlags(0, 32, name: "IntSelect", 131 valueProviderCallback: (idx, _) => interrupts[idx].IsFiq, 132 writeCallback: (idx, _, value) => 133 { 134 interrupts[idx].IsIrq = !value; 135 this.Log(LogLevel.Debug, "Interrupt #{0} configured as {1}", idx, value ? "FIQ" : "IRQ"); 136 UpdateInterrupts(idx); 137 }); 138 139 Registers.InterruptEnable.Define(this) 140 .WithFlags(0, 32, FieldMode.Set, name: "IntEnable", 141 writeCallback: (idx, _, value) => 142 { 143 if(value) 144 { 145 interrupts[idx].Enabled = true; 146 this.Log(LogLevel.Debug, "Interrupt #{0} enabled", idx); 147 UpdateInterrupts(idx); 148 } 149 }); 150 151 Registers.InterruptEnableClear.Define(this) 152 .WithFlags(0, 32, FieldMode.Set, name: "IntEnableClear", 153 writeCallback: (idx, _, value) => 154 { 155 if(value) 156 { 157 interrupts[idx].Enabled = false; 158 this.Log(LogLevel.Debug, "Interrupt #{0} disabled", idx); 159 UpdateInterrupts(idx); 160 } 161 }); 162 163 Registers.DefaultVectorAddress.Define(this) 164 .WithValueField(0, 32, out defaultVectorAddress, name: "Default VectorAddr"); 165 166 Registers.VectorAddress0.DefineMany(this, 16, (register, idx) => 167 { 168 register.WithValueField(0, 32, out vectorAddress[idx], name: "VectorAddr"); 169 }); 170 171 Registers.VectorControl0.DefineMany(this, 16, (register, idx) => 172 { 173 register 174 .WithValueField(0, 5, out irqSource[idx], name: "IntSource") 175 .WithFlag(5, out irqSourceEnabled[idx], name: "E") 176 .WithReservedBits(6, 26) 177 .WithWriteCallback((_, __) => 178 { 179 UpdateVectorMapping(idx); 180 UpdateInterrupts(idx); 181 }); 182 }); 183 184 Registers.ActiveInterruptVectorAddress.Define(this) 185 .WithValueField(0, 32, out activeVectorAddress, name: "VectorAddr", 186 valueProviderCallback: _ => 187 { 188 lock(activeInterrupts) 189 { 190 ulong activeVectorAddress = 0; 191 if(activeInterrupts.TryDequeue(out var interrupt, out var __)) 192 { 193 servicedInterrupts.Push(interrupt); 194 activeVectorAddress = (interrupt.VectorId != -1) 195 ? vectorAddress[interrupt.VectorId].Value 196 : defaultVectorAddress.Value; 197 } 198 RefreshIrqFiqState(); 199 return activeVectorAddress; 200 } 201 }, 202 writeCallback: (_, __) => 203 { 204 lock(activeInterrupts) 205 { 206 if(servicedInterrupts.Count == 0) 207 { 208 this.Log(LogLevel.Warning, "Tried to finish a vectored exception, but there is none active"); 209 return; 210 } 211 var irqId = FinishCurrentInterrupt().Id; 212 this.Log(LogLevel.Debug, "Finished IRQ #{0}", irqId); 213 RefreshIrqFiqState(); 214 } 215 }); 216 217 Registers.PeripheralIdentification0.Define(this) 218 .WithValueField(0, 8, FieldMode.Read, name: "Partnumber0", valueProviderCallback: _ => 0x90) 219 .WithReservedBits(8, 24); 220 221 Registers.PeripheralIdentification1.Define(this) 222 .WithValueField(0, 4, FieldMode.Read, name: "Partnumber1", valueProviderCallback: _ => 0x01) 223 .WithValueField(4, 4, FieldMode.Read, name: "Designer0", valueProviderCallback: _ => 0x01) 224 .WithReservedBits(8, 24); 225 226 Registers.PeripheralIdentification2.Define(this) 227 .WithValueField(0, 4, FieldMode.Read, name: "Designer1", valueProviderCallback: _ => 0x00) 228 .WithValueField(4, 4, FieldMode.Read, name: "Revision", valueProviderCallback: _ => 0x01) 229 .WithReservedBits(8, 24); 230 231 Registers.PeripheralIdentification3.Define(this) 232 .WithValueField(0, 8, FieldMode.Read, name: "Configuration", valueProviderCallback: _ => 0x00) 233 .WithReservedBits(8, 24); 234 235 Registers.SoftwareInterrupt.Define(this) 236 .WithFlags(0, 32, FieldMode.Set, name: "SoftInt", writeCallback: (id, _, value) => 237 { 238 if(value) 239 { 240 this.Log(LogLevel.Debug, "Setting soft IRQ {0}", id); 241 interrupts[id].SoftwareState = true; 242 UpdateInterrupts(id); 243 } 244 }); 245 246 Registers.SoftwareInterruptClear.Define(this) 247 .WithFlags(0, 32, FieldMode.Set, name: "SoftIntClear", writeCallback: (id, _, value) => 248 { 249 if(value) 250 { 251 this.Log(LogLevel.Debug, "Clearing soft IRQ {0}", id); 252 interrupts[id].SoftwareState = false; 253 UpdateInterrupts(id); 254 } 255 }); 256 } 257 UpdateVectorMapping(int id)258 private void UpdateVectorMapping(int id) 259 { 260 if(irqSourceEnabled[id].Value) 261 { 262 interrupts[irqSource[id].Value].VectorId = id; 263 } 264 else 265 { 266 foreach(var interrupt in interrupts) 267 { 268 if(interrupt.VectorId == id) 269 { 270 interrupt.VectorId = -1; 271 } 272 } 273 } 274 } 275 276 private readonly Interrupt[] interrupts; 277 private readonly Collections.PriorityQueue<Interrupt, int> activeInterrupts; 278 private readonly Stack<Interrupt> servicedInterrupts; 279 280 private IFlagRegisterField[] irqSourceEnabled = new IFlagRegisterField[NumberOfInputLines]; 281 private IValueRegisterField[] irqSource = new IValueRegisterField[NumberOfInputLines]; 282 private IValueRegisterField[] vectorAddress = new IValueRegisterField[NumberOfInputLines]; 283 private IValueRegisterField activeVectorAddress; 284 private IValueRegisterField defaultVectorAddress; 285 286 private const int NumberOfInputLines = 32; 287 288 private class Interrupt 289 { Interrupt(int id)290 public Interrupt(int id) 291 { 292 Id = id; 293 IsIrq = true; 294 } 295 Reset()296 public void Reset() 297 { 298 IsIrq = true; 299 Enabled = false; 300 PinState = false; 301 SoftwareState = false; 302 VectorId = -1; 303 } 304 305 public int Id { get; } 306 public bool IsIrq { get; set; } 307 public bool Enabled { get; set; } 308 public bool PinState { get; set; } 309 public bool SoftwareState { get; set; } 310 public int VectorId { get; set; } 311 312 public bool IsActive => Enabled && (PinState || SoftwareState); 313 public int Priority => VectorId != -1 ? VectorId : int.MaxValue; 314 public bool IsFiq => !IsIrq; 315 } 316 317 private enum Registers 318 { 319 IrqStatus = 0x0, // VICIRQSTATUS, RO 320 FiqStatus = 0x4, // VICFIQSTATUS, RO 321 RawInterruptStatus = 0x8, // VICRAWINTR, RO 322 InterruptSelect = 0xC, // VICINTSELECT, R/W 323 InterruptEnable = 0x10, // VICINTENABLE, R/W 324 InterruptEnableClear = 0x14, // VICINTENCLEAR, W 325 SoftwareInterrupt = 0x18, // VICSOFTINT, R/W 326 SoftwareInterruptClear = 0x1C, // VICSOFTINTCLEAR, W 327 ProtectionEnable = 0x20, // VICPROTECTION, R/W 328 ActiveInterruptVectorAddress = 0x30, // VICVECTADDR, R/W 329 DefaultVectorAddress = 0x34, // VICDEFVECTADDR, R/W 330 VectorAddress0 = 0x100, // VICVECTADDR0, R/W 331 VectorAddress1 = 0x104, // VICVECTADDR1, R/W 332 VectorAddress2 = 0x108, // VICVECTADDR2, R/W 333 VectorAddress3 = 0x10C, // VICVECTADDR3, R/W 334 VectorAddress4 = 0x110, // VICVECTADDR4, R/W 335 VectorAddress5 = 0x114, // VICVECTADDR5, R/W 336 VectorAddress6 = 0x118, // VICVECTADDR6, R/W 337 VectorAddress7 = 0x11C, // VICVECTADDR7, R/W 338 VectorAddress8 = 0x120, // VICVECTADDR8, R/W 339 VectorAddress9 = 0x124, // VICVECTADDR9, R/W 340 VectorAddress10 = 0x128, // VICVECTADDR10, R/W 341 VectorAddress11 = 0x12C, // VICVECTADDR11, R/W 342 VectorAddress12 = 0x130, // VICVECTADDR12, R/W 343 VectorAddress13 = 0x134, // VICVECTADDR13, R/W 344 VectorAddress14 = 0x138, // VICVECTADDR14, R/W 345 VectorAddress15 = 0x13C, // VICVECTADDR15, R/W 346 VectorControl0 = 0x200, // VICVECTCNTL0, R/W 347 VectorControl1 = 0x204, // VICVECTCNTL1, R/W 348 VectorControl2 = 0x208, // VICVECTCNTL2, R/W 349 VectorControl3 = 0x20C, // VICVECTCNTL3, R/W 350 VectorControl4 = 0x210, // VICVECTCNTL4, R/W 351 VectorControl5 = 0x214, // VICVECTCNTL5, R/W 352 VectorControl6 = 0x218, // VICVECTCNTL6, R/W 353 VectorControl7 = 0x21C, // VICVECTCNTL7, R/W 354 VectorControl8 = 0x220, // VICVECTCNTL8, R/W 355 VectorControl9 = 0x224, // VICVECTCNTL9, R/W 356 VectorControl10 = 0x228, // VICVECTCNTL10, R/W 357 VectorControl11 = 0x22C, // VICVECTCNTL11, R/W 358 VectorControl12 = 0x230, // VICVECTCNTL12, R/W 359 VectorControl13 = 0x234, // VICVECTCNTL13, R/W 360 VectorControl14 = 0x238, // VICVECTCNTL14, R/W 361 VectorControl15 = 0x23C, // VICVECTCNTL15, R/W 362 PeripheralIdentification0 = 0xFE0, // VICPERIPHID0, RO 363 PeripheralIdentification1 = 0xFE4, // VICPERIPHID1, RO 364 PeripheralIdentification2 = 0xFE8, // VICPERIPHID2, RO 365 PeripheralIdentification3 = 0xFEC, // VICPERIPHID3, RO 366 PrimeCellIdentification0 = 0xFF0, // VICPCELLID0, RO 367 PrimeCellIdentification1 = 0xFF4, // VICPCELLID1, RO 368 PrimeCellIdentification2 = 0xFF8, // VICPCELLID2, RO 369 PrimeCellIdentification3 = 0xFFC, // VICPCELLID3, RO 370 } 371 } 372 } 373