1 // 2 // Copyright (c) 2010-2021 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.Collections.ObjectModel; 10 using System.Linq; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure; 13 using Antmicro.Renode.Exceptions; 14 using Antmicro.Renode.Logging; 15 using Antmicro.Renode.Utilities; 16 using Antmicro.Renode.Core.Structure.Registers; 17 using Antmicro.Renode.Peripherals.Bus; 18 19 namespace Antmicro.Renode.Peripherals.IRQControllers 20 { 21 public class PULP_InterruptController : BasicDoubleWordPeripheral, INumberedGPIOOutput, IKnownSize, IIRQController, IPeripheralContainer<PULP_EventController, NullRegistrationPoint> 22 { PULP_InterruptController(IMachine machine)23 public PULP_InterruptController(IMachine machine) : base(machine) 24 { 25 var irqs = new Dictionary<int, IGPIO>(); 26 for(var i = 0; i < NumberOfOutgoingInterrupts; i++) 27 { 28 irqs[i] = new GPIO(); 29 } 30 Connections = new ReadOnlyDictionary<int, IGPIO>(irqs); 31 32 Registers.Mask.Define(this) 33 .WithValueField(0, 32, writeCallback: (_, value) => mask.Value = value, valueProviderCallback: _ => mask.Value, name: "MASK") 34 ; 35 36 Registers.MaskSet.Define(this) 37 .WithValueField(0, 32, out mask, FieldMode.Read | FieldMode.Set, name: "MASK_SET") 38 ; 39 40 Registers.MaskClear.Define(this) 41 .WithValueField(0, 32, writeCallback: (_, value) => mask.Value &= ~value, valueProviderCallback: _ => mask.Value, name: "MASK_CLEAR") 42 ; 43 44 Registers.Interrupt.Define(this) 45 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => interrupt.Value, name: "INT") 46 ; 47 Registers.InterruptSet.Define(this) 48 .WithValueField(0, 32, out interrupt, FieldMode.Read | FieldMode.Set, name: "INT_SET") 49 ; 50 51 Registers.InterruptClear.Define(this) 52 .WithValueField(0, 32, writeCallback: (_, value) => interrupt.Value &= ~value, valueProviderCallback: _ => interrupt.Value, name: "INT_CLEAR") 53 ; 54 55 Registers.FIFO.Define(this) 56 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => TryGetEvent(), name: "FIFO") 57 ; 58 } 59 WriteDoubleWord(long offset, uint value)60 public override void WriteDoubleWord(long offset, uint value) 61 { 62 base.WriteDoubleWord(offset, value); 63 Update(); 64 } 65 Reset()66 public override void Reset() 67 { 68 base.Reset(); 69 Update(); 70 events.Clear(); 71 } 72 OnGPIO(int number, bool value)73 public void OnGPIO(int number, bool value) 74 { 75 if(!value) 76 { 77 return; 78 } 79 interrupt.Value |= 1u << number; 80 Update(); 81 } 82 OnEvent(int number, bool value)83 public void OnEvent(int number, bool value) 84 { 85 if(!value) 86 { 87 return; 88 } 89 events.Enqueue((uint)number); 90 interrupt.Value |= 1u << SoCEvent; 91 Update(); 92 } 93 Register(PULP_EventController peripheral, NullRegistrationPoint registrationPoint)94 public void Register(PULP_EventController peripheral, NullRegistrationPoint registrationPoint) 95 { 96 if(eventController != null) 97 { 98 throw new RegistrationException("Cannot register more than one peripheral."); 99 } 100 machine.RegisterAsAChildOf(this, peripheral, registrationPoint); 101 eventController = peripheral; 102 } 103 Unregister(PULP_EventController peripheral)104 public void Unregister(PULP_EventController peripheral) 105 { 106 if(eventController == null || eventController != peripheral) 107 { 108 throw new RegistrationException("The specified peripheral was never registered."); 109 } 110 machine.UnregisterAsAChildOf(this, peripheral); 111 eventController = null; 112 } 113 GetRegistrationPoints(PULP_EventController peripheral)114 public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(PULP_EventController peripheral) 115 { 116 return eventController != null ? 117 new [] { NullRegistrationPoint.Instance } : 118 Enumerable.Empty<NullRegistrationPoint>(); 119 } 120 121 public IEnumerable<IRegistered<PULP_EventController, NullRegistrationPoint>> Children 122 { 123 get 124 { 125 return eventController != null ? 126 new [] { Registered.Create(eventController, NullRegistrationPoint.Instance) } : 127 Enumerable.Empty<IRegistered<PULP_EventController, NullRegistrationPoint>>(); 128 } 129 } 130 131 public IReadOnlyDictionary<int, IGPIO> Connections { get; } 132 public long Size => 0x800; 133 Update()134 private void Update() 135 { 136 var effectiveInterrupt = interrupt.Value & mask.Value; 137 for(byte i = 0; i < NumberOfOutgoingInterrupts; i++) 138 { 139 Connections[i].Set(BitHelper.IsBitSet(effectiveInterrupt, i)); 140 } 141 } 142 TryGetEvent()143 private uint TryGetEvent() 144 { 145 if(!events.TryDequeue(out var result)) 146 { 147 this.Log(LogLevel.Debug, "Trying to dequeue from an empty event list"); 148 } 149 if(events.Count == 0) 150 { 151 interrupt.Value &= ~(1u << SoCEvent); 152 Update(); 153 } 154 return result; 155 } 156 157 private PULP_EventController eventController; 158 159 private readonly Queue<uint> events = new Queue<uint>(); 160 private readonly IValueRegisterField mask; 161 private readonly IValueRegisterField interrupt; 162 163 private const int NumberOfOutgoingInterrupts = 32; //guess 164 private const int SoCEvent = 26; 165 166 private enum Registers : long 167 { 168 Mask = 0x0, 169 MaskSet = 0x4, 170 MaskClear = 0x8, 171 Interrupt = 0xC, 172 InterruptSet = 0x10, 173 InterruptClear = 0x14, 174 Acknowledge = 0x18, 175 AcknowledgeSet = 0x1C, 176 AcknowledgeClear = 0x20, 177 FIFO = 0x24 178 } 179 } 180 } 181