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 
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Logging;
11 using System;
12 using System.Collections.Generic;
13 using System.Linq;
14 
15 namespace Antmicro.Renode.Peripherals.IRQControllers
16 {
17     public class RenesasRZG_IRQController: BasicDoubleWordPeripheral, IKnownSize, IIRQController, INumberedGPIOOutput
18     {
RenesasRZG_IRQController(IMachine machine)19         public RenesasRZG_IRQController(IMachine machine) : base(machine)
20         {
21             Connections = Enumerable
22                 .Range(0, NrOfGpioOutputs)
23                 .ToDictionary<int, int, IGPIO>(idx => idx, _ => new GPIO());
24 
25             pinFunctionInterrupts = Enumerable
26                 .Range(0, NrOfPinFunctionOutputs)
27                 .Select(_ => new GPIO()).ToArray();
28 
29             DefineRegisters();
30             Reset();
31         }
32 
OnGPIO(int number, bool value)33         public void OnGPIO(int number, bool value)
34         {
35             if(number < NrOfNonMaskableInputs)
36             {
37                 this.WarningLog("Received non maskable interrupt on pin {0} which is not implemented.", number);
38             }
39             else if(number < NrOfNonMaskableInputs + NrOfPinFunctionInputs)
40             {
41                 number -= NrOfNonMaskableInputs;
42                 previousPinFunctionState[number] = pinFunctionState[number];
43                 pinFunctionState[number] = value;
44                 UpdateInterrupts();
45             }
46             else if(number < NrOfAllInputs)
47             {
48                 number -= NrOfNonMaskableInputs + NrOfPinFunctionInputs;
49                 previousGpioState[number] = gpioState[number];
50                 gpioState[number] = value;
51                 UpdateInterrupts();
52             }
53             else
54             {
55                 this.ErrorLog("GPIO number {0} is out of range [0; {1})", number, NrOfGpioInputs);
56             }
57         }
58 
Reset()59         public override void Reset()
60         {
61             base.Reset();
62             Array.Clear(gpioState, 0, gpioState.Length);
63             Array.Clear(previousGpioState, 0, previousGpioState.Length);
64             Array.Clear(pinFunctionState, 0, pinFunctionState.Length);
65             Array.Clear(previousPinFunctionState, 0, previousPinFunctionState.Length);
66             UpdateInterrupts();
67         }
68 
69         public long Size => 0x100;
70 
71         public GPIO IRQ0 => pinFunctionInterrupts[0];
72         public GPIO IRQ1 => pinFunctionInterrupts[1];
73         public GPIO IRQ2 => pinFunctionInterrupts[2];
74         public GPIO IRQ3 => pinFunctionInterrupts[3];
75         public GPIO IRQ4 => pinFunctionInterrupts[4];
76         public GPIO IRQ5 => pinFunctionInterrupts[5];
77         public GPIO IRQ6 => pinFunctionInterrupts[6];
78         public GPIO IRQ7 => pinFunctionInterrupts[7];
79         public IReadOnlyDictionary<int, IGPIO> Connections { get; }
80 
DefineRegisters()81         private void DefineRegisters()
82         {
83             Registers.NonMaskableInterruptStatusControl.Define(this)
84                 .WithTaggedFlag("NSTAT", 0)
85                 .WithReservedBits(1, 15)
86                 .WithTaggedFlag("NSMON", 16)
87                 .WithReservedBits(17, 15);
88 
89             Registers.NonMaskableInterruptTypeSelection.Define(this)
90                 .WithTaggedFlag("NSEL", 0)
91                 .WithReservedBits(1, 31);
92 
93             Registers.InterruptStatusControl.Define(this)
94                 .WithFlags(0, 8, out pinFunctionInterruptStatus, FieldMode.Read | FieldMode.WriteZeroToSet,
95                     writeCallback: InterruptStatusControlWriteCallback,
96                     name: "ISTAT")
97                 .WithReservedBits(8, 24);
98 
99             Registers.InterruptTypeSelection.Define(this)
100                 .WithEnumFields(0, 2, 8, out pinFunctionInterruptType, name: "IISEL")
101                 .WithReservedBits(16, 16);
102 
103             Registers.GpioInterruptStatusControl.Define(this)
104                 .WithFlags(0, 32, out gpioInterruptStatus, FieldMode.Read | FieldMode.WriteZeroToSet,
105                     writeCallback: GpioInterruptStatusControlWriteCallback,
106                     name: "TSTAT");
107 
108             Registers.GpioInterruptTypeSelection0.Define(this)
109                 .WithEnumFields<DoubleWordRegister, GpioInterruptType>(0, 2, 16, out var gpioInterruptType1, name: "TITSEL")
110                 .WithWriteCallback((_, __) => UpdateInterrupts());
111 
112             Registers.GpioInterruptTypeSelection1.Define(this)
113                 .WithEnumFields<DoubleWordRegister, GpioInterruptType>(0, 2, 16, out var gpioInterruptType2, name: "TITSEL")
114                 .WithWriteCallback((_, __) => UpdateInterrupts());
115 
116             gpioInterruptType = gpioInterruptType1.Concat(gpioInterruptType2).ToArray();
117 
118             Registers.GpioInterruptSourceSelection0.DefineMany(this,
119                 NrOfGpioSourceSelectionRegisters, BuildGpioInterruptSourceSelectionRegister);
120 
121             Registers.BusErrorInterruptStatusControl0.Define(this)
122                 .WithTaggedFlags("BESTA", 0, 32);
123 
124             Registers.BusErrorInterruptStatusControl1.Define(this)
125                 .WithTaggedFlags("BESTA", 0, 13)
126                 .WithReservedBits(13, 19);
127 
128             Registers.EccRamErrorInterruptStatusControl0.Define(this)
129                 .WithTaggedFlags("E1STAT", 0, 8)
130                 .WithTaggedFlags("E2STAT", 8, 8)
131                 .WithTaggedFlags("OFSTAT", 16, 8)
132                 .WithReservedBits(24, 8);
133 
134             Registers.EccRamErrorInterruptStatusControl1.Define(this)
135                 .WithTaggedFlags("E1STAT", 0, 8)
136                 .WithTaggedFlags("E2STAT", 8, 8)
137                 .WithTaggedFlags("OFSTAT", 16, 8)
138                 .WithReservedBits(24, 8);
139         }
140 
BuildGpioInterruptSourceSelectionRegister(DoubleWordRegister register, int registerIdx)141         private void BuildGpioInterruptSourceSelectionRegister(DoubleWordRegister register, int registerIdx)
142         {
143             var interruptOffset = registerIdx * 4;
144             register
145                 .WithValueField(0, 7, out gpioInterruptSelect[interruptOffset], name: $"TSSEL{interruptOffset}")
146                 .WithFlag(7, out gpioInterruptEnabled[interruptOffset], name: $"TIEN{interruptOffset}")
147                 .WithValueField(8, 7, out gpioInterruptSelect[interruptOffset + 1], name: $"TSSEL{interruptOffset + 1}")
148                 .WithFlag(15, out gpioInterruptEnabled[interruptOffset + 1], name: $"TIEN{interruptOffset + 1}")
149                 .WithValueField(16, 7, out gpioInterruptSelect[interruptOffset + 2], name: $"TSSEL{interruptOffset + 2}")
150                 .WithFlag(23, out gpioInterruptEnabled[interruptOffset + 2], name: $"TIEN{interruptOffset + 2}")
151                 .WithValueField(24, 7, out gpioInterruptSelect[interruptOffset + 3], name: $"TSSEL{interruptOffset + 3}")
152                 .WithFlag(31, out gpioInterruptEnabled[interruptOffset + 3], name: $"TIEN{interruptOffset + 3}")
153                 .WithWriteCallback((_, __) => UpdateInterrupts());
154         }
155 
UpdateInterrupts()156         private void UpdateInterrupts()
157         {
158             for(var interruptIdx = 0; interruptIdx < NrOfGpioOutputs; interruptIdx++)
159             {
160                 var gpioIdx = gpioInterruptSelect[interruptIdx].Value;
161                 var state = gpioState[gpioIdx];
162                 var gpioStateChanged = state ^ previousGpioState[gpioIdx];
163                 var isInterruptEnabled = gpioInterruptEnabled[interruptIdx].Value;
164                 var trigger = gpioInterruptType[interruptIdx].Value;
165 
166                 if(isInterruptEnabled)
167                 {
168                     switch(trigger)
169                     {
170                         case GpioInterruptType.RisingEdge:
171                             if(gpioStateChanged && state)
172                             {
173                                 gpioInterruptStatus[interruptIdx].Value = true;
174                                 Connections[interruptIdx].Blink();
175                                 this.DebugLog("TINT{0}: blinked", interruptIdx);
176                             }
177                             break;
178                         case GpioInterruptType.FallingEdge:
179                             if(gpioStateChanged && !state)
180                             {
181                                 gpioInterruptStatus[interruptIdx].Value = true;
182                                 Connections[interruptIdx].Blink();
183                                 this.DebugLog("TINT{0}: blinked", interruptIdx);
184                             }
185                             break;
186                         case GpioInterruptType.HighLevel:
187                             gpioInterruptStatus[interruptIdx].Value = state;
188                             Connections[interruptIdx].Set(state);
189                             this.DebugLog("TINT{0}: {1}", interruptIdx, state ? "set" : "unset");
190                             break;
191                         case GpioInterruptType.LowLevel:
192                             gpioInterruptStatus[interruptIdx].Value = !state;
193                             Connections[interruptIdx].Set(!state);
194                             this.DebugLog("TINT{0}: {1}", interruptIdx, !state ? "set" : "unset");
195                             break;
196                     }
197                 }
198                 else
199                 {
200                     gpioInterruptStatus[interruptIdx].Value = false;
201                     Connections[interruptIdx].Unset();
202                     this.DebugLog("TINT{0}: unset", interruptIdx);
203                 }
204             }
205 
206             for(var interruptIdx = 0; interruptIdx < NrOfPinFunctionOutputs; interruptIdx++)
207             {
208                 var state = pinFunctionState[interruptIdx];
209                 var trigger = pinFunctionInterruptType[interruptIdx].Value;
210                 var irqStateChanged = state ^ previousPinFunctionState[interruptIdx];
211 
212                 switch(trigger)
213                 {
214                     case PinFunctionInterruptType.LowLevel:
215                         pinFunctionInterruptStatus[interruptIdx].Value = !state;
216                         pinFunctionInterrupts[interruptIdx].Set(!state);
217                         this.DebugLog("IRQ{0}: {1}", interruptIdx, !state ? "set" : "unset");
218                         break;
219                     case PinFunctionInterruptType.RisingEdge:
220                         if(irqStateChanged && state)
221                         {
222                             pinFunctionInterruptStatus[interruptIdx].Value = true;
223                             pinFunctionInterrupts[interruptIdx].Blink();
224                             this.DebugLog("IRQ{0}: blinked", interruptIdx);
225                         }
226                         break;
227                     case PinFunctionInterruptType.FallingEdge:
228                         if(irqStateChanged && !state)
229                         {
230                             pinFunctionInterruptStatus[interruptIdx].Value = true;
231                             pinFunctionInterrupts[interruptIdx].Blink();
232                             this.DebugLog("IRQ{0}: blinked", interruptIdx);
233                         }
234                         break;
235                     case PinFunctionInterruptType.BothEdges:
236                         if(irqStateChanged)
237                         {
238                             pinFunctionInterruptStatus[interruptIdx].Value = true;
239                             pinFunctionInterrupts[interruptIdx].Blink();
240                             this.DebugLog("IRQ{0}: blinked", interruptIdx);
241                         }
242                         break;
243                 }
244             }
245         }
246 
InterruptStatusControlWriteCallback(int interruptIdx, bool oldVal, bool newVal)247         private void InterruptStatusControlWriteCallback(int interruptIdx, bool oldVal, bool newVal)
248         {
249             var trigger = pinFunctionInterruptType[interruptIdx].Value;
250             if(trigger == PinFunctionInterruptType.LowLevel || newVal)
251             {
252                 pinFunctionInterruptStatus[interruptIdx].Value = oldVal;
253             }
254         }
255 
GpioInterruptStatusControlWriteCallback(int interruptIdx, bool oldVal, bool newVal)256         private void GpioInterruptStatusControlWriteCallback(int interruptIdx, bool oldVal, bool newVal)
257         {
258             var trigger = gpioInterruptType[interruptIdx].Value;
259             switch(trigger)
260             {
261                 case GpioInterruptType.RisingEdge:
262                 case GpioInterruptType.FallingEdge:
263                     if(newVal)
264                     {
265                         gpioInterruptStatus[interruptIdx].Value = oldVal;
266                     }
267                     break;
268                 default:
269                     gpioInterruptStatus[interruptIdx].Value = oldVal;
270                     break;
271             }
272         }
273 
274         private IValueRegisterField[] gpioInterruptSelect = new IValueRegisterField[NrOfGpioOutputs];
275         private IFlagRegisterField[] gpioInterruptEnabled = new IFlagRegisterField[NrOfGpioOutputs];
276         private IFlagRegisterField[] pinFunctionInterruptStatus;
277         private IFlagRegisterField[] gpioInterruptStatus;
278         private IEnumRegisterField<PinFunctionInterruptType>[] pinFunctionInterruptType;
279         private IEnumRegisterField<GpioInterruptType>[] gpioInterruptType;
280 
281         private readonly GPIO[] pinFunctionInterrupts;
282         private readonly bool[] pinFunctionState = new bool[NrOfPinFunctionInputs];
283         private readonly bool[] previousPinFunctionState = new bool[NrOfPinFunctionInputs];
284         private readonly bool[] gpioState = new bool[NrOfGpioInputs];
285         private readonly bool[] previousGpioState = new bool[NrOfGpioInputs];
286 
287         private const int NrOfNonMaskableInputs = 1;
288         private const int NrOfPinFunctionInputs = 8;
289         private const int NrOfGpioInputs = 123;
290         private const int NrOfAllInputs = NrOfNonMaskableInputs + NrOfPinFunctionInputs + NrOfGpioInputs;
291         private const int NrOfGpioOutputs = 32;
292         private const int NrOfPinFunctionOutputs = NrOfPinFunctionInputs;
293         private const int NrOfGpioSourceSelectionRegisters = 8;
294 
295         private enum PinFunctionInterruptType
296         {
297             LowLevel    = 0x0,
298             FallingEdge = 0x1,
299             RisingEdge  = 0x2,
300             BothEdges   = 0x3,
301         }
302 
303         private enum GpioInterruptType
304         {
305             RisingEdge  = 0x0,
306             FallingEdge = 0x1,
307             HighLevel   = 0x2,
308             LowLevel    = 0x3,
309         }
310 
311         private enum Registers
312         {
313             NonMaskableInterruptStatusControl   = 0x00, // NSCR
314             NonMaskableInterruptTypeSelection   = 0x04, // NITSR
315             InterruptStatusControl              = 0x10, // ISCR
316             InterruptTypeSelection              = 0x14, // IITSR
317             GpioInterruptStatusControl          = 0x20, // TSCR
318             GpioInterruptTypeSelection0         = 0x24, // TITSR0
319             GpioInterruptTypeSelection1         = 0x28, // TITSR1
320             GpioInterruptSourceSelection0       = 0x30, // TSSR0
321             GpioInterruptSourceSelection1       = 0x34, // TSSR1
322             GpioInterruptSourceSelection2       = 0x38, // TSSR2
323             GpioInterruptSourceSelection3       = 0x3C, // TSSR3
324             GpioInterruptSourceSelection4       = 0x40, // TSSR4
325             GpioInterruptSourceSelection5       = 0x44, // TSSR5
326             GpioInterruptSourceSelection6       = 0x48, // TSSR6
327             GpioInterruptSourceSelection7       = 0x4C, // TSSR7
328             BusErrorInterruptStatusControl0     = 0x50, // BEISR0
329             BusErrorInterruptStatusControl1     = 0x54, // BEISR1
330             EccRamErrorInterruptStatusControl0  = 0x60, // EREISR0
331             EccRamErrorInterruptStatusControl1  = 0x64, // EREISR1
332         }
333     }
334 }
335