From: George Wright Date: Sat, 7 Dec 2024 21:00:23 +0000 (-0800) Subject: add rudimentary rtc impl X-Git-Url: http://git.gwright.org.uk/?a=commitdiff_plain;h=6cd47848d141cb50388b4b86690da2964f73b969;p=WindEmu.git add rudimentary rtc impl --- diff --git a/WindCore/WindCore.pro b/WindCore/WindCore.pro index 6c67c42..db3af5a 100644 --- a/WindCore/WindCore.pro +++ b/WindCore/WindCore.pro @@ -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 diff --git a/WindCore/sa1100.cpp b/WindCore/sa1100.cpp index 0a8864f..c74ee63 100644 --- a/WindCore/sa1100.cpp +++ b/WindCore/sa1100.cpp @@ -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(); diff --git a/WindCore/sa1100.h b/WindCore/sa1100.h index 9de390e..6212d85 100644 --- a/WindCore/sa1100.h +++ b/WindCore/sa1100.h @@ -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; diff --git a/WindCore/sa1100/interrupt_controller.cpp b/WindCore/sa1100/interrupt_controller.cpp index 3f6e433..7f0b6d0 100644 --- a/WindCore/sa1100/interrupt_controller.cpp +++ b/WindCore/sa1100/interrupt_controller.cpp @@ -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 diff --git a/WindCore/sa1100/interrupt_controller.h b/WindCore/sa1100/interrupt_controller.h index ac4fe50..06dd8ff 100644 --- a/WindCore/sa1100/interrupt_controller.h +++ b/WindCore/sa1100/interrupt_controller.h @@ -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 index 0000000..6e2d503 --- /dev/null +++ b/WindCore/sa1100/rtc.cpp @@ -0,0 +1,169 @@ +// 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" + + +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 index 0000000..a30ae5c --- /dev/null +++ b/WindCore/sa1100/rtc.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +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