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

index d0b542dc25df53c919c0c10d40c2a97a24432305..5f957b77f01518b59683b516730743a24c8d4c2e 100644 (file)
@@ -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 (file)
index 0000000..4fd7846
--- /dev/null
@@ -0,0 +1,157 @@
+// 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
diff --git a/WindCore/series7/rtc.h b/WindCore/series7/rtc.h
new file mode 100644 (file)
index 0000000..1ce97a6
--- /dev/null
@@ -0,0 +1,72 @@
+// 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