diff --git a/Components/RP5C01/RP5C01.cpp b/Components/RP5C01/RP5C01.cpp new file mode 100644 index 000000000..8932c6c6e --- /dev/null +++ b/Components/RP5C01/RP5C01.cpp @@ -0,0 +1,100 @@ +// +// RP5C01.cpp +// Clock Signal +// +// Created by Thomas Harte on 14/01/2023. +// Copyright © 2023 Thomas Harte. All rights reserved. +// + +#include "RP5C01.hpp" + +using namespace Ricoh::RP5C01; + +RP5C01::RP5C01(HalfCycles clock_rate) : clock_rate_(clock_rate) {} + +void RP5C01::run_for(HalfCycles cycles) { + sub_seconds_ += cycles; + + // Guess: this happens so rarely (i.e. once a second, ordinarily) that + // it's not worth worrying about the branch prediction consequences. + // + // ... and ditto all the conditionals below, which will be very rarely reached. + if(sub_seconds_ < clock_rate_) { + return; + } + const auto elapsed_seconds = int(sub_seconds_.as_integral() / clock_rate_.as_integral()); + sub_seconds_ %= clock_rate_; + + // Update time within day. + seconds_ += elapsed_seconds; + + constexpr int day_length = 60 * 60 * 24; + if(seconds_ < day_length) { + return; + } + const int elapsed_days = seconds_ / day_length; + seconds_ %= day_length; + + // Day of the week doesn't aggregate upwards. + day_of_the_week_ = (day_of_the_week_ + elapsed_days) % 7; + + // Assumed for now: day and month run from 0. + // A leap year count of 0 implies a leap year. + // TODO: verify. + day_ += elapsed_days; + while(true) { + int month_length = 1; + switch(month_) { + case 0: month_length = 31; break; + case 1: month_length = 28 + !leap_year_; break; + case 2: month_length = 31; break; + case 3: month_length = 30; break; + case 4: month_length = 31; break; + case 5: month_length = 30; break; + case 6: month_length = 31; break; + case 7: month_length = 31; break; + case 8: month_length = 30; break; + case 9: month_length = 31; break; + case 10: month_length = 30; break; + case 11: month_length = 31; break; + } + + if(day_ < month_length) { + return; + } + + day_ -= month_length; + ++month_; + + if(month_ == 12) { + month_ = 0; + ++year_; + leap_year_ = (leap_year_ + 1) & 3; + } + } +} + +/// Performs a write of @c value to @c address. +void RP5C01::write(int address, uint8_t value) { + // Registers D–F don't depend on the mode. + if(address >= 0xd) { + switch(address) { + default: break; + case 0xd: + timer_enabled_ = value & 0x8; + alarm_enabled_ = value & 0x4; + mode_ = value & 0x3; + break; + case 0xe: + // Test register; unclear what is supposed to happen. + break; + case 0xf: + one_hz_on_ = !(value & 0x8); + sixteen_hz_on_ = !(value & 0x4); + // TODO: timer reset on bit 1, alarm reset on bit 0 + break; + } + + return; + } +} diff --git a/Components/RP5C01/RP5C01.hpp b/Components/RP5C01/RP5C01.hpp new file mode 100644 index 000000000..24c1ad38b --- /dev/null +++ b/Components/RP5C01/RP5C01.hpp @@ -0,0 +1,62 @@ +// +// RP5C01.hpp +// Clock Signal +// +// Created by Thomas Harte on 14/01/2023. +// Copyright © 2023 Thomas Harte. All rights reserved. +// + +#ifndef RP5C01_hpp +#define RP5C01_hpp + +#include "../../ClockReceiver/ClockReceiver.hpp" + +#include +#include + +namespace Ricoh { +namespace RP5C01 { + +class RP5C01 { + public: + RP5C01(HalfCycles clock_rate); + + /// @returns the result of a read from @c address. + uint8_t read(int address); + + /// Performs a write of @c value to @c address. + void write(int address, uint8_t value); + + /// Advances time. + void run_for(HalfCycles); + + private: + std::array ram_; + + HalfCycles sub_seconds_; + const HalfCycles clock_rate_; + + // Contains the seconds, minutes and hours fields. + int seconds_ = 0; + + // Calendar entries. + int day_of_the_week_ = 0; + int day_ = 0; + int month_ = 0; + int year_ = 1988; + int leap_year_ = 0; + + // Other flags. + bool timer_enabled_ = false; + bool alarm_enabled_ = false; + int mode_ = 0; + bool one_hz_on_ = false; + bool sixteen_hz_on_ = false; +}; + +} +} + +#include + +#endif /* RP5C01_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 996493baf..3844079a6 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1064,6 +1064,8 @@ 4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */; }; 4BF0BC68297108D600CCA2B5 /* MemorySlotHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0BC67297108D100CCA2B5 /* MemorySlotHandler.cpp */; }; 4BF0BC69297108D600CCA2B5 /* MemorySlotHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0BC67297108D100CCA2B5 /* MemorySlotHandler.cpp */; }; + 4BF0BC712973318E00CCA2B5 /* RP5C01.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */; }; + 4BF0BC722973318E00CCA2B5 /* RP5C01.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */; }; 4BF437EE209D0F7E008CBD6B /* SegmentParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */; }; 4BF437EF209D0F7E008CBD6B /* SegmentParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */; }; 4BF701A026FFD32300996424 /* AmigaBlitterTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BF7019F26FFD32300996424 /* AmigaBlitterTests.mm */; }; @@ -2211,6 +2213,8 @@ 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DigitalPhaseLockedLoopBridge.mm; sourceTree = ""; }; 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLLTests.swift; sourceTree = ""; }; 4BF0BC67297108D100CCA2B5 /* MemorySlotHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MemorySlotHandler.cpp; sourceTree = ""; }; + 4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RP5C01.cpp; sourceTree = ""; }; + 4BF0BC702973318E00CCA2B5 /* RP5C01.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RP5C01.hpp; sourceTree = ""; }; 4BF40A5525424C770033EA39 /* LanguageCardSwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LanguageCardSwitches.hpp; sourceTree = ""; }; 4BF40A5A254263140033EA39 /* AuxiliaryMemorySwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AuxiliaryMemorySwitches.hpp; sourceTree = ""; }; 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentParser.cpp; sourceTree = ""; }; @@ -4579,6 +4583,7 @@ 4B302181208A550100773308 /* DiskII */, 4B4B1A39200198C900A0F866 /* KonamiSCC */, 4BC23A212467600E001A6030 /* OPx */, + 4BF0BC6E2973318E00CCA2B5 /* RP5C01 */, 4B0ACBFF237756EC008902D0 /* Serial */, 4BB0A6582044FD3000FB3688 /* SN76489 */, ); @@ -4948,6 +4953,15 @@ path = Formats; sourceTree = ""; }; + 4BF0BC6E2973318E00CCA2B5 /* RP5C01 */ = { + isa = PBXGroup; + children = ( + 4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */, + 4BF0BC702973318E00CCA2B5 /* RP5C01.hpp */, + ); + path = RP5C01; + sourceTree = ""; + }; 4BF660691F281573002CB053 /* ClockReceiver */ = { isa = PBXGroup; children = ( @@ -5630,6 +5644,7 @@ 4B5B37322777C7FC0047F238 /* IPF.cpp in Sources */, 4B894519201967B4007DE474 /* ConfidenceCounter.cpp in Sources */, 4B055AEE1FAE9BBF0060FFFF /* Keyboard.cpp in Sources */, + 4BF0BC722973318E00CCA2B5 /* RP5C01.cpp in Sources */, 4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */, 4B1B88BC202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */, 4BC890D4230F86020025A55A /* DirectAccessDevice.cpp in Sources */, @@ -5983,6 +5998,7 @@ 4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */, 4B8DD3862634D37E00B3C866 /* SNA.cpp in Sources */, 4B4DEC06252BFA56004583AC /* 65816Base.cpp in Sources */, + 4BF0BC712973318E00CCA2B5 /* RP5C01.cpp in Sources */, 4B894524201967B4007DE474 /* Tape.cpp in Sources */, 4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */, 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */,