From 4ef7c6dc50ddfd09b35de97ac9fc6c190cd3a06e Mon Sep 17 00:00:00 2001 From: George Wright Date: Wed, 24 Jun 2026 19:21:35 -0700 Subject: [PATCH] sa1100: add initial rtc implementation --- CMakeLists.txt | 1 + WindCore/series7/rtc.cpp | 157 +++++++++++++++++++++++++++++++++++++++ WindCore/series7/rtc.h | 72 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 WindCore/series7/rtc.cpp create mode 100644 WindCore/series7/rtc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d0b542d..5f957b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ set(WIND_CORE_SOURCES WindCore/series7/lcd_controller.cpp WindCore/series7/os_timer.cpp WindCore/series7/reset_controller.cpp + WindCore/series7/rtc.cpp WindCore/series7/sa1100.cpp WindCore/series7/sa1100_memory.cpp ) diff --git a/WindCore/series7/rtc.cpp b/WindCore/series7/rtc.cpp new file mode 100644 index 0000000..4fd7846 --- /dev/null +++ b/WindCore/series7/rtc.cpp @@ -0,0 +1,157 @@ +// 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 "rtc.h" + +#include "logger.h" + +namespace SA1100 { + +RTC::RTC(const uint32_t clockSpeed) : mClockSpeed(clockSpeed) { + initRegisters(); + mLatestTime = time(nullptr); +} + +void RTC::initRegisters() { + mRTAR = 0; + mRCNR = 0; + mRTTR = 0; + mRTSR = 0; + mNextRtcCheckCycle = 0; +} + +void RTC::reset() { + // :SA-1110 Developer's Manual: Wei 2003-Dec-08: + // + // bit (4 ~ 31) of RTSR are set to 0 when reset, + // bit (0 ~ 3) have unknown value. + mRTSR &= STATUS_VALID_BIT_MASK; + + mRTTR = 0; +} + +void RTC::run(int64_t passedCycles) { + if (passedCycles < mNextRtcCheckCycle) + return; + + mNextRtcCheckCycle = + passedCycles + + mClockSpeed / 100; // Check 100 times per second of virtual time + + // :SA-1110 Developer's Manual: Wei 2003-Dec-08: + // + // The counter is incremented on rising edges of the 1-Hz clock. + auto currentTime = time(nullptr); + if (currentTime > mLatestTime) { + ++mRCNR; + mLatestTime = currentTime; + } + + // :SA-1110 Developer's Manual: Wei 2003-Dec-08: + // + // If RTAR == RCNR and the enable bit (in status register) is set, + // then the alarm bit in the RTC status register is set. + switch (mRTSR & STATUS_ENABLE_BIT_MASK) { + case 0: + break; + + case STATUS_ALE_BIT: + if (mRTAR == mRCNR) { + mRTSR |= STATUS_AL_BIT; + } + break; + + case STATUS_HZE_BIT: + mRTSR |= STATUS_HZ_BIT; + break; + + case (STATUS_ALE_BIT | STATUS_HZE_BIT): + if (mRTAR == mRCNR) { + mRTSR |= STATUS_AL_BIT; + } + + mRTSR |= STATUS_HZ_BIT; + break; + } +} + +uint32_t RTC::read32(const uint32_t address) const { + switch (address) { + case RTAR: + LOG_REG_R("RTC RTAR", address, mRTAR); + return mRTAR; + + case RCNR: + LOG_REG_R("RTC RCNR", address, mRCNR); + return mRCNR; + + case RTTR: + LOG_REG_R("RTC RTTR", address, mRTTR); + return mRTTR; + + case RTSR: + LOG_REG_R("RTC RTSR", address, mRTSR); + return mRTSR; + + default: + LOG_REG_R("RTC Unknown", address, 0); + return 0; + } +} + +void RTC::write32(const uint32_t address, const uint32_t value) { + switch (address) { + case RTAR: + LOG_REG_W("RTC RTAR", address, value); + mRTAR = value; + break; + + case RCNR: + LOG_REG_W("RTC RCNR", address, value); + mRCNR = value; + break; + + case RTTR: + LOG_REG_W("RTC RTTR", address, value); + // :NOTE: Wei 2004-Jun-06: + // + // I don't support RTC Trim Procedure yet. + // Thus just let it pass by. + + mRTTR = (value & 0x3FFFFFF); + break; + + case RTSR: + LOG_REG_W("RTC RTSR", address, value); + // :SA-1110 Developer's Manual: p.90, p.91: Wei 2003-Dec-09: + // + // Each status bit may be cleared by writing a one to the status register in + // the desired bit position. + // ... + // The AL & HZ bits (bit 0 & 1) are cleared by writing ones to them. + // ... + // All reserved bits are read as 0s and are unaffected by writes. + mRTSR &= ~(value & STATUS_VALID_BIT_MASK); + break; + + default: + LOG_REG_W("RTC Unknown", address, value); + break; + } +} + +} // namespace SA1100 diff --git a/WindCore/series7/rtc.h b/WindCore/series7/rtc.h new file mode 100644 index 0000000..1ce97a6 --- /dev/null +++ b/WindCore/series7/rtc.h @@ -0,0 +1,72 @@ +// 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 RTC_H +#define RTC_H + +#include +#include + +namespace SA1100 { + +class RTC { +public: + RTC(const uint32_t clockSpeed); + inline uint32_t getInterruptStatus() const { return mRTSR; } + + void reset(); + void run(int64_t passedCycles); + + uint32_t read32(const uint32_t address) const; + void write32(const uint32_t address, const uint32_t value); + + enum { + STATUS_AL_BIT = (1 << 0), + STATUS_HZ_BIT = (1 << 1), + STATUS_ALE_BIT = (1 << 2), + STATUS_HZE_BIT = (1 << 3), + + STATUS_ENABLE_BIT_MASK = (STATUS_ALE_BIT | STATUS_HZE_BIT), + + STATUS_VALID_BIT_MASK = + (STATUS_AL_BIT | STATUS_HZ_BIT | STATUS_ALE_BIT | STATUS_HZE_BIT) + }; + +private: + void initRegisters(); + + enum { + RTAR = 0x90010000, + RCNR = 0x90010004, + RTTR = 0x90010008, + RTSR = 0x90010010 + }; + + uint32_t mRTAR; // RTC alarm register + uint32_t mRCNR; // RTC count register + uint32_t mRTTR; // RTC timer trim register + uint32_t mRTSR; // RTC status register + + time_t mLatestTime; + int64_t mNextRtcCheckCycle = 0; + + uint32_t mClockSpeed; +}; + +} // namespace SA1100 + +#endif // RTC_H -- 2.45.2