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