mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
I think this is a prima facie acceptable implementation of the fast tape hack.
This commit is contained in:
parent
bb0cd89574
commit
1c4acfb599
@ -42,6 +42,7 @@ Machine::Machine() :
|
|||||||
_audioOutputPosition(0),
|
_audioOutputPosition(0),
|
||||||
_audioOutputPositionError(0),
|
_audioOutputPositionError(0),
|
||||||
_current_pixel_line(-1),
|
_current_pixel_line(-1),
|
||||||
|
_use_fast_tape_hack(false),
|
||||||
_crt(std::unique_ptr<Outputs::CRT::CRT>(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1, 1)))
|
_crt(std::unique_ptr<Outputs::CRT::CRT>(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1, 1)))
|
||||||
{
|
{
|
||||||
_crt->set_rgb_sampling_function(
|
_crt->set_rgb_sampling_function(
|
||||||
@ -263,7 +264,65 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(isReadOperation(operation))
|
if(isReadOperation(operation))
|
||||||
*value = _os[address & 16383];
|
{
|
||||||
|
if(
|
||||||
|
_use_fast_tape_hack &&
|
||||||
|
(operation == CPU6502::BusOperation::ReadOpcode) &&
|
||||||
|
(
|
||||||
|
(address == 0xf4e5) || (address == 0xf4e6) || // double NOPs at 0xf4e5, 0xf6de, 0xf6fa and 0xfa51
|
||||||
|
(address == 0xf6de) || (address == 0xf6df) || // act to disable the normal branch into tape-handling
|
||||||
|
(address == 0xf6fa) || (address == 0xf6fb) || // code, forcing the OS along the serially-accessed ROM
|
||||||
|
(address == 0xfa51) || (address == 0xfa52) || // pathway.
|
||||||
|
|
||||||
|
(address == 0xf0a8) // 0xf0a8 is from where a service call would normally be
|
||||||
|
// dispatched; we can check whether it would be call 14
|
||||||
|
// (i.e. read byte) and, if so, whether the OS was about to
|
||||||
|
// issue a read byte call to a ROM despite being the tape
|
||||||
|
// FS being selected. If so then this is a get byte that
|
||||||
|
// we should service synthetically. Put the byte into Y
|
||||||
|
// and set A to zero to report that action was taken, then
|
||||||
|
// allow the PC read to return an RTS.
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint8_t service_call = (uint8_t)get_value_of_register(CPU6502::Register::X);
|
||||||
|
if(address == 0xf0a8)
|
||||||
|
{
|
||||||
|
if(!_ram[0x247] && service_call == 14)
|
||||||
|
{
|
||||||
|
_tape.set_delegate(nullptr);
|
||||||
|
|
||||||
|
// TODO: handle tape wrap around.
|
||||||
|
|
||||||
|
int cycles_left_while_plausibly_in_data = 50;
|
||||||
|
_tape.clear_interrupts(Interrupt::ReceiveDataFull);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
uint8_t tapeStatus = _tape.run_for_input_pulse();
|
||||||
|
cycles_left_while_plausibly_in_data--;
|
||||||
|
if(!cycles_left_while_plausibly_in_data) _fast_load_is_in_data = false;
|
||||||
|
if( (tapeStatus & Interrupt::ReceiveDataFull) &&
|
||||||
|
(_fast_load_is_in_data || _tape.get_data_register() == 0x2a)
|
||||||
|
) break;
|
||||||
|
}
|
||||||
|
_tape.set_delegate(this);
|
||||||
|
|
||||||
|
_fast_load_is_in_data = true;
|
||||||
|
set_value_of_register(CPU6502::Register::A, 0);
|
||||||
|
set_value_of_register(CPU6502::Register::Y, _tape.get_data_register());
|
||||||
|
*value = 0x60; // 0x60 is RTS
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*value = _os[address & 16383];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*value = 0xea;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*value = _os[address & 16383];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -866,6 +925,40 @@ inline uint8_t Tape::get_data_register()
|
|||||||
return (uint8_t)(_data_register >> 2);
|
return (uint8_t)(_data_register >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8_t Tape::run_for_input_pulse()
|
||||||
|
{
|
||||||
|
get_next_tape_pulse();
|
||||||
|
|
||||||
|
_crossings[0] = _crossings[1];
|
||||||
|
_crossings[1] = _crossings[2];
|
||||||
|
_crossings[2] = _crossings[3];
|
||||||
|
|
||||||
|
_crossings[3] = Tape::Unrecognised;
|
||||||
|
if(_input.current_pulse.type != Storage::Tape::Pulse::Zero)
|
||||||
|
{
|
||||||
|
float pulse_length = (float)_input.current_pulse.length.length / (float)_input.current_pulse.length.clock_rate;
|
||||||
|
if(pulse_length >= 0.35 / 2400.0 && pulse_length < 0.7 / 2400.0) _crossings[3] = Tape::Short;
|
||||||
|
if(pulse_length >= 0.35 / 1200.0 && pulse_length < 0.7 / 1200.0) _crossings[3] = Tape::Long;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_crossings[0] == Tape::Long && _crossings[1] == Tape::Long)
|
||||||
|
{
|
||||||
|
push_tape_bit(0);
|
||||||
|
_crossings[0] = _crossings[1] = Tape::Recognised;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_crossings[0] == Tape::Short && _crossings[1] == Tape::Short && _crossings[2] == Tape::Short && _crossings[3] == Tape::Short)
|
||||||
|
{
|
||||||
|
push_tape_bit(1);
|
||||||
|
_crossings[0] = _crossings[1] =
|
||||||
|
_crossings[2] = _crossings[3] = Tape::Recognised;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _interrupt_status;
|
||||||
|
}
|
||||||
|
|
||||||
inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
||||||
{
|
{
|
||||||
if(_is_enabled)
|
if(_is_enabled)
|
||||||
@ -879,35 +972,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
|||||||
_input.time_into_pulse += (unsigned int)_input.pulse_stepper->step();
|
_input.time_into_pulse += (unsigned int)_input.pulse_stepper->step();
|
||||||
if(_input.time_into_pulse == _input.current_pulse.length.length)
|
if(_input.time_into_pulse == _input.current_pulse.length.length)
|
||||||
{
|
{
|
||||||
get_next_tape_pulse();
|
run_for_input_pulse();
|
||||||
|
|
||||||
_crossings[0] = _crossings[1];
|
|
||||||
_crossings[1] = _crossings[2];
|
|
||||||
_crossings[2] = _crossings[3];
|
|
||||||
|
|
||||||
_crossings[3] = Tape::Unrecognised;
|
|
||||||
if(_input.current_pulse.type != Storage::Tape::Pulse::Zero)
|
|
||||||
{
|
|
||||||
float pulse_length = (float)_input.current_pulse.length.length / (float)_input.current_pulse.length.clock_rate;
|
|
||||||
if(pulse_length >= 0.35 / 2400.0 && pulse_length < 0.7 / 2400.0) _crossings[3] = Tape::Short;
|
|
||||||
if(pulse_length >= 0.35 / 1200.0 && pulse_length < 0.7 / 1200.0) _crossings[3] = Tape::Long;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_crossings[0] == Tape::Long && _crossings[1] == Tape::Long)
|
|
||||||
{
|
|
||||||
push_tape_bit(0);
|
|
||||||
_crossings[0] = _crossings[1] = Tape::Recognised;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(_crossings[0] == Tape::Short && _crossings[1] == Tape::Short && _crossings[2] == Tape::Short && _crossings[3] == Tape::Short)
|
|
||||||
{
|
|
||||||
push_tape_bit(1);
|
|
||||||
_crossings[0] = _crossings[1] =
|
|
||||||
_crossings[2] = _crossings[3] = Tape::Recognised;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ class Tape {
|
|||||||
inline void set_delegate(Delegate *delegate) { _delegate = delegate; }
|
inline void set_delegate(Delegate *delegate) { _delegate = delegate; }
|
||||||
|
|
||||||
inline void run_for_cycles(unsigned int number_of_cycles);
|
inline void run_for_cycles(unsigned int number_of_cycles);
|
||||||
|
inline uint8_t run_for_input_pulse();
|
||||||
|
|
||||||
inline void set_is_running(bool is_running) { _is_running = is_running; }
|
inline void set_is_running(bool is_running) { _is_running = is_running; }
|
||||||
inline void set_is_enabled(bool is_enabled) { _is_enabled = is_enabled; }
|
inline void set_is_enabled(bool is_enabled) { _is_enabled = is_enabled; }
|
||||||
@ -158,6 +159,7 @@ class Machine: public CPU6502::Processor<Machine>, Tape::Delegate {
|
|||||||
virtual void tape_did_change_interrupt_status(Tape *tape);
|
virtual void tape_did_change_interrupt_status(Tape *tape);
|
||||||
|
|
||||||
void update_output();
|
void update_output();
|
||||||
|
inline void set_use_fast_tape_hack(bool activate) { _use_fast_tape_hack = activate; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -199,6 +201,8 @@ class Machine: public CPU6502::Processor<Machine>, Tape::Delegate {
|
|||||||
|
|
||||||
// Tape.
|
// Tape.
|
||||||
Tape _tape;
|
Tape _tape;
|
||||||
|
bool _use_fast_tape_hack;
|
||||||
|
bool _fast_load_is_in_data;
|
||||||
|
|
||||||
// Outputs.
|
// Outputs.
|
||||||
std::unique_ptr<Outputs::CRT::CRT> _crt;
|
std::unique_ptr<Outputs::CRT::CRT> _crt;
|
||||||
|
@ -42,6 +42,7 @@ class ElectronDocument: MachineDocument {
|
|||||||
switch pathExtension.lowercaseString {
|
switch pathExtension.lowercaseString {
|
||||||
case "uef":
|
case "uef":
|
||||||
electron.openUEFAtURL(url)
|
electron.openUEFAtURL(url)
|
||||||
|
electron.useFastLoadingHack = true
|
||||||
return
|
return
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,6 @@
|
|||||||
|
|
||||||
- (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty;
|
- (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty;
|
||||||
|
|
||||||
|
@property (nonatomic, assign) BOOL useFastLoadingHack;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -131,4 +131,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack {
|
||||||
|
_useFastLoadingHack = useFastLoadingHack;
|
||||||
|
_electron.set_use_fast_tape_hack(useFastLoadingHack ? true : false);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user