diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index 56cbbbe10..6282d7a46 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -13,6 +13,7 @@ #include "../CRTMachine.hpp" #include "../KeyboardMachine.hpp" #include "../Utility/MemoryFuzzer.hpp" +#include "../Utility/StringSerialiser.hpp" #include "../../Processors/6502/6502.hpp" #include "../../Components/AudioToggle/AudioToggle.hpp" @@ -118,8 +119,7 @@ class ConcreteMachine: } // MARK - typing - std::string input_string_; - std::size_t input_string_pointer_ = std::numeric_limits::max(); + std::unique_ptr string_serialiser_; public: ConcreteMachine(): @@ -201,8 +201,8 @@ class ConcreteMachine: default: break; case 0xc000: - if(input_string_pointer_ != std::numeric_limits::max()) { - *value = static_cast(input_string_[input_string_pointer_]) | 0x80; + if(string_serialiser_) { + *value = string_serialiser_->head() | 0x80; } else { *value = keyboard_input_; } @@ -225,10 +225,9 @@ class ConcreteMachine: case 0xc010: keyboard_input_ &= 0x7f; - if(input_string_pointer_ != std::numeric_limits::max()) { - ++input_string_pointer_; - if(input_string_pointer_ == input_string_.size()) - input_string_pointer_ = std::numeric_limits::max(); + if(string_serialiser_) { + if(!string_serialiser_->advance()) + string_serialiser_.reset(); } break; @@ -361,22 +360,7 @@ class ConcreteMachine: } void type_string(const std::string &string) override { - input_string_.clear(); - input_string_.reserve(string.size()); - - // Commute any \ns that are not immediately after \rs to \rs; remove the rest. - bool saw_carriage_return = false; - for(auto character: string) { - if(character != '\n') { - input_string_.push_back(character); - } else { - if(!saw_carriage_return) { - input_string_.push_back('\r'); - } - } - saw_carriage_return = character == '\r'; - } - input_string_pointer_ = 0; + string_serialiser_.reset(new Utility::StringSerialiser(string, true)); } // MARK: ConfigurationTarget diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index d2066ec9e..87e90638a 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -659,7 +659,7 @@ class ConcreteMachine: user_port_via_.run_for(Cycles(1)); keyboard_via_.run_for(Cycles(1)); - if(typer_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && address == 0xEB1E) { + if(typer_ && address == 0xeb1e && operation == CPU::MOS6502::BusOperation::ReadOpcode) { if(!typer_->type_next_character()) { clear_all_keys(); typer_.reset(); diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index b1d8b0a2e..cbc6fd4d4 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -18,7 +18,7 @@ #include "../KeyboardMachine.hpp" #include "../Utility/MemoryFuzzer.hpp" -#include "../Utility/Typer.hpp" +#include "../Utility/StringSerialiser.hpp" #include "../../Processors/6502/6502.hpp" #include "../../Components/6522/6522.hpp" @@ -305,13 +305,11 @@ template class Co switch(rom_type_) { case Analyser::Static::Oric::Target::ROM::BASIC10: tape_get_byte_address_ = 0xe630; - scan_keyboard_address_ = 0xf43c; tape_speed_address_ = 0x67; break; case Analyser::Static::Oric::Target::ROM::BASIC11: case Analyser::Static::Oric::Target::ROM::Pravetz: tape_get_byte_address_ = 0xe6c9; - scan_keyboard_address_ = 0xf495; tape_speed_address_ = 0x024d; break; } @@ -424,14 +422,13 @@ template class Co } } - if(typer_ && address == scan_keyboard_address_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) { - // the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't - // do anything until at least the second, regardless of machine - if(!keyboard_read_count_) keyboard_read_count_++; - else if(!typer_->type_next_character()) { - clear_all_keys(); - typer_.reset(); - } + // $02df is where the Oric ROMs — all of them, including BASIC 1.0, 1.1 and the Pravetz — have the + // IRQ routine store an incoming keystroke in order for reading to occur later. By capturing the + // read rather than the decode and write: (i) nothing is lost while BASIC is parsing; and + // (ii) keyboard input is much more rapid. + if(string_serialiser_ && address == 0x02df && operation == CPU::MOS6502::BusOperation::Read) { + *value = string_serialiser_->head() | 0x80; + if(!string_serialiser_->advance()) string_serialiser_.reset(); } via_.run_for(Cycles(1)); @@ -490,8 +487,7 @@ template class Co // for Utility::TypeRecipient::Delegate void type_string(const std::string &string) override final { - std::unique_ptr mapper(new CharacterMapper); - Utility::TypeRecipient::add_typer(string, std::move(mapper)); + string_serialiser_.reset(new Utility::StringSerialiser(string, true)); } // for Microdisc::Delegate @@ -581,7 +577,7 @@ template class Co } // ROM bookkeeping - uint16_t tape_get_byte_address_ = 0, scan_keyboard_address_ = 0, tape_speed_address_ = 0; + uint16_t tape_get_byte_address_ = 0, tape_speed_address_ = 0; int keyboard_read_count_ = 0; // Outputs @@ -625,6 +621,9 @@ template class Co irq_line |= microdisc_.get_interrupt_request_line(); m6502_.set_irq_line(irq_line); } + + // MARK - typing + std::unique_ptr string_serialiser_; }; } diff --git a/Machines/Utility/StringSerialiser.cpp b/Machines/Utility/StringSerialiser.cpp new file mode 100644 index 000000000..ffbc97b58 --- /dev/null +++ b/Machines/Utility/StringSerialiser.cpp @@ -0,0 +1,46 @@ +// +// StringSerialiser.cpp +// Clock Signal +// +// Created by Thomas Harte on 13/05/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#include "StringSerialiser.hpp" + +using namespace Utility; + +StringSerialiser::StringSerialiser(const std::string &source, bool use_linefeed_only) { + if(!use_linefeed_only) { + input_string_ = source; + } else { + input_string_.reserve(source.size()); + + // Commute any \ns that are not immediately after \rs to \rs; remove the rest. + bool saw_carriage_return = false; + for(auto character: source) { + if(character != '\n') { + input_string_.push_back(character); + } else { + if(!saw_carriage_return) { + input_string_.push_back('\r'); + } + } + saw_carriage_return = character == '\r'; + } + } +} + +uint8_t StringSerialiser::head() { + if(input_string_pointer_ == input_string_.size()) + return '\0'; + return static_cast(input_string_[input_string_pointer_]); +} + +bool StringSerialiser::advance() { + if(input_string_pointer_ != input_string_.size()) { + ++input_string_pointer_; + return input_string_pointer_ != input_string_.size(); + } + return false; +} diff --git a/Machines/Utility/StringSerialiser.hpp b/Machines/Utility/StringSerialiser.hpp new file mode 100644 index 000000000..d08459aea --- /dev/null +++ b/Machines/Utility/StringSerialiser.hpp @@ -0,0 +1,30 @@ +// +// StringSerialiser.hpp +// Clock Signal +// +// Created by Thomas Harte on 13/05/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef StringSerialiser_hpp +#define StringSerialiser_hpp + +#include + +namespace Utility { + +class StringSerialiser { + public: + StringSerialiser(const std::string &source, bool use_linefeed_only = false); + + uint8_t head(); + bool advance(); + + private: + std::string input_string_; + std::size_t input_string_pointer_ = 0; +}; + +} + +#endif /* StringSerialiser_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index cab4b4feb..8ffd5537e 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -140,6 +140,8 @@ 4B15AA0E2082C799005E6C8D /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B15AA0A2082C799005E6C8D /* Video.cpp */; }; 4B15AA0F2082C799005E6C8D /* AppleII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B15AA0C2082C799005E6C8D /* AppleII.cpp */; }; 4B15AA102082C799005E6C8D /* AppleII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B15AA0C2082C799005E6C8D /* AppleII.cpp */; }; + 4B17B58B20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */; }; + 4B17B58C20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */; }; 4B1B88BB202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */; }; 4B1B88BC202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */; }; 4B1B88BD202E3D3D00B67DFF /* MultiMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FCC3F201EC24200960631 /* MultiMachine.cpp */; }; @@ -740,6 +742,8 @@ 4B1667F91FFF215E00A16032 /* ASCII16kb.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ASCII16kb.hpp; path = MSX/Cartridges/ASCII16kb.hpp; sourceTree = ""; }; 4B1667FA1FFF215E00A16032 /* ASCII8kb.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ASCII8kb.hpp; path = MSX/Cartridges/ASCII8kb.hpp; sourceTree = ""; }; 4B1667FB1FFF215F00A16032 /* KonamiWithSCC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KonamiWithSCC.hpp; path = MSX/Cartridges/KonamiWithSCC.hpp; sourceTree = ""; }; + 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StringSerialiser.cpp; sourceTree = ""; }; + 4B17B58A20A8A9D9007CCA8F /* StringSerialiser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StringSerialiser.hpp; sourceTree = ""; }; 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiKeyboardMachine.cpp; sourceTree = ""; }; 4B1B88BA202E2EC100B67DFF /* MultiKeyboardMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiKeyboardMachine.hpp; sourceTree = ""; }; 4B1B88BE202E3DB200B67DFF /* MultiConfigurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiConfigurable.cpp; sourceTree = ""; }; @@ -1674,6 +1678,8 @@ 4B2B3A491F9B8FA70062DABF /* MemoryFuzzer.hpp */, 4B2B3A4A1F9B8FA70062DABF /* Typer.hpp */, 4B79A4FE1FC9082300EEDAD5 /* TypedDynamicMachine.hpp */, + 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */, + 4B17B58A20A8A9D9007CCA8F /* StringSerialiser.hpp */, ); path = Utility; sourceTree = ""; @@ -3672,6 +3678,7 @@ 4B15AA102082C799005E6C8D /* AppleII.cpp in Sources */, 4B055AA91FAE85EF0060FFFF /* CommodoreGCR.cpp in Sources */, 4B055ADB1FAE9B460060FFFF /* 6560.cpp in Sources */, + 4B17B58C20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */, 4B055AA01FAE85DA0060FFFF /* MFMSectorDump.cpp in Sources */, 4BEBFB522002DB30000708CC /* DiskROM.cpp in Sources */, 4B055AA11FAE85DA0060FFFF /* OricMFMDSK.cpp in Sources */, @@ -3838,6 +3845,7 @@ 4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */, 4B4518821F75E91A00926311 /* PCMSegment.cpp in Sources */, 4B894522201967B4007DE474 /* StaticAnalyser.cpp in Sources */, + 4B17B58B20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */, 4BE7C9181E3D397100A5496D /* TIA.cpp in Sources */, 4B80AD001F85CACA00176895 /* BestEffortUpdater.cpp in Sources */, 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,