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 System; 8 using System.Linq; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.Peripherals.GPIOPort 16 { 17 public class ARM_AHB_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 18 { ARM_AHB_GPIO(IMachine machine, uint alternateFunctionResetValue = 0, bool hasDedicatedIRQs = false)19 public ARM_AHB_GPIO(IMachine machine, uint alternateFunctionResetValue = 0, bool hasDedicatedIRQs = false) : base(machine, NumberOfGPIOs) 20 { 21 this.alternateFunctionResetValue = alternateFunctionResetValue; 22 this.hasDedicatedIRQs = hasDedicatedIRQs; 23 RegistersCollection = new DoubleWordRegisterCollection(this); 24 25 if(hasDedicatedIRQs) 26 { 27 DedicatedIRQs = new GPIO[NumberOfDedicatedIRQs]; 28 DedicatedIRQs[0] = DedicatedIRQ0; 29 DedicatedIRQs[1] = DedicatedIRQ1; 30 DedicatedIRQs[2] = DedicatedIRQ2; 31 DedicatedIRQs[3] = DedicatedIRQ3; 32 DedicatedIRQs[4] = DedicatedIRQ4; 33 DedicatedIRQs[5] = DedicatedIRQ5; 34 DedicatedIRQs[6] = DedicatedIRQ6; 35 DedicatedIRQs[7] = DedicatedIRQ7; 36 } 37 38 DefineRegisters(); 39 Reset(); 40 } 41 ReadDoubleWord(long offset)42 public uint ReadDoubleWord(long offset) 43 { 44 return RegistersCollection.Read(offset); 45 } 46 WriteDoubleWord(long offset, uint value)47 public void WriteDoubleWord(long offset, uint value) 48 { 49 RegistersCollection.Write(offset, value); 50 } 51 OnGPIO(int number, bool value)52 public override void OnGPIO(int number, bool value) 53 { 54 var previousValue = State[number]; 55 base.OnGPIO(number, value); 56 OnPinStateChanged(number, previousValue, value); 57 } 58 Reset()59 public override void Reset() 60 { 61 bool[] cachedState = new bool[NumberOfGPIOs]; 62 63 Array.Copy(State, cachedState, State.Length); 64 base.Reset(); 65 RegistersCollection.Reset(); 66 UpdateInterrupts(); 67 68 for(byte i = 0; i < NumberOfGPIOs; i++) 69 { 70 if(!softReset.Value) 71 { 72 pinAlternateFunctionEnabled[i] = BitHelper.IsBitSet(alternateFunctionResetValue, i); 73 pinOutputEnabled[i] = false; 74 pullEnable[i].Value = false; 75 pullUpDown[i].Value = false; 76 interruptEnabled[i] = false; 77 interruptStatus[i] = false; 78 } 79 else 80 { 81 State[i] = cachedState[i]; 82 } 83 } 84 } 85 86 public long Size => 0x1000; 87 88 // Combined IRQ is a standard ARM AHB GPIO IRQ which is asserted when any of the pins for which IRQ is enabled is triggered 89 [DefaultInterrupt] 90 public GPIO CombinedIRQ { get; } = new GPIO(); 91 92 // In UT32 variant, a GPIO ports can optionally feature dedicated per-pin IRQs for first eight pins. For those pins the dedicated IRQ is asserted instead of the combined IRQ 93 public GPIO DedicatedIRQ0 { get; } = new GPIO(); 94 public GPIO DedicatedIRQ1 { get; } = new GPIO(); 95 public GPIO DedicatedIRQ2 { get; } = new GPIO(); 96 public GPIO DedicatedIRQ3 { get; } = new GPIO(); 97 public GPIO DedicatedIRQ4 { get; } = new GPIO(); 98 public GPIO DedicatedIRQ5 { get; } = new GPIO(); 99 public GPIO DedicatedIRQ6 { get; } = new GPIO(); 100 public GPIO DedicatedIRQ7 { get; } = new GPIO(); 101 102 public DoubleWordRegisterCollection RegistersCollection { get; } 103 UpdatePinOutput(int idx, bool value)104 private void UpdatePinOutput(int idx, bool value) 105 { 106 if(!pinOutputEnabled[idx]) 107 { 108 this.Log(LogLevel.Noisy, "Attempted to set pin{0} to {1}, but it's not configured as output; ignoring", idx, value); 109 return; 110 } 111 112 if(State[idx] == value) 113 { 114 return; 115 } 116 117 Connections[idx].Set(value); 118 State[idx] = value; 119 } 120 OnPinStateChanged(int idx, bool previous, bool current)121 private void OnPinStateChanged(int idx, bool previous, bool current) 122 { 123 var interruptPending = false; 124 switch(interruptPolarity[idx]) 125 { 126 case InterruptPolarity.LowFalling: 127 if(interruptType[idx] == InterruptType.EdgeTriggered) 128 { 129 interruptPending = !current && (previous != current); 130 } 131 if(interruptType[idx] == InterruptType.LevelTriggered) 132 { 133 interruptPending = !current; 134 } 135 break; 136 case InterruptPolarity.HighRising: 137 if(interruptType[idx] == InterruptType.EdgeTriggered) 138 { 139 interruptPending = current && (previous != current); 140 } 141 if(interruptType[idx] == InterruptType.LevelTriggered) 142 { 143 interruptPending = current; 144 } 145 break; 146 default: 147 throw new Exception("Should not reach here."); 148 } 149 150 interruptStatus[idx] |= interruptPending; 151 UpdateInterrupts(); 152 } 153 UpdateInterrupts()154 private void UpdateInterrupts() 155 { 156 var pendingCombinedInterrupt = false; 157 for(var i = 0; i < NumberOfConnections; ++i) 158 { 159 var pendingInterrupt = interruptEnabled[i] && interruptStatus[i]; 160 if(hasDedicatedIRQs && i < NumberOfDedicatedIRQs) 161 { 162 DedicatedIRQs[i].Set(pendingInterrupt); 163 } 164 else 165 { 166 pendingCombinedInterrupt |= pendingInterrupt; 167 } 168 } 169 CombinedIRQ.Set(pendingCombinedInterrupt); 170 } 171 DefineRegisters()172 private void DefineRegisters() 173 { 174 Registers.Data.Define(this) 175 .WithFlags(0, 16, name: "DATA", 176 valueProviderCallback: (i, _) => 177 { 178 if(pinOutputEnabled[i]) 179 { 180 this.Log(LogLevel.Noisy, "Trying to get value from pin {0} which is configured as output"); 181 return false; 182 } 183 return State[i]; 184 }, 185 writeCallback: (i, _, val) => UpdatePinOutput(i, val)) 186 .WithReservedBits(16, 16); 187 ; 188 Registers.DataOutput.Define(this) 189 .WithFlags(0, 16, name: "DATAOUT", 190 valueProviderCallback: (i, _) => State[i] && pinOutputEnabled[i], 191 writeCallback: (i, _, val) => UpdatePinOutput(i, val)) 192 .WithReservedBits(16, 16); 193 ; 194 Registers.OutputEnableSet.Define(this) 195 .WithFlags(0, 16, name: "OUTENSET", 196 valueProviderCallback: (i, _) => pinOutputEnabled[i], 197 writeCallback: (i, _, val) => { if(val) pinOutputEnabled[i] = true; }) 198 .WithReservedBits(16, 16); 199 ; 200 Registers.OutputEnableClear.Define(this) 201 .WithFlags(0, 16, name: "OUTENCLR", 202 valueProviderCallback: (i, _) => pinOutputEnabled[i], 203 writeCallback: (i, _, val) => { if(val) pinOutputEnabled[i] = false; }) 204 .WithReservedBits(16, 16); 205 ; 206 Registers.AlternateFunctionSet.Define(this) 207 .WithFlags(0, 16, name: "ALTFUNCSET", 208 valueProviderCallback: (i, _) => pinAlternateFunctionEnabled[i], 209 writeCallback: (i, _, val) => { if(val) pinAlternateFunctionEnabled[i] = true; }) 210 .WithReservedBits(16, 16); 211 ; 212 Registers.AlternateFunctionClear.Define(this) 213 .WithFlags(0, 16, name: "ALTFUNCCLR", 214 valueProviderCallback: (i, _) => pinAlternateFunctionEnabled[i], 215 writeCallback: (i, _, val) => { if(val) pinAlternateFunctionEnabled[i] = false; }) 216 .WithReservedBits(16, 16); 217 ; 218 Registers.InterruptEnableSet.Define(this) 219 .WithFlags(0, 16, name: "INTENSET", 220 valueProviderCallback: (i, _) => interruptEnabled[i], 221 writeCallback: (i, _, val) => { if(val) interruptEnabled[i] = true; }) 222 .WithReservedBits(16, 16) 223 .WithWriteCallback((_, __) => UpdateInterrupts()); 224 ; 225 Registers.InterruptEnableClear.Define(this) 226 .WithFlags(0, 16, name: "INTENCLR", 227 valueProviderCallback: (i, _) => interruptEnabled[i], 228 writeCallback: (i, _, val) => { if(val) interruptEnabled[i] = false; }) 229 .WithReservedBits(16, 16) 230 .WithWriteCallback((_, __) => UpdateInterrupts()); 231 ; 232 Registers.InterruptTypeSet.Define(this) 233 .WithFlags(0, 16, name: "INTTYPESET", 234 valueProviderCallback: (i, _) => interruptType[i] == InterruptType.LevelTriggered ? false : true, 235 writeCallback: (i, _, val) => { if(val) interruptType[i] = InterruptType.EdgeTriggered; }) 236 .WithReservedBits(16, 16); 237 ; 238 Registers.InterruptTypeClear.Define(this) 239 .WithFlags(0, 16, name: "INTTYPECLR", 240 valueProviderCallback: (i, _) => interruptType[i] == InterruptType.LevelTriggered ? false : true, 241 writeCallback: (i, _, val) => { if(val) interruptType[i] = InterruptType.LevelTriggered; }) 242 .WithReservedBits(16, 16) 243 .WithWriteCallback((_, __) => UpdateInterrupts()); 244 ; 245 Registers.InterruptPolaritySet.Define(this) 246 .WithFlags(0, 16, name: "INTPOLSET", 247 valueProviderCallback: (i, _) => interruptPolarity[i] == InterruptPolarity.LowFalling ? false : true, 248 writeCallback: (i, _, val) => { if(val) interruptPolarity[i] = InterruptPolarity.HighRising; }) 249 .WithReservedBits(16, 16) 250 .WithWriteCallback((_, __) => UpdateInterrupts()); 251 ; 252 Registers.InterruptPolarityClear.Define(this) 253 .WithFlags(0, 16, name: "INTPOLCLR", 254 valueProviderCallback: (i, _) => interruptPolarity[i] == InterruptPolarity.LowFalling ? false : true, 255 writeCallback: (i, _, val) => { if(val) interruptPolarity[i] = InterruptPolarity.LowFalling; }) 256 .WithReservedBits(16, 16) 257 .WithWriteCallback((_, __) => UpdateInterrupts()); 258 ; 259 Registers.InterruptStatus_InterruptClear.Define(this) 260 .WithFlags(0, 16, name: "INTSTATUS_INTCLEAR", 261 valueProviderCallback: (i, _) => interruptStatus[i], 262 writeCallback: (i, _, value) => 263 { 264 if(value) 265 { 266 interruptStatus[i] = false; 267 } 268 }) 269 .WithReservedBits(16, 16) 270 .WithWriteCallback((_, __) => UpdateInterrupts()) 271 ; 272 Registers.SoftReset.Define(this) 273 .WithFlag(0, out softReset, name: "SOFTRESET") 274 .WithReservedBits(1, 31); 275 ; 276 Registers.PullEnable.Define(this) 277 .WithFlags(0, 16, out pullEnable, name: "PULL_ENABLE") 278 .WithReservedBits(16, 16); 279 ; 280 281 Registers.PullUpDown.Define(this) 282 .WithFlags(0, 16, out pullUpDown, name: "PULL_UP_DOWN") 283 .WithReservedBits(16, 16); 284 ; 285 286 Registers.MaskLowByte0.DefineMany(this, 256, (register, idx) => 287 { 288 register 289 .WithTag("MASKLOWBYTE", 0, 8) 290 .WithReservedBits(8, 24); 291 }); 292 293 Registers.MaskHighByte0.DefineMany(this, 256, (register, idx) => 294 { 295 register 296 .WithTag("MASKHIGHBYTE", 0, 8) 297 .WithReservedBits(8, 24); 298 }); 299 } 300 301 private IFlagRegisterField softReset; 302 private IFlagRegisterField[] pullEnable; 303 private IFlagRegisterField[] pullUpDown; 304 private GPIO[] DedicatedIRQs { get; } 305 306 private readonly bool[] pinOutputEnabled = new bool[NumberOfGPIOs]; 307 private readonly bool[] pinAlternateFunctionEnabled = new bool[NumberOfGPIOs]; 308 private readonly bool[] interruptEnabled = new bool[NumberOfGPIOs]; 309 private readonly bool[] interruptStatus = new bool[NumberOfGPIOs]; 310 private readonly uint alternateFunctionResetValue; 311 private readonly bool hasDedicatedIRQs; 312 private readonly InterruptType[] interruptType = new InterruptType[NumberOfGPIOs]; 313 private readonly InterruptPolarity[] interruptPolarity = new InterruptPolarity[NumberOfGPIOs]; 314 315 private const int NumberOfGPIOs = 16; 316 private const int NumberOfDedicatedIRQs = 8; 317 318 private enum InterruptType 319 { 320 LevelTriggered = 0, 321 EdgeTriggered, 322 } 323 324 private enum InterruptPolarity 325 { 326 LowFalling = 0, 327 HighRising, 328 } 329 330 private enum Registers 331 { 332 Data = 0x000, 333 DataOutput = 0x004, 334 OutputEnableSet = 0x010, 335 OutputEnableClear = 0x014, 336 AlternateFunctionSet = 0x018, 337 AlternateFunctionClear = 0x01c, 338 InterruptEnableSet = 0x020, 339 InterruptEnableClear = 0x024, 340 InterruptTypeSet = 0x028, 341 InterruptTypeClear = 0x02c, 342 InterruptPolaritySet = 0x030, 343 InterruptPolarityClear = 0x034, 344 InterruptStatus_InterruptClear = 0x038, 345 SoftReset = 0x03c, // UT32 specific 346 PullEnable = 0x040, // UT32 specific 347 PullUpDown = 0x044, // UT32 specific 348 MaskLowByte0 = 0x400, // 256 MaskLowByte registers, 0x400-0x7fc 349 MaskHighByte0 = 0x800, // 256 MaskHighByte registers, 0x800-0xbfc 350 } 351 } 352 } 353