--- /dev/null
+// 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
--- /dev/null
+// 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