1 // 2 // Copyright (c) 2010-2023 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.Peripherals.Bus; 11 using Antmicro.Renode.Logging; 12 using System.Collections.Generic; 13 14 namespace Antmicro.Renode.Peripherals.IRQControllers 15 { 16 public sealed class MSCM : IIRQController, INumberedGPIOOutput, IWordPeripheral, IDoubleWordPeripheral, IKnownSize 17 { MSCM(IMachine machine)18 public MSCM(IMachine machine) 19 { 20 sysbus = machine.GetSystemBus(this); 21 routingTable = new bool[NumberOfInterrupts * 2]; 22 destinations = new Destination[NumberOfInterrupts * 2]; 23 interProcessorInterrupts = new GPIO[8]; 24 for(var i = 0; i < interProcessorInterrupts.Length; i++) 25 { 26 interProcessorInterrupts[i] = new GPIO(); 27 } 28 29 Connections = new IGPIORedirector(232, HandleIRQConnect, HandleIRQDisconnect); 30 } 31 32 public IReadOnlyDictionary<int, IGPIO> Connections { get; private set; } 33 ReadWord(long offset)34 public ushort ReadWord(long offset) 35 { 36 if(offset >= RoutingControlStart && offset < RoutingControlEnd) 37 { 38 var interruptNo = (offset - RoutingControlStart) / 2; 39 lock(routingTable) 40 { 41 return (ushort)((routingTable[interruptNo] ? 1u : 0u) + (routingTable[NumberOfInterrupts + interruptNo] ? 2u : 0u)); 42 } 43 } 44 this.LogUnhandledRead(offset); 45 return 0; 46 } 47 WriteWord(long offset, ushort value)48 public void WriteWord(long offset, ushort value) 49 { 50 if(offset >= RoutingControlStart && offset < RoutingControlEnd) 51 { 52 var interruptNo = (offset - RoutingControlStart) / 2; 53 var cpu0 = (value & 1) != 0; 54 var cpu1 = (value & 2) != 0; 55 lock(routingTable) 56 { 57 this.DebugLog("Interrupt no {0} set to be routed to CPU0: {1}, CPU1: {2}", interruptNo, cpu0, cpu1); 58 routingTable[interruptNo] = cpu0; 59 routingTable[NumberOfInterrupts + interruptNo] = cpu1; 60 } 61 } 62 else 63 { 64 this.LogUnhandledWrite(offset, value); 65 } 66 } 67 ReadDoubleWord(long offset)68 public uint ReadDoubleWord(long offset) 69 { 70 switch((Register)offset) 71 { 72 case Register.CP0: 73 return HandleCPRead(0); 74 case Register.CP1: 75 return HandleCPRead(1); 76 } 77 this.LogUnhandledRead(offset); 78 return 0; 79 } 80 WriteDoubleWord(long offset, uint value)81 public void WriteDoubleWord(long offset, uint value) 82 { 83 switch((Register)offset) 84 { 85 case Register.CP0: 86 HandleCPWrite(0, value); 87 break; 88 case Register.CP1: 89 HandleCPWrite(1, value); 90 break; 91 case Register.GenerateInterrupt: 92 HandleGenerateInterrupt(value); 93 break; 94 } 95 this.LogUnhandledWrite(offset, value); 96 } 97 98 public long Size 99 { 100 get 101 { 102 return 0x1000; 103 } 104 } 105 HandleIRQConnect(int sourceNumber, IGPIOReceiver destination, int destinationNumber)106 private void HandleIRQConnect(int sourceNumber, IGPIOReceiver destination, int destinationNumber) 107 { 108 if(sourceNumber > 223) 109 { 110 lock(interProcessorInterrupts) 111 { 112 if(sourceNumber - 224 >= interProcessorInterrupts.Length) 113 { 114 throw new ArgumentException("Invalid source number."); 115 } 116 interProcessorInterrupts[sourceNumber - 224].Connect(destination, destinationNumber); 117 } 118 return; 119 } 120 lock(routingTable) 121 { 122 destinations[sourceNumber] = new Destination(destination, destinationNumber); 123 } 124 } 125 HandleIRQDisconnect(int sourceNumber)126 private void HandleIRQDisconnect(int sourceNumber) 127 { 128 lock(routingTable) 129 { 130 destinations[sourceNumber] = new Destination(); 131 } 132 } 133 OnGPIO(int number, bool value)134 public void OnGPIO(int number, bool value) 135 { 136 lock(routingTable) 137 { 138 if(routingTable[number]) 139 { 140 destinations[number].OnGPIO(value); 141 } 142 } 143 } 144 Reset()145 public void Reset() 146 { 147 Array.Clear(routingTable, 0, routingTable.Length); 148 } 149 HandleGenerateInterrupt(uint value)150 private void HandleGenerateInterrupt(uint value) 151 { 152 var interruptId = (int)value & 3; 153 var targetListField = (value >> 24) & 3; 154 var cpuTargetList = (uint)((value >> 16) & 3); 155 if(!sysbus.TryGetCurrentCPU(out var askingCpu)) 156 { 157 this.Log(LogLevel.Warning, "Generate interrupt write by not a CPU - ignoring."); 158 return; 159 } 160 switch(targetListField) 161 { 162 case 1: 163 cpuTargetList = 2 - askingCpu.MultiprocessingId; 164 break; 165 case 2: 166 cpuTargetList = askingCpu.MultiprocessingId + 1; 167 break; 168 } 169 lock(interProcessorInterrupts) 170 { 171 if((cpuTargetList & 1) != 0) 172 { 173 interProcessorInterrupts[interruptId].Set(); 174 } 175 if((cpuTargetList & 2) != 0) 176 { 177 interProcessorInterrupts[4 + interruptId].Set(); 178 } 179 } 180 } 181 HandleCPRead(int cpuNumber)182 private uint HandleCPRead(int cpuNumber) 183 { 184 lock(interProcessorInterrupts) 185 { 186 var returnValue = 0u; 187 for(var i = 0; i < 4; i++) 188 { 189 returnValue |= interProcessorInterrupts[4 * cpuNumber + i].IsSet ? 1u : 0u; 190 returnValue <<= 1; 191 } 192 returnValue >>= 1; 193 return returnValue; 194 } 195 } 196 HandleCPWrite(int cpuNumber, uint value)197 private void HandleCPWrite(int cpuNumber, uint value) 198 { 199 lock(interProcessorInterrupts) 200 { 201 for(var i = 0; i < 4; i++) 202 { 203 if((value & 1) != 0) 204 { 205 interProcessorInterrupts[4 * cpuNumber + i].Unset(); 206 } 207 value >>= 1; 208 } 209 } 210 } 211 212 private Destination[] destinations; 213 private readonly bool[] routingTable; 214 private readonly GPIO[] interProcessorInterrupts; 215 private readonly IBusController sysbus; 216 217 private const int NumberOfInterrupts = 112; 218 private const int RoutingControlStart = 0x880; 219 private const int RoutingControlEnd = RoutingControlStart + NumberOfInterrupts*2; 220 221 private enum Register 222 { 223 CP0 = 0x800, 224 CP1 = 0x804, 225 GenerateInterrupt = 0x820 226 } 227 228 private struct Destination 229 { DestinationAntmicro.Renode.Peripherals.IRQControllers.MSCM.Destination230 public Destination(IGPIOReceiver receiver, int destinationNo) 231 { 232 this.receiver = receiver; 233 this.destinationNo = destinationNo; 234 } 235 OnGPIOAntmicro.Renode.Peripherals.IRQControllers.MSCM.Destination236 public void OnGPIO(bool state) 237 { 238 receiver.OnGPIO(destinationNo, state); 239 } 240 241 public readonly IGPIOReceiver receiver; 242 public readonly int destinationNo; 243 } 244 } 245 } 246 247