diff --git a/Machines/Commodore/Plus4/Plus4.cpp b/Machines/Commodore/Plus4/Plus4.cpp index e4409f0fb..426dcb964 100644 --- a/Machines/Commodore/Plus4/Plus4.cpp +++ b/Machines/Commodore/Plus4/Plus4.cpp @@ -238,30 +238,33 @@ public: audio_queue_.lock_flush(); } - // HACK. NOCOMMIT. -// int pulse_num_ = 0; - template Cycles perform(const AddressT address, CPU::MOS6502Mk2::data_t value) { // Determine from the TED video subsystem the length of this clock cycle as perceived by the 6502, // relative to the master clock. - const auto length = video_.cycle_length(operation == CPU::MOS6502Mk2::BusOperation::Ready); + auto length = video_.cycle_length(operation == CPU::MOS6502Mk2::BusOperation::Ready); // Update other subsystems. - timers_subcycles_ += length; - const auto timers_cycles = timers_subcycles_.divide(video_.timer_cycle_length()); - timers_.tick(timers_cycles.as()); + advance_timers_and_tape(length); + if(operation != CPU::MOS6502Mk2::BusOperation::Ready && skip_range_) { + if( + operation == CPU::MOS6502Mk2::BusOperation::ReadOpcode && + (address < skip_range_->low || address >= skip_range_->high) + ) { + skip_range_ = std::nullopt; + } + length = Cycles(0); + } else { + video_.run_for(length); - tape_handler_.run_for(length); - video_.run_for(length); + if(c1541_) { + c1541_cycles_ += length * Cycles(1'000'000); + c1541_->run_for(c1541_cycles_.divide(media_divider_)); + } - if(c1541_) { - c1541_cycles_ += length * Cycles(1'000'000); - c1541_->run_for(c1541_cycles_.divide(media_divider_)); + time_since_audio_update_ += length; } - time_since_audio_update_ += length; - if(operation == CPU::MOS6502Mk2::BusOperation::Ready) { return length; } @@ -284,6 +287,12 @@ public: value = io_direction_; } else { value = io_input(); + + if(!skip_range_) { + if(const auto pc = m6502_.registers().pc; pc >= 0x333 && pc < 0x3f2 ) { + skip_range_ = tape_handler_.skip_range(pc.full, m6502_, map_); + } + } } } else { if(!address) { @@ -676,7 +685,15 @@ private: Serial::Bus serial_bus_; SerialPort serial_port_; + void advance_timers_and_tape(const Cycles length) { + timers_subcycles_ += length; + const auto timers_cycles = timers_subcycles_.divide(video_.timer_cycle_length()); + timers_.tick(timers_cycles.as()); + + tape_handler_.run_for(length); + } TapeHandler tape_handler_; + std::optional skip_range_; uint8_t io_direction_ = 0x00, io_output_ = 0x00; uint8_t io_input() const { diff --git a/Machines/Commodore/Plus4/TapeHandler.hpp b/Machines/Commodore/Plus4/TapeHandler.hpp index 00c6cc3c3..abdf23d5a 100644 --- a/Machines/Commodore/Plus4/TapeHandler.hpp +++ b/Machines/Commodore/Plus4/TapeHandler.hpp @@ -13,9 +13,14 @@ #include "Storage/Tape/Parsers/Commodore.hpp" #include +#include namespace Commodore::Plus4 { +struct SkipRange { + uint16_t low, high; +}; + /*! All tape assistance, bundled into a single place, including: @@ -181,6 +186,28 @@ struct TapeHandler: public ClockingHint::Observer { return false; } + template + std::optional skip_range(const uint16_t pc, M6502T &, MemoryT &map) { + + // Check for sequence: + // + // 24 01 BIT 01 + // d0 fc BNE 3c8 <- PC will be here; trigger is the BIT operation above. + // 24 01 BIT 01 + // f0 fc BEQ 3cc + + if( + map.read(pc) == 0xd0 && map.read(pc+1) == 0xfc && + map.read(pc-2) == 0x24 && map.read(pc-1) == 0x01 && + map.read(pc+2) == 0x24 && map.read(pc+3) == 0x01 && + map.read(pc+4) == 0xf0 && map.read(pc+5) == 0xfc + ) { + return SkipRange{uint16_t(pc - 2), uint16_t(pc + 6)}; + } + + return std::nullopt; + } + private: std::unique_ptr tape_player_; bool play_button_ = false;