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 Antmicro.Renode.Core;
8 using Antmicro.Renode.Core.Structure.Registers;
9 using Antmicro.Renode.Exceptions;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Bus;
12 using System;
13 using System.Collections.Generic;
14 using static Antmicro.Renode.Peripherals.Bus.GaislerAPBPlugAndPlayRecord;
15 
16 namespace Antmicro.Renode.Peripherals.GPIOPort
17 {
18     public sealed class Gaisler_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize, IGaislerAPB
19     {
20         // Connections [0; numberOfConnections) are the actual connections.
21         // Connections [numberOfConnections; numberOfConnections + numberOfInterrupts) are the interrupt outputs.
Gaisler_GPIO(IMachine machine, int numberOfConnections, int numberOfInterrupts, string inputOnlyPins = R)22         public Gaisler_GPIO(IMachine machine, int numberOfConnections, int numberOfInterrupts, string inputOnlyPins = "") : base(machine, numberOfConnections + numberOfInterrupts)
23         {
24             if(numberOfConnections < 1 || numberOfConnections > 32)
25             {
26                 throw new ConstructionException("Number of connections has to be in [1; 32]");
27             }
28             if(numberOfInterrupts < 1 || numberOfInterrupts > 15)
29             {
30                 throw new ConstructionException("Number of interrupts has to be in [1; 15].");
31             }
32 
33             RegistersCollection = new DoubleWordRegisterCollection(this);
34             numberOfActualConnections = numberOfConnections; // NumberOfConnections from BaseGPIOPort also counts the IRQ outputs.
35             this.numberOfInterrupts = numberOfInterrupts;
36             this.inputOnlyPins = new HashSet<int>();
37             try
38             {
39                 foreach(var pin in inputOnlyPins.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
40                 {
41                     this.inputOnlyPins.Add(int.Parse(pin));
42                 }
43             }
44             catch(Exception e)
45             {
46                 throw new ConstructionException($"Failed to parse {nameof(inputOnlyPins)}: {e.Message}", e);
47             }
48             interrupts = new IGPIO[numberOfInterrupts];
49             for(var i = 0; i < numberOfInterrupts; i++)
50             {
51                 interrupts[i] = Connections[numberOfConnections + i];
52             }
53 
54             DefineRegisters();
55             Reset();
56         }
57 
Reset()58         public override void Reset()
59         {
60             base.Reset();
61             foreach(var interrupt in interrupts)
62             {
63                 interrupt.Unset();
64             }
65         }
66 
OnGPIO(int number, bool value)67         public override void OnGPIO(int number, bool value)
68         {
69             if(!CheckPinNumber(number))
70             {
71                 return;
72             }
73             if(isOutput[number].Value)
74             {
75                 this.WarningLog("Writing to GPIO #{0} which is configured as an output", number);
76                 return;
77             }
78 
79             base.OnGPIO(number, value);
80             if(TryGetInterruptIndex(number, out var it))
81             {
82                 UpdateInterrupt(it);
83             }
84         }
85 
86         public long Size => 0x100;
87 
88         public DoubleWordRegisterCollection RegistersCollection { get; }
89 
ReadDoubleWord(long offset)90         public uint ReadDoubleWord(long offset)
91         {
92             return RegistersCollection.Read(offset);
93         }
94 
WriteDoubleWord(long offset, uint value)95         public void WriteDoubleWord(long offset, uint value)
96         {
97             RegistersCollection.Write(offset, value);
98         }
99 
GetVendorID()100         public uint GetVendorID() => VendorID;
101 
GetDeviceID()102         public uint GetDeviceID() => DeviceID;
103 
GetInterruptNumber()104         public uint GetInterruptNumber() => 0;
105 
GetSpaceType()106         public SpaceType GetSpaceType() => SpaceType.APBIOSpace;
107 
DefineRegisters()108         private void DefineRegisters()
109         {
110             Registers.Data.Define(this)
111                 .WithFlags(0, numberOfActualConnections, FieldMode.Read, name: "data",
112                     valueProviderCallback: (i, _) => State[i] && !isOutput[i].Value);
113 
114             // The GRLIB BSP's GRGPIO driver writes all 1s and reads back the value to determine how many GPIO
115             // lines exist, but afterwards it will write 0s there so we don't define tags with allowed value 1
116             Registers.Output.Define(this)
117                 .WithFlags(0, numberOfActualConnections, out outputValue, name: "output",
118                     changeCallback: (i, _, value) => UpdateOutput(i));
119 
120             Registers.Direction.Define(this)
121                 .WithFlags(0, numberOfActualConnections, out isOutput, name: "direction",
122                     changeCallback: (i, _, value) => UpdateOutput(i));
123 
124             Registers.InterruptMask.Define(this)
125                 .WithFlags(FirstInterruptPinIndex, numberOfInterrupts, out interruptMask, name: "interruptMask",
126                     changeCallback: (i, _, value) => UpdateInterrupt(i));
127 
128             Registers.InterruptPolarity.Define(this)
129                 .WithFlags(FirstInterruptPinIndex, numberOfInterrupts, out interruptPolarity, name: "interruptPolarity",
130                     changeCallback: (i, _, value) => UpdateInterrupt(i));
131 
132             Registers.InterruptEdge.Define(this)
133                 .WithFlags(FirstInterruptPinIndex, numberOfInterrupts, out interruptEdge, name: "interruptEdge",
134                     changeCallback: (i, _, value) => UpdateInterrupt(i));
135 
136             Registers.Bypass.Define(this)
137                 .WithValueField(0, 32, name: "bypass");
138         }
139 
TryGetInterruptIndex(int pin, out int it)140         private bool TryGetInterruptIndex(int pin, out int it)
141         {
142             it = pin - FirstInterruptPinIndex;
143             return it >= 0 && it < numberOfInterrupts;
144         }
145 
UpdateInterrupt(int it)146         private void UpdateInterrupt(int it)
147         {
148             var pin = FirstInterruptPinIndex + it;
149 
150             // Output pins cannot trigger interrupts
151             if(isOutput[pin].Value)
152             {
153                 return;
154             }
155 
156             var interruptState = interruptMask[it].Value && State[pin] == interruptPolarity[it].Value;
157             // For edge-triggered interrupts we blink the output on the appropriate edge
158             if(interruptEdge[it].Value)
159             {
160                 if(interruptState)
161                 {
162                     interrupts[it].Blink();
163                 }
164             }
165             else
166             {
167                 interrupts[it].Set(interruptState);
168             }
169         }
170 
UpdateOutput(int pin)171         private void UpdateOutput(int pin)
172         {
173             if(!isOutput[pin].Value)
174             {
175                 return;
176             }
177             if(inputOnlyPins.Contains(pin))
178             {
179                 this.WarningLog("Ignoring attempt to drive input-only pin #{0}", pin);
180                 return;
181             }
182             Connections[pin].Set(outputValue[pin].Value);
183         }
184 
185         private const uint VendorID = 0x01; // Gaisler Research
186         private const uint DeviceID = 0x01a; // GRGPIO
187         private const int FirstInterruptPinIndex = 1;
188         private readonly int numberOfInterrupts;
189         private readonly int numberOfActualConnections;
190         private readonly IGPIO[] interrupts;
191         private readonly HashSet<int> inputOnlyPins;
192 
193         private IFlagRegisterField[] isOutput;
194         private IFlagRegisterField[] outputValue;
195         private IFlagRegisterField[] interruptMask;
196         private IFlagRegisterField[] interruptPolarity;
197         private IFlagRegisterField[] interruptEdge;
198 
199         private enum Registers : uint
200         {
201             Data = 0x00,
202             Output = 0x04,
203             Direction = 0x08,
204             InterruptMask = 0x0c,
205             InterruptPolarity = 0x10,
206             InterruptEdge = 0x14,
207             Bypass = 0x18,
208         }
209     }
210 }
211