1 // 2 // Copyright (c) 2010-2024 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; 8 using System.Collections.Generic; 9 using System.Linq; 10 using System.Reflection; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals; 15 16 namespace Antmicro.Renode.Utilities 17 { 18 // it's not possible to limit generic type parameter to enum in C# directly, so we verify it in the constructor 19 public class InterruptManager<TInterrupt> where TInterrupt : struct, IConvertible 20 { InterruptManager(IPeripheral master, IGPIO irq = null, string gpioName = null, int subvector = -1)21 public InterruptManager(IPeripheral master, IGPIO irq = null, string gpioName = null, int subvector = -1) 22 { 23 if(!typeof(TInterrupt).IsEnum) 24 { 25 throw new ArgumentException("TInterrupt must be an enum"); 26 } 27 28 this.master = master; 29 activeInterrupts = new HashSet<TInterrupt>(); 30 enabledInterrupts = new HashSet<TInterrupt>(); 31 subvectors = new Dictionary<IGPIO, HashSet<TInterrupt>>(); 32 gpioNames = new Dictionary<IGPIO, string>(); 33 nonsettableInterrupts = new HashSet<TInterrupt>(); 34 enabledOnResetInterrupts = new HashSet<TInterrupt>(); 35 36 var subvectorIdToGpio = new Dictionary<int, IGPIO>(); 37 38 if(irq != null) 39 { 40 subvectorIdToGpio.Add(subvector, irq); 41 gpioNames[irq] = gpioName ?? string.Empty; 42 } 43 else 44 { 45 // scan for irq providers 46 foreach(var member in master.GetType().GetProperties()) 47 { 48 var irqProviderAttribute = (IrqProviderAttribute)member.GetCustomAttributes(typeof(IrqProviderAttribute), false).SingleOrDefault(); 49 if(irqProviderAttribute == null) 50 { 51 continue; 52 } 53 54 var field = member.GetMethod.Invoke(master, new object[0]); 55 if(field == null) 56 { 57 throw new ArgumentException("Trying to create the InterruptManager instance, but the IrqProvider object is not initialized"); 58 } 59 var gpioField = field as IGPIO; 60 if(gpioField == null) 61 { 62 throw new ArgumentException("IrqProviderAttribute can only be used on properties of type IGPIO."); 63 } 64 65 subvectorIdToGpio.Add(irqProviderAttribute.SubvectorId, gpioField); 66 gpioNames[gpioField] = irqProviderAttribute.Name ?? member.Name; 67 } 68 } 69 70 // this iterates over all values of an enum (SpecialName here is to filter out non-value members of enum type) 71 foreach(var member in typeof(TInterrupt).GetFields().Where(x => !x.Attributes.HasFlag(FieldAttributes.SpecialName))) 72 { 73 var subvectorId = 0; 74 var subvectorAttribute = member.GetCustomAttributes(false).OfType<SubvectorAttribute>().SingleOrDefault(); 75 var nonsettableAttribute = member.GetCustomAttributes(false).OfType<NotSettableAttribute>().SingleOrDefault(); 76 var enabledOnResetAttribute = member.GetCustomAttributes(false).OfType<EnabledOnResetAttribute>().SingleOrDefault(); 77 78 if(subvectorAttribute != null) 79 { 80 if(!subvectorIdToGpio.ContainsKey(subvectorAttribute.SubvectorId)) 81 { 82 throw new ArgumentException(string.Format("There is no gpio defined for subvector {0}", subvectorAttribute.SubvectorId)); 83 } 84 subvectorId = subvectorAttribute.SubvectorId; 85 } 86 else 87 { 88 if(!subvectorIdToGpio.ContainsKey(-1)) 89 { 90 throw new ArgumentException("There is no default gpio defined"); 91 } 92 subvectorId = -1; 93 } 94 95 var gpio = subvectorIdToGpio[subvectorId]; 96 if(!subvectors.TryGetValue(gpio, out HashSet<TInterrupt> interrupts)) 97 { 98 interrupts = new HashSet<TInterrupt>(); 99 subvectors.Add(gpio, interrupts); 100 } 101 102 var interrupt = (TInterrupt)Enum.Parse(typeof(TInterrupt), member.Name); 103 interrupts.Add(interrupt); 104 if(nonsettableAttribute != null) 105 { 106 nonsettableInterrupts.Add(interrupt); 107 } 108 109 if(enabledOnResetAttribute != null) 110 { 111 enabledOnResetInterrupts.Add(interrupt); 112 } 113 } 114 115 Reset(); 116 } 117 Reset()118 public void Reset() 119 { 120 activeInterrupts.Clear(); 121 enabledInterrupts.Clear(); 122 foreach(var irq in enabledOnResetInterrupts) 123 { 124 enabledInterrupts.Add(irq); 125 } 126 RefreshInterrupts(); 127 } 128 129 public TRegister GetRegister<TRegister>(Func<TInterrupt, bool, bool> valueProviderCallback = null, Action<TInterrupt, bool, bool> writeCallback = null) where TRegister : PeripheralRegister 130 { 131 var mode = default(FieldMode); 132 if(valueProviderCallback != null) 133 { 134 mode |= FieldMode.Read; 135 } 136 if(writeCallback != null) 137 { 138 mode |= FieldMode.Write; 139 } 140 141 var result = CreateRegister<TRegister>(); 142 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 143 { 144 var local = interruptType; 145 result.DefineFlagField((int)(object)interruptType, mode, name: interruptType.ToString(), 146 valueProviderCallback: valueProviderCallback == null ? null : (Func<bool, bool>)(oldValue => valueProviderCallback(local, oldValue)), 147 writeCallback: writeCallback == null ? null : (Action<bool, bool>)((oldValue, newValue) => writeCallback(local, oldValue, newValue))); 148 } 149 return result; 150 } 151 152 public TRegister GetMaskedInterruptFlagRegister<TRegister>() where TRegister : PeripheralRegister 153 { 154 var result = CreateRegister<TRegister>(); 155 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 156 { 157 var local = interruptType; 158 result.DefineFlagField((int)(object)interruptType, FieldMode.Read, name: interruptType.ToString(), 159 valueProviderCallback: _ => IsSet(local) && IsEnabled(local)); 160 } 161 return result; 162 } 163 164 public TRegister GetRawInterruptFlagRegister<TRegister>() where TRegister : PeripheralRegister 165 { 166 var result = CreateRegister<TRegister>(); 167 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 168 { 169 var local = interruptType; 170 result.DefineFlagField((int)(object)interruptType, FieldMode.Read, name: interruptType.ToString(), 171 valueProviderCallback: _ => IsSet(local)); 172 } 173 return result; 174 } 175 176 public TRegister GetInterruptEnableSetRegister<TRegister>() where TRegister : PeripheralRegister 177 { 178 var result = CreateRegister<TRegister>(); 179 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 180 { 181 var local = interruptType; 182 result.DefineFlagField((int)(object)interruptType, name: interruptType.ToString(), 183 valueProviderCallback: _ => IsEnabled(local), 184 writeCallback: (_, v) => { if(v) EnableInterrupt(local, true); }); 185 } 186 return result; 187 } 188 189 public TRegister GetInterruptEnableClearRegister<TRegister>() where TRegister : PeripheralRegister 190 { 191 var result = CreateRegister<TRegister>(); 192 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 193 { 194 var local = interruptType; 195 result.DefineFlagField((int)(object)interruptType, name: interruptType.ToString(), 196 valueProviderCallback: _ => IsEnabled(local), 197 writeCallback: (_, v) => { if(v) EnableInterrupt(local, false); }); 198 } 199 return result; 200 } 201 202 public TRegister GetInterruptEnableRegister<TRegister>() where TRegister : PeripheralRegister 203 { 204 var result = CreateRegister<TRegister>(); 205 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 206 { 207 var local = interruptType; 208 result.DefineFlagField((int)(object)interruptType, name: interruptType.ToString(), 209 valueProviderCallback: _ => IsEnabled(local), 210 writeCallback: (_, v) => EnableInterrupt(local, v)); 211 } 212 return result; 213 } 214 215 public TRegister GetInterruptSetRegister<TRegister>() where TRegister : PeripheralRegister 216 { 217 var result = CreateRegister<TRegister>(); 218 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 219 { 220 var local = interruptType; 221 if(!nonsettableInterrupts.Contains(interruptType)) 222 { 223 result.DefineFlagField((int)(object)interruptType, FieldMode.Set, name: interruptType.ToString(), 224 writeCallback: (_, __) => SetInterrupt(local)); 225 } 226 } 227 228 return result; 229 } 230 231 public TRegister GetInterruptClearRegister<TRegister>() where TRegister : PeripheralRegister 232 { 233 var result = CreateRegister<TRegister>(); 234 foreach(TInterrupt interruptType in Enum.GetValues(typeof(TInterrupt))) 235 { 236 var local = interruptType; 237 if(!nonsettableInterrupts.Contains(interruptType)) 238 { 239 result.DefineFlagField((int)(object)interruptType, FieldMode.Set, name: interruptType.ToString(), 240 writeCallback: (_, __) => ClearInterrupt(local)); 241 } 242 } 243 244 return result; 245 } 246 EnableInterrupt(TInterrupt interrupt, bool status = true)247 public void EnableInterrupt(TInterrupt interrupt, bool status = true) 248 { 249 if(status) 250 { 251 enabledInterrupts.Add(interrupt); 252 } 253 else 254 { 255 enabledInterrupts.Remove(interrupt); 256 } 257 RefreshInterrupts(); 258 } 259 DisableInterrupt(TInterrupt interrupt)260 public void DisableInterrupt(TInterrupt interrupt) 261 { 262 EnableInterrupt(interrupt, false); 263 } 264 SetInterrupt(TInterrupt interrupt, bool status = true)265 public void SetInterrupt(TInterrupt interrupt, bool status = true) 266 { 267 if(status) 268 { 269 activeInterrupts.Add(interrupt); 270 } 271 else 272 { 273 activeInterrupts.Remove(interrupt); 274 } 275 RefreshInterrupts(); 276 } 277 IsSet(TInterrupt interrupt)278 public bool IsSet(TInterrupt interrupt) 279 { 280 return activeInterrupts.Contains(interrupt); 281 } 282 IsEnabled(TInterrupt interrupt)283 public bool IsEnabled(TInterrupt interrupt) 284 { 285 return enabledInterrupts.Contains(interrupt); 286 } 287 ClearInterrupt(TInterrupt interrupt)288 public void ClearInterrupt(TInterrupt interrupt) 289 { 290 SetInterrupt(interrupt, false); 291 } 292 293 private TRegister CreateRegister<TRegister>() where TRegister : PeripheralRegister 294 { 295 TRegister result = null; 296 if(typeof(TRegister) == typeof(DoubleWordRegister)) 297 { 298 result = (TRegister)(PeripheralRegister)new DoubleWordRegister(master); 299 } 300 else if(typeof(TRegister) == typeof(WordRegister)) 301 { 302 result = (TRegister)(PeripheralRegister)new WordRegister(master); 303 } 304 else if(typeof(TRegister) == typeof(ByteRegister)) 305 { 306 result = (TRegister)(PeripheralRegister)new ByteRegister(master); 307 } 308 return result; 309 } 310 RefreshInterrupts()311 private void RefreshInterrupts() 312 { 313 foreach(var irq in subvectors) 314 { 315 var value = enabledInterrupts.Intersect(irq.Value).Intersect(activeInterrupts).Any(); 316 irq.Key.Set(value); 317 master.Log(LogLevel.Noisy, "{0} set to: {1}", gpioNames[irq.Key], value); 318 } 319 } 320 321 private readonly HashSet<TInterrupt> enabledOnResetInterrupts; 322 private readonly HashSet<TInterrupt> nonsettableInterrupts; 323 private readonly Dictionary<IGPIO, string> gpioNames; 324 private readonly Dictionary<IGPIO, HashSet<TInterrupt>> subvectors; 325 private readonly HashSet<TInterrupt> activeInterrupts; 326 private readonly HashSet<TInterrupt> enabledInterrupts; 327 private readonly IPeripheral master; 328 } 329 330 [AttributeUsage(AttributeTargets.Field)] 331 public class SubvectorAttribute : Attribute 332 { SubvectorAttribute(int subvectorId)333 public SubvectorAttribute(int subvectorId) 334 { 335 SubvectorId = subvectorId; 336 } 337 338 public int SubvectorId { get; private set; } 339 } 340 341 [AttributeUsage(AttributeTargets.Field)] 342 public class NotSettableAttribute : Attribute 343 { 344 } 345 346 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 347 public class IrqProviderAttribute : Attribute 348 { IrqProviderAttribute()349 public IrqProviderAttribute() 350 { 351 SubvectorId = -1; 352 } 353 IrqProviderAttribute(string name, int subvectorId)354 public IrqProviderAttribute(string name, int subvectorId) 355 { 356 if(subvectorId < 0) 357 { 358 throw new ArgumentException("Subvector id must be non-negative"); 359 } 360 361 Name = name; 362 SubvectorId = subvectorId; 363 } 364 365 public string Name { get; private set; } 366 public int SubvectorId { get; private set; } 367 } 368 369 [AttributeUsage(AttributeTargets.Field)] 370 public class EnabledOnResetAttribute : Attribute 371 { 372 } 373 } 374