From c733a4dbf8d1432df4e939343859db6a5db0f084 Mon Sep 17 00:00:00 2001 From: Thomas Harte <thomas.harte@gmail.com> Date: Fri, 23 Jul 2021 21:58:52 -0400 Subject: [PATCH] Beefs up interrupt awareness. --- Components/6526/6526.hpp | 1 + .../Implementation/6526Implementation.hpp | 60 +++++++++++++++---- .../6526/Implementation/6526Storage.hpp | 5 +- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/Components/6526/6526.hpp b/Components/6526/6526.hpp index 43a735f11..6026de66d 100644 --- a/Components/6526/6526.hpp +++ b/Components/6526/6526.hpp @@ -63,6 +63,7 @@ template <typename PortHandlerT, Personality personality> class MOS6526: template <int port> void set_port_output(); template <int port> uint8_t get_port_input(); void update_interrupts(); + void posit_interrupt(uint8_t mask); }; } diff --git a/Components/6526/Implementation/6526Implementation.hpp b/Components/6526/Implementation/6526Implementation.hpp index 6cb226fd8..8a3571faf 100644 --- a/Components/6526/Implementation/6526Implementation.hpp +++ b/Components/6526/Implementation/6526Implementation.hpp @@ -27,8 +27,20 @@ template <int port> uint8_t MOS6526<BusHandlerT, personality>::get_port_input() return (input & ~data_direction_[port]) | (output_[port] & data_direction_[port]); } +template <typename BusHandlerT, Personality personality> +void MOS6526<BusHandlerT, personality>::posit_interrupt(uint8_t mask) { + interrupt_state_ |= mask; + update_interrupts(); +} + template <typename BusHandlerT, Personality personality> void MOS6526<BusHandlerT, personality>::update_interrupts() { + if(interrupt_state_ & interrupt_control_) { + interrupt_state_ |= 0x80; + + printf("6526 should signal interrupt\n"); + assert(false); + } } template <typename BusHandlerT, Personality personality> @@ -67,8 +79,12 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) { // upon a write to the LSB. case 8: if constexpr (personality == Personality::P8250) { - tod_ = (tod_ & 0xffff00) | uint32_t(value); - tod_increment_mask_ = uint32_t(~0); + if(control_[1] & 0x80) { + tod_alarm_ = (tod_alarm_ & 0xffff00) | uint32_t(value); + } else { + tod_ = (tod_ & 0xffff00) | uint32_t(value); + tod_increment_mask_ = uint32_t(~0); + } } else { printf("6526 TOD clock not implemented\n"); assert(false); @@ -76,8 +92,12 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) { break; case 9: if constexpr (personality == Personality::P8250) { - tod_ = (tod_ & 0xff00ff) | uint32_t(value << 8); - tod_increment_mask_ = 0; + if(control_[1] & 0x80) { + tod_alarm_ = (tod_alarm_ & 0xff00ff) | uint32_t(value << 8); + } else { + tod_ = (tod_ & 0xff00ff) | uint32_t(value << 8); + tod_increment_mask_ = 0; + } } else { printf("6526 TOD clock not implemented\n"); assert(false); @@ -85,8 +105,12 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) { break; case 10: if constexpr (personality == Personality::P8250) { - tod_ = (tod_ & 0x00ffff) | uint32_t(value << 16); - tod_increment_mask_ = 0; + if(control_[1] & 0x80) { + tod_alarm_ = (tod_alarm_ & 0x00ffff) | uint32_t(value << 16); + } else { + tod_ = (tod_ & 0x00ffff) | uint32_t(value << 16); + tod_increment_mask_ = 0; + } } else { printf("6526 TOD clock not implemented\n"); assert(false); @@ -101,10 +125,14 @@ void MOS6526<BusHandlerT, personality>::write(int address, uint8_t value) { break; // Interrupt control. - case 13: - interrupt_control_ = value; + case 13: { + if(interrupt_control_ & 0x80) { + interrupt_control_ |= value & 0x7f; + } else { + interrupt_control_ &= ~(value & 0x7f); + } update_interrupts(); - break; + } break; // Control. case 14: @@ -126,7 +154,6 @@ uint8_t MOS6526<BusHandlerT, personality>::read(int address) { switch(address) { case 0: return get_port_input<0>(); case 1: return get_port_input<1>(); - case 13: return interrupt_control_; case 2: case 3: return data_direction_[address - 2]; @@ -137,6 +164,14 @@ uint8_t MOS6526<BusHandlerT, personality>::read(int address) { case 6: return uint8_t(counters_[1].value >> 0); case 7: return uint8_t(counters_[1].value >> 0); + // Interrupt state. + case 13: { + const uint8_t result = interrupt_state_; + interrupt_state_ = 0; + update_interrupts(); + return result; + } break; + case 14: case 15: return control_[address - 14]; @@ -211,14 +246,17 @@ void MOS6526<BusHandlerT, personality>::advance_tod(int count) { 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_) & 0xffffff; tod_ += 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. } } - } } diff --git a/Components/6526/Implementation/6526Storage.hpp b/Components/6526/Implementation/6526Storage.hpp index 630e6e9af..8c76976de 100644 --- a/Components/6526/Implementation/6526Storage.hpp +++ b/Components/6526/Implementation/6526Storage.hpp @@ -17,14 +17,15 @@ struct MOS6526Storage { uint8_t output_[2] = {0, 0}; uint8_t data_direction_[2] = {0, 0}; + uint8_t interrupt_control_ = 0; + uint8_t interrupt_state_ = 0; + uint8_t control_[2] = {0, 0}; uint32_t tod_increment_mask_ = uint32_t(~0); uint32_t tod_latch_ = 0; uint32_t tod_ = 0; - - bool write_tod_alarm_ = false; uint32_t tod_alarm_ = 0; struct Counter {