diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 930893570..14ff65f82 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -28,8 +28,16 @@ #include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp" #include "../../Outputs/Speaker/Implementation/SampleSource.hpp" +#include "../../Configurable/StandardOptions.hpp" + namespace MSX { +std::vector> get_options() { + return Configurable::standard_options( + static_cast(Configurable::DisplayRGBComposite | Configurable::QuickLoadTape) + ); +} + /*! Provides a sample source that can programmatically be set to one of two values. */ @@ -97,7 +105,8 @@ class ConcreteMachine: public CPU::Z80::BusHandler, public CRTMachine::Machine, public ConfigurationTarget::Machine, - public KeyboardMachine::Machine { + public KeyboardMachine::Machine, + public Configurable::Device { public: ConcreteMachine(): z80_(*this), @@ -187,57 +196,59 @@ class ConcreteMachine: uint16_t address = cycle.address ? *cycle.address : 0x0000; switch(cycle.operation) { case CPU::Z80::PartialMachineCycle::ReadOpcode: - if(address == 0x1a63) { - // TAPION + if(use_fast_tape_) { + if(address == 0x1a63) { + // TAPION - // Enable the tape motor. - i8255_.set_register(0xab, 0x8); + // Enable the tape motor. + i8255_.set_register(0xab, 0x8); - // Disable interrupts. - z80_.set_value_of_register(CPU::Z80::Register::IFF1, 0); - z80_.set_value_of_register(CPU::Z80::Register::IFF2, 0); + // Disable interrupts. + z80_.set_value_of_register(CPU::Z80::Register::IFF1, 0); + z80_.set_value_of_register(CPU::Z80::Register::IFF2, 0); - // Use the parser to find a header, and if one is found then populate - // LOWLIM and WINWID, and reset carry. Otherwise set carry. - using Parser = Storage::Tape::MSX::Parser; - std::unique_ptr new_speed = Parser::find_header(tape_player_); - if(new_speed) { - ram_[0xfca4] = new_speed->minimum_start_bit_duration; - ram_[0xfca5] = new_speed->low_high_disrimination_duration; - z80_.set_value_of_register(CPU::Z80::Register::Flags, 0); - } else { - z80_.set_value_of_register(CPU::Z80::Register::Flags, 1); + // Use the parser to find a header, and if one is found then populate + // LOWLIM and WINWID, and reset carry. Otherwise set carry. + using Parser = Storage::Tape::MSX::Parser; + std::unique_ptr new_speed = Parser::find_header(tape_player_); + if(new_speed) { + ram_[0xfca4] = new_speed->minimum_start_bit_duration; + ram_[0xfca5] = new_speed->low_high_disrimination_duration; + z80_.set_value_of_register(CPU::Z80::Register::Flags, 0); + } else { + z80_.set_value_of_register(CPU::Z80::Register::Flags, 1); + } + + // RET. + *cycle.value = 0xc9; + break; } - // RET. - *cycle.value = 0xc9; - break; - } + if(address == 0x1abc) { + // TAPIN - if(address == 0x1abc) { - // TAPIN + // Grab the current values of LOWLIM and WINWID. + using Parser = Storage::Tape::MSX::Parser; + Parser::FileSpeed tape_speed; + tape_speed.minimum_start_bit_duration = ram_[0xfca4]; + tape_speed.low_high_disrimination_duration = ram_[0xfca5]; - // Grab the current values of LOWLIM and WINWID. - using Parser = Storage::Tape::MSX::Parser; - Parser::FileSpeed tape_speed; - tape_speed.minimum_start_bit_duration = ram_[0xfca4]; - tape_speed.low_high_disrimination_duration = ram_[0xfca5]; + // Ask the tape parser to grab a byte. + int next_byte = Parser::get_byte(tape_speed, tape_player_); - // Ask the tape parser to grab a byte. - int next_byte = Parser::get_byte(tape_speed, tape_player_); + // If a byte was found, return it with carry unset. Otherwise set carry to + // indicate error. + if(next_byte >= 0) { + z80_.set_value_of_register(CPU::Z80::Register::A, static_cast(next_byte)); + z80_.set_value_of_register(CPU::Z80::Register::Flags, 0); + } else { + z80_.set_value_of_register(CPU::Z80::Register::Flags, 1); + } - // If a byte was found, return it with carry unset. Otherwise set carry to - // indicate error. - if(next_byte >= 0) { - z80_.set_value_of_register(CPU::Z80::Register::A, static_cast(next_byte)); - z80_.set_value_of_register(CPU::Z80::Register::Flags, 0); - } else { - z80_.set_value_of_register(CPU::Z80::Register::Flags, 1); + // RET. + *cycle.value = 0xc9; + break; } - - // RET. - *cycle.value = 0xc9; - break; } case CPU::Z80::PartialMachineCycle::Read: *cycle.value = read_pointers_[address >> 14][address & 16383]; @@ -408,6 +419,37 @@ class ConcreteMachine: return keyboard_mapper_; } + // MARK: - Configuration options. + std::vector> get_options() override { + return MSX::get_options(); + } + + void set_selections(const Configurable::SelectionSet &selections_by_option) override { + bool quickload; + if(Configurable::get_quick_load_tape(selections_by_option, quickload)) { + use_fast_tape_ = quickload; + } + + Configurable::Display display; + if(Configurable::get_display(selections_by_option, display)) { + get_crt()->set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + } + } + + Configurable::SelectionSet get_accurate_selections() override { + Configurable::SelectionSet selection_set; + Configurable::append_quick_load_tape_selection(selection_set, false); + Configurable::append_display_selection(selection_set, Configurable::Display::Composite); + return selection_set; + } + + Configurable::SelectionSet get_user_friendly_selections() override { + Configurable::SelectionSet selection_set; + Configurable::append_quick_load_tape_selection(selection_set, true); + Configurable::append_display_selection(selection_set, Configurable::Display::RGB); + return selection_set; + } + private: void update_audio() { speaker_.run_for(audio_queue_, time_since_ay_update_.divide_cycles(Cycles(2))); @@ -467,6 +509,7 @@ class ConcreteMachine: Outputs::Speaker::LowpassSpeaker> speaker_; Storage::Tape::BinaryTapePlayer tape_player_; + bool use_fast_tape_ = false; i8255PortHandler i8255_port_handler_; AYPortHandler ay_port_handler_; diff --git a/Machines/MSX/MSX.hpp b/Machines/MSX/MSX.hpp index 103d635f8..f52c4befc 100644 --- a/Machines/MSX/MSX.hpp +++ b/Machines/MSX/MSX.hpp @@ -9,6 +9,8 @@ #ifndef MSX_hpp #define MSX_hpp +#include "../../Configurable/Configurable.hpp" + namespace MSX { class Machine { @@ -17,6 +19,8 @@ class Machine { static Machine *MSX(); }; +std::vector> get_options(); + } #endif /* MSX_hpp */ diff --git a/Machines/Utility/MachineForTarget.cpp b/Machines/Utility/MachineForTarget.cpp index 5783317a0..730284163 100644 --- a/Machines/Utility/MachineForTarget.cpp +++ b/Machines/Utility/MachineForTarget.cpp @@ -64,6 +64,7 @@ std::map>> Machin std::map>> options; options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::Electron), Electron::get_options())); + options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::MSX), MSX::get_options())); options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::Oric), Oric::get_options())); options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::Vic20), Commodore::Vic20::get_options())); options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::ZX8081), ZX8081::get_options()));