From ee71be0e7e4e015aac29e8d049f749c044c8f894 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 21 Aug 2017 21:56:42 -0400 Subject: [PATCH] Added the option not to include ready line support in the 6502 core, and took advantage of it in the Electron, Oric and Vic-20 implementations. Also tagged those as forceinline and/or override final where applicable. --- ClockReceiver/ForceInline.hpp | 8 ++ Machines/AmstradCPC/AmstradCPC.cpp | 28 +++---- Machines/Atari2600/Cartridges/Cartridge.hpp | 2 +- Machines/Commodore/1540/C1540.hpp | 2 +- Machines/Commodore/Vic-20/Vic20.cpp | 42 +++++----- Machines/Electron/Electron.cpp | 37 ++++----- Machines/Oric/Oric.cpp | 44 ++++++----- Machines/ZX8081/ZX8081.cpp | 44 ++++++----- .../Bridges/TestMachine6502.h | 2 - .../Bridges/TestMachine6502.mm | 4 - .../Clock SignalTests/PCMPatchedTrackTests.mm | 79 +++++++------------ Processors/6502/6502.hpp | 29 ++----- Processors/6502/6502AllRAM.cpp | 26 +++--- Processors/6502/6502AllRAM.hpp | 1 - Processors/Z80/Z80AllRAM.cpp | 2 +- 15 files changed, 158 insertions(+), 192 deletions(-) diff --git a/ClockReceiver/ForceInline.hpp b/ClockReceiver/ForceInline.hpp index 2b6cf5589..c843c07f6 100644 --- a/ClockReceiver/ForceInline.hpp +++ b/ClockReceiver/ForceInline.hpp @@ -9,10 +9,18 @@ #ifndef ForceInline_hpp #define ForceInline_hpp +//#ifdef DEBUG +// +//#define forceinline inline +// +//#elseif + #ifdef __GNUC__ #define forceinline __attribute__((always_inline)) inline #elif _MSC_VER #define forceinline __forceinline #endif +//#endif + #endif /* ForceInline_h */ diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 7e630a4fc..40b4515ed 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -827,35 +827,35 @@ class ConcreteMachine: } /// A CRTMachine function; indicates that outputs should be created now. - void setup_output(float aspect_ratio) final override { + void setup_output(float aspect_ratio) override final { crtc_bus_handler_.setup_output(aspect_ratio); ay_.setup_output(); ay_.ay()->set_port_handler(&key_state_); } /// A CRTMachine function; indicates that outputs should be destroyed now. - void close_output() final override { + void close_output() override final { crtc_bus_handler_.close_output(); ay_.close_output(); } /// @returns the CRT in use. - std::shared_ptr get_crt() final override { + std::shared_ptr get_crt() override final { return crtc_bus_handler_.get_crt(); } /// @returns the speaker in use. - std::shared_ptr get_speaker() final override { + std::shared_ptr get_speaker() override final { return ay_.get_speaker(); } /// Wires virtual-dispatched CRTMachine run_for requests to the static Z80 method. - void run_for(const Cycles cycles) final override { + void run_for(const Cycles cycles) override final { z80_.run_for(cycles); } /// The ConfigurationTarget entry point; should configure this meachine as described by @c target. - void configure_as_target(const StaticAnalyser::Target &target) final override { + void configure_as_target(const StaticAnalyser::Target &target) override final { switch(target.amstradcpc.model) { case StaticAnalyser::AmstradCPCModel::CPC464: rom_model_ = ROMType::OS464; @@ -896,7 +896,7 @@ class ConcreteMachine: insert_media(target.media); } - bool insert_media(const StaticAnalyser::Media &media) final override { + bool insert_media(const StaticAnalyser::Media &media) override final { // If there are any tapes supplied, use the first of them. if(!media.tapes.empty()) { tape_player_.set_tape(media.tapes.front()); @@ -914,37 +914,37 @@ class ConcreteMachine: } // See header; provides the system ROMs. - void set_rom(ROMType type, std::vector data) final override { + void set_rom(ROMType type, std::vector data) override final { roms_[(int)type] = data; } - void set_component_is_sleeping(void *component, bool is_sleeping) final override { + void set_component_is_sleeping(void *component, bool is_sleeping) override final { fdc_is_sleeping_ = fdc_.is_sleeping(); tape_player_is_sleeping_ = tape_player_.is_sleeping(); } #pragma mark - Keyboard - void set_typer_for_string(const char *string) final override { + void set_typer_for_string(const char *string) override final { std::unique_ptr mapper(new CharacterMapper()); Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); } - HalfCycles get_typer_delay() final override { + HalfCycles get_typer_delay() override final { return Cycles(4000000); // Wait 1 second before typing. } - HalfCycles get_typer_frequency() final override { + HalfCycles get_typer_frequency() override final { return Cycles(160000); // Type one character per frame. } // See header; sets a key as either pressed or released. - void set_key_state(uint16_t key, bool isPressed) final override { + void set_key_state(uint16_t key, bool isPressed) override final { key_state_.set_is_pressed(isPressed, key >> 4, key & 7); } // See header; sets all keys to released. - void clear_all_keys() final override { + void clear_all_keys() override final { key_state_.clear_all_keys(); } diff --git a/Machines/Atari2600/Cartridges/Cartridge.hpp b/Machines/Atari2600/Cartridges/Cartridge.hpp index 20f52c9a9..2580244e5 100644 --- a/Machines/Atari2600/Cartridges/Cartridge.hpp +++ b/Machines/Atari2600/Cartridges/Cartridge.hpp @@ -184,7 +184,7 @@ template class Cartridge: } protected: - CPU::MOS6502::Processor> m6502_; + CPU::MOS6502::Processor, true> m6502_; std::vector rom_; private: diff --git a/Machines/Commodore/1540/C1540.hpp b/Machines/Commodore/1540/C1540.hpp index 59b1ba745..f1fe08a68 100644 --- a/Machines/Commodore/1540/C1540.hpp +++ b/Machines/Commodore/1540/C1540.hpp @@ -152,7 +152,7 @@ class Machine: void drive_via_did_set_data_density(void *driveVIA, int density); private: - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; uint8_t ram_[0x800]; uint8_t rom_[0x4000]; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 7095f4138..8bb641c0a 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -14,6 +14,8 @@ #include "../../../Components/6560/6560.hpp" #include "../../../Components/6522/6522.hpp" +#include "../../../ClockReceiver/ForceInline.hpp" + #include "../../../Storage/Tape/Parsers/Commodore.hpp" #include "../SerialBus.hpp" @@ -253,7 +255,7 @@ class ConcreteMachine: delete[] rom_; } - void set_rom(ROMSlot slot, size_t length, const uint8_t *data) { + void set_rom(ROMSlot slot, size_t length, const uint8_t *data) override final { uint8_t *target = nullptr; size_t max_length = 0x2000; switch(slot) { @@ -273,7 +275,7 @@ class ConcreteMachine: } } - void configure_as_target(const StaticAnalyser::Target &target) { + void configure_as_target(const StaticAnalyser::Target &target) override final { if(target.loadingCommand.length()) { set_typer_for_string(target.loadingCommand.c_str()); } @@ -304,7 +306,7 @@ class ConcreteMachine: insert_media(target.media); } - bool insert_media(const StaticAnalyser::Media &media) { + bool insert_media(const StaticAnalyser::Media &media) override final { if(!media.tapes.empty()) { tape_->set_tape(media.tapes.front()); } @@ -326,20 +328,20 @@ class ConcreteMachine: return !media.tapes.empty() || (!media.disks.empty() && c1540_ != nullptr) || !media.cartridges.empty(); } - void set_key_state(uint16_t key, bool isPressed) { + void set_key_state(uint16_t key, bool isPressed) override final { keyboard_via_->set_key_state(key, isPressed); } - void clear_all_keys() { + void clear_all_keys() override final { keyboard_via_->clear_all_keys(); } - void set_joystick_state(JoystickInput input, bool isPressed) { + void set_joystick_state(JoystickInput input, bool isPressed) override final { user_port_via_->set_joystick_state(input, isPressed); keyboard_via_->set_joystick_state(input, isPressed); } - void set_memory_size(MemorySize size) { + void set_memory_size(MemorySize size) override final { memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_)); memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_)); @@ -373,7 +375,7 @@ class ConcreteMachine: } } - void set_region(Region region) { + void set_region(Region region) override final { region_ = region; switch(region) { case PAL: @@ -393,12 +395,12 @@ class ConcreteMachine: } } - void set_use_fast_tape_hack(bool activate) { + void set_use_fast_tape_hack(bool activate) override final { use_fast_tape_hack_ = activate; } // to satisfy CPU::MOS6502::Processor - Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { + forceinline Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { // run the phase-1 part of this cycle, in which the VIC accesses memory if(!is_running_at_zero_cost_) mos6560_->run_for(Cycles(1)); @@ -494,15 +496,15 @@ class ConcreteMachine: return Cycles(1); } - void flush() { + forceinline void flush() { mos6560_->flush(); } - void run_for(const Cycles cycles) { + void run_for(const Cycles cycles) override final { m6502_.run_for(cycles); } - void setup_output(float aspect_ratio) { + void setup_output(float aspect_ratio) override final { mos6560_.reset(new Vic6560()); mos6560_->get_speaker()->set_high_frequency_cut_off(1600); // There is a 1.6Khz low-pass filter in the Vic-20. set_region(region_); @@ -514,34 +516,34 @@ class ConcreteMachine: mos6560_->colour_memory = colour_memory_; } - void close_output() { + void close_output() override final { mos6560_ = nullptr; } - std::shared_ptr get_crt() { + std::shared_ptr get_crt() override final { return mos6560_->get_crt(); } - std::shared_ptr get_speaker() { + std::shared_ptr get_speaker() override final { return mos6560_->get_speaker(); } - void mos6522_did_change_interrupt_status(void *mos6522) { + void mos6522_did_change_interrupt_status(void *mos6522) override final { m6502_.set_nmi_line(user_port_via_->get_interrupt_line()); m6502_.set_irq_line(keyboard_via_->get_interrupt_line()); } - void set_typer_for_string(const char *string) { + void set_typer_for_string(const char *string) override final { std::unique_ptr mapper(new CharacterMapper()); Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); } - void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) { + void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) override final { keyboard_via_->set_control_line_input(KeyboardVIA::Port::A, KeyboardVIA::Line::One, !tape->get_input()); } private: - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; uint8_t character_rom_[0x1000]; uint8_t basic_rom_[0x2000]; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index c4072061a..9fef59337 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -11,6 +11,7 @@ #include "../../Processors/6502/6502.hpp" #include "../../Storage/Tape/Tape.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" +#include "../../ClockReceiver/ForceInline.hpp" #include "../Typer.hpp" @@ -44,7 +45,7 @@ class ConcreteMachine: set_clock_rate(2000000); } - void set_rom(ROMSlot slot, std::vector data, bool is_writeable) { + void set_rom(ROMSlot slot, std::vector data, bool is_writeable) override final { uint8_t *target = nullptr; switch(slot) { case ROMSlotDFS: dfs_ = data; return; @@ -60,7 +61,7 @@ class ConcreteMachine: memcpy(target, &data[0], std::min((size_t)16384, data.size())); } - void set_key_state(uint16_t key, bool isPressed) { + void set_key_state(uint16_t key, bool isPressed) override final { if(key == KeyBreak) { m6502_.set_reset_line(isPressed); } else { @@ -71,16 +72,16 @@ class ConcreteMachine: } } - void clear_all_keys() { + void clear_all_keys() override final { memset(key_states_, 0, sizeof(key_states_)); if(is_holding_shift_) set_key_state(KeyShift, true); } - void set_use_fast_tape_hack(bool activate) { + void set_use_fast_tape_hack(bool activate) override final { use_fast_tape_hack_ = activate; } - void configure_as_target(const StaticAnalyser::Target &target) { + void configure_as_target(const StaticAnalyser::Target &target) override final { if(target.loadingCommand.length()) { set_typer_for_string(target.loadingCommand.c_str()); } @@ -104,7 +105,7 @@ class ConcreteMachine: insert_media(target.media); } - bool insert_media(const StaticAnalyser::Media &media) { + bool insert_media(const StaticAnalyser::Media &media) override final { if(!media.tapes.empty()) { tape_.set_tape(media.tapes.front()); } @@ -122,7 +123,7 @@ class ConcreteMachine: return !media.tapes.empty() || !media.disks.empty() || !media.cartridges.empty(); } - Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { + forceinline Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { unsigned int cycles = 1; if(address < 0x8000) { @@ -342,13 +343,13 @@ class ConcreteMachine: return Cycles((int)cycles); } - void flush() { + forceinline void flush() { update_display(); update_audio(); speaker_->flush(); } - void setup_output(float aspect_ratio) { + void setup_output(float aspect_ratio) override final { video_output_.reset(new VideoOutput(ram_)); // The maximum output frequency is 62500Hz and all other permitted output frequencies are integral divisions of that; @@ -358,36 +359,36 @@ class ConcreteMachine: speaker_->set_input_rate(2000000 / Speaker::clock_rate_divider); } - void close_output() { + void close_output() override final { video_output_.reset(); } - std::shared_ptr get_crt() { + std::shared_ptr get_crt() override final { return video_output_->get_crt(); } - std::shared_ptr get_speaker() { + std::shared_ptr get_speaker() override final { return speaker_; } - virtual void run_for(const Cycles cycles) { + void run_for(const Cycles cycles) override final { m6502_.run_for(cycles); } - void tape_did_change_interrupt_status(Tape *tape) { + void tape_did_change_interrupt_status(Tape *tape) override final { interrupt_status_ = (interrupt_status_ & ~(Interrupt::TransmitDataEmpty | Interrupt::ReceiveDataFull | Interrupt::HighToneDetect)) | tape_.get_interrupt_status(); evaluate_interrupts(); } - HalfCycles get_typer_delay() { + HalfCycles get_typer_delay() override final { return m6502_.get_is_resetting() ? Cycles(625*25*128) : Cycles(0); // wait one second if resetting } - HalfCycles get_typer_frequency() { + HalfCycles get_typer_frequency() override final { return Cycles(625*128*2); // accept a new character every two frames } - void set_typer_for_string(const char *string) { + void set_typer_for_string(const char *string) override final { std::unique_ptr mapper(new CharacterMapper()); Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); } @@ -430,7 +431,7 @@ class ConcreteMachine: m6502_.set_irq_line(interrupt_status_ & 1); } - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; // Things that directly constitute the memory map. uint8_t roms_[16][16384]; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 0df5d8be0..ce1978954 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -22,6 +22,8 @@ #include "../../Storage/Tape/Tape.hpp" #include "../../Storage/Tape/Parsers/Oric.hpp" +#include "../../ClockReceiver/ForceInline.hpp" + #include #include #include @@ -54,7 +56,7 @@ class ConcreteMachine: Memory::Fuzz(ram_, sizeof(ram_)); } - void set_rom(ROM rom, const std::vector &data) { + void set_rom(ROM rom, const std::vector &data) override final { switch(rom) { case BASIC11: basic11_rom_ = std::move(data); break; case BASIC10: basic10_rom_ = std::move(data); break; @@ -66,7 +68,7 @@ class ConcreteMachine: } } - void set_key_state(uint16_t key, bool isPressed) { + void set_key_state(uint16_t key, bool isPressed) override final { if(key == KeyNMI) { m6502_.set_nmi_line(isPressed); } else { @@ -77,20 +79,20 @@ class ConcreteMachine: } } - void clear_all_keys() { + void clear_all_keys() override final { memset(keyboard_->rows, 0, sizeof(keyboard_->rows)); } - void set_use_fast_tape_hack(bool activate) { + void set_use_fast_tape_hack(bool activate) override final { use_fast_tape_hack_ = activate; } - void set_output_device(Outputs::CRT::OutputDevice output_device) { + void set_output_device(Outputs::CRT::OutputDevice output_device) override final { video_output_->set_output_device(output_device); } // to satisfy ConfigurationTarget::Machine - void configure_as_target(const StaticAnalyser::Target &target) { + void configure_as_target(const StaticAnalyser::Target &target) override final { if(target.oric.has_microdisc) { microdisc_is_enabled_ = true; microdisc_did_change_paging_flags(µdisc_); @@ -120,7 +122,7 @@ class ConcreteMachine: insert_media(target.media); } - bool insert_media(const StaticAnalyser::Media &media) { + bool insert_media(const StaticAnalyser::Media &media) override final { if(media.tapes.size()) { via_.tape->set_tape(media.tapes.front()); } @@ -135,7 +137,7 @@ class ConcreteMachine: } // to satisfy CPU::MOS6502::BusHandler - Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { + forceinline Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { if(address > ram_top_) { if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1]; @@ -193,55 +195,55 @@ class ConcreteMachine: return Cycles(1); } - void flush() { + forceinline void flush() { update_video(); via_.flush(); } // to satisfy CRTMachine::Machine - void setup_output(float aspect_ratio) { + void setup_output(float aspect_ratio) override final { via_.ay8910.reset(new GI::AY38910::AY38910()); via_.ay8910->set_clock_rate(1000000); video_output_.reset(new VideoOutput(ram_)); if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_); } - void close_output() { + void close_output() override final { video_output_.reset(); via_.ay8910.reset(); } - std::shared_ptr get_crt() { + std::shared_ptr get_crt() override final { return video_output_->get_crt(); } - std::shared_ptr get_speaker() { + std::shared_ptr get_speaker() override final { return via_.ay8910; } - void run_for(const Cycles cycles) { + void run_for(const Cycles cycles) override final { m6502_.run_for(cycles); } // to satisfy MOS::MOS6522IRQDelegate::Delegate - void mos6522_did_change_interrupt_status(void *mos6522) { + void mos6522_did_change_interrupt_status(void *mos6522) override final { set_interrupt_line(); } // to satisfy Storage::Tape::BinaryTapePlayer::Delegate - void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) { + void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) override final { // set CB1 via_.set_control_line_input(VIA::Port::B, VIA::Line::One, !tape_player->get_input()); } // for Utility::TypeRecipient::Delegate - void set_typer_for_string(const char *string) { + void set_typer_for_string(const char *string) override final { std::unique_ptr mapper(new CharacterMapper); Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); } // for Microdisc::Delegate - void microdisc_did_change_paging_flags(class Microdisc *microdisc) { + void microdisc_did_change_paging_flags(class Microdisc *microdisc) override final { int flags = microdisc->get_paging_flags(); if(!(flags&Microdisc::PagingFlags::BASICDisable)) { ram_top_ = 0xbfff; @@ -256,12 +258,12 @@ class ConcreteMachine: } } - void wd1770_did_change_output(WD::WD1770 *wd1770) { + void wd1770_did_change_output(WD::WD1770 *wd1770) override final { set_interrupt_line(); } private: - CPU::MOS6502::Processor m6502_; + CPU::MOS6502::Processor m6502_; // RAM and ROM std::vector basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_; @@ -292,7 +294,7 @@ class ConcreteMachine: public: TapePlayer() : Storage::Tape::BinaryTapePlayer(1000000) {} - uint8_t get_next_byte(bool fast) { + inline uint8_t get_next_byte(bool fast) { return (uint8_t)parser_.get_next_byte(get_tape(), fast); } diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 6758c6853..fab9c8986 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -12,6 +12,8 @@ #include "../../Storage/Tape/Tape.hpp" #include "../../Storage/Tape/Parsers/ZX8081.hpp" +#include "../../ClockReceiver/ForceInline.hpp" + #include "../MemoryFuzzer.hpp" #include "../Typer.hpp" @@ -45,7 +47,7 @@ class ConcreteMachine: clear_all_keys(); } - HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { + forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { HalfCycles previous_counter = horizontal_counter_; horizontal_counter_ += cycle.length; @@ -204,31 +206,31 @@ class ConcreteMachine: return HalfCycles(0); } - void flush() { + forceinline void flush() { video_->flush(); } - void setup_output(float aspect_ratio) { + void setup_output(float aspect_ratio) override final { video_.reset(new Video); } - void close_output() { + void close_output() override final { video_.reset(); } - std::shared_ptr get_crt() { + std::shared_ptr get_crt() override final { return video_->get_crt(); } - std::shared_ptr get_speaker() { + std::shared_ptr get_speaker() override final { return nullptr; } - void run_for(const Cycles cycles) { + void run_for(const Cycles cycles) override final { z80_.run_for(cycles); } - void configure_as_target(const StaticAnalyser::Target &target) { + void configure_as_target(const StaticAnalyser::Target &target) override final { is_zx81_ = target.zx8081.isZX81; if(is_zx81_) { rom_ = zx81_rom_; @@ -275,7 +277,7 @@ class ConcreteMachine: insert_media(target.media); } - bool insert_media(const StaticAnalyser::Media &media) { + bool insert_media(const StaticAnalyser::Media &media) override final { if(!media.tapes.empty()) { tape_player_.set_tape(media.tapes.front()); } @@ -283,12 +285,12 @@ class ConcreteMachine: return !media.tapes.empty(); } - void set_typer_for_string(const char *string) { + void set_typer_for_string(const char *string) override final { std::unique_ptr mapper(new CharacterMapper(is_zx81_)); Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); } - void set_rom(ROMType type, std::vector data) { + void set_rom(ROMType type, std::vector data) override final { switch(type) { case ZX80: zx80_rom_ = data; break; case ZX81: zx81_rom_ = data; break; @@ -297,37 +299,37 @@ class ConcreteMachine: #pragma mark - Keyboard - void set_key_state(uint16_t key, bool isPressed) { + void set_key_state(uint16_t key, bool isPressed) override final { if(isPressed) key_states_[key >> 8] &= (uint8_t)(~key); else key_states_[key >> 8] |= (uint8_t)key; } - void clear_all_keys() { + void clear_all_keys() override final { memset(key_states_, 0xff, 8); } #pragma mark - Tape control - void set_use_fast_tape_hack(bool activate) { + void set_use_fast_tape_hack(bool activate) override final { use_fast_tape_hack_ = activate; } - void set_use_automatic_tape_motor_control(bool enabled) { + void set_use_automatic_tape_motor_control(bool enabled) override final { use_automatic_tape_motor_control_ = enabled; if(!enabled) { tape_player_.set_motor_control(false); } } - void set_tape_is_playing(bool is_playing) { + void set_tape_is_playing(bool is_playing) override final { tape_player_.set_motor_control(is_playing); } #pragma mark - Typer timing - HalfCycles get_typer_delay() { return Cycles(7000000); } - HalfCycles get_typer_frequency() { return Cycles(390000); } + HalfCycles get_typer_delay() override final { return Cycles(7000000); } + HalfCycles get_typer_frequency() override final { return Cycles(390000); } private: CPU::Z80::Processor z80_; @@ -367,17 +369,17 @@ class ConcreteMachine: #pragma mark - Video - void set_vsync(bool sync) { + inline void set_vsync(bool sync) { vsync_ = sync; update_sync(); } - void set_hsync(bool sync) { + inline void set_hsync(bool sync) { hsync_ = sync; update_sync(); } - void update_sync() { + inline void update_sync() { video_->set_sync(vsync_ || hsync_); } }; diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h index 66a1d0d7e..24f12a975 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h @@ -31,8 +31,6 @@ extern const uint8_t CSTestMachine6502JamOpcode; - (void)setValue:(uint16_t)value forRegister:(CSTestMachine6502Register)reg; - (uint16_t)valueForRegister:(CSTestMachine6502Register)reg; -- (void)returnFromSubroutine; - @property (nonatomic, readonly) BOOL isJammed; @property (nonatomic, readonly) uint32_t timestamp; @property (nonatomic, assign) BOOL irqLine; diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm index 50aff4217..b7295e7d0 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm @@ -97,10 +97,6 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg) #pragma mark - Actions -- (void)returnFromSubroutine { - _processor->return_from_subroutine(); -} - - (void)runForNumberOfCycles:(int)cycles { _processor->run_for(Cycles(cycles)); } diff --git a/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm b/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm index 711a8691e..2d66ebb4a 100644 --- a/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm +++ b/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm @@ -18,33 +18,29 @@ #pragma mark - Prebuilt tracks -- (std::shared_ptr)togglingTrack -{ +- (std::shared_ptr)togglingTrack { Storage::Disk::PCMSegment segment; segment.data = { 0xff, 0xff, 0xff, 0xff }; segment.number_of_bits = 32; return std::shared_ptr(new Storage::Disk::PCMTrack(segment)); } -- (std::shared_ptr)patchableTogglingTrack -{ +- (std::shared_ptr)patchableTogglingTrack { std::shared_ptr track = self.togglingTrack; return std::shared_ptr(new Storage::Disk::PCMPatchedTrack(track)); } -- (std::shared_ptr)fourSegmentPatchedTrack -{ +- (std::shared_ptr)fourSegmentPatchedTrack { std::shared_ptr patchableTrack = self.patchableTogglingTrack; Storage::Disk::PCMPatchedTrack *patchable = static_cast(patchableTrack.get()); - for(int c = 0; c < 4; c++) - { + for(int c = 0; c < 4; c++) { Storage::Disk::PCMSegment segment; segment.data = {0xff}; segment.number_of_bits = 8; segment.length_of_a_bit.length = 1; segment.length_of_a_bit.clock_rate = 32; - patchable->add_segment(Storage::Time(c, 4), segment); + patchable->add_segment(Storage::Time(c, 4), segment, false); } return patchableTrack; @@ -52,41 +48,34 @@ #pragma mark - -- (std::vector)eventsFromTrack:(std::shared_ptr)track -{ +- (std::vector)eventsFromTrack:(std::shared_ptr)track { std::vector events; - while(1) - { + while(1) { events.push_back(track->get_next_event()); if(events.back().type == Storage::Disk::Track::Event::IndexHole) break; } return events; } -- (Storage::Time)timeForEvents:(const std::vector &)events -{ +- (Storage::Time)timeForEvents:(const std::vector &)events { Storage::Time result(0); - for(auto event : events) - { + for(auto event : events) { result += event.length; } return result; } -- (void)patchTrack:(std::shared_ptr)track withSegment:(Storage::Disk::PCMSegment)segment atTime:(Storage::Time)time -{ +- (void)patchTrack:(std::shared_ptr)track withSegment:(Storage::Disk::PCMSegment)segment atTime:(Storage::Time)time { Storage::Disk::PCMPatchedTrack *patchable = static_cast(track.get()); - patchable->add_segment(time, segment); + patchable->add_segment(time, segment, false); } #pragma mark - Repeating Asserts -- (void)assertOneThirtyTwosForTrack:(std::shared_ptr)track -{ +- (void)assertOneThirtyTwosForTrack:(std::shared_ptr)track { // Confirm that there are now flux transitions (just the first five will do) // located 1/32nd of a rotation apart. - for(int c = 0; c < 5; c++) - { + for(int c = 0; c < 5; c++) { Storage::Disk::Track::Event event = track->get_next_event(); XCTAssert( event.length == (c ? Storage::Time(1, 32) : Storage::Time(1, 64)), @@ -94,8 +83,7 @@ } } -- (void)assertEvents:(const std::vector &)events hasEntries:(size_t)numberOfEntries withEntry:(size_t)entry ofLength:(Storage::Time)time -{ +- (void)assertEvents:(const std::vector &)events hasEntries:(size_t)numberOfEntries withEntry:(size_t)entry ofLength:(Storage::Time)time { XCTAssert(events.size() == numberOfEntries, @"Should be %zu total events", numberOfEntries); XCTAssert(events[entry].length == time, @"Event %zu should have been %d/%d long, was %d/%d", entry, time.length, time.clock_rate, events[entry].length.length, events[entry].length.clock_rate); @@ -106,20 +94,17 @@ #pragma mark - Unpatched tracks -- (void)testUnpatchedRawTrack -{ +- (void)testUnpatchedRawTrack { [self assertOneThirtyTwosForTrack:self.togglingTrack]; } -- (void)testUnpatchedTrack -{ +- (void)testUnpatchedTrack { [self assertOneThirtyTwosForTrack:self.patchableTogglingTrack]; } #pragma mark - Insertions affecting one existing segment -- (void)testSingleSplice -{ +- (void)testSingleSplice { std::shared_ptr patchableTrack = self.patchableTogglingTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 32), 1, {0xff}) atTime:Storage::Time(3, 128)]; @@ -133,16 +118,14 @@ XCTAssert(total_length == Storage::Time(1), @"Total track length should still be 1"); } -- (void)testLeftReplace -{ +- (void)testLeftReplace { std::shared_ptr patchableTrack = self.patchableTogglingTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(0)]; [self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:0 ofLength:Storage::Time(33, 64)]; } -- (void)testRightReplace -{ +- (void)testRightReplace { std::shared_ptr patchableTrack = self.patchableTogglingTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(1, 2)]; @@ -151,30 +134,26 @@ #pragma mark - Insertions affecting three existing segments -- (void)testMultiSegmentTrack -{ +- (void)testMultiSegmentTrack { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:33 withEntry:4 ofLength:Storage::Time(1, 32)]; } -- (void)testMultiTrimBothSideReplace -{ +- (void)testMultiTrimBothSideReplace { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(1, 8)]; [self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:4 ofLength:Storage::Time(17, 32)]; } -- (void)testMultiTrimRightReplace -{ +- (void)testMultiTrimRightReplace { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 8)]; [self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:4 ofLength:Storage::Time(13, 32)]; } -- (void)testMultiTrimLeftReplace -{ +- (void)testMultiTrimLeftReplace { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 4)]; @@ -183,24 +162,21 @@ #pragma mark - Insertions affecting two existing segments -- (void)testTwoSegmentOverlap -{ +- (void)testTwoSegmentOverlap { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 32), 8, {0x00}) atTime:Storage::Time(1, 8)]; [self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:25 withEntry:4 ofLength:Storage::Time(9, 32)]; } -- (void)testTwoSegmentRightReplace -{ +- (void)testTwoSegmentRightReplace { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 8)]; [self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:4 ofLength:Storage::Time(13, 32)]; } -- (void)testTwoSegmentLeftReplace -{ +- (void)testTwoSegmentLeftReplace { std::shared_ptr patchableTrack = self.fourSegmentPatchedTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(0)]; @@ -209,8 +185,7 @@ #pragma mark - Wrapping segment -- (void)testWrappingSegment -{ +- (void)testWrappingSegment { std::shared_ptr patchableTrack = self.patchableTogglingTrack; [self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(5, 2), 1, {0x00}) atTime:Storage::Time(0)]; diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index e1f9706e2..6bdf0951c 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -9,6 +9,7 @@ #ifndef MOS6502_cpp #define MOS6502_cpp +#include #include #include @@ -131,12 +132,8 @@ class BusHandler { @discussion Subclasses should implement @c perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) in order to provide the bus on which the 6502 operates and @c flush(), which is called upon completion of a continuous run of cycles to allow a subclass to bring any on-demand activities up to date. - - Additional functionality can be provided by the host machine by providing a jam handler and inserting jam opcodes where appropriate; - that will cause call outs when the program counter reaches those addresses. @c return_from_subroutine can be used to exit from a - jammed state. */ -template class Processor: public ProcessorBase { +template class Processor: public ProcessorBase { private: T &bus_handler_; const MicroOp *scheduled_program_counter_; @@ -355,11 +352,11 @@ template class Processor: public ProcessorBase { while(number_of_cycles > Cycles(0)) { - while (ready_is_active_ && number_of_cycles > Cycles(0)) { + while(uses_ready_line && ready_is_active_ && number_of_cycles > Cycles(0)) { number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue); } - if(!ready_is_active_) { + if(!uses_ready_line || !ready_is_active_) { if(nextBusOperation != BusOperation::None) { bus_access(); } @@ -822,7 +819,7 @@ template class Processor: public ProcessorBase { continue; } - if(ready_line_is_enabled_ && isReadOperation(nextBusOperation)) { + if(uses_ready_line && ready_line_is_enabled_ && isReadOperation(nextBusOperation)) { ready_is_active_ = true; break; } @@ -883,27 +880,13 @@ template class Processor: public ProcessorBase { } } - /*! - Interrupts current execution flow to perform an RTS and, if the 6502 is currently jammed, - to unjam it. - */ - void return_from_subroutine() { - s_++; - bus_handler_.perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++; - bus_handler_.perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high); - pc_.full++; - - if(is_jammed_) { - scheduled_program_counter_ = nullptr; - } - } - /*! Sets the current level of the RDY line. @param active @c true if the line is logically active; @c false otherwise. */ inline void set_ready_line(bool active) { + assert(uses_ready_line); if(active) { ready_line_is_enabled_ = true; } else { diff --git a/Processors/6502/6502AllRAM.cpp b/Processors/6502/6502AllRAM.cpp index 1efb36ab3..bbb14830b 100644 --- a/Processors/6502/6502AllRAM.cpp +++ b/Processors/6502/6502AllRAM.cpp @@ -14,10 +14,11 @@ using namespace CPU::MOS6502; namespace { -class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor { +class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler { public: - ConcreteAllRAMProcessor() { - set_power_on(false); + ConcreteAllRAMProcessor() : + mos6502_(*this) { + mos6502_.set_power_on(false); } inline Cycles perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) { @@ -37,32 +38,31 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor::run_for(cycles); + mos6502_.run_for(cycles); } bool is_jammed() { - return Processor::is_jammed(); + return mos6502_.is_jammed(); } void set_irq_line(bool value) { - Processor::set_irq_line(value); + mos6502_.set_irq_line(value); } void set_nmi_line(bool value) { - Processor::set_nmi_line(value); - } - - void return_from_subroutine() { - Processor::return_from_subroutine(); + mos6502_.set_nmi_line(value); } uint16_t get_value_of_register(Register r) { - return Processor::get_value_of_register(r); + return mos6502_.get_value_of_register(r); } void set_value_of_register(Register r, uint16_t value) { - Processor::set_value_of_register(r, value); + mos6502_.set_value_of_register(r, value); } + + private: + CPU::MOS6502::Processor mos6502_; }; } diff --git a/Processors/6502/6502AllRAM.hpp b/Processors/6502/6502AllRAM.hpp index 7559d7092..bfee139f6 100644 --- a/Processors/6502/6502AllRAM.hpp +++ b/Processors/6502/6502AllRAM.hpp @@ -26,7 +26,6 @@ class AllRAMProcessor: virtual bool is_jammed() = 0; virtual void set_irq_line(bool value) = 0; virtual void set_nmi_line(bool value) = 0; - virtual void return_from_subroutine() = 0; virtual uint16_t get_value_of_register(Register r) = 0; virtual void set_value_of_register(Register r, uint16_t value) = 0; diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index 8ab6a7aee..75a4215af 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -96,7 +96,7 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler { } private: - CPU::Z80::Processor z80_; + CPU::Z80::Processor z80_; }; }