1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-27 02:55:07 +00:00

Start sketching out an RP5C01.

This commit is contained in:
Thomas Harte 2023-01-14 14:17:28 -05:00
parent 3bc38d35c9
commit 48a4355592
3 changed files with 178 additions and 0 deletions

View File

@ -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 DF 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;
}
}

View File

@ -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 <array>
#include <cstdint>
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<uint8_t, 26> 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 <stdio.h>
#endif /* RP5C01_hpp */

View File

@ -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 = "<group>"; };
4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLLTests.swift; sourceTree = "<group>"; };
4BF0BC67297108D100CCA2B5 /* MemorySlotHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MemorySlotHandler.cpp; sourceTree = "<group>"; };
4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RP5C01.cpp; sourceTree = "<group>"; };
4BF0BC702973318E00CCA2B5 /* RP5C01.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RP5C01.hpp; sourceTree = "<group>"; };
4BF40A5525424C770033EA39 /* LanguageCardSwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LanguageCardSwitches.hpp; sourceTree = "<group>"; };
4BF40A5A254263140033EA39 /* AuxiliaryMemorySwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AuxiliaryMemorySwitches.hpp; sourceTree = "<group>"; };
4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentParser.cpp; sourceTree = "<group>"; };
@ -4579,6 +4583,7 @@
4B302181208A550100773308 /* DiskII */,
4B4B1A39200198C900A0F866 /* KonamiSCC */,
4BC23A212467600E001A6030 /* OPx */,
4BF0BC6E2973318E00CCA2B5 /* RP5C01 */,
4B0ACBFF237756EC008902D0 /* Serial */,
4BB0A6582044FD3000FB3688 /* SN76489 */,
);
@ -4948,6 +4953,15 @@
path = Formats;
sourceTree = "<group>";
};
4BF0BC6E2973318E00CCA2B5 /* RP5C01 */ = {
isa = PBXGroup;
children = (
4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */,
4BF0BC702973318E00CCA2B5 /* RP5C01.hpp */,
);
path = RP5C01;
sourceTree = "<group>";
};
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 */,