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