1 //
2 // Copyright (c) 2010-2023 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.Linq;
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Exceptions;
14 
15 namespace Antmicro.Renode.Peripherals.GPIOPort
16 {
17     public class LiteX_GPIO : BaseGPIOPort, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize
18     {
LiteX_GPIO(IMachine machine, Type type, bool enableIrq = false)19         public LiteX_GPIO(IMachine machine, Type type, bool enableIrq = false) : base(machine, NumberOfPins)
20         {
21             this.type = type;
22             this.enableIrq = enableIrq;
23 
24             if(type == Type.Out && enableIrq)
25             {
26                 throw new ConstructionException("Out GPIO does not support interrupts");
27             }
28 
29             IRQ = new GPIO();
30 
31             previousState = new bool[NumberOfPins];
32 
33             RegistersCollection = new DoubleWordRegisterCollection(this);
34             Size = DefineRegisters();
35         }
36 
ReadDoubleWord(long offset)37         public uint ReadDoubleWord(long offset)
38         {
39             return RegistersCollection.Read(offset);
40         }
41 
WriteDoubleWord(long offset, uint value)42         public void WriteDoubleWord(long offset, uint value)
43         {
44             RegistersCollection.Write(offset, value);
45         }
46 
Reset()47         public override void Reset()
48         {
49             base.Reset();
50             RegistersCollection.Reset();
51 
52             for(var i = 0; i < previousState.Length; i++)
53             {
54                 previousState[i] = false;
55             }
56 
57             IRQ.Unset();
58         }
59 
60         public GPIO IRQ { get; }
61 
62         public long Size { get; }
63 
64         public DoubleWordRegisterCollection RegistersCollection { get; }
65 
OnGPIO(int number, bool value)66         public override void OnGPIO(int number, bool value)
67         {
68             if(!CheckPinNumber(number))
69             {
70                 return;
71             }
72 
73             base.OnGPIO(number, value);
74 
75             if(!enableIrq)
76             {
77                 // irq support is not enabled
78                 return;
79             }
80 
81             if(State[number] == previousState[number])
82             {
83                 // nothing to do
84                 return;
85             }
86 
87             previousState[number] = State[number];
88 
89             if(irqMode[number].Value == IrqMode.Edge)
90             {
91                 if(irqEdge[number].Value == IrqEdge.Rising)
92                 {
93                     if(State[number])
94                     {
95                         irqPending[number].Value = true;
96                         UpdateInterrupts();
97                     }
98                 }
99                 else // it must be Falling
100                 {
101                     if(!State[number])
102                     {
103                         irqPending[number].Value = true;
104                         UpdateInterrupts();
105                     }
106                 }
107             }
108             else // it must be Change
109             {
110                 irqPending[number].Value = true;
111                 UpdateInterrupts();
112             }
113         }
114 
DefineRegisters()115         private int DefineRegisters()
116         {
117             var offset = 0;
118             if(type != Type.Out)
119             {
120                 offset += DefineInRegisters(offset);
121             }
122 
123             if(type != Type.In)
124             {
125                 offset += DefineOutRegisters(offset);
126             }
127 
128             return offset;
129         }
130 
DefineInRegisters(long offset)131         private int DefineInRegisters(long offset)
132         {
133             var size = 0;
134 
135             ((Registers)offset).Define(this)
136                 .WithValueField(0, NumberOfPins, FieldMode.Read, name: "In",
137                     valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(State));
138             size += 0x4;
139 
140             if(enableIrq)
141             {
142                 ((Registers)offset + 0x4).Define(this)
143                     .WithEnumFields<DoubleWordRegister, IrqMode>(0, 1, NumberOfPins, out irqMode, name: "IRQ mode");
144                 size += 0x4;
145 
146                 ((Registers)offset + 0x8).Define(this)
147                     .WithEnumFields<DoubleWordRegister, IrqEdge>(0, 1, NumberOfPins, out irqEdge, name: "IRQ edge");
148                 size += 0x4;
149 
150                 // status - return 0s for now
151                 ((Registers)offset + 0xc).Define(this)
152                     .WithFlags(0, NumberOfPins, FieldMode.Read, name: "IRQ status");
153                 size += 0x4;
154 
155                 ((Registers)offset + 0x10).Define(this)
156                     .WithFlags(0, NumberOfPins, out irqPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "IRQ pending")
157                     .WithWriteCallback((_, __) => UpdateInterrupts());
158                 size += 0x4;
159 
160                 ((Registers)offset + 0x14).Define(this)
161                     .WithFlags(0, NumberOfPins, out irqEnable, name: "IRQ enable")
162                     .WithWriteCallback((_, __) => UpdateInterrupts());
163                 size += 0x4;
164             }
165 
166             return size;
167         }
168 
DefineOutRegisters(long offset)169         private int DefineOutRegisters(long offset)
170         {
171             var size = 0;
172 
173             ((Registers)offset).Define(this)
174                 .WithValueField(0, NumberOfPins, name: "Out",
175                     writeCallback: (_, val) =>
176                     {
177                         var bits = BitHelper.GetBits((uint)val);
178                         for(var i = 0; i < bits.Length; i++)
179                         {
180                             Connections[i].Set(bits[i]);
181                         }
182                     },
183                     valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(Connections.Where(x => x.Key >= 0).OrderBy(x => x.Key).Select(x => x.Value.IsSet)));
184             size += 0x4;
185 
186             return size;
187         }
188 
UpdateInterrupts()189         private void UpdateInterrupts()
190         {
191             var flag = false;
192             for(var i = 0; i < NumberOfPins; i++)
193             {
194                 flag |= irqEnable[i].Value && irqPending[i].Value;
195             }
196 
197             if(IRQ.IsSet != flag)
198             {
199                 this.Log(LogLevel.Debug, "Setting IRQ to {0}", flag);
200             }
201             IRQ.Set(flag);
202         }
203 
204         private readonly Type type;
205         private readonly bool enableIrq;
206 
207         private IEnumRegisterField<IrqEdge>[] irqEdge;
208         private IEnumRegisterField<IrqMode>[] irqMode;
209 
210         private IFlagRegisterField[] irqPending;
211         private IFlagRegisterField[] irqEnable;
212 
213         private readonly bool[] previousState;
214 
215         private const int NumberOfPins = 32;
216 
217         public enum Type
218         {
219             In,
220             Out,
221             InOut
222         }
223 
224         private enum IrqMode
225         {
226             Edge = 0,
227             Change = 1
228         }
229 
230         private enum IrqEdge
231         {
232             Rising = 0,
233             Falling = 1
234         }
235 
236         private enum Registers
237         {
238             Register1 = 0x0,
239             Register2 = 0x4,
240             Register3 = 0x8,
241             Register4 = 0xc,
242             Register5 = 0x10,
243             Register6 = 0x14,
244             Register7 = 0x18,
245             // the actual layout of registers
246             // depends on the model configuration
247         }
248     }
249 }
250 
251