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