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