From 33512988fbf45fdb4c08be70d57a6a9baec9f718 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 30 Oct 2016 22:39:47 -0400 Subject: [PATCH 1/6] Added a basic cycle skipper plus some notes. --- Machines/Oric/Oric.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 67e84e892..f8d0c2f06 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -40,6 +40,21 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { if(address >= 0xc000) { +// // 024D = 0 => fast; otherwise slow +// // E6C9 = read byte: return byte in A +// if(address == 0xe6c9 && operation == CPU6502::BusOperation::ReadOpcode) +// { +// printf("."); +// } + + if(address == 0xe720 && operation == CPU6502::BusOperation::ReadOpcode) + { + while(!_via.tape->get_input()) + { + _via.run_for_cycles(1); + _via.tape->run_for_cycles(1); + } + } if(isReadOperation(operation)) *value = _rom[address&16383]; } else From 419629ee6e65a211edab8268b47d4306f80fb4c2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 2 Nov 2016 21:09:49 -0400 Subject: [PATCH 2/6] Completed proof of theory for fast loading. It's just an around-the-back direct-to-file hack for now though. --- Machines/Oric/Oric.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 9b0af4e88..6a80be2d3 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -40,22 +40,36 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { if(address >= 0xc000) { + if(isReadOperation(operation)) *value = _rom[address&16383]; + // // 024D = 0 => fast; otherwise slow // // E6C9 = read byte: return byte in A -// if(address == 0xe6c9 && operation == CPU6502::BusOperation::ReadOpcode) -// { -// printf("."); -// } - - if(address == 0xe720 && operation == CPU6502::BusOperation::ReadOpcode) + if(address == 0xe6c9 && operation == CPU6502::BusOperation::ReadOpcode) { - while(!_via.tape->get_input()) + static FILE *test = NULL; + static int lead_counter = 0; + if(!test) { - _via.run_for_cycles(1); - _via.tape->run_for_cycles(1); + test = fopen("/Users/thomasharte/Desktop/Soft/Oric/Tapes/Slalom.tap", "rb"); + } + if(test && !feof(test)) + { + uint8_t next_byte; +// if(lead_counter < 64) +// { +// next_byte = 0x16; +// lead_counter++; +// } +// else + next_byte = (uint8_t)fgetc(test); + set_value_of_register(CPU6502::A, next_byte); + set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero); + uint8_t stack = get_value_of_register(CPU6502::S) + 1; + uint16_t return_address = _ram[0x0100 | stack] | (_ram[0x0100 | (stack+1)] << 8); + printf("%02x -> %04x | ", next_byte, return_address+1); + *value = 0x60; // i.e. RTS } } - if(isReadOperation(operation)) *value = _rom[address&16383]; } else { From 827a91936867b8b5debb91de497ad5b6244551f2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 2 Nov 2016 22:30:53 -0400 Subject: [PATCH 3/6] This is an initial attempt at reading actual tape data. It loses sync though. --- Machines/Oric/Oric.cpp | 104 ++++++++++++++++++++++++++++++----------- Machines/Oric/Oric.hpp | 24 +++++++++- Storage/Tape/Tape.hpp | 2 +- 3 files changed, 102 insertions(+), 28 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 6a80be2d3..5c55df61d 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -14,7 +14,7 @@ using namespace Oric; Machine::Machine() : _cycles_since_video_update(0) { set_clock_rate(1000000); - _via.tape.reset(new Storage::Tape::BinaryTapePlayer(1000000)); + _via.tape.reset(new TapePlayer); _via.set_interrupt_delegate(this); _keyboard.reset(new Keyboard); _via.keyboard = _keyboard; @@ -42,33 +42,14 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { if(isReadOperation(operation)) *value = _rom[address&16383]; -// // 024D = 0 => fast; otherwise slow -// // E6C9 = read byte: return byte in A + // 024D = 0 => fast; otherwise slow + // E6C9 = read byte: return byte in A if(address == 0xe6c9 && operation == CPU6502::BusOperation::ReadOpcode) { - static FILE *test = NULL; - static int lead_counter = 0; - if(!test) - { - test = fopen("/Users/thomasharte/Desktop/Soft/Oric/Tapes/Slalom.tap", "rb"); - } - if(test && !feof(test)) - { - uint8_t next_byte; -// if(lead_counter < 64) -// { -// next_byte = 0x16; -// lead_counter++; -// } -// else - next_byte = (uint8_t)fgetc(test); - set_value_of_register(CPU6502::A, next_byte); - set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero); - uint8_t stack = get_value_of_register(CPU6502::S) + 1; - uint16_t return_address = _ram[0x0100 | stack] | (_ram[0x0100 | (stack+1)] << 8); - printf("%02x -> %04x | ", next_byte, return_address+1); - *value = 0x60; // i.e. RTS - } + uint8_t next_byte = _via.tape->get_next_byte(!_ram[0x024d]); + set_value_of_register(CPU6502::A, next_byte); + set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero); + *value = 0x60; // i.e. RTS } } else @@ -224,3 +205,74 @@ void Machine::VIA::update_ay() _cycles_since_ay_update = 0; ay8910->set_control_lines( (GI::AY38910::ControlLines)((_ay_bdir ? GI::AY38910::BCDIR : 0) | (_ay_bc1 ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2)); } + +#pragma mark - TapePlayer + +Machine::TapePlayer::TapePlayer() : + Storage::Tape::BinaryTapePlayer(1000000), + _is_catching_bytes(false), + _cycle_length(0.0f), + _was_high(false), + _queued_lengths_pointer(0) +{} + +uint8_t Machine::TapePlayer::get_next_byte(bool fast) +{ + _is_in_fast_mode = fast; + _is_catching_bytes = true; + + _bit_count = 0; + while(_bit_count < 13) + { + process_next_event(); + } + + _is_catching_bytes = false; + printf("%02x ", (uint8_t)(_shift_register >> 3)); + return (uint8_t)(_shift_register >> 3); +} + +void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) +{ + Storage::Tape::BinaryTapePlayer::process_input_pulse(pulse); + + if(_is_catching_bytes) + { + _cycle_length += pulse.length.get_float(); + bool is_high = get_input(); + if(is_high != _was_high) + { + // queue up the new length + _queued_lengths[_queued_lengths_pointer] = (int)(_cycle_length * 4800.0f + 0.5f); + _cycle_length = 0.0f; + _queued_lengths_pointer++; + + // search for bits + if(_is_in_fast_mode) + { + if(_queued_lengths_pointer >= 2) + { + if(_queued_lengths[0] == 1) + { + int new_bit = 0; + if(_queued_lengths[1] == 2) new_bit = 0; else new_bit = 1; + _shift_register = (_shift_register >> 1) | (new_bit << 12); + _bit_count++; + memmove(_queued_lengths, &_queued_lengths[2], sizeof(int)*14); + _queued_lengths_pointer -= 2; + } + else + { + memmove(_queued_lengths, &_queued_lengths[1], sizeof(int)*15); + _queued_lengths_pointer--; + } + } + } + else + { + // TODO + } + } + _was_high = is_high; + } +} diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 96ededdb2..295aeafb8 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -97,6 +97,28 @@ class Machine: uint8_t rows[8]; }; + // The tape + class TapePlayer: public Storage::Tape::BinaryTapePlayer { + public: + TapePlayer(); + uint8_t get_next_byte(bool fast); + + private: + bool _is_in_fast_mode; + bool _is_catching_bytes; + + float _cycle_length; + bool _was_high; + + int _queued_lengths[16]; + int _queued_lengths_pointer; + + int _shift_register; + int _bit_count; + + virtual void process_input_pulse(Storage::Tape::Tape::Pulse pulse); + }; + // VIA (which owns the tape and the AY) class VIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { public: @@ -109,7 +131,7 @@ class Machine: inline void run_for_cycles(unsigned int number_of_cycles); std::shared_ptr ay8910; - std::shared_ptr tape; + std::shared_ptr tape; std::shared_ptr keyboard; void synchronise(); diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 7b1dd7b84..14053a7a2 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -117,7 +117,7 @@ class BinaryTapePlayer: public TapePlayer { }; void set_delegate(Delegate *delegate); - private: + protected: Delegate *_delegate; virtual void process_input_pulse(Storage::Tape::Tape::Pulse pulse); bool _input_level; From e9f1a6a79d69f79193668510e1acaa39bac66d03 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 3 Nov 2016 07:34:48 -0400 Subject: [PATCH 4/6] This appears to be it. The secret? Don't worry about the stop bits. They're just processing time. Latch onto the next start. --- Machines/Oric/Oric.cpp | 37 ++++++++++++++++++++++++------------- Machines/Oric/Oric.hpp | 3 ++- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 5c55df61d..f04eeabcc 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -72,7 +72,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } _via.run_for_cycles(1); - _via.tape->run_for_cycles(1); _cycles_since_video_update++; return 1; } @@ -197,6 +196,7 @@ void Machine::VIA::run_for_cycles(unsigned int number_of_cycles) { _cycles_since_ay_update += number_of_cycles; MOS::MOS6522::run_for_cycles(number_of_cycles); + tape->run_for_cycles(number_of_cycles); } void Machine::VIA::update_ay() @@ -213,7 +213,8 @@ Machine::TapePlayer::TapePlayer() : _is_catching_bytes(false), _cycle_length(0.0f), _was_high(false), - _queued_lengths_pointer(0) + _queued_lengths_pointer(0), + _shift_register(0) {} uint8_t Machine::TapePlayer::get_next_byte(bool fast) @@ -222,14 +223,16 @@ uint8_t Machine::TapePlayer::get_next_byte(bool fast) _is_catching_bytes = true; _bit_count = 0; - while(_bit_count < 13) + _was_high = get_input(); + _queued_lengths_pointer = 0; + _shift_register = 0; + while(_bit_count < 10) { process_next_event(); } _is_catching_bytes = false; - printf("%02x ", (uint8_t)(_shift_register >> 3)); - return (uint8_t)(_shift_register >> 3); + return (uint8_t)(_shift_register >> 1); } void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) @@ -243,7 +246,7 @@ void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) if(is_high != _was_high) { // queue up the new length - _queued_lengths[_queued_lengths_pointer] = (int)(_cycle_length * 4800.0f + 0.5f); + _queued_lengths[_queued_lengths_pointer] = _cycle_length; _cycle_length = 0.0f; _queued_lengths_pointer++; @@ -252,18 +255,21 @@ void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) { if(_queued_lengths_pointer >= 2) { - if(_queued_lengths[0] == 1) + float first_two = _queued_lengths[0] + _queued_lengths[1]; + if(first_two < 0.000512*2.0 && _queued_lengths[0] >= _queued_lengths[1] - 0.000256) { - int new_bit = 0; - if(_queued_lengths[1] == 2) new_bit = 0; else new_bit = 1; - _shift_register = (_shift_register >> 1) | (new_bit << 12); - _bit_count++; - memmove(_queued_lengths, &_queued_lengths[2], sizeof(int)*14); + int new_bit = (first_two < 0.000512) ? 1 : 0; + if(_bit_count || !new_bit) + { + _shift_register |= (new_bit << _bit_count); + _bit_count++; + } + memmove(_queued_lengths, &_queued_lengths[2], sizeof(float)*14); _queued_lengths_pointer -= 2; } else { - memmove(_queued_lengths, &_queued_lengths[1], sizeof(int)*15); + memmove(_queued_lengths, &_queued_lengths[1], sizeof(float)*15); _queued_lengths_pointer--; } } @@ -276,3 +282,8 @@ void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) _was_high = is_high; } } + +void Machine::TapePlayer::run_for_cycles(int number_of_cycles) +{ + if(!_is_catching_bytes) Storage::Tape::BinaryTapePlayer::run_for_cycles(number_of_cycles); +} diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 295aeafb8..5b108bc82 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -102,6 +102,7 @@ class Machine: public: TapePlayer(); uint8_t get_next_byte(bool fast); + void run_for_cycles(int number_of_cycles); private: bool _is_in_fast_mode; @@ -110,7 +111,7 @@ class Machine: float _cycle_length; bool _was_high; - int _queued_lengths[16]; + float _queued_lengths[16]; int _queued_lengths_pointer; int _shift_register; From 9c2df231ce114874a846541d4ab093b04917cf2b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 3 Nov 2016 07:59:30 -0400 Subject: [PATCH 5/6] Made fast loading optional. --- Machines/Oric/Oric.cpp | 27 ++++++++++--------- Machines/Oric/Oric.hpp | 19 +++++++------ .../Clock Signal/Base.lproj/OricOptions.xib | 25 +++++++++++++---- .../Clock Signal/Machine/Wrappers/CSOric.h | 6 +++-- .../Clock Signal/Machine/Wrappers/CSOric.mm | 7 +++++ 5 files changed, 57 insertions(+), 27 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index f04eeabcc..cb1ffec81 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -11,7 +11,7 @@ using namespace Oric; -Machine::Machine() : _cycles_since_video_update(0) +Machine::Machine() : _cycles_since_video_update(0), _use_fast_tape_hack(false) { set_clock_rate(1000000); _via.tape.reset(new TapePlayer); @@ -44,7 +44,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // 024D = 0 => fast; otherwise slow // E6C9 = read byte: return byte in A - if(address == 0xe6c9 && operation == CPU6502::BusOperation::ReadOpcode) + if(address == 0xe6c9 && _use_fast_tape_hack && operation == CPU6502::BusOperation::ReadOpcode) { uint8_t next_byte = _via.tape->get_next_byte(!_ram[0x024d]); set_value_of_register(CPU6502::A, next_byte); @@ -126,6 +126,11 @@ void Machine::clear_all_keys() memset(_keyboard->rows, 0, sizeof(_keyboard->rows)); } +void Machine::set_use_fast_tape_hack(bool activate) +{ + _use_fast_tape_hack = activate; +} + void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) { // set CB1 @@ -196,7 +201,7 @@ void Machine::VIA::run_for_cycles(unsigned int number_of_cycles) { _cycles_since_ay_update += number_of_cycles; MOS::MOS6522::run_for_cycles(number_of_cycles); - tape->run_for_cycles(number_of_cycles); + tape->run_for_cycles((int)number_of_cycles); } void Machine::VIA::update_ay() @@ -210,11 +215,7 @@ void Machine::VIA::update_ay() Machine::TapePlayer::TapePlayer() : Storage::Tape::BinaryTapePlayer(1000000), - _is_catching_bytes(false), - _cycle_length(0.0f), - _was_high(false), - _queued_lengths_pointer(0), - _shift_register(0) + _is_catching_bytes(false) {} uint8_t Machine::TapePlayer::get_next_byte(bool fast) @@ -222,17 +223,19 @@ uint8_t Machine::TapePlayer::get_next_byte(bool fast) _is_in_fast_mode = fast; _is_catching_bytes = true; - _bit_count = 0; _was_high = get_input(); _queued_lengths_pointer = 0; - _shift_register = 0; + _data_register = 0; + _cycle_length = 0.0f; + + _bit_count = 0; while(_bit_count < 10) { process_next_event(); } _is_catching_bytes = false; - return (uint8_t)(_shift_register >> 1); + return (uint8_t)(_data_register >> 1); } void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) @@ -261,7 +264,7 @@ void Machine::TapePlayer::process_input_pulse(Storage::Tape::Tape::Pulse pulse) int new_bit = (first_two < 0.000512) ? 1 : 0; if(_bit_count || !new_bit) { - _shift_register |= (new_bit << _bit_count); + _data_register |= (new_bit << _bit_count); _bit_count++; } memmove(_queued_lengths, &_queued_lengths[2], sizeof(float)*14); diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 5b108bc82..c84d189d1 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -61,6 +61,8 @@ class Machine: void set_key_state(Key key, bool isPressed); void clear_all_keys(); + void set_use_fast_tape_hack(bool activate); + // to satisfy ConfigurationTarget::Machine void configure_as_target(const StaticAnalyser::Target &target); @@ -105,20 +107,21 @@ class Machine: void run_for_cycles(int number_of_cycles); private: - bool _is_in_fast_mode; - bool _is_catching_bytes; + bool _is_catching_bytes; // `true` to enable tape byte parsing, `false` otherwise + bool _is_in_fast_mode; // `true` to indicate that tape byte parsing should use the Oric's fast encoding, `false` otherwise - float _cycle_length; - bool _was_high; + float _cycle_length; // a counter for the amount of time since the tape input changed + bool _was_high; // a latch to spot when the tape input changes - float _queued_lengths[16]; - int _queued_lengths_pointer; + float _queued_lengths[16]; // a history of previous half-wave lengths + int _queued_lengths_pointer; // a pointer into the history, showing the number of lengths waiting to be parsed - int _shift_register; - int _bit_count; + int _data_register; // the accumulation of input bits + int _bit_count; // a counter of accumulated bits virtual void process_input_pulse(Storage::Tape::Tape::Pulse pulse); }; + bool _use_fast_tape_hack; // VIA (which owns the tape and the AY) class VIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib b/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib index e1cdad4d0..aea4e9546 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib @@ -1,5 +1,5 @@ - + @@ -14,12 +14,22 @@ - + - + + @@ -38,15 +48,20 @@ + + + + + - + - + diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h index 3cd3e67d4..c284944c1 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.h @@ -8,9 +8,11 @@ #import "CSMachine.h" #import "CSKeyboardMachine.h" +#import "CSFastLoading.h" -@interface CSOric : CSMachine +@interface CSOric : CSMachine -@property(nonatomic, assign) BOOL useCompositeOutput; +@property (nonatomic, assign) BOOL useFastLoadingHack; +@property (nonatomic, assign) BOOL useCompositeOutput; @end diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm index c6dde0e4a..f25982c71 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm @@ -135,6 +135,13 @@ #pragma mark - Options +- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack { + @synchronized(self) { + _useFastLoadingHack = useFastLoadingHack; + _oric.set_use_fast_tape_hack(useFastLoadingHack ? true : false); + } +} + - (void)setUseCompositeOutput:(BOOL)useCompositeOutput { @synchronized(self) { _useCompositeOutput = useCompositeOutput; From a2e5fd2a1f42fb79740f2662d27f2499f807a3e3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 3 Nov 2016 08:02:13 -0400 Subject: [PATCH 6/6] Corrected layout error. --- .../Mac/Clock Signal/Base.lproj/ElectronOptions.xib | 4 ++-- .../Mac/Clock Signal/Base.lproj/OricOptions.xib | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/ElectronOptions.xib b/OSBindings/Mac/Clock Signal/Base.lproj/ElectronOptions.xib index 2e05438f5..2997bc731 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/ElectronOptions.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/ElectronOptions.xib @@ -1,5 +1,5 @@ - + @@ -60,7 +60,7 @@ - + diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib b/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib index aea4e9546..694172ae7 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/OricOptions.xib @@ -14,15 +14,15 @@ - + - +