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 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Extensions; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Logging; 13 using System; 14 using System.Linq; 15 using System.Collections.Generic; 16 17 namespace Antmicro.Renode.Peripherals.GPIOPort 18 { 19 public class RenesasRZG_GPIO : BaseGPIOPort, IBytePeripheral, IWordPeripheral, IDoubleWordPeripheral, IKnownSize 20 { RenesasRZG_GPIO(Machine machine)21 public RenesasRZG_GPIO(Machine machine) : base(machine, NrOfPins) 22 { 23 // Prepare gpio indices offsets per port for easy lookup 24 gpioOffsetPerPort[0] = 0; 25 for(var portIdx = 1; portIdx < NrOfPorts; portIdx++) 26 { 27 gpioOffsetPerPort[portIdx] = gpioOffsetPerPort[portIdx - 1] + GetNrOfGPIOPinsForPort(portIdx - 1); 28 } 29 30 DefineRegisters(); 31 } 32 33 // Every register, allows all access widths less than or equal to it's own width. ReadByte(long offset)34 public byte ReadByte(long offset) 35 { 36 // We align offset to registers width 37 if(doubleWordRegisters.HasRegisterAtOffset(offset & ~0x3)) 38 { 39 return this.ReadByteUsingDoubleWord(offset); 40 } 41 else if(wordRegisters.HasRegisterAtOffset(offset & ~0x1)) 42 { 43 return this.ReadByteUsingWord(offset); 44 } 45 return byteRegisters.Read(offset); 46 } 47 WriteByte(long offset, byte value)48 public void WriteByte(long offset, byte value) 49 { 50 // We align offset to registers width 51 if(doubleWordRegisters.HasRegisterAtOffset(offset & ~0x3)) 52 { 53 this.WriteByteUsingDoubleWord(offset, value); 54 return; 55 } 56 if(wordRegisters.HasRegisterAtOffset(offset & ~0x1)) 57 { 58 this.WriteByteUsingWord(offset, value); 59 return; 60 } 61 byteRegisters.Write(offset, value); 62 } 63 ReadWord(long offset)64 public ushort ReadWord(long offset) 65 { 66 // We align offset to registers width 67 if(doubleWordRegisters.HasRegisterAtOffset(offset & ~0x3)) 68 { 69 return this.ReadWordUsingDoubleWord(offset); 70 } 71 return wordRegisters.Read(offset); 72 } 73 WriteWord(long offset, ushort value)74 public void WriteWord(long offset, ushort value) 75 { 76 // We align offset to registers width 77 if(doubleWordRegisters.HasRegisterAtOffset(offset & ~0x3)) 78 { 79 this.WriteWordUsingDoubleWord(offset, value); 80 return; 81 } 82 wordRegisters.Write(offset, value); 83 } 84 ReadDoubleWord(long offset)85 public uint ReadDoubleWord(long offset) 86 { 87 return doubleWordRegisters.Read(offset); 88 } 89 WriteDoubleWord(long offset, uint value)90 public void WriteDoubleWord(long offset, uint value) 91 { 92 doubleWordRegisters.Write(offset, value); 93 } 94 Reset()95 public override void Reset() 96 { 97 base.Reset(); 98 byteRegisters.Reset(); 99 wordRegisters.Reset(); 100 doubleWordRegisters.Reset(); 101 Array.Clear(output, 0, output.Length); 102 Array.Clear(portMode, 0, portMode.Length); 103 Array.Clear(interruptEnabled, 0, interruptEnabled.Length); 104 Array.Clear(pinFunction, 0, pinFunction.Length); 105 Array.Clear(pinFunctionEnabled, 0, pinFunctionEnabled.Length); 106 foreach (var irq in functionInterrupts) 107 { 108 irq.Unset(); 109 } 110 } 111 OnGPIO(int number, bool value)112 public override void OnGPIO(int number, bool value) 113 { 114 base.OnGPIO(number, value); 115 UpdateGPIO(); 116 } 117 118 public long Size => 0x10000; 119 120 public GPIO IRQ0 => functionInterrupts[0]; 121 public GPIO IRQ1 => functionInterrupts[1]; 122 public GPIO IRQ2 => functionInterrupts[2]; 123 public GPIO IRQ3 => functionInterrupts[3]; 124 public GPIO IRQ4 => functionInterrupts[4]; 125 public GPIO IRQ5 => functionInterrupts[5]; 126 public GPIO IRQ6 => functionInterrupts[6]; 127 public GPIO IRQ7 => functionInterrupts[7]; 128 DefineRegisters()129 private void DefineRegisters() 130 { 131 var byteRegistersMap = new Dictionary <long, ByteRegister>(); 132 var wordRegistersMap = new Dictionary <long, WordRegister>(); 133 var doubleWordRegistersMap = new Dictionary <long, DoubleWordRegister>(); 134 135 // Interrupt enable registers are not distributed uniformly across it's region 136 // we keep track of their current offset in this variable instead of calculating it every time. 137 var interruptEnableControlOffset = (long)Registers.InterruptEnableControl; 138 139 // Although different ports have different number of GPIO pins, with maximum of 5 usable pins, 140 // they have the same registers structure. 141 for(var portIdx = 0; portIdx < NrOfPorts; portIdx++) 142 { 143 var portOffset = (long)Registers.Port + portIdx; 144 byteRegistersMap[portOffset] = new ByteRegister(this) 145 .WithFlags(0, NrOfPinsInPortRegister, 146 writeCallback: CreateGPIOOutputWriteCallback(portIdx), 147 valueProviderCallback: CreateGPIOOutputValueProviderCallback(portIdx), 148 name: "P") 149 .WithWriteCallback((_, __) => UpdateGPIO()); 150 151 var portModeOffset = (long)Registers.PortMode + portIdx * 0x2; 152 wordRegistersMap[portModeOffset] = new WordRegister(this) 153 .WithEnumFields<WordRegister, PortMode>(0, 2, 5, 154 valueProviderCallback: CreatePortModeValueProviderCallback(portIdx), 155 writeCallback: CreatePortModeWriteCallback(portIdx), 156 name: "PM") 157 .WithWriteCallback((_, __) => UpdateGPIO()); 158 159 var portModeControlOffset = (long)Registers.PortModeControl + portIdx; 160 byteRegistersMap[portModeControlOffset] = new ByteRegister(this) 161 .WithFlags(0, 5, 162 writeCallback: CreatePortModeControlWriteCallback(portIdx), 163 valueProviderCallback: CreatePortModeControlValueProviderCallback(portIdx), 164 name: "PMC") 165 .WithWriteCallback((_, __) => UpdateGPIO()); 166 167 var portFunctionControlOffset = (long)Registers.PortFunctionControl + portIdx * 0x4; 168 doubleWordRegistersMap[portFunctionControlOffset] = new DoubleWordRegister(this) 169 .WithValueField(0, 3, 170 writeCallback: CreatePortFunctionControlWriteCallback(portIdx, 0), 171 valueProviderCallback: CreatePortFunctionControlValueProviderCallback(portIdx, 0), 172 name: "PFC0") 173 .WithReservedBits(3, 1) 174 .WithValueField(4, 3, 175 writeCallback: CreatePortFunctionControlWriteCallback(portIdx, 1), 176 valueProviderCallback: CreatePortFunctionControlValueProviderCallback(portIdx, 1), 177 name: "PFC1") 178 .WithReservedBits(7, 1) 179 .WithValueField(8, 3, 180 writeCallback: CreatePortFunctionControlWriteCallback(portIdx, 2), 181 valueProviderCallback: CreatePortFunctionControlValueProviderCallback(portIdx, 2), 182 name: "PFC2") 183 .WithReservedBits(11, 1) 184 .WithValueField(12, 3, 185 writeCallback: CreatePortFunctionControlWriteCallback(portIdx, 3), 186 valueProviderCallback: CreatePortFunctionControlValueProviderCallback(portIdx, 3), 187 name: "PFC3") 188 .WithReservedBits(15, 1) 189 .WithValueField(16, 3, 190 writeCallback: CreatePortFunctionControlWriteCallback(portIdx, 4), 191 valueProviderCallback: CreatePortFunctionControlValueProviderCallback(portIdx, 4), 192 name: "PFC4") 193 .WithReservedBits(19, 13) 194 .WithWriteCallback((_, __) => UpdateGPIO()); 195 196 var portInputOffset = (long)Registers.PortInput + portIdx; 197 byteRegistersMap[portInputOffset] = new ByteRegister(this) 198 .WithFlags(0, NrOfPinsInPortRegister, FieldMode.Read, 199 valueProviderCallback: CreateGPIOInputValueProviderCallback(portIdx), 200 name: "PIN"); 201 202 doubleWordRegistersMap[interruptEnableControlOffset] = new DoubleWordRegister(this) 203 .WithFlag(0, 204 writeCallback: CreateInterruptEnableControlWriteCallback(portIdx, 0), 205 valueProviderCallback: CreateInterruptEnableControlValueProviderCallback(portIdx, 0), 206 name: "ISEL0") 207 .WithReservedBits(1, 7) 208 .WithFlag(8, 209 writeCallback: CreateInterruptEnableControlWriteCallback(portIdx, 1), 210 valueProviderCallback: CreateInterruptEnableControlValueProviderCallback(portIdx, 1), 211 name: "ISEL1") 212 .WithReservedBits(9, 7) 213 .WithFlag(16, 214 writeCallback: CreateInterruptEnableControlWriteCallback(portIdx, 2), 215 valueProviderCallback: CreateInterruptEnableControlValueProviderCallback(portIdx, 2), 216 name: "ISEL2") 217 .WithReservedBits(17, 7) 218 .WithFlag(24, 219 writeCallback: CreateInterruptEnableControlWriteCallback(portIdx, 3), 220 valueProviderCallback: CreateInterruptEnableControlValueProviderCallback(portIdx, 3), 221 name: "ISEL3") 222 .WithReservedBits(25, 7) 223 .WithWriteCallback((_, __) => UpdateGPIO()); 224 225 interruptEnableControlOffset += 0x4; 226 227 if(GetNrOfGPIOPinsForPort(portIdx) > 4) 228 { 229 // We have 5 pins per port at most, so we only define here one flag 230 doubleWordRegistersMap[interruptEnableControlOffset] = new DoubleWordRegister(this) 231 .WithFlag(0, 232 writeCallback: CreateInterruptEnableControlWriteCallback(portIdx, 4), 233 valueProviderCallback: CreateInterruptEnableControlValueProviderCallback(portIdx, 4), 234 name: "ISEL0") 235 .WithReservedBits(1, 7) 236 .WithTaggedFlag("ISEL1", 8) 237 .WithReservedBits(9, 7) 238 .WithTaggedFlag("ISEL2", 16) 239 .WithReservedBits(17, 7) 240 .WithTaggedFlag("ISEL3", 24) 241 .WithReservedBits(25, 7) 242 .WithWriteCallback((_, __) => UpdateGPIO()); 243 244 interruptEnableControlOffset += 0x4; 245 } 246 } 247 248 // Some registers are not uniformly distributed over their regions. 249 // We define them in separate loops. 250 for(var registerIdx = 0; registerIdx < NrOfDrivingAbilityControlRegisters; registerIdx++) 251 { 252 var drivingAbilityControlOffset = (long)Registers.DrivingAbilityControl + registerIdx * 0x4; 253 doubleWordRegistersMap[drivingAbilityControlOffset] = new DoubleWordRegister(this) 254 .WithTag("IOLH0", 0, 2) 255 .WithReservedBits(2, 6) 256 .WithTag("IOLH1", 8, 2) 257 .WithReservedBits(10, 6) 258 .WithTag("IOLH2", 16, 2) 259 .WithReservedBits(18, 6) 260 .WithTag("IOLH3", 24, 2) 261 .WithReservedBits(26, 6); 262 } 263 264 for(var registerIdx = 0; registerIdx < NrOfSlewRateSwitchingRegisters; registerIdx++) 265 { 266 var slewRateSwitchingOffset = (long)Registers.SlewRateSwitching + registerIdx * 0x4; 267 doubleWordRegistersMap[slewRateSwitchingOffset] = new DoubleWordRegister(this) 268 .WithTag("SR0", 0, 1) 269 .WithReservedBits(1, 7) 270 .WithTag("SR1", 8, 1) 271 .WithReservedBits(9, 7) 272 .WithTag("SR2", 16, 1) 273 .WithReservedBits(17, 7) 274 .WithTag("SR3", 24, 1) 275 .WithReservedBits(25, 7); 276 } 277 278 for(var registerIdx = 0; registerIdx < NrOfPullUpPullDownSwitchingRegisters; registerIdx++) 279 { 280 var pullUpPullDownSwitchingOffset = (long)Registers.PullUpPullDownSwitching + registerIdx * 0x4; 281 doubleWordRegistersMap[pullUpPullDownSwitchingOffset] = new DoubleWordRegister(this) 282 .WithTag("PUPD0", 0, 2) 283 .WithReservedBits(2, 6) 284 .WithTag("PUPD1", 8, 2) 285 .WithReservedBits(10, 6) 286 .WithTag("PUPD2", 16, 2) 287 .WithReservedBits(18, 6) 288 .WithTag("PUPD3", 24, 2) 289 .WithReservedBits(26, 6); 290 } 291 292 for(var registerIdx = 0; registerIdx < NrOfDigitalNoiseFilterRegisters; registerIdx++) 293 { 294 var digitalNoiseFilterSwitchingOffset = (long)Registers.DigitalNoiseFilterSwitching + registerIdx * 0x4; 295 doubleWordRegistersMap[digitalNoiseFilterSwitchingOffset] = new DoubleWordRegister(this) 296 .WithTag("FILON0", 0, 1) 297 .WithReservedBits(1, 7) 298 .WithTag("FILON1", 8, 1) 299 .WithReservedBits(9, 7) 300 .WithTag("FILON2", 16, 1) 301 .WithReservedBits(17, 7) 302 .WithTag("FILON3", 24, 1) 303 .WithReservedBits(25, 7); 304 305 var digitalNoiseFilterNumberOffset = (long)Registers.DigitalNoiseFilterNumber + registerIdx * 0x4; 306 doubleWordRegistersMap[digitalNoiseFilterNumberOffset] = new DoubleWordRegister(this) 307 .WithTag("FILNUM0", 0, 2) 308 .WithReservedBits(2, 6) 309 .WithTag("FILNUM1", 8, 2) 310 .WithReservedBits(10, 6) 311 .WithTag("FILNUM2", 16, 2) 312 .WithReservedBits(18, 6) 313 .WithTag("FILNUM3", 24, 2) 314 .WithReservedBits(26, 6); 315 316 var digitalNoiseFilterClockSelectionOffset = (long)Registers.DigitalNoiseFilterClockSelection + registerIdx * 0x4; 317 doubleWordRegistersMap[digitalNoiseFilterClockSelectionOffset] = new DoubleWordRegister(this) 318 .WithTag("FILCLK0", 0, 2) 319 .WithReservedBits(2, 6) 320 .WithTag("FILCLK1", 8, 2) 321 .WithReservedBits(10, 6) 322 .WithTag("FILCLK2", 16, 2) 323 .WithReservedBits(18, 6) 324 .WithTag("FILCLK3", 24, 2) 325 .WithReservedBits(26, 6); 326 } 327 328 byteRegistersMap[(long)Registers.SDChannel0VoltageControlRegister] = new ByteRegister(this) 329 .WithTaggedFlag("SD0_PVDD", 0) 330 .WithReservedBits(1, 7); 331 332 byteRegistersMap[(long)Registers.SDChannel1VoltageControlRegister] = new ByteRegister(this) 333 .WithTaggedFlag("SD1_PVDD", 0) 334 .WithReservedBits(1, 7); 335 336 byteRegistersMap[(long)Registers.QSPIVoltageControlRegister] = new ByteRegister(this) 337 .WithTaggedFlag("QSPI_PVDD", 0) 338 .WithReservedBits(1, 7); 339 340 byteRegistersMap[(long)Registers.EthernetChannel0IOVoltageModeControl] = new ByteRegister(this) 341 .WithTaggedFlag("ETH0_1.8V_PVDD", 0) 342 .WithTaggedFlag("ETH0_2.5V_PVDD", 1) 343 .WithReservedBits(2, 6); 344 345 byteRegistersMap[(long)Registers.EthernetChannel1IOVoltageModeControl] = new ByteRegister(this) 346 .WithTaggedFlag("ETH1_1.8V_PVDD", 0) 347 .WithTaggedFlag("ETH1_2.5V_PVDD", 1) 348 .WithReservedBits(2, 6); 349 350 byteRegistersMap[(long)Registers.WriteProtected] = new ByteRegister(this) 351 .WithReservedBits(0, 6) 352 .WithTaggedFlag("PFCWE", 6) 353 .WithTaggedFlag("BOWI", 7); 354 355 byteRegistersMap[(long)Registers.EthernetMiiRgmiiModeControl] = new ByteRegister(this) 356 .WithTaggedFlag("ETH0_MODE", 0) 357 .WithTaggedFlag("ETH1_MODE", 1) 358 .WithReservedBits(2, 6); 359 360 byteRegisters = new ByteRegisterCollection(this, byteRegistersMap); 361 wordRegisters = new WordRegisterCollection(this, wordRegistersMap); 362 doubleWordRegisters = new DoubleWordRegisterCollection(this, doubleWordRegistersMap); 363 } 364 UpdateGPIO()365 private void UpdateGPIO() 366 { 367 for(var gpioIdx = 0; gpioIdx < NrOfPins; gpioIdx++) 368 { 369 var mode = portMode[gpioIdx]; 370 if(interruptEnabled[gpioIdx]) 371 { 372 Connections[gpioIdx].Set(State[gpioIdx]); 373 } 374 else if(mode == PortMode.Output) 375 { 376 Connections[gpioIdx].Set(output[gpioIdx]); 377 } 378 else if(mode == PortMode.OutputInput) 379 { 380 Connections[gpioIdx].Set(State[gpioIdx] || output[gpioIdx]); 381 } 382 else 383 { 384 Connections[gpioIdx].Set(false); 385 } 386 this.DebugLog("GPIO pin {0}: {1}", gpioIdx, Connections[gpioIdx].IsSet ? "set" : "unset"); 387 } 388 389 foreach(var entry in pinAndFunctionToInterruptMap) 390 { 391 var gpioIdx = entry.Key.Item1; 392 var functionIdx = entry.Key.Item2; 393 var interruptIdx = entry.Value; 394 395 if(pinFunctionEnabled[gpioIdx] && pinFunction[gpioIdx] == functionIdx) 396 { 397 functionInterrupts[interruptIdx].Set(State[gpioIdx]); 398 this.DebugLog("IRQ{0}: {1}", interruptIdx, State[gpioIdx] ? "set" : "unset"); 399 } 400 else 401 { 402 functionInterrupts[interruptIdx].Set(false); 403 this.DebugLog("IRQ{0}: unset", interruptIdx); 404 } 405 } 406 } 407 CreateGPIOOutputValueProviderCallback(int portIdx)408 private Func<int, bool, bool> CreateGPIOOutputValueProviderCallback(int portIdx) 409 { 410 return (pinIdx, _) => 411 { 412 // Documentation doesn't state what should be done when accessing pins with indices 413 // greater than real number of pins 414 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 415 { 416 switch(portMode[gpioIdx]) 417 { 418 case PortMode.Output: 419 return output[gpioIdx]; 420 case PortMode.OutputInput: 421 return State[gpioIdx] || output[gpioIdx]; 422 default: 423 return false; 424 } 425 } 426 LogOutOfRangePinWrite(portIdx, pinIdx, Registers.Port); 427 return false; 428 }; 429 } 430 CreateGPIOOutputWriteCallback(int portIdx)431 private Action<int, bool, bool> CreateGPIOOutputWriteCallback(int portIdx) 432 { 433 return (pinIdx, _, value) => 434 { 435 // Documentation doesn't state what should be done when accessing pins with indices 436 // greater than real number of pins 437 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 438 { 439 var mode = portMode[gpioIdx]; 440 if(mode == PortMode.Output || mode == PortMode.OutputInput) 441 { 442 output[gpioIdx] = value; 443 } 444 } 445 else 446 { 447 LogOutOfRangePinRead(portIdx, pinIdx, Registers.Port); 448 } 449 }; 450 } 451 CreateGPIOInputValueProviderCallback(int portIdx)452 private Func<int, bool, bool> CreateGPIOInputValueProviderCallback(int portIdx) 453 { 454 return (pinIdx, _) => 455 { 456 // Documentation doesn't state what should be done when accessing pins with indices 457 // greater than real number of pins 458 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 459 { 460 switch(portMode[gpioIdx]) 461 { 462 case PortMode.Input: 463 return State[gpioIdx]; 464 case PortMode.OutputInput: 465 return State[gpioIdx] || output[gpioIdx]; 466 default: 467 return false; 468 } 469 } 470 LogOutOfRangePinRead(portIdx, pinIdx, Registers.PortInput); 471 return false; 472 }; 473 } 474 CreatePortModeValueProviderCallback(int portIdx)475 private Func<int, PortMode, PortMode> CreatePortModeValueProviderCallback(int portIdx) 476 { 477 return (pinIdx, _) => 478 { 479 // Documentation doesn't state what should be done when accessing pins with indices 480 // greater than real number of pins 481 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 482 { 483 return portMode[gpioIdx]; 484 } 485 LogOutOfRangePinRead(portIdx, pinIdx, Registers.PortMode); 486 return PortMode.HighImpedance; 487 }; 488 } 489 CreatePortModeWriteCallback(int portIdx)490 private Action<int, PortMode, PortMode> CreatePortModeWriteCallback(int portIdx) 491 { 492 return (pinIdx, _, value) => 493 { 494 // Documentation doesn't state what should be done when accessing pins with indices 495 // greater than real number of pins 496 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 497 { 498 portMode[gpioIdx] = value; 499 switch(value) 500 { 501 case PortMode.HighImpedance: 502 output[gpioIdx] = false; 503 State[gpioIdx] = false; 504 break; 505 case PortMode.Output: 506 State[gpioIdx] = false; 507 break; 508 case PortMode.Input: 509 output[gpioIdx] = false; 510 break; 511 case PortMode.OutputInput: 512 // Setting this mode doesn't change anything. 513 break; 514 default: 515 throw new Exception("unreachable"); 516 } 517 } 518 else 519 { 520 LogOutOfRangePinWrite(portIdx, pinIdx, Registers.PortMode); 521 } 522 }; 523 } 524 CreatePortModeControlValueProviderCallback(int portIdx)525 private Func<int, bool, bool> CreatePortModeControlValueProviderCallback(int portIdx) 526 { 527 return (pinIdx, _) => 528 { 529 // Documentation doesn't state what should be done when accessing pins with indices 530 // greater than real number of pins 531 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 532 { 533 return pinFunctionEnabled[gpioIdx]; 534 } 535 LogOutOfRangePinRead(portIdx, pinIdx, Registers.PortModeControl); 536 return false; 537 }; 538 } 539 CreatePortModeControlWriteCallback(int portIdx)540 private Action<int, bool, bool> CreatePortModeControlWriteCallback(int portIdx) 541 { 542 return (pinIdx, _, value) => 543 { 544 // Documentation doesn't state what should be done when accessing pins with indices 545 // greater than real number of pins 546 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 547 { 548 pinFunctionEnabled[gpioIdx] = value; 549 } 550 else 551 { 552 LogOutOfRangePinWrite(portIdx, pinIdx, Registers.PortMode); 553 } 554 }; 555 } 556 CreateInterruptEnableControlValueProviderCallback(int portIdx, int pinIdx)557 private Func<bool, bool> CreateInterruptEnableControlValueProviderCallback(int portIdx, int pinIdx) 558 { 559 return (_) => 560 { 561 // Documentation doesn't state what should be done when accessing pins with indices 562 // greater than real number of pins 563 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 564 { 565 return interruptEnabled[gpioIdx]; 566 } 567 LogOutOfRangePinRead(portIdx, pinIdx, Registers.PortMode); 568 return false; 569 }; 570 } 571 CreateInterruptEnableControlWriteCallback(int portIdx, int pinIdx)572 private Action<bool, bool> CreateInterruptEnableControlWriteCallback(int portIdx, int pinIdx) 573 { 574 return (_, value) => 575 { 576 // Documentation doesn't state what should be done when accessing pins with indices 577 // greater than real number of pins 578 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 579 { 580 interruptEnabled[gpioIdx] = value; 581 } 582 else 583 { 584 LogOutOfRangePinWrite(portIdx, pinIdx, Registers.InterruptEnableControl); 585 } 586 }; 587 } 588 CreatePortFunctionControlValueProviderCallback(int portIdx, int pinIdx)589 private Func<ulong, ulong> CreatePortFunctionControlValueProviderCallback(int portIdx, int pinIdx) 590 { 591 return (_) => 592 { 593 // Documentation doesn't state what should be done when accessing pins with indices 594 // greater than real number of pins 595 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 596 { 597 return (ulong)pinFunction[gpioIdx]; 598 } 599 LogOutOfRangePinRead(portIdx, pinIdx, Registers.PortMode); 600 return 0; 601 }; 602 } 603 CreatePortFunctionControlWriteCallback(int portIdx, int pinIdx)604 private Action<ulong, ulong> CreatePortFunctionControlWriteCallback(int portIdx, int pinIdx) 605 { 606 return (_, value) => 607 { 608 // Documentation doesn't state what should be done when accessing pins with indices 609 // greater than real number of pins 610 if(TryGetGPIOIdx(portIdx, pinIdx, out var gpioIdx)) 611 { 612 // We only implement interrupt peripheral functions. 613 // We also allow selecting default function for pin, which does nothing. 614 if(value == DefaultPinFunctionIdx || pinAndFunctionToInterruptMap.ContainsKey(Tuple.Create(gpioIdx, (int)value))) 615 { 616 pinFunction[gpioIdx] = (int)value; 617 } 618 else if(value > MaxPinFunctionIdx) 619 { 620 this.WarningLog( 621 "Trying to set pin function to invalid value {0}. Function value won't change.", 622 value 623 ); 624 } 625 else 626 { 627 this.WarningLog( 628 "Trying to enable function {0} which is not currently supported for port {1}, pin {2}. Function value won't change.", 629 value, 630 portIdx, 631 pinIdx 632 ); 633 } 634 } 635 else 636 { 637 LogOutOfRangePinWrite(portIdx, pinIdx, Registers.InterruptEnableControl); 638 } 639 }; 640 } 641 TryGetGPIOIdx(int portIdx, int pinIdx, out int gpioIdx)642 private bool TryGetGPIOIdx(int portIdx, int pinIdx, out int gpioIdx) 643 { 644 if(pinIdx > GetNrOfGPIOPinsForPort(portIdx)) 645 { 646 gpioIdx = -1; 647 return false; 648 } 649 gpioIdx = gpioOffsetPerPort[portIdx] + pinIdx; 650 return true; 651 } 652 GetNrOfGPIOPinsForPort(int portIdx)653 private int GetNrOfGPIOPinsForPort(int portIdx) 654 { 655 // Different ports, have different number of GPIO pins. 656 switch(portIdx) 657 { 658 case 42: 659 case 48: 660 return 5; 661 case 43: 662 case 44: 663 case 45: 664 case 46: 665 case 47: 666 return 4; 667 case 5: 668 case 7: 669 case 8: 670 case 13: 671 case 17: 672 case 20: 673 case 37: 674 case 39: 675 case 40: 676 return 3; 677 default: 678 return 2; 679 } 680 } 681 LogOutOfRangePinRead(int portIdx, int pinIdx, Registers register)682 private void LogOutOfRangePinRead(int portIdx, int pinIdx, Registers register) 683 { 684 this.WarningLog( 685 "Trying to read from port {0}, pin {1} in register {2}. This pin doesn't exist. Returning 0x0.", 686 portIdx, 687 pinIdx, 688 register 689 ); 690 } 691 LogOutOfRangePinWrite(int portIdx, int pinIdx, Registers register)692 private void LogOutOfRangePinWrite(int portIdx, int pinIdx, Registers register) 693 { 694 this.WarningLog( 695 "Trying to write to port {0}, pin {1} in register {2}. This pin doesn't exist. Nothing will happen.", 696 portIdx, 697 pinIdx, 698 register 699 ); 700 } 701 702 private const int NrOfPorts = 49; 703 private const int NrOfPins = 123; 704 private const int NrOfFunctionInterrutps = 8; 705 private const int NrOfPinsInPortRegister = 8; 706 private const int NrOfDrivingAbilityControlRegisters = 46; 707 private const int NrOfSlewRateSwitchingRegisters = 46; 708 private const int NrOfPullUpPullDownSwitchingRegisters = 33; 709 private const int NrOfDigitalNoiseFilterRegisters = 52; 710 private const int MaxPinFunctionIdx = 5; 711 private const int DefaultPinFunctionIdx = 0; 712 713 private readonly bool[] output = new bool[NrOfPins]; 714 private readonly bool[] interruptEnabled = new bool[NrOfPins]; 715 private readonly int[] pinFunction = new int[NrOfPins]; 716 private readonly bool[] pinFunctionEnabled = new bool[NrOfPins]; 717 private readonly PortMode[] portMode = new PortMode[NrOfPins]; 718 private readonly int[] gpioOffsetPerPort = new int[NrOfPorts]; 719 private readonly GPIO[] functionInterrupts = Enumerable.Range(0, NrOfFunctionInterrutps).Select(_ => new GPIO()).ToArray(); 720 private readonly Dictionary<Tuple<int, int>, int> pinAndFunctionToInterruptMap = new Dictionary<Tuple<int, int>, int> 721 { 722 {Tuple.Create(0, 1), 0}, 723 {Tuple.Create(1, 1), 1}, 724 {Tuple.Create(2, 1), 2}, 725 {Tuple.Create(3, 1), 3}, 726 {Tuple.Create(4, 1), 4}, 727 {Tuple.Create(5, 1), 5}, 728 {Tuple.Create(6, 1), 6}, 729 {Tuple.Create(7, 1), 7}, 730 {Tuple.Create(30, 4), 0}, 731 {Tuple.Create(31, 4), 1}, 732 {Tuple.Create(32, 4), 2}, 733 {Tuple.Create(32, 3), 7}, 734 {Tuple.Create(37, 4), 3}, 735 {Tuple.Create(38, 4), 4}, 736 {Tuple.Create(39, 4), 5}, 737 {Tuple.Create(40, 4), 6}, 738 {Tuple.Create(41, 4), 7}, 739 {Tuple.Create(98, 4), 4}, 740 {Tuple.Create(99, 4), 5}, 741 {Tuple.Create(100, 4), 6}, 742 {Tuple.Create(101, 4), 7}, 743 {Tuple.Create(114, 3), 0}, 744 {Tuple.Create(115, 3), 1}, 745 {Tuple.Create(116, 3), 2}, 746 {Tuple.Create(117, 3), 3}, 747 }; 748 749 private ByteRegisterCollection byteRegisters; 750 private WordRegisterCollection wordRegisters; 751 private DoubleWordRegisterCollection doubleWordRegisters; 752 753 private enum PortMode 754 { 755 HighImpedance = 0x0, 756 Input = 0x1, 757 Output = 0x2, 758 OutputInput = 0x3, 759 } 760 761 private enum Registers 762 { 763 Port = 0x10, 764 PortMode = 0x120, 765 PortModeControl = 0x210, 766 PortFunctionControl = 0x440, 767 PortInput = 0x810, 768 DrivingAbilityControl = 0x1010, 769 SlewRateSwitching = 0x1410, 770 PullUpPullDownSwitching = 0x1C80, 771 DigitalNoiseFilterSwitching = 0x2008, 772 DigitalNoiseFilterNumber = 0x2408, 773 DigitalNoiseFilterClockSelection = 0x2808, 774 InterruptEnableControl = 0x2C80, 775 SDChannel0VoltageControlRegister = 0x3000, 776 SDChannel1VoltageControlRegister = 0x3004, 777 QSPIVoltageControlRegister = 0x3008, 778 EthernetChannel0IOVoltageModeControl = 0x300C, 779 EthernetChannel1IOVoltageModeControl = 0x3010, 780 WriteProtected = 0x3014, 781 EthernetMiiRgmiiModeControl = 0x3018, 782 } 783 } 784 } 785