From 40660fe680b88ee4c3233f2be26045bc79157025 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 12 Sep 2016 22:06:03 -0400 Subject: [PATCH] Made yet another guess at Commodore analysis. Elevated fast tape-related unnatural speed up to the OS-side mechanisms. --- Machines/CRTMachine.hpp | 15 ++++++- Machines/Commodore/Vic-20/Vic20.cpp | 40 +++++++++++++------ .../Documents/MachineDocument.swift | 4 ++ .../Mac/Clock Signal/Machine/CSMachine.h | 3 ++ .../Mac/Clock Signal/Machine/CSMachine.mm | 12 ++++++ .../Updater/CSBestEffortUpdater.h | 1 + .../Updater/CSBestEffortUpdater.m | 4 +- .../Commodore/CommodoreAnalyser.cpp | 33 ++++++--------- 8 files changed, 76 insertions(+), 36 deletions(-) diff --git a/Machines/CRTMachine.hpp b/Machines/CRTMachine.hpp index 6e00b482f..9cc2f869f 100644 --- a/Machines/CRTMachine.hpp +++ b/Machines/CRTMachine.hpp @@ -21,6 +21,8 @@ namespace CRTMachine { */ class Machine { public: + Machine() : clock_is_unlimited_(false) {} + virtual void setup_output(float aspect_ratio) = 0; virtual void close_output() = 0; @@ -33,23 +35,34 @@ class Machine { double get_clock_rate() { return clock_rate_; } + bool get_clock_is_unlimited() { + return clock_is_unlimited_; + } class Delegate { public: virtual void machine_did_change_clock_rate(Machine *machine) = 0; + virtual void machine_did_change_clock_is_unlimited(Machine *machine) = 0; }; void set_delegate(Delegate *delegate) { this->delegate_ = delegate; } protected: - double clock_rate_; void set_clock_rate(double clock_rate) { if(clock_rate_ != clock_rate) { clock_rate_ = clock_rate; if(delegate_) delegate_->machine_did_change_clock_rate(this); } } + void set_clock_is_unlimited(bool clock_is_unlimited) { + if(clock_is_unlimited != clock_is_unlimited_) { + clock_is_unlimited_ = clock_is_unlimited; + if(delegate_) delegate_->machine_did_change_clock_is_unlimited(this); + } + } private: Delegate *delegate_; + double clock_rate_; + bool clock_is_unlimited_; }; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 49f9c7a28..606bbdebf 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -130,10 +130,12 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } *value = result; - // test for PC at F92F + // This combined with the stuff below constitutes the fast tape hack. Performed here: if the + // PC hits the start of the loop that just waits for an interesting tape interrupt to have + // occurred then skip both 6522s and the tape ahead to the next interrupt without any further + // CPU or 6560 costs. if(_use_fast_tape_hack && _tape.has_tape() && address == 0xf92f && operation == CPU6502::BusOperation::ReadOpcode) { - // advance time on the tape and the VIAs until an interrupt is signalled while(!_userPortVIA->get_interrupt_line() && !_keyboardVIA->get_interrupt_line()) { _userPortVIA->run_for_half_cycles(2); @@ -141,9 +143,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin _tape.run_for_cycles(1); } } - - // f7af: find tape header, exit with header in buffer - // F8C0: Read tape block } else { @@ -167,13 +166,32 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin _tape.run_for_cycles(1); if(_c1540) _c1540->run_for_cycles(1); - if(_use_fast_tape_hack && operation == CPU6502::BusOperation::ReadOpcode) + // If using fast tape then: + // if the PC hits 0xf98e, the ROM's tape loading routine, then begin zero cost processing; + // if the PC heads into RAM + // + // Where 'zero cost processing' is taken to be taking the 6560 off the bus (because I know it's + // expensive, and not relevant) then running the tape, the CPU and both 6522s as usual but not + // counting cycles towards the processing budget. So the limit is the host machine. + // + // Note the additional test above for PC hitting 0xf92f, which is a loop in the ROM that waits + // for an interesting interrupt. Up there the fast tape hack goes even further in also cutting + // the CPU out of the action. + if(_use_fast_tape_hack && _tape.has_tape()) { - if(address == 0xF98E) _is_running_at_zero_cost = true; - if(address == 0xff56) _is_running_at_zero_cost = false; + if(address == 0xf98e && operation == CPU6502::BusOperation::ReadOpcode) + { + _is_running_at_zero_cost = true; + set_clock_is_unlimited(true); + } + if(address < 0xe000 && operation == CPU6502::BusOperation::ReadOpcode) + { + _is_running_at_zero_cost = false; + set_clock_is_unlimited(false); + } } - return _is_running_at_zero_cost ? 0 : 1; + return 1; } #pragma mark - 6522 delegate @@ -277,10 +295,6 @@ void Machine::set_prg(const char *file_name, size_t length, const uint8_t *data) #pragma mar - Tape -// LAB_FBDB = new tape byte setup; -// loops at LAB_F92F -// LAB_F8C0 = initiate tape read - void Machine::configure_as_target(const StaticAnalyser::Target &target) { if(target.tapes.size()) diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 9e85e3e50..fe8937330 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -73,6 +73,10 @@ class MachineDocument: setupClockRate() } + func machineDidChangeClockIsUnlimited(machine: CSMachine!) { + self.bestEffortUpdater.runAsUnlimited = machine.clockIsUnlimited + } + private func setupClockRate() { // establish and provide the audio queue, taking advice as to an appropriate sampling rate let maximumSamplingRate = CSAudioQueue.preferredSamplingRate() diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index 1a503e8c5..843644503 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -13,6 +13,7 @@ @class CSMachine; @protocol CSMachineDelegate - (void)machineDidChangeClockRate:(CSMachine *)machine; +- (void)machineDidChangeClockIsUnlimited:(CSMachine *)machine; @end @interface CSMachine : NSObject @@ -28,7 +29,9 @@ @property (nonatomic, strong) CSAudioQueue *audioQueue; @property (nonatomic, readonly) CSOpenGLView *view; @property (nonatomic, weak) id delegate; + @property (nonatomic, readonly) double clockRate; +@property (nonatomic, readonly) BOOL clockIsUnlimited; - (void)paste:(NSString *)string; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 2b67f9caa..950427945 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -16,6 +16,7 @@ @interface CSMachine() - (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length; - (void)machineDidChangeClockRate; +- (void)machineDidChangeClockIsUnlimited; @end struct SpeakerDelegate: public Outputs::Speaker::Delegate { @@ -30,6 +31,9 @@ struct MachineDelegate: CRTMachine::Machine::Delegate { void machine_did_change_clock_rate(CRTMachine::Machine *sender) { [machine machineDidChangeClockRate]; } + void machine_did_change_clock_is_unlimited(CRTMachine::Machine *sender) { + [machine machineDidChangeClockIsUnlimited]; + } }; @implementation CSMachine { @@ -56,6 +60,10 @@ struct MachineDelegate: CRTMachine::Machine::Delegate { [self.delegate machineDidChangeClockRate:self]; } +- (void)machineDidChangeClockIsUnlimited { + [self.delegate machineDidChangeClockIsUnlimited:self]; +} + - (void)dealloc { [_view performWithGLContext:^{ @synchronized(self) { @@ -119,6 +127,10 @@ struct MachineDelegate: CRTMachine::Machine::Delegate { return self.machine->get_clock_rate(); } +- (BOOL)clockIsUnlimited { + return self.machine->get_clock_is_unlimited() ? YES : NO; +} + - (void)paste:(NSString *)paste { Utility::TypeRecipient *typeRecipient = dynamic_cast(self.machine); if(typeRecipient) diff --git a/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h index f8608a600..2ed7a43bc 100644 --- a/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h +++ b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.h @@ -21,6 +21,7 @@ @interface CSBestEffortUpdater : NSObject @property (nonatomic, assign) double clockRate; +@property (nonatomic, assign) BOOL runAsUnlimited; @property (nonatomic, weak) id delegate; - (void)update; diff --git a/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m index 781b978bb..10c0a133d 100644 --- a/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m +++ b/OSBindings/Mac/Clock Signal/Updater/CSBestEffortUpdater.m @@ -44,8 +44,10 @@ double cyclesToRunFor = timeToRunFor * self.clockRate + _cyclesError; _cyclesError = fmod(cyclesToRunFor, 1.0); - NSUInteger integerCyclesToRunFor = (NSUInteger)cyclesToRunFor; + NSUInteger integerCyclesToRunFor = (NSUInteger)MIN(cyclesToRunFor, self.clockRate * 0.5); + // treat 'unlimited' as running at a factor of 10 + if(self.runAsUnlimited) integerCyclesToRunFor *= 10; [self.delegate bestEffortUpdater:self runForCycles:integerCyclesToRunFor didSkipPreviousUpdate:_hasSkipped]; } _previousTimeInterval = timeInterval; diff --git a/StaticAnalyser/Commodore/CommodoreAnalyser.cpp b/StaticAnalyser/Commodore/CommodoreAnalyser.cpp index f5da45244..787c4124b 100644 --- a/StaticAnalyser/Commodore/CommodoreAnalyser.cpp +++ b/StaticAnalyser/Commodore/CommodoreAnalyser.cpp @@ -42,33 +42,24 @@ void StaticAnalyser::Commodore::AddTargets( if(files.front().is_basic()) { target.loadingCommand = "LOAD\"\",1,0\nRUN\n"; - - // make a first guess based on file size - size_t file_size = files.front().data.size(); - if(file_size > 6655) target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB; - else if(file_size > 3583) target.vic20.memory_model = Vic20MemoryModel::EightKB; - else target.vic20.memory_model = Vic20MemoryModel::Unexpanded; } else { - // TODO: this is machine code. So, ummm? - printf("Need to deal with machine code from %04x to %04x???\n", files.front().starting_address, files.front().ending_address); target.loadingCommand = "LOAD\"\",1,1\nRUN\n"; - - // make a first guess based on loading address - switch(files.front().starting_address) - { - case 0x1001: - default: break; - case 0x1201: - target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB; - break; - case 0x0401: - target.vic20.memory_model = Vic20MemoryModel::EightKB; - break; - } } + // make a first guess based on loading address + switch(files.front().starting_address) + { + case 0x1001: + default: break; + case 0x1201: + target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB; + break; + case 0x0401: + target.vic20.memory_model = Vic20MemoryModel::EightKB; + break; + } // General approach: increase memory size conservatively such that the largest file found will fit. for(File &file : files)