From 460a6cb6fe9e9154091ec6ee16fe1aa5a3b49565 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 1 Aug 2021 18:14:10 -0400 Subject: [PATCH] Attempts a more literal implementation. --- Components/6526/6526.hpp | 1 + .../Implementation/6526Implementation.hpp | 27 ++++-- .../6526/Implementation/6526Storage.hpp | 87 +++++++++++-------- 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/Components/6526/6526.hpp b/Components/6526/6526.hpp index 656fd344a..7366565a5 100644 --- a/Components/6526/6526.hpp +++ b/Components/6526/6526.hpp @@ -67,6 +67,7 @@ template class MOS6526: template uint8_t get_port_input(); void update_interrupts(); void posit_interrupt(uint8_t mask); + void advance_counters(int); }; } diff --git a/Components/6526/Implementation/6526Implementation.hpp b/Components/6526/Implementation/6526Implementation.hpp index 498d52c3d..c1613e31a 100644 --- a/Components/6526/Implementation/6526Implementation.hpp +++ b/Components/6526/Implementation/6526Implementation.hpp @@ -234,18 +234,29 @@ uint8_t MOS6526::read(int address) { template void MOS6526::run_for(const HalfCycles half_cycles) { half_divider_ += half_cycles; - const int sub = half_divider_.divide_cycles().template as(); - if(!sub) return; + int sub = half_divider_.divide_cycles().template as(); + while(sub--) { + // TODO: use CNT potentially to clock timer A. + counter_[0].advance(false); + counter_[1].advance(counter_[0].hit_zero); + posit_interrupt((counter_[0].hit_zero ? 0x01 : 0x00) | (counter_[1].hit_zero ? 0x02 : 0x00)); + } +} + +/*template +void MOS6526::advance_counters(int sub) { // Is counter A running and linked to the clock input? int counter_a_underflows = 0; - if((counter_[0].control & 0x21) == 0x01) { + if(counter_[0].control & 0x20) { + printf("Unimplemented: Timer A CNT \n"); + } else { counter_a_underflows = counter_[0].subtract(sub); + } - // This might be clocking the serial output too. - if(counter_[0].control & 0x40) { - printf("Unimplemented shift register clocking\n"); - } + // Counter A might be clocking the shift register. + if(counter_a_underflows && counter_[0].control & 0x40) { + printf("Unimplemented shift register clocking\n"); } // Update counter B. @@ -267,7 +278,7 @@ void MOS6526::run_for(const HalfCycles half_cycles) { // Apply interrupts. posit_interrupt((counter_a_underflows ? 0x01 : 0x00) | (counter_b_underflows ? 0x02 : 0x00)); -} +}*/ template void MOS6526::advance_tod(int count) { diff --git a/Components/6526/Implementation/6526Storage.hpp b/Components/6526/Implementation/6526Storage.hpp index 412117881..cb3d41f9c 100644 --- a/Components/6526/Implementation/6526Storage.hpp +++ b/Components/6526/Implementation/6526Storage.hpp @@ -30,56 +30,75 @@ struct MOS6526Storage { uint16_t reload = 0; uint16_t value = 0; uint8_t control = 0; + bool hit_zero = false; template void set_reload(uint8_t v) { reload = (reload & (0xff00 >> shift)) | uint16_t(v << shift); - if constexpr (shift == 8) { - if(!(control&1)) { - value = reload; - - if(control&8) { - control |= 1; // At a guess: start one-shot automatically (?) - } - } - } +// if constexpr (shift == 8) { +// if(!(control&1)) { +// value = reload; +// } +// } } template void set_control(uint8_t v) { control = v & 0xef; if(v & 0x10) { + pending |= ReloadInTwo; + } + } + + void advance(bool chained_input) { + // TODO: remove most of the conditionals here. + + pending <<= 1; + + if(hit_zero && pending&(OneShotInOne | OneShotNow)) { + control &= ~1; + } + + if((control & 0x01) || chained_input) { + pending |= ApplyClockInTwo; + } + if(control & 0x08) { + pending |= OneShotInOne; + } + + if((pending & ReloadNow) || (hit_zero && (pending & ApplyClockInTwo))) { value = reload; + pending &= ~ApplyClockInTwo; } - // Force reload + one-shot => start counting (?) - if((v & 0x18) == 0x18) { - control |= 1; - } - } + pending &= PendingClearMask; - int subtract(int count) { - if(control & 8) { - // One-shot. - if(value < count) { - value = reload; - control &= 0xfe; - return 1; - } else { - value -= count; - } - return 0; + if(pending & ApplyClockNow) { + --value; + hit_zero = !value; } else { - // Continuous. - value -= count; - - value -= (reload + 1); - const int underflows = -value / (reload + 1); - value %= (reload + 1); - value += (reload + 1); - - return underflows; + hit_zero = false; } } + + private: + int pending = 0; + + static constexpr int ReloadInThree = 1 << 0; + static constexpr int ReloadInTwo = 1 << 1; + static constexpr int ReloadInOne = 1 << 2; + static constexpr int ReloadNow = 1 << 3; + + static constexpr int OneShotInOne = 1 << 4; + static constexpr int OneShotNow = 1 << 5; + + static constexpr int ApplyClockInThree = 1 << 6; + static constexpr int ApplyClockInTwo = 1 << 7; + static constexpr int ApplyClockInOne = 1 << 8; + static constexpr int ApplyClockNow = 1 << 9; + + static constexpr int PendingClearMask = ~(ReloadNow | OneShotNow); + + bool active_ = false; } counter_[2]; };