From a3e00249805fa4758d9abe101119c7f33607b913 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Jul 2017 18:55:03 -0400 Subject: [PATCH] Chopped time accumulation out of the default `Tape` process because it's proving to be sufficiently expensive for a TZX as not to be worthwhile. Introduced a cheaper position capturing/restoring method. --- Machines/ZX8081/ZX8081.cpp | 4 ++-- Storage/Tape/Tape.cpp | 39 +++++++++++++++++++++++++++++--------- Storage/Tape/Tape.hpp | 25 ++++++++++++++++++++---- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 83f6b8e54..23fe0db44 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -130,7 +130,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { case CPU::Z80::PartialMachineCycle::ReadOpcodeWait: // Check for use of the fast tape hack. if(use_fast_tape_hack_ && address == tape_trap_address_ && tape_player_.has_tape()) { - Storage::Time time = tape_player_.get_tape()->get_current_time(); + uint64_t prior_offset = tape_player_.get_tape()->get_offset(); int next_byte = parser_.get_next_byte(tape_player_.get_tape()); if(next_byte != -1) { uint16_t hl = get_value_of_register(CPU::Z80::Register::HL); @@ -144,7 +144,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { tape_advance_delay_ = 1000; return 0; } else { - tape_player_.get_tape()->seek(time); + tape_player_.get_tape()->set_offset(prior_offset); } } diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index 24528e58b..de4892b35 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -20,22 +20,43 @@ TapePlayer::TapePlayer(unsigned int input_clock_rate) : #pragma mark - Seeking void Storage::Tape::Tape::seek(Time &seek_time) { - current_time_.set_zero(); - next_time_.set_zero(); - while(next_time_ <= seek_time) get_next_pulse(); + Time next_time(0); + reset(); + while(next_time <= seek_time) { + get_next_pulse(); + next_time += pulse_.length; + } +} + +Storage::Time Tape::get_current_time() { + Time time(0); + uint64_t steps = get_offset(); + reset(); + while(steps--) { + get_next_pulse(); + time += pulse_.length; + } + return time; } void Storage::Tape::Tape::reset() { - current_time_.set_zero(); - next_time_.set_zero(); + offset_ = 0; virtual_reset(); } Tape::Pulse Tape::get_next_pulse() { - Tape::Pulse pulse = virtual_get_next_pulse(); - current_time_ = next_time_; - next_time_ += pulse.length; - return pulse; + pulse_ = virtual_get_next_pulse(); + offset_++; + return pulse_; +} + +uint64_t Tape::get_offset() { + return offset_; +} + +void Tape::set_offset(uint64_t offset) { + reset(); + while(offset--) get_next_pulse(); } #pragma mark - Player diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 2cd6c028b..6f72ee4f7 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -52,16 +52,33 @@ class Tape { /// @returns @c true if the tape has progressed beyond all recorded content; @c false otherwise. virtual bool is_at_end() = 0; - /// @returns the amount of time preceeding the most recently-returned pulse. - virtual Time get_current_time() { return current_time_; } + /*! + Returns a numerical representation of progression into the tape. Precision is arbitrary but + required to be at least to the whole pulse. Greater numbers are later than earlier numbers, + but not necessarily continuous. + */ + virtual uint64_t get_offset(); - /// Advances or reverses the tape to the last time before or at @c time from which a pulse starts. + /*! + Moves the tape to the first time at which the specified offset would be returned by get_offset. + */ + virtual void set_offset(uint64_t); + + /*! + Calculates and returns the amount of time that has elapsed since the time began. Potentially expensive. + */ + virtual Time get_current_time(); + + /*! + Seeks to @c time. Potentially expensive. + */ virtual void seek(Time &time); virtual ~Tape() {}; private: - Time current_time_, next_time_; + uint64_t offset_; + Tape::Pulse pulse_; virtual Pulse virtual_get_next_pulse() = 0; virtual void virtual_reset() = 0;