From: George Wright Date: Thu, 25 Jun 2026 01:55:23 +0000 (-0700) Subject: sa1100: add initial gpio controller implementation X-Git-Url: http://git.gwright.org.uk/?a=commitdiff_plain;h=4c5580fe76c0506cdc1dbcdc2a5cea5082811d5f;p=WindEmu.git sa1100: add initial gpio controller implementation --- diff --git a/CMakeLists.txt b/CMakeLists.txt index cae2a76..54da465 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000..39a6ad7 --- /dev/null +++ b/WindCore/series7/gpio_controller.cpp @@ -0,0 +1,187 @@ +// ARMware - an ARM emulator +// Copyright (C) <2007> Wei Hu +// +// 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 . +// + +#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 index 0000000..f7bb094 --- /dev/null +++ b/WindCore/series7/gpio_controller.h @@ -0,0 +1,100 @@ +// ARMware - an ARM emulator +// Copyright (C) <2007> Wei Hu +// +// 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 . +// + +#ifndef GPIO_CONTROLLER_H +#define GPIO_CONTROLLER_H + +#include + +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