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 using System;
9 using Antmicro.Renode.Peripherals.IRQControllers;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Peripherals.Bus.Wrappers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Core;
14 using Antmicro.Renode.Core.Extensions;
15 using System.Collections.Generic;
16 
17 namespace Antmicro.Renode.Peripherals.IRQControllers
18 {
19     public sealed class MPC5567_INTC : IIRQController, IKnownSize, IDoubleWordPeripheral, IBytePeripheral
20     {
MPC5567_INTC()21         public MPC5567_INTC()
22         {
23             sync = new object();
24             IRQ = new GPIO();
25             priorities = new byte[NumberOfInterrupts];
26             pendingInterrupts = new bool[NumberOfInterrupts];
27             acknowledgedInterrupts = new Stack<int>();
28         }
29 
ReadByte(long offset)30         public byte ReadByte(long offset)
31         {
32             if(offset >= (long)Register.InterruptPriority0 && offset <= (long)Register.InterruptPriorityLast)
33             {
34                 return HandlePriorityRead(offset - (long)Register.InterruptPriority0);
35             }
36             this.LogUnhandledRead(offset);
37             return 0;
38         }
39 
WriteByte(long offset, byte value)40         public void WriteByte(long offset, byte value)
41         {
42             if(offset >= (long)Register.InterruptPriority0 && offset <= (long)Register.InterruptPriorityLast)
43             {
44                 HandlePriorityWrite(offset - (long)Register.InterruptPriority0, value);
45                 return;
46             }
47             if(offset >= (long)Register.SoftwareSetClear0 && offset <= (long)Register.SoftwareSetClearLast)
48             {
49                 HandleSoftwareSetClearWrite(offset - (long)Register.SoftwareSetClear0, value);
50                 return;
51             }
52             this.LogUnhandledWrite(offset, value);
53         }
54 
ReadDoubleWord(long offset)55         public uint ReadDoubleWord(long offset)
56         {
57             switch((Register)offset)
58             {
59             case Register.InterruptAcknowledge:
60                 return AcknowledgeInterrupts();
61             case Register.CurrentPriority:
62                 return (uint)(acknowledgedInterrupts.Count > 0 ? acknowledgedInterrupts.Peek() : 0);
63             default:
64                 if(offset >= (long)Register.InterruptPriority0 && offset <= (long)Register.InterruptPriorityLast)
65                 {
66                     return this.ReadDoubleWordUsingByte(offset);
67                 }
68                 this.LogUnhandledRead(offset);
69                 break;
70             }
71             return 0;
72         }
73 
WriteDoubleWord(long offset, uint value)74         public void WriteDoubleWord(long offset, uint value)
75         {
76             switch((Register)offset)
77             {
78             case Register.Configuration:
79                 if(value != 0)
80                 {
81                     this.Log(LogLevel.Warning, "Unhandled configuration value written 0x{0:X}.", value);
82                 }
83                 break;
84             case Register.CurrentPriority:
85                 if(value != 0)
86                 {
87                     this.Log(LogLevel.Warning, "Unhandled priority value written 0x{0:X}.", value);
88                 }
89                 break;
90             case Register.EndOfInterrupt:
91                 HandleEndOfInterrupt();
92                 break;
93             default:
94                 if(offset >= (long)Register.InterruptPriority0 && offset <= (long)Register.InterruptPriorityLast)
95                 {
96                     this.WriteDoubleWordUsingByte(offset, value);
97                     break;
98                 }
99                 if(offset >= (long)Register.SoftwareSetClear0 && offset <= (long)Register.SoftwareSetClearLast)
100                 {
101                     this.WriteDoubleWordUsingByte(offset, value);
102                     break;
103                 }
104                 this.LogUnhandledWrite(offset, value);
105                 break;
106             }
107         }
108 
109         public GPIO IRQ { get; private set; }
110 
OnGPIO(int number, bool value)111         public void OnGPIO(int number, bool value)
112         {
113             lock(sync)
114             {
115                 pendingInterrupts[number] = value;
116                 Update();
117             }
118         }
119 
Reset()120         public void Reset()
121         {
122             acknowledgedInterrupts.Clear();
123             Array.Clear(pendingInterrupts, 0, pendingInterrupts.Length);
124             Array.Clear(priorities, 0, priorities.Length);
125         }
126 
127         public long Size { get { return 0x4000; } }
128 
HandlePriorityRead(long interruptNo)129         private byte HandlePriorityRead(long interruptNo)
130         {
131             lock(sync)
132             {
133                 return priorities[interruptNo];
134             }
135         }
136 
HandlePriorityWrite(long interruptNo, byte value)137         private void HandlePriorityWrite(long interruptNo, byte value)
138         {
139             lock(sync)
140             {
141                 priorities[interruptNo] = value;
142             }
143         }
144 
HandleSoftwareSetClearWrite(long interruptNo, byte value)145         private void HandleSoftwareSetClearWrite(long interruptNo, byte value)
146         {
147             var set = (value & 2) != 0;
148             var clear = (value & 1) != 0;
149             if(set && clear)
150             {
151                 set = false;
152             }
153             if(set)
154             {
155                 OnGPIO((int)interruptNo, true);
156             }
157             if(clear)
158             {
159                 OnGPIO((int)interruptNo, false);
160             }
161         }
162 
HandleEndOfInterrupt()163         private void HandleEndOfInterrupt()
164         {
165             lock(sync)
166             {
167                 if(acknowledgedInterrupts.Count > 0)
168                 {
169                     acknowledgedInterrupts.Pop();
170                 }
171                 Update();
172             }
173         }
174 
AcknowledgeInterrupts()175         private uint AcknowledgeInterrupts()
176         {
177             lock(sync)
178             {
179                 var best = FindBestInterrupt();
180                 acknowledgedInterrupts.Push(best);
181                 IRQ.Unset(); // since we've selected the best interrupt
182                 return (uint)best * 4;
183             }
184         }
185 
Update()186         private void Update()
187         {
188             var result = FindBestInterrupt();
189             IRQ.Set(result != -1);
190         }
191 
FindBestInterrupt()192         private int FindBestInterrupt()
193         {
194             var result = -1;
195             for(var i = 0; i < pendingInterrupts.Length; i++)
196             {
197                 if(pendingInterrupts[i] && (result == -1 || priorities[i] > priorities[result]) && !acknowledgedInterrupts.Contains(i))
198                 {
199                     result = i;
200                 }
201             }
202             return result;
203         }
204 
205         private readonly Stack<int> acknowledgedInterrupts;
206         private readonly bool[] pendingInterrupts;
207         private readonly byte[] priorities;
208         private readonly object sync;
209 
210         private const int NumberOfInterrupts = 360;
211 
212         [RegisterMapper.RegistersDescription]
213         private enum Register
214         {
215             Configuration = 0x0,
216             // INTC_MCR, INTC module configuration register
217             CurrentPriority = 0x8,
218             InterruptAcknowledge = 0x10,
219             EndOfInterrupt = 0x18,
220             SoftwareSetClear0 = 0x20,
221             SoftwareSetClearLast = 0x27,
222             InterruptPriority0 = 0x40,
223             InterruptPriorityLast = InterruptPriority0 + NumberOfInterrupts
224         }
225     }
226 }
227 
228