From 7cb82fccc07d142b415b3ca1285e037aca5da26a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 21 Oct 2019 22:40:38 -0400 Subject: [PATCH] Attempts properly to maintain interrupt flag; adds delegate. --- Components/6850/6850.cpp | 41 ++++++++++++++++++++++++---------------- Components/6850/6850.hpp | 17 +++++++++++++++-- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Components/6850/6850.cpp b/Components/6850/6850.cpp index 64fb3c943..c98c70fdb 100644 --- a/Components/6850/6850.cpp +++ b/Components/6850/6850.cpp @@ -8,10 +8,6 @@ #include "6850.hpp" -#define LOG_PREFIX "[6850] " -#define NDEBUG -#include "../../Outputs/Log.hpp" - using namespace Motorola::ACIA; const HalfCycles ACIA::SameAsTransmit; @@ -25,17 +21,16 @@ ACIA::ACIA(HalfCycles transmit_clock_rate, HalfCycles receive_clock_rate) : uint8_t ACIA::read(int address) { if(address&1) { - LOG("Read from receive register"); - interrupt_request_ = false; + clear_interrupt_cause(ReceiveNeedsRead); received_data_ |= NoValueMask; } else { - LOG("Read status"); + clear_interrupt_cause(StatusNeedsRead); return ((received_data_ & NoValueMask) ? 0x00 : 0x01) | ((next_transmission_ == NoValueMask) ? 0x02 : 0x00) | (data_carrier_detect.read() ? 0x04 : 0x00) | (clear_to_send.read() ? 0x08 : 0x00) | - (interrupt_request_ ? 0x80 : 0x00) + (interrupt_causes_ ? 0x80 : 0x00) ; // b0: receive data full. @@ -54,7 +49,7 @@ void ACIA::write(int address, uint8_t value) { if(address&1) { next_transmission_ = value; consider_transmission(); - interrupt_request_ = false; + clear_interrupt_cause(TransmitNeedsWrite); } else { if((value&3) == 3) { transmit.reset_writing(); @@ -114,7 +109,7 @@ void ACIA::run_for(HalfCycles length) { } else { transmit.advance_writer(transmit_advance); update_clocking_observer(); - interrupt_request_ |= transmit_interrupt_enabled_; + if(transmit_interrupt_enabled_) add_interrupt_cause(TransmitNeedsWrite); } } else { transmit.advance_writer(transmit_advance); @@ -143,11 +138,7 @@ void ACIA::consider_transmission() { // Output all that. const int total_bits = expected_bits(); - if(!next_transmission_) { - printf(""); - } transmit.write(divider_ * 2, total_bits, transmission); - printf("Transmitted %02x [%03x]\n", next_transmission_, transmission); // Mark the transmit register as empty again. next_transmission_ = NoValueMask; @@ -168,7 +159,7 @@ ClockingHint::Preference ACIA::preferred_clocking() { } bool ACIA::get_interrupt_line() const { - return interrupt_request_; + return interrupt_causes_; } int ACIA::expected_bits() { @@ -193,7 +184,7 @@ bool ACIA::serial_line_did_produce_bit(Serial::Line *line, int bit) { if(bits_received_ >= bit_target) { bits_received_ = 0; received_data_ = uint8_t(bits_incoming_ >> (12 - bit_target)); - interrupt_request_ |= receive_interrupt_enabled_; + if(receive_interrupt_enabled_) add_interrupt_cause(ReceiveNeedsRead); update_clocking_observer(); return false; } @@ -204,3 +195,21 @@ bool ACIA::serial_line_did_produce_bit(Serial::Line *line, int bit) { if(bits_received_ == 1) update_clocking_observer(); return true; } + +void ACIA::set_interrupt_delegate(InterruptDelegate *delegate) { + interrupt_delegate_ = delegate; +} + +void ACIA::add_interrupt_cause(int cause) { + const bool is_changing_state = !interrupt_causes_; + interrupt_causes_ |= cause | StatusNeedsRead; + if(interrupt_delegate_ && is_changing_state) + interrupt_delegate_->acia6850_did_change_interrupt_status(this); +} + +void ACIA::clear_interrupt_cause(int cause) { + const bool was_set = interrupt_causes_; + interrupt_causes_ &= ~cause; + if(interrupt_delegate_ && was_set && !interrupt_causes_) + interrupt_delegate_->acia6850_did_change_interrupt_status(this); +} diff --git a/Components/6850/6850.hpp b/Components/6850/6850.hpp index e13e48469..85eeb01eb 100644 --- a/Components/6850/6850.hpp +++ b/Components/6850/6850.hpp @@ -65,6 +65,11 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate { // ClockingHint::Source. ClockingHint::Preference preferred_clocking() final; + struct InterruptDelegate { + virtual void acia6850_did_change_interrupt_status(ACIA *acia) = 0; + }; + void set_interrupt_delegate(InterruptDelegate *delegate); + private: int divider_ = 1; enum class Parity { @@ -86,12 +91,20 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate { bool receive_interrupt_enabled_ = false; bool transmit_interrupt_enabled_ = false; - bool interrupt_request_ = false; - HalfCycles transmit_clock_rate_; HalfCycles receive_clock_rate_; bool serial_line_did_produce_bit(Serial::Line *line, int bit) final; + + enum InterruptCause: int { + TransmitNeedsWrite = 1 << 0, + ReceiveNeedsRead = 1 << 1, + StatusNeedsRead = 1 << 2 + }; + int interrupt_causes_ = 0; + void add_interrupt_cause(int cause); + void clear_interrupt_cause(int cause); + InterruptDelegate *interrupt_delegate_ = nullptr; }; }