]> localhost Git - WindEmu.git/commitdiff
sa1100: add initial gpio controller implementation
authorGeorge Wright <gw@gwright.org.uk>
Thu, 25 Jun 2026 01:55:23 +0000 (18:55 -0700)
committerGeorge Wright <gw@gwright.org.uk>
Fri, 26 Jun 2026 03:44:07 +0000 (20:44 -0700)
CMakeLists.txt
WindCore/series7/gpio_controller.cpp [new file with mode: 0644]
WindCore/series7/gpio_controller.h [new file with mode: 0644]

index cae2a76a7584105d142ee2e566f427330bf3fedc..54da4653e31079ecb2933fbb1aae9fdbafb436a4 100644 (file)
@@ -23,6 +23,7 @@ set(WIND_CORE_SOURCES
     WindCore/osaris/clps7600.cpp
     WindCore/series5mx/etna.cpp
     WindCore/series5mx/windermere.cpp
+    WindCore/series7/gpio_controller.cpp
     WindCore/series7/sa1100.cpp
     WindCore/series7/sa1100_memory.cpp
 )
diff --git a/WindCore/series7/gpio_controller.cpp b/WindCore/series7/gpio_controller.cpp
new file mode 100644 (file)
index 0000000..39a6ad7
--- /dev/null
@@ -0,0 +1,187 @@
+// ARMware - an ARM emulator
+// Copyright (C) <2007>  Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "gpio_controller.h"
+
+#include "logger.h"
+
+namespace SA1100 {
+
+void GPIOController::initRegisters() {
+  mGPLR = (1 << 16) | (1 << 18) | (1 << 20);
+  mGPDR = 0;
+  mGPSR = 0;
+  mGPCR = 0;
+  mGRER = 0;
+  mGFER = 0;
+  mGEDR = 0;
+  mGAFR = 0;
+}
+
+void GPIOController::reset() {
+  mGPLR = (1 << 16) | (1 << 18) | (1 << 20);
+  mGEDR = 0;
+  mGPDR = 0;
+  mGAFR = 0;
+  mGPLR_backup = mGPLR;
+}
+
+void GPIOController::run() {
+  const uint32_t temp = mGPLR ^ mGPLR_backup;
+
+  if (temp != 0) {
+    mGEDR |= (mGRER & (mGPLR & temp));
+    mGEDR |= (mGFER & (mGPLR_backup & temp));
+
+    mGPLR_backup = mGPLR;
+  }
+}
+
+uint32_t GPIOController::read32(const uint32_t address) const {
+  switch (address) {
+  case GPLR:
+    LOG_REG_R("GPIO GPLR", address, mGPLR);
+    return mGPLR;
+
+  case GPDR:
+    LOG_REG_R("GPIO GPDR", address, mGPDR);
+    return mGPDR;
+
+  case GPSR:
+    // :SA-1110 Developer's Manual: p.77: Wei 2004-Jun-05:
+    //
+    // GPSR & GPCR are write-only registers.
+    LOG_REG_R("GPIO GPSR", address, 0);
+    return 0;
+
+  case GPCR:
+    // :SA-1110 Developer's Manual: p.77: Wei 2004-Jun-05:
+    //
+    // GPSR & GPCR are write-only registers.
+    LOG_REG_R("GPIO GPCR", address, 0);
+    return 0;
+
+  case GRER:
+    LOG_REG_R("GPIO GRER", address, mGRER);
+    return mGRER;
+
+  case GFER:
+    LOG_REG_R("GPIO GFER", address, mGFER);
+    return mGFER;
+
+  case GEDR:
+    LOG_REG_R("GPIO GEDR", address, mGEDR);
+    return mGEDR;
+
+  case GAFR:
+    LOG_REG_R("GPIO GAFR", address, mGAFR);
+    return mGAFR;
+
+  default:
+    LOG_REG_R("GPIO Unknown", address, 0);
+    return 0;
+  }
+}
+
+void GPIOController::write32(const uint32_t address, const uint32_t value) {
+  switch (address) {
+  case GPLR:
+    // :SA-1110 Developer's Manual: p.75: Wei 2004-Jun-05:
+    //
+    // GPLR is a read-only register.
+    LOG_REG_W("GPIO GPLR", address, value);
+    break;
+
+  case GPDR:
+    // :SA-1110 Developer's Manual: p.76: Wei 2004-Jun-05:
+    //
+    // The upper 4 bits are always 0.
+    LOG_REG_W("GPIO GPDR", address, value);
+    mGPDR = (value & 0xFFFFFFF);
+    break;
+
+  case GPSR: {
+    LOG_REG_W("GPIO GPSR", address, value);
+
+    // Determine what pins are configured as output and we want to set it value
+    // now.
+    const uint32_t temp = (mGPDR & (value & 0xFFFFFFF));
+    const uint32_t new_GPLR = mGPLR | temp;
+    const uint32_t diff = mGPLR ^ new_GPLR;
+
+    // Update GEDR
+    mGEDR |= (mGRER & (new_GPLR & diff));
+
+    // Update GPLR
+    mGPLR = new_GPLR;
+  } break;
+
+  case GPCR: {
+    LOG_REG_W("GPIO GPCR", address, value);
+
+    // Determine what pins are configured as output and we want to clear it
+    // value now.
+    const uint32_t temp = (mGPDR & (value & 0xFFFFFFF));
+
+    // Update GEDR
+    mGEDR |= (mGFER & (mGPLR & temp));
+
+    // Update GPLR
+
+    // :SA-1110 Developer's Manual: p.77: Wei 2004-Jul-1:
+    //
+    // To clear an output pin, a one is written to the corresponding bit within
+    // the GPCR.
+    mGPLR &= ~temp;
+  } break;
+
+  case GRER:
+    LOG_REG_W("GPIO GRER", address, value);
+    mGRER = (value & 0xFFFFFFF);
+    break;
+
+  case GFER:
+    LOG_REG_W("GPIO GFER", address, value);
+    mGFER = (value & 0xFFFFFFF);
+    break;
+
+  case GEDR:
+    LOG_REG_W("GPIO GEDR", address, value);
+    // :SA-1110 Developer's Manual: p.79: Wei 2004-Jun-05:
+    //
+    // GEDR status bits are cleared by writing a one to them.
+    // Writing a zero to a GEDR status bit has no effect.
+    mGEDR &= ~(value & 0xFFFFFFF);
+    break;
+
+  case GAFR:
+    LOG_REG_W("GPIO GAFR", address, value);
+    // :SA-1110 Developer's Manual: p.80: Wei 2004-Jun-06:
+    //
+    // A bit set in this register indicates that the corresponding GPIO pin
+    // is to be used for its alternate function.
+    // assert(LDD_BITS == (value & LDD_BITS));
+
+    mGAFR = (value & 0xFFFFFFF);
+    break;
+
+  default:
+    break;
+  }
+}
+
+} // namespace SA1100
diff --git a/WindCore/series7/gpio_controller.h b/WindCore/series7/gpio_controller.h
new file mode 100644 (file)
index 0000000..f7bb094
--- /dev/null
@@ -0,0 +1,100 @@
+// ARMware - an ARM emulator
+// Copyright (C) <2007>  Wei Hu <wei.hu.tw@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef GPIO_CONTROLLER_H
+#define GPIO_CONTROLLER_H
+
+#include <cstdint>
+
+namespace SA1100 {
+
+class GPIOController {
+public:
+  GPIOController() { initRegisters(); }
+
+  void run();
+  void reset();
+
+  uint32_t getInterruptStatus() const { return mGEDR; }
+
+  enum PinState { High, Low };
+
+  void setPinState(int pin, PinState state) {
+    auto GPLR_old = mGPLR;
+    // :SA-1110 Developer's Manual: p.80: Wei 2004-Jul-1:
+    //
+    // A zero in GAFR indicates that the corresponding GPIO pin is to be used
+    // for its normal GPIO function.
+    if (0 == (mGAFR & (1 << pin))) {
+      switch (state) {
+      case PinState::High:
+        mGPLR |= (1 << pin);
+        break;
+      case PinState::Low:
+        mGPLR &= ~(1 << pin);
+        break;
+      }
+    }
+  }
+
+  uint32_t read32(const uint32_t address) const;
+  void write32(const uint32_t address, const uint32_t value);
+
+private:
+  void initRegisters();
+
+  enum {
+    GPLR = 0x90040000,
+    GPDR = 0x90040004,
+    GPSR = 0x90040008,
+    GPCR = 0x9004000C,
+    GRER = 0x90040010,
+    GFER = 0x90040014,
+    GEDR = 0x90040018,
+    GAFR = 0x9004001C
+  };
+
+  // Alternative function
+  enum {
+    LDD_8 = (1 << 2),
+    LDD_9 = (1 << 3),
+    LDD_10 = (1 << 4),
+    LDD_11 = (1 << 5),
+    LDD_12 = (1 << 6),
+    LDD_13 = (1 << 7),
+    LDD_14 = (1 << 8),
+    LDD_15 = (1 << 9),
+
+    LDD_BITS =
+        (LDD_8 | LDD_9 | LDD_10 | LDD_11 | LDD_12 | LDD_13 | LDD_14 | LDD_15)
+  };
+
+  uint32_t mGPLR; // GPIO level register: bit n = GPIO_n, 1 = high
+  uint32_t mGPDR; // GPIO direction register: bit n = GPIO_n, 1 = output
+  uint32_t mGPSR; // GPIO pin output set register
+  uint32_t mGPCR; // GPIO pin output clear register
+  uint32_t mGRER; // GPIO rising-edge detect register
+  uint32_t mGFER; // GPIO falling-edge detect register
+  uint32_t mGEDR; // GPIO edge detect status register
+  uint32_t mGAFR; // GPIO alternate function register
+
+  uint32_t mGPLR_backup;
+};
+
+} // namespace SA1100
+
+#endif // GPIO_CONTROLLER_H