1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-24 12:30:17 +00:00

Made yet another guess at Commodore analysis. Elevated fast tape-related unnatural speed up to the OS-side mechanisms.

This commit is contained in:
Thomas Harte 2016-09-12 22:06:03 -04:00
parent e54a2326a3
commit 40660fe680
8 changed files with 76 additions and 36 deletions

View File

@ -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_;
};
}

View File

@ -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())

View File

@ -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()

View File

@ -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<CSMachineDelegate> delegate;
@property (nonatomic, readonly) double clockRate;
@property (nonatomic, readonly) BOOL clockIsUnlimited;
- (void)paste:(NSString *)string;

View File

@ -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<Utility::TypeRecipient *>(self.machine);
if(typeRecipient)

View File

@ -21,6 +21,7 @@
@interface CSBestEffortUpdater : NSObject
@property (nonatomic, assign) double clockRate;
@property (nonatomic, assign) BOOL runAsUnlimited;
@property (nonatomic, weak) id<CSBestEffortUpdaterDelegate> delegate;
- (void)update;

View File

@ -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;

View File

@ -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)