]> localhost Git - WindEmu.git/commitdiff
add rudimentary rtc impl
authorGeorge Wright <gw@gwright.org.uk>
Sat, 7 Dec 2024 21:00:23 +0000 (13:00 -0800)
committerGeorge Wright <gw@gwright.org.uk>
Sat, 7 Dec 2024 21:00:23 +0000 (13:00 -0800)
WindCore/WindCore.pro
WindCore/sa1100.cpp
WindCore/sa1100.h
WindCore/sa1100/interrupt_controller.cpp
WindCore/sa1100/interrupt_controller.h
WindCore/sa1100/rtc.cpp [new file with mode: 0644]
WindCore/sa1100/rtc.h [new file with mode: 0644]

index 6c67c42cbb149c9c851af7a524687b5aadf94885..db3af5a0638cc2e03df21c7fd132b6435b19763a 100644 (file)
@@ -41,7 +41,8 @@ SOURCES += \
     sa1100/power_manager.cpp \
     sa1100/os_timer.cpp \
     sa1100/reset_controller.cpp \
-    sa1100/uart.cpp
+    sa1100/uart.cpp \
+    sa1100/rtc.cpp
 
 HEADERS += \
     arm710.h \
@@ -71,7 +72,9 @@ HEADERS += \
     sa1100/os_timer.h \
     sa1100/reset_controller.h \
     sa1100/serial_3.h \
-    sa1100/uart.h
+    sa1100/uart.h \
+    sa1100/rtc.h
+
 unix {
     target.path = /usr/lib
     INSTALLS += target
index 0a8864f9bea68fdbc08dfb6ef6e161bbf22e8548..c74ee6399bc8ac855024ff802701df8b3d6b91cf 100644 (file)
@@ -11,7 +11,8 @@ Emulator::Emulator() : EmuBase(false) {
        gpioController = new GPIOController();
        serial3 = new Serial3(serialOutput);
        resetController = new ResetController();
-       intController = new IntController(lcdController, osTimer, gpioController, serial3);
+       rtc = new RTC();
+       intController = new IntController(lcdController, osTimer, gpioController, serial3, rtc);
        powerManager = new PowerManager();
        MemoryBlockC0 = new uint8_t[memoryMask+1];
        MemoryBlockC8 = new uint8_t[memoryMask+1];
@@ -28,6 +29,7 @@ Emulator::~Emulator() {
        delete intController;
        delete powerManager;
        delete resetController;
+       delete rtc;
        delete[] MemoryBlockC0;
        delete[] MemoryBlockC8;
        // delete[] MemoryBlockD0;
@@ -115,7 +117,7 @@ uint32_t Emulator::readSCM32(uint32_t physAddr) {
        case 0x9001:
                // RTC
                printf("Getting RTC at 0x%08x\n", physAddr);
-               return 0x0;
+               return rtc->get_data(physAddr);
        case 0x9002:
                // Power manager
                printf("Getting power manager at 0x%08x\n", physAddr);
@@ -150,6 +152,7 @@ bool Emulator::writeSCM32(uint32_t value, uint32_t physAddr) {
        case 0x9001:
                // RTC
                printf("RTC write 0x%08x at 0x%08x\n", value, physAddr);
+               rtc->put_data(physAddr, value);
                return true;
        case 0x9002:
                // Power manager
@@ -951,7 +954,7 @@ void Emulator::configure() {
        uart2.cpu = this;
 
        nextTickAt = TICK_INTERVAL;
-       rtc = getRTC();
+       nextRTCTick = 0;
        memoryConfig.reset();
        setProcessorID(0x4401A111);
        powerManager->reset();
@@ -960,6 +963,7 @@ void Emulator::configure() {
        intController->reset();
        gpioController->reset();
        asic14->reset();
+       rtc->reset();
        reset();
 }
 
@@ -988,6 +992,7 @@ bool Emulator::executeUntil(int64_t cycles) {
                lcdController->reset();
                intController->reset();
                gpioController->reset();
+               rtc->reset();
                reset();
        }
 
@@ -995,7 +1000,6 @@ bool Emulator::executeUntil(int64_t cycles) {
                if (passedCycles >= nextTickAt) {
                        // increment RTCDIV
                        if ((pwrsr & 0x3F) == 0x3F) {
-                               rtc++;
                                pwrsr &= ~0x3F;
                        } else {
                                pwrsr++;
@@ -1007,6 +1011,11 @@ bool Emulator::executeUntil(int64_t cycles) {
                if (passedCycles % TICKS_3_6864_MHZ == 0) {
                        osTimer->tick();
                }
+               if (passedCycles >= nextRTCTick) {
+                       printf("RTC tick\n");
+                       rtc->run();
+                       nextRTCTick += TICKS_1_HZ;
+               }
                gpioController->run();
                serial3->run();
                intController->run();
index 9de390eed2ca6e0ae011c8aeba99fcb62f4bf0a7..6212d8516ccf084a538352bfcce36275a4579694 100644 (file)
@@ -14,6 +14,7 @@
 #include "sa1100/os_timer.h"
 #include "sa1100/reset_controller.h"
 #include "sa1100/serial_3.h"
+#include "sa1100/rtc.h"
 
 namespace SA1100 {
 
@@ -48,9 +49,9 @@ private:
     uint32_t pwrsr = 0x00002000; // cold start flag
     uint32_t lcdControl = 0;
     uint32_t lcdAddress = 0;
-    uint32_t rtc = 0;
        uint16_t lastSSIRequest = 0;
        int ssiReadCounter = 0;
+       uint32_t nextRTCTick = 0;
 
        uint32_t kScan = 0;
        uint8_t keyboardColumns[8] = {0,0,0,0,0,0,0};
@@ -66,6 +67,7 @@ private:
        IntController* intController;
        PowerManager* powerManager;
        ResetController* resetController;
+       RTC* rtc;
        Serial3* serial3;
        ASIC14* asic14;
 
index 3f6e43306cf0a513f35ec3971f887127036dba6d..7f0b6d0014218e42f462fcd7538f9d7ba48ed5ff 100644 (file)
@@ -22,11 +22,13 @@ namespace SA1100 {
   IntController::IntController(LCDController* const lcdController,
                                OsTimer* const osTimer,
                                GPIOController* const gpioController,
-                               Serial3* const serial3)
+                               Serial3* const serial3,
+                               RTC* const rtc)
     : mOsTimer(osTimer),
       mLCDController(lcdController),
       mGPIOController(gpioController),
-      mSerial3(serial3) {
+      mSerial3(serial3),
+      mRTC(rtc) {
     init_register();
   }
   
@@ -275,34 +277,37 @@ namespace SA1100 {
     
     // check RTC
     
-    // {
-    //   uint32_t const rtc_status = mp_rtc->get_interrupt_status();
+    {
+      uint32_t const rtc_status = mRTC->get_interrupt_status();
       
-    //   switch (rtc_status)
-    //   {
-    //   case 0:
-    //     m_ICPR &= ~(RTC_ALARM_BIT_MASK | RTC_HZ_BIT_MASK);
-    //     break;
+      switch (rtc_status)
+      {
+      case 0:
+        m_ICPR &= ~(RTC_ALARM_BIT_MASK | RTC_HZ_BIT_MASK);
+        break;
         
-    //   case RTC::STATUS_AL_BIT:
-    //     m_ICPR |= RTC_ALARM_BIT_MASK;
-    //     m_ICPR &= ~RTC_HZ_BIT_MASK;
-    //     break;
+      case RTC::STATUS_AL_BIT:
+        printf("RTC alarm fire\n");
+        m_ICPR |= RTC_ALARM_BIT_MASK;
+        m_ICPR &= ~RTC_HZ_BIT_MASK;
+        break;
         
-    //   case RTC::STATUS_HZ_BIT:
-    //     m_ICPR |= RTC_HZ_BIT_MASK;
-    //     m_ICPR &= ~RTC_ALARM_BIT_MASK;
-    //     break;
+      case RTC::STATUS_HZ_BIT:
+        printf("RTC 1hz fire\n");
+        m_ICPR |= RTC_HZ_BIT_MASK;
+        m_ICPR &= ~RTC_ALARM_BIT_MASK;
+        break;
         
-    //   case (RTC::STATUS_AL_BIT | RTC::STATUS_HZ_BIT):
-    //     m_ICPR |= (RTC_ALARM_BIT_MASK | RTC_HZ_BIT_MASK);
-    //     break;
+      case (RTC::STATUS_AL_BIT | RTC::STATUS_HZ_BIT):
+        printf("RTC 1hz and alarm fire\n");
+        m_ICPR |= (RTC_ALARM_BIT_MASK | RTC_HZ_BIT_MASK);
+        break;
         
-    //   default:
-    //     assert(!"Should not reach here.");
-    //     break;
-    //   }
-    // }
+      default:
+        assert(!"Should not reach here.");
+        break;
+      }
+    }
     
     // check LCD controller
     
index ac4fe50725daeaeb76a200e9ef689bb76d8e0387..06dd8ffcdd151e4c1e4dc12b2fbb682d1d75ed4f 100644 (file)
@@ -25,6 +25,7 @@
 #include "os_timer.h"
 #include "serial_3.h"
 #include "uart.h"
+#include "rtc.h"
 
 namespace SA1100 {
 
@@ -84,6 +85,7 @@ class IntController {
     LCDController* const mLCDController;
     GPIOController* const mGPIOController;
     Serial3* const mSerial3;
+    RTC* const mRTC;
     
     // Register location
     
@@ -133,7 +135,8 @@ class IntController {
     IntController(LCDController* const lcdController,
                   OsTimer* const osTimer,
                   GPIOController* const gpioController,
-                  Serial3* const serial3);
+                  Serial3* const serial3,
+                  RTC* const rtc);
     
     // Operation
     
diff --git a/WindCore/sa1100/rtc.cpp b/WindCore/sa1100/rtc.cpp
new file mode 100644 (file)
index 0000000..6e2d503
--- /dev/null
@@ -0,0 +1,169 @@
+// 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"
+
+
+namespace SA1100 {
+
+RTC::RTC()
+{
+    init_register();
+}
+
+void RTC::run()
+{
+    // :SA-1110 Developer's Manual: Wei 2003-Dec-08:
+    //
+    // The counter is incremented on rising edges of the 1-Hz clock.
+    ++m_RCNR;
+
+    // :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 (m_RTSR & STATUS_ENABLE_BIT_MASK)
+    {
+    case 0:
+        break;
+        
+    case STATUS_ALE_BIT:
+        if (m_RTAR == m_RCNR)
+        {
+    #if TRACE_RTC
+        g_log_file << "RTC: enable alarm: " << std::hex << m_RCNR << std::endl;
+    #endif
+        
+        m_RTSR |= STATUS_AL_BIT;
+        }
+        break;
+        
+    case STATUS_HZE_BIT:
+    #if TRACE_RTC
+        g_log_file << "RTC: enable hz: " << std::hex << m_RCNR << std::endl;
+    #endif
+        
+        m_RTSR |= STATUS_HZ_BIT;
+        break;
+        
+    case (STATUS_ALE_BIT | STATUS_HZE_BIT):
+        if (m_RTAR == m_RCNR)
+        {
+    #if TRACE_RTC
+        g_log_file << "RTC: enable alarm: " << std::hex << m_RCNR << std::endl;
+    #endif
+        
+        m_RTSR |= STATUS_AL_BIT;
+        }
+        
+    #if TRACE_RTC
+        g_log_file << "RTC: enable hz: " << std::hex << m_RCNR << std::endl;
+    #endif
+        
+        m_RTSR |= STATUS_HZ_BIT;
+        break;
+    }
+}
+
+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.
+    m_RTSR &= STATUS_VALID_BIT_MASK;
+
+    m_RTTR = 0;
+}
+
+uint32_t RTC::get_data(uint32_t const address) const
+{
+    #if TRACE_RTC
+    g_log_file << "RTC: get value at " << std::hex << address << std::endl;
+    #endif
+
+    switch (address)
+    {
+    case RTAR: return m_RTAR;
+    case RCNR: return m_RCNR;
+    case RTTR: return m_RTTR;
+    case RTSR: return m_RTSR;
+        
+    default:
+        /*assert(!"Should not reach here.");*/
+        return 0;
+    }
+}
+
+void RTC::put_data(uint32_t const address, uint32_t const value)
+{
+    switch (address)
+    {
+    case RTAR:
+    #if TRACE_RTC
+        g_log_file << "RTC: set alarm: " << std::hex << value << std::endl;
+    #endif
+        
+        m_RTAR = value;
+        break;
+        
+    case RCNR:
+    #if TRACE_RTC
+        g_log_file << "RTC: set RCNR: " << std::hex << value << std::endl;
+    #endif
+        
+        m_RCNR = value;
+        break;
+        
+    case RTTR:
+        // :NOTE: Wei 2004-Jun-06:
+        //
+        // I don't support RTC Trim Procedure yet.
+        // Thus just let it pass by.
+    #if TRACE_RTC
+        g_log_file << "RTC: Trim Procedure, using " << value << std::endl;
+    #endif
+        
+        m_RTTR = (value & 0x3FFFFFF);
+        break;
+        
+    case RTSR:
+    #if TRACE_RTC
+        g_log_file << "RTC: setting RTSR: orig: " << std::hex << m_RTSR << ", value: " << value << std::endl;
+    #endif
+        
+        // :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.
+        m_RTSR &= ~(value & STATUS_VALID_BIT_MASK);
+        
+    #if TRACE_RTC
+        g_log_file << "RTC: setting RTSR: new: " << std::hex << m_RTSR << std::endl;
+    #endif
+        break;
+        
+    default:
+        /*assert(!"Should not reach here.");*/
+        break;
+    }
+}
+
+} // namespace SA1100
diff --git a/WindCore/sa1100/rtc.h b/WindCore/sa1100/rtc.h
new file mode 100644 (file)
index 0000000..a30ae5c
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <stdint.h>
+
+namespace SA1100 {
+
+class RTC {
+  public:
+    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:
+    enum
+    {
+      RTAR = 0x90010000,
+      RCNR = 0x90010004,
+      RTTR = 0x90010008,
+      RTSR = 0x90010010
+    };
+
+    uint32_t m_RTAR; // RTC alarm register
+    uint32_t m_RCNR; // RTC count register
+    uint32_t m_RTTR; // RTC timer trim register
+    uint32_t m_RTSR; // RTC status register
+
+    void init_register() {
+      m_RTAR = 0;
+      m_RCNR = 0;
+      m_RTTR = 0;
+      m_RTSR = 0;
+    }
+
+  public:
+    RTC();
+    inline uint32_t
+    get_interrupt_status() const
+    {
+      return m_RTSR;
+    }
+
+    void run();
+    void reset();
+
+    uint32_t get_data(uint32_t const address) const;
+
+    void put_data(uint32_t const address, uint32_t const value);
+};
+
+} // namespace SA1100