--- /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 "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
--- /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 RTC_H
+#define RTC_H
+
+#include <cstdint>
+#include <ctime>
+
+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