From 6210605bc70d653eca0fe01fd1ac0c71da10bf3e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Aug 2021 19:10:09 -0400 Subject: [PATCH] Transfers full TOD responsibility onto the chip-specific templates. --- .../Implementation/6526Implementation.hpp | 138 +++--------------- .../6526/Implementation/6526Storage.hpp | 96 +++++++++++- 2 files changed, 111 insertions(+), 123 deletions(-) diff --git a/Components/6526/Implementation/6526Implementation.hpp b/Components/6526/Implementation/6526Implementation.hpp index 0bd776db4..bd507f72a 100644 --- a/Components/6526/Implementation/6526Implementation.hpp +++ b/Components/6526/Implementation/6526Implementation.hpp @@ -73,61 +73,16 @@ void MOS6526::write(int address, uint8_t value) { break; // Counters; writes set the reload values. - case 4: counter_[0].template set_reload<0>(value); break; - case 5: counter_[0].template set_reload<8>(value); break; - case 6: counter_[1].template set_reload<0>(value); break; - case 7: counter_[1].template set_reload<8>(value); break; + case 4: counter_[0].template set_reload<0>(value); break; + case 5: counter_[0].template set_reload<8>(value); break; + case 6: counter_[1].template set_reload<0>(value); break; + case 7: counter_[1].template set_reload<8>(value); break; // Time-of-day clock. - // - // 8520: a binary counter; stopped on any write, restarted - // upon a write to the LSB. - case 8: - if constexpr (personality == Personality::P8250) { - if(counter_[1].control & 0x80) { - tod_.alarm = (tod_.alarm & 0xffff00) | uint32_t(value); - } else { - tod_.value = (tod_.value & 0xffff00) | uint32_t(value); - tod_.increment_mask = uint32_t(~0); - } - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; - case 9: - if constexpr (personality == Personality::P8250) { - if(counter_[1].control & 0x80) { - tod_.alarm = (tod_.alarm & 0xff00ff) | uint32_t(value << 8); - } else { - tod_.value = (tod_.value & 0xff00ff) | uint32_t(value << 8); - tod_.increment_mask = 0; - } - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; - case 10: - if constexpr (personality == Personality::P8250) { - if(counter_[1].control & 0x80) { - tod_.alarm = (tod_.alarm & 0x00ffff) | uint32_t(value << 16); - } else { - tod_.value = (tod_.value & 0x00ffff) | uint32_t(value << 16); - tod_.increment_mask = 0; - } - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; - - case 11: - if constexpr (personality != Personality::P8250) { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; + case 8: tod_.template write<0>(value); break; + case 9: tod_.template write<1>(value); break; + case 10: tod_.template write<2>(value); break; + case 11: tod_.template write<3>(value); break; // Interrupt control. case 13: { @@ -139,9 +94,15 @@ void MOS6526::write(int address, uint8_t value) { update_interrupts(); } break; - // Control. - case 14: counter_[0].template set_control(value); break; - case 15: counter_[1].template set_control(value); break; + // Control. Posted to both the counters and the clock as it affects both. + case 14: + counter_[0].template set_control(value); + tod_.template set_control(value); + break; + case 15: + counter_[1].template set_control(value); + tod_.template set_control(value); + break; default: printf("Unhandled 6526 write: %02x to %d\n", value, address); @@ -179,53 +140,10 @@ uint8_t MOS6526::read(int address) { return counter_[address - 14].control; // Time-of-day clock. - // - // 8250: Latch on MSB. Unlatch on LSB. Read raw if not latched. - case 8: - if constexpr (personality == Personality::P8250) { - if(tod_.latch) { - const uint8_t result = tod_.latch & 0xff; - tod_.latch = 0; - return result; - } else { - return tod_.value & 0xff; - } - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; - case 9: - if constexpr (personality == Personality::P8250) { - if(tod_.latch) { - return (tod_.latch >> 8) & 0xff; - } else { - return (tod_.value >> 8) & 0xff; - } - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; - case 10: - if constexpr (personality == Personality::P8250) { - tod_.latch = tod_.value | 0xff00'0000; - return (tod_.value >> 16) & 0xff; - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - } - break; - - case 11: - if constexpr (personality == Personality::P8250) { - return 0x00; // Assumed. Just a guss. - } else { - printf("6526 TOD clock not implemented\n"); - assert(false); - - } - break; + case 8: return tod_.template read<0>(); + case 9: return tod_.template read<1>(); + case 10: return tod_.template read<2>(); + case 11: return tod_.template read<3>(); default: printf("Unhandled 6526 read from %d\n", address); @@ -259,18 +177,8 @@ void MOS6526::run_for(const HalfCycles half_cycles) { template void MOS6526::advance_tod(int count) { if(!count) return; - - if constexpr(personality == Personality::P8250) { - // The 8250 uses a simple binary counter to replace the - // 6526's time-of-day clock. So this is easy. - const uint32_t distance_to_alarm = (tod_.alarm - tod_.value) & 0xffffff; - tod_.value += uint32_t(count) & tod_.increment_mask; - if(distance_to_alarm <= uint32_t(count)) { - posit_interrupt(0x04); - } - } else { - // The 6526 uses a time-of-day clock. This may or may not - // be accurate. + if(tod_.advance(count)) { + posit_interrupt(0x04); } } diff --git a/Components/6526/Implementation/6526Storage.hpp b/Components/6526/Implementation/6526Storage.hpp index 5e7f5c596..59517e55a 100644 --- a/Components/6526/Implementation/6526Storage.hpp +++ b/Components/6526/Implementation/6526Storage.hpp @@ -12,15 +12,95 @@ namespace MOS { namespace MOS6526 { -template struct TODStorage {}; -template <> struct TODStorage { - // TODO. +class TODBase { + public: + template void set_control(uint8_t value) { + if constexpr (is_timer2) { + write_alarm = value & 0x80; + } else { + is_50Hz = value & 0x80; + } + } + + protected: + bool write_alarm = false, is_50Hz = false; }; -template <> struct TODStorage { - uint32_t increment_mask = uint32_t(~0); - uint32_t latch = 0; - uint32_t value = 0; - uint32_t alarm = 0; + +template class TODStorage {}; +template <> class TODStorage: public TODBase { + public: + // TODO. + + template void write(uint8_t) { + printf("6526 TOD clock not implemented\n"); + assert(false); + } + + template uint8_t read() { + printf("6526 TOD clock not implemented\n"); + assert(false); + } + + bool advance(int) { + printf("6526 TOD clock not implemented\n"); + assert(false); + } +}; +template <> class TODStorage: public TODBase { + private: + uint32_t increment_mask_ = uint32_t(~0); + uint32_t latch_ = 0; + uint32_t value_ = 0; + uint32_t alarm_ = 0; + + public: + template void write(uint8_t v) { + if constexpr (byte == 3) { + return; + } + constexpr int shift = byte << 3; + + // Write to either the alarm or the current value as directed; + // writing to any part of the current value other than the LSB + // pauses incrementing until the LSB is written. + if(write_alarm) { + alarm_ = (alarm_ & (0x00ff'ffff >> (24 - shift))) | uint32_t(v << shift); + } else { + value_ = (alarm_ & (0x00ff'ffff >> (24 - shift))) | uint32_t(v << shift); + increment_mask_ = (shift == 0) ? uint32_t(~0) : 0; + } + } + + template uint8_t read() { + if constexpr (byte == 3) { + return 0xff; // Assumed. Just a guss. + } + constexpr int shift = byte << 3; + + if(latch_) { + // Latching: if this is a latched read from the LSB, + // empty the latch. + const uint8_t result = uint8_t((latch_ >> shift) & 0xff); + if constexpr (shift == 0) { + latch_ = 0; + } + return result; + } else { + // Latching: if this is a read from the MSB, latch now. + if constexpr (shift == 16) { + latch_ = value_ | 0xff00'0000; + } + return uint8_t((value_ >> shift) & 0xff); + } + } + + bool advance(int count) { + // The 8250 uses a simple binary counter to replace the + // 6526's time-of-day clock. So this is easy. + const uint32_t distance_to_alarm = (alarm_ - value_) & 0xffffff; + value_ += uint32_t(count) & increment_mask_; + return distance_to_alarm <= uint32_t(count); + } }; struct MOS6526Storage {