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:
parent
e54a2326a3
commit
40660fe680
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user