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;
8 using System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 using Antmicro.Renode.Logging;
15 
16 namespace Antmicro.Renode.Peripherals.GPIOPort
17 {
18     public class SiFive_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IKnownSize
19     {
SiFive_GPIO(IMachine machine)20         public SiFive_GPIO(IMachine machine) : base(machine, NumberOfPins)
21         {
22             locker = new object();
23             pins = new Pin[NumberOfPins];
24 
25             var registersMap = new Dictionary<long, DoubleWordRegister>
26             {
27                 {(long)Registers.PinValue, new DoubleWordRegister(this)
28                     .WithValueField(0, 32,
29                         valueProviderCallback: _ =>
30                         {
31                             var readOperations = pins.Select(x => (x.pinOperation & Operation.Read) != 0);
32                             var result = readOperations.Zip(State, (operation, state) => operation && state);
33                             return BitHelper.GetValueFromBitsArray(result);
34                         })
35                 },
36 
37                 {(long)Registers.PinInputEnable, new DoubleWordRegister(this)
38                     .WithValueField(0, 32,
39                         writeCallback: (_, val) =>
40                         {
41                             var bits = BitHelper.GetBits((uint)val);
42                             for(var i = 0; i < bits.Length; i++)
43                             {
44                                 Misc.FlipFlag(ref pins[i].pinOperation, Operation.Read, bits[i]);
45                             }
46                         })
47                 },
48 
49                 {(long)Registers.PinOutputEnable, new DoubleWordRegister(this)
50                     .WithValueField(0, 32,
51 	                    writeCallback: (_, val) =>
52                         {
53                             var bits = BitHelper.GetBits((uint)val);
54                             for (var i = 0; i < bits.Length; i++)
55                             {
56                                 Misc.FlipFlag(ref pins[i].pinOperation, Operation.Write, bits[i]);
57                             }
58                         })
59                 },
60 
61                 {(long)Registers.OutputPortValue, new DoubleWordRegister(this)
62                     .WithValueField(0, 32,
63                         writeCallback: (_, val) =>
64                         {
65                             lock(locker)
66                             {
67                                 var bits = BitHelper.GetBits((uint)val);
68                                 for(var i = 0; i < bits.Length; i++)
69                                 {
70                                     SetPinValue(i, bits[i]);
71                                 }
72                             }
73                         })
74                 },
75 
76                 {(long)Registers.FallInterruptPending, new DoubleWordRegister(this)
77                     .WithFlags(0, 32, out fallInterruptPending, FieldMode.Read | FieldMode.WriteOneToClear)
78                     .WithWriteCallback((_, __) =>
79                     {
80                         UpdateInterrupts();
81                     })
82                 },
83 
84                 {(long)Registers.FallInterruptEnable, new DoubleWordRegister(this)
85                     .WithFlags(0, 32, out fallInterruptEnable)
86                     .WithWriteCallback((_, __) =>
87                     {
88                         UpdateInterrupts();
89                     })
90                 },
91 
92                 {(long)Registers.RiseInterruptPending, new DoubleWordRegister(this)
93                     .WithFlags(0, 32, out riseInterruptPending, FieldMode.Read | FieldMode.WriteOneToClear)
94                     .WithWriteCallback((_, __) =>
95                     {
96                         UpdateInterrupts();
97                     })
98                 },
99 
100                 {(long)Registers.RiseInterruptEnable, new DoubleWordRegister(this)
101                     .WithFlags(0, 32, out riseInterruptEnable)
102                     .WithWriteCallback((_, __) =>
103                     {
104                         UpdateInterrupts();
105                     })
106                 },
107 
108                 {(long)Registers.HighInterruptPending, new DoubleWordRegister(this)
109                     .WithFlags(0, 32, out highInterruptPending, FieldMode.Read | FieldMode.WriteOneToClear)
110                     .WithWriteCallback((_, __) =>
111                     {
112                         UpdateInterrupts();
113                     })
114                 },
115 
116                 {(long)Registers.HighInterruptEnable, new DoubleWordRegister(this)
117                     .WithFlags(0, 32, out highInterruptEnable)
118                     .WithWriteCallback((_, __) =>
119                     {
120                         UpdateInterrupts();
121                     })
122                 },
123 
124                 {(long)Registers.LowInterruptPending, new DoubleWordRegister(this)
125                     .WithFlags(0, 32, out lowInterruptPending, FieldMode.Read | FieldMode.WriteOneToClear)
126                     .WithWriteCallback((_, __) =>
127                     {
128                         UpdateInterrupts();
129                     })
130                 },
131 
132                 {(long)Registers.LowInterruptEnable, new DoubleWordRegister(this)
133                     .WithFlags(0, 32, out lowInterruptEnable)
134                     .WithWriteCallback((_, __) =>
135                     {
136                         UpdateInterrupts();
137                     })
138                 }
139             };
140 
141             registers = new DoubleWordRegisterCollection(this, registersMap);
142         }
143 
ReadDoubleWord(long offset)144         public uint ReadDoubleWord(long offset)
145         {
146             return registers.Read(offset);
147         }
148 
WriteDoubleWord(long offset, uint value)149         public void WriteDoubleWord(long offset, uint value)
150         {
151             registers.Write(offset, value);
152         }
153 
OnGPIO(int number, bool value)154         public override void OnGPIO(int number, bool value)
155         {
156             SetPinValue(number, value);
157         }
158 
Reset()159         public override void Reset()
160         {
161             lock(locker)
162             {
163                 base.Reset();
164                 registers.Reset();
165             }
166         }
167 
168         public long Size => 0x1000;
169 
170         /* UpdateIterrupts() sets the value of Connections[i]. */
UpdateInterrupts()171         private void UpdateInterrupts()
172         {
173             lock(locker)
174             {
175                 for(var i = 0; i < State.Length; i++)
176                 {
177                     var value = State[i];
178                     highInterruptPending[i].Value = value;
179                     lowInterruptPending[i].Value = !value;
180                 }
181 
182                 for(var i = 0; i < NumberOfPins; i++)
183                 {
184                     var falling = fallInterruptEnable[i].Value && fallInterruptPending[i].Value;
185                     var rising = riseInterruptEnable[i].Value && riseInterruptPending[i].Value;
186                     var high = highInterruptEnable[i].Value && highInterruptPending[i].Value;
187                     var low = lowInterruptEnable[i].Value && lowInterruptPending[i].Value;
188 
189                     Connections[i].Set(falling || rising || high || low);
190                 }
191             }
192         }
193 
SetPinValue(int i, bool value)194         private void SetPinValue(int i, bool value)
195         {
196             lock(locker)
197             {
198                 if((pins[i].pinOperation & Operation.Write) == 0)
199                 {
200                     this.Log(LogLevel.Warning, "Trying to write a pin that isn't configured for writing. Skipping.");
201                     return;
202                 }
203 
204                 var interruptsEnabled = fallInterruptEnable[i].Value || riseInterruptEnable[i].Value || highInterruptEnable[i].Value || lowInterruptEnable[i].Value;
205                 var prevState = State[i];
206                 base.OnGPIO(i, value);
207                 if(interruptsEnabled)
208                 {
209                     /* We're handling these 2 interrupts here because we need to know previous pin's state.
210                        The other two are handled in UpdateInterrupts() */
211                     if(!prevState && value)
212                     {
213                         riseInterruptPending[i].Value = true;
214                     }
215                     else if(prevState && !value)
216                     {
217                         fallInterruptPending[i].Value = true;
218                     }
219                     UpdateInterrupts();
220                 }
221                 else
222                 {
223                     Connections[i].Set(value);
224                 }
225             }
226         }
227 
228         private readonly DoubleWordRegisterCollection registers;
229         private readonly object locker;
230         private readonly Pin[] pins;
231 
232         private const int NumberOfPins = 32;
233 
234         private IFlagRegisterField[] fallInterruptEnable;
235         private IFlagRegisterField[] fallInterruptPending;
236         private IFlagRegisterField[] riseInterruptEnable;
237         private IFlagRegisterField[] riseInterruptPending;
238         private IFlagRegisterField[] highInterruptEnable;
239         private IFlagRegisterField[] highInterruptPending;
240         private IFlagRegisterField[] lowInterruptEnable;
241         private IFlagRegisterField[] lowInterruptPending;
242 
243         private struct Pin
244         {
245             public Operation pinOperation;
246         }
247 
248         [Flags]
249         private enum Operation : long
250         {
251             Disabled = 0x0,
252             Read = 0x1,
253             Write = 0x2
254         }
255 
256         private enum Registers : long
257         {
258             PinValue = 0x00,
259             PinInputEnable = 0x04,
260             PinOutputEnable = 0x08,
261             OutputPortValue = 0x0C,
262             InternalPullUpEnable = 0x10,
263             PinDriveStrength = 0x14,
264             RiseInterruptEnable = 0x18,
265             RiseInterruptPending = 0x1C,
266             FallInterruptEnable = 0x20,
267             FallInterruptPending = 0x24,
268             HighInterruptEnable = 0x28,
269             HighInterruptPending = 0x2C,
270             LowInterruptEnable = 0x30,
271             LowInterruptPending = 0x34,
272             HwIOFunctionEnable = 0x38,
273             HwIOFunctionSelect = 0x3C,
274             OutputXor = 0x40
275         }
276     }
277 }
278