From 42b5b66305b96b89f2bf4fa92c4517076c7b313c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 16 Aug 2017 11:56:52 -0400 Subject: [PATCH] Remove the 6502's use of runtime polymorphism in favour of ordinary templating. --- Machines/Atari2600/Atari2600.cpp | 30 +++++++-------- Machines/Atari2600/Cartridges/Cartridge.hpp | 14 ++++--- .../Cartridges/CartridgeActivisionStack.hpp | 2 + .../Cartridges/CartridgeAtari16k.hpp | 2 + .../Cartridges/CartridgeAtari32k.hpp | 2 + .../Atari2600/Cartridges/CartridgeAtari8k.hpp | 2 + .../Cartridges/CartridgeCBSRAMPlus.hpp | 2 + .../Cartridges/CartridgeCommaVid.hpp | 2 + .../Cartridges/CartridgeMNetwork.hpp | 2 + .../Atari2600/Cartridges/CartridgeMegaBoy.hpp | 2 + .../Cartridges/CartridgeParkerBros.hpp | 2 + .../Cartridges/CartridgePitfall2.hpp | 2 + .../Cartridges/CartridgeTigervision.hpp | 2 + .../Atari2600/Cartridges/CartridgeUnpaged.hpp | 2 + Machines/Commodore/1540/C1540.cpp | 9 +++-- Machines/Commodore/1540/C1540.hpp | 4 +- Machines/Commodore/Vic-20/Vic20.cpp | 17 ++++++--- Machines/Commodore/Vic-20/Vic20.hpp | 6 ++- Machines/Electron/Electron.cpp | 19 ++++++---- Machines/Electron/Electron.hpp | 6 ++- Machines/Oric/Oric.cpp | 11 +++--- Machines/Oric/Oric.hpp | 4 +- Processors/6502/6502.hpp | 37 +++++++++++-------- 23 files changed, 117 insertions(+), 64 deletions(-) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index e3d732b9e..0d705ed45 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -83,35 +83,35 @@ void Machine::set_switch_is_enabled(Atari2600Switch input, bool state) { void Machine::configure_as_target(const StaticAnalyser::Target &target) { const std::vector &rom = target.cartridges.front()->get_segments().front().data; switch(target.atari.paging_model) { - case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new CartridgeActivisionStack(rom)); break; - case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new CartridgeCBSRAMPlus(rom)); break; - case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new CartridgeCommaVid(rom)); break; - case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new CartridgeMegaBoy(rom)); break; - case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new CartridgeMNetwork(rom)); break; - case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new CartridgeUnpaged(rom)); break; - case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new CartridgeParkerBros(rom)); break; - case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new CartridgePitfall2(rom)); break; - case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new CartridgeTigervision(rom)); break; + case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::CartridgeActivisionStack(rom)); break; + case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new Cartridge::CartridgeCBSRAMPlus(rom)); break; + case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new Cartridge::CartridgeCommaVid(rom)); break; + case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new Cartridge::CartridgeMegaBoy(rom)); break; + case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new Cartridge::CartridgeMNetwork(rom)); break; + case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new Cartridge::CartridgeUnpaged(rom)); break; + case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new Cartridge::CartridgeParkerBros(rom)); break; + case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new Cartridge::CartridgePitfall2(rom)); break; + case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new Cartridge::CartridgeTigervision(rom)); break; case StaticAnalyser::Atari2600PagingModel::Atari8k: if(target.atari.uses_superchip) { - bus_.reset(new CartridgeAtari8kSuperChip(rom)); + bus_.reset(new Cartridge::CartridgeAtari8kSuperChip(rom)); } else { - bus_.reset(new CartridgeAtari8k(rom)); + bus_.reset(new Cartridge::CartridgeAtari8k(rom)); } break; case StaticAnalyser::Atari2600PagingModel::Atari16k: if(target.atari.uses_superchip) { - bus_.reset(new CartridgeAtari16kSuperChip(rom)); + bus_.reset(new Cartridge::CartridgeAtari16kSuperChip(rom)); } else { - bus_.reset(new CartridgeAtari16k(rom)); + bus_.reset(new Cartridge::CartridgeAtari16k(rom)); } break; case StaticAnalyser::Atari2600PagingModel::Atari32k: if(target.atari.uses_superchip) { - bus_.reset(new CartridgeAtari32kSuperChip(rom)); + bus_.reset(new Cartridge::CartridgeAtari32kSuperChip(rom)); } else { - bus_.reset(new CartridgeAtari32k(rom)); + bus_.reset(new Cartridge::CartridgeAtari32k(rom)); } break; } diff --git a/Machines/Atari2600/Cartridges/Cartridge.hpp b/Machines/Atari2600/Cartridges/Cartridge.hpp index 638964fe8..059ae3915 100644 --- a/Machines/Atari2600/Cartridges/Cartridge.hpp +++ b/Machines/Atari2600/Cartridges/Cartridge.hpp @@ -13,17 +13,19 @@ #include "../Bus.hpp" namespace Atari2600 { +namespace Cartridge { template class Cartridge: - public CPU::MOS6502::Processor>, + public CPU::MOS6502::BusHandler, public Bus { public: Cartridge(const std::vector &rom) : + m6502_(*this), rom_(rom) {} - void run_for(const Cycles cycles) { CPU::MOS6502::Processor>::run_for(cycles); } - void set_reset_line(bool state) { CPU::MOS6502::Processor>::set_reset_line(state); } + void run_for(const Cycles cycles) { m6502_.run_for(cycles); } + void set_reset_line(bool state) { m6502_.set_reset_line(state); } void advance_cycles(int cycles) {} // to satisfy CPU::MOS6502::Processor @@ -91,7 +93,7 @@ template class Cartridge: case 0x00: update_video(); tia_->set_sync(*value & 0x02); break; case 0x01: update_video(); tia_->set_blank(*value & 0x02); break; - case 0x02: CPU::MOS6502::Processor>::set_ready_line(true); break; + case 0x02: m6502_.set_ready_line(true); break; case 0x03: update_video(); tia_->reset_horizontal_counter(); break; // TODO: audio will now be out of synchronisation — fix @@ -156,7 +158,7 @@ template class Cartridge: } } - if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) CPU::MOS6502::Processor>::set_ready_line(false); + if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) m6502_.set_ready_line(false); return Cycles(cycles_run_for / 3); } @@ -168,9 +170,11 @@ template class Cartridge: } protected: + CPU::MOS6502::Processor> m6502_; std::vector rom_; }; +} } #endif /* Atari2600_Cartridge_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeActivisionStack.hpp b/Machines/Atari2600/Cartridges/CartridgeActivisionStack.hpp index 6f26074f9..b79807470 100644 --- a/Machines/Atari2600/Cartridges/CartridgeActivisionStack.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeActivisionStack.hpp @@ -10,6 +10,7 @@ #define Atari2600_CartridgeActivisionStack_hpp namespace Atari2600 { +namespace Cartridge { class CartridgeActivisionStack: public Cartridge { public: @@ -45,6 +46,7 @@ class CartridgeActivisionStack: public Cartridge { uint8_t last_opcode_; }; +} } #endif /* Atari2600_CartridgeActivisionStack_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeAtari16k.hpp b/Machines/Atari2600/Cartridges/CartridgeAtari16k.hpp index 383fd449d..c109d76e4 100644 --- a/Machines/Atari2600/Cartridges/CartridgeAtari16k.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeAtari16k.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeAtari16k: public Cartridge { public: @@ -61,6 +62,7 @@ class CartridgeAtari16kSuperChip: public Cartridge { uint8_t ram_[128]; }; +} } #endif /* Atari2600_CartridgeAtari16k_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeAtari32k.hpp b/Machines/Atari2600/Cartridges/CartridgeAtari32k.hpp index 6d3a2cab7..3ae85f052 100644 --- a/Machines/Atari2600/Cartridges/CartridgeAtari32k.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeAtari32k.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeAtari32k: public Cartridge { public: @@ -61,6 +62,7 @@ class CartridgeAtari32kSuperChip: public Cartridge { uint8_t ram_[128]; }; +} } #endif /* Atari2600_CartridgeAtari32k_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeAtari8k.hpp b/Machines/Atari2600/Cartridges/CartridgeAtari8k.hpp index e753277ae..04e489c91 100644 --- a/Machines/Atari2600/Cartridges/CartridgeAtari8k.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeAtari8k.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeAtari8k: public Cartridge { public: @@ -63,6 +64,7 @@ class CartridgeAtari8kSuperChip: public Cartridge { uint8_t ram_[128]; }; +} } #endif /* Atari2600_CartridgeAtari8k_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeCBSRAMPlus.hpp b/Machines/Atari2600/Cartridges/CartridgeCBSRAMPlus.hpp index 88b1277f4..ffde1af7b 100644 --- a/Machines/Atari2600/Cartridges/CartridgeCBSRAMPlus.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeCBSRAMPlus.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeCBSRAMPlus: public Cartridge { public: @@ -39,6 +40,7 @@ class CartridgeCBSRAMPlus: public Cartridge { uint8_t ram_[256]; }; +} } #endif /* Atari2600_CartridgeCBSRAMPlus_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeCommaVid.hpp b/Machines/Atari2600/Cartridges/CartridgeCommaVid.hpp index d547f8da2..26c8e89ce 100644 --- a/Machines/Atari2600/Cartridges/CartridgeCommaVid.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeCommaVid.hpp @@ -10,6 +10,7 @@ #define Atari2600_CartridgeCommaVid_hpp namespace Atari2600 { +namespace Cartridge { class CartridgeCommaVid: public Cartridge { public: @@ -37,6 +38,7 @@ class CartridgeCommaVid: public Cartridge { uint8_t ram_[1024]; }; +} } #endif /* Atari2600_CartridgeCommaVid_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeMNetwork.hpp b/Machines/Atari2600/Cartridges/CartridgeMNetwork.hpp index 0d3305847..b759e70db 100644 --- a/Machines/Atari2600/Cartridges/CartridgeMNetwork.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeMNetwork.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeMNetwork: public Cartridge { public: @@ -63,6 +64,7 @@ class CartridgeMNetwork: public Cartridge { uint8_t low_ram_[1024], high_ram_[1024]; }; +} } #endif /* Atari2600_CartridgeMNetwork_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeMegaBoy.hpp b/Machines/Atari2600/Cartridges/CartridgeMegaBoy.hpp index 03997d4fc..1d2a09e73 100644 --- a/Machines/Atari2600/Cartridges/CartridgeMegaBoy.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeMegaBoy.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeMegaBoy: public Cartridge { public: @@ -40,6 +41,7 @@ class CartridgeMegaBoy: public Cartridge { uint8_t current_page_; }; +} } #endif /* CartridgeMegaBoy_h */ diff --git a/Machines/Atari2600/Cartridges/CartridgeParkerBros.hpp b/Machines/Atari2600/Cartridges/CartridgeParkerBros.hpp index 184a75cc2..4138991ba 100644 --- a/Machines/Atari2600/Cartridges/CartridgeParkerBros.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeParkerBros.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeParkerBros: public Cartridge { public: @@ -41,6 +42,7 @@ class CartridgeParkerBros: public Cartridge { uint8_t *rom_ptr_[4]; }; +} } #endif /* Atari2600_CartridgeParkerBros_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp b/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp index 7921a918a..c77239113 100644 --- a/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp +++ b/Machines/Atari2600/Cartridges/CartridgePitfall2.hpp @@ -10,6 +10,7 @@ #define Atari2600_CartridgePitfall2_hpp namespace Atari2600 { +namespace Cartridge { class CartridgePitfall2: public Cartridge { public: @@ -128,6 +129,7 @@ class CartridgePitfall2: public Cartridge { Cycles cycles_since_audio_update_; }; +} } #endif /* Atari2600_CartridgePitfall2_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeTigervision.hpp b/Machines/Atari2600/Cartridges/CartridgeTigervision.hpp index 12b12abef..1abcedac5 100644 --- a/Machines/Atari2600/Cartridges/CartridgeTigervision.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeTigervision.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeTigervision: public Cartridge { public: @@ -35,6 +36,7 @@ class CartridgeTigervision: public Cartridge { uint8_t *rom_ptr_[2]; }; +} } #endif /* Atari2600_CartridgeTigervision_hpp */ diff --git a/Machines/Atari2600/Cartridges/CartridgeUnpaged.hpp b/Machines/Atari2600/Cartridges/CartridgeUnpaged.hpp index 542c458c8..cc09b5a53 100644 --- a/Machines/Atari2600/Cartridges/CartridgeUnpaged.hpp +++ b/Machines/Atari2600/Cartridges/CartridgeUnpaged.hpp @@ -12,6 +12,7 @@ #include "Cartridge.hpp" namespace Atari2600 { +namespace Cartridge { class CartridgeUnpaged: public Cartridge { public: @@ -25,6 +26,7 @@ class CartridgeUnpaged: public Cartridge { } }; +} } #endif /* Atari2600_CartridgeUnpaged_hpp */ diff --git a/Machines/Commodore/1540/C1540.cpp b/Machines/Commodore/1540/C1540.cpp index e996b73c4..fe74bd13b 100644 --- a/Machines/Commodore/1540/C1540.cpp +++ b/Machines/Commodore/1540/C1540.cpp @@ -13,6 +13,7 @@ using namespace Commodore::C1540; Machine::Machine() : + m6502_(*this), shift_register_(0), Storage::Disk::Controller(1000000, 4, 300), serial_port_(new SerialPort), @@ -80,7 +81,7 @@ void Machine::set_disk(std::shared_ptr disk) { } void Machine::run_for(const Cycles cycles) { - CPU::MOS6502::Processor::run_for(cycles); + m6502_.run_for(cycles); set_motor_on(drive_VIA_.get_motor_enabled()); if(drive_VIA_.get_motor_enabled()) // TODO: motor speed up/down Storage::Disk::Controller::run_for(cycles); @@ -90,7 +91,7 @@ void Machine::run_for(const Cycles cycles) { void Machine::mos6522_did_change_interrupt_status(void *mos6522) { // both VIAs are connected to the IRQ line - set_irq_line(serial_port_VIA_->get_interrupt_line() || drive_VIA_.get_interrupt_line()); + m6502_.set_irq_line(serial_port_VIA_->get_interrupt_line() || drive_VIA_.get_interrupt_line()); } #pragma mark - Disk drive @@ -108,10 +109,10 @@ void Machine::process_input_bit(int value, unsigned int cycles_since_index_hole) drive_VIA_.set_data_input((uint8_t)shift_register_); bit_window_offset_ = 0; if(drive_VIA_.get_should_set_overflow()) { - set_overflow_line(true); + m6502_.set_overflow_line(true); } } - else set_overflow_line(false); + else m6502_.set_overflow_line(false); } // the 1540 does not recognise index holes diff --git a/Machines/Commodore/1540/C1540.hpp b/Machines/Commodore/1540/C1540.hpp index 4fdf87322..59b1ba745 100644 --- a/Machines/Commodore/1540/C1540.hpp +++ b/Machines/Commodore/1540/C1540.hpp @@ -120,7 +120,7 @@ class SerialPort : public ::Commodore::Serial::Port { Provides an emulation of the C1540. */ class Machine: - public CPU::MOS6502::Processor, + public CPU::MOS6502::BusHandler, public MOS::MOS6522IRQDelegate::Delegate, public DriveVIA::Delegate, public Storage::Disk::Controller { @@ -152,6 +152,8 @@ class Machine: void drive_via_did_set_data_density(void *driveVIA, int density); private: + 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 2c748af0e..794310ba2 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -17,6 +17,7 @@ using namespace Commodore::Vic20; Machine::Machine() : + m6502_(*this), rom_(nullptr), is_running_at_zero_cost_(false), tape_(new Storage::Tape::BinaryTapePlayer(1022727)), @@ -138,7 +139,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint *value = 0x0c; // i.e. NOP abs } else if(address == 0xf90b) { - uint8_t x = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X); + uint8_t x = (uint8_t)m6502_.get_value_of_register(CPU::MOS6502::Register::X); if(x == 0xe) { Storage::Tape::Commodore::Parser parser; std::unique_ptr data = parser.get_next_data(tape_->get_tape()); @@ -159,13 +160,13 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint // set tape status, carry and flag user_basic_memory_[0x90] |= 0x40; - uint8_t flags = (uint8_t)get_value_of_register(CPU::MOS6502::Register::Flags); + uint8_t flags = (uint8_t)m6502_.get_value_of_register(CPU::MOS6502::Register::Flags); flags &= ~(uint8_t)(CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Interrupt); - set_value_of_register(CPU::MOS6502::Register::Flags, flags); + m6502_.set_value_of_register(CPU::MOS6502::Register::Flags, flags); // to ensure that execution proceeds to 0xfccf, pretend a NOP was here and // ensure that the PC leaps to 0xfccf - set_value_of_register(CPU::MOS6502::Register::ProgramCounter, 0xfccf); + m6502_.set_value_of_register(CPU::MOS6502::Register::ProgramCounter, 0xfccf); *value = 0xea; // i.e. NOP implied } } @@ -194,11 +195,15 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint return Cycles(1); } +void Machine::run_for(const Cycles cycles) { + m6502_.run_for(cycles); +} + #pragma mark - 6522 delegate void Machine::mos6522_did_change_interrupt_status(void *mos6522) { - set_nmi_line(user_port_via_->get_interrupt_line()); - set_irq_line(keyboard_via_->get_interrupt_line()); + m6502_.set_nmi_line(user_port_via_->get_interrupt_line()); + m6502_.set_irq_line(keyboard_via_->get_interrupt_line()); } #pragma mark - Setup diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index 6e459a976..957ed58da 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -139,7 +139,7 @@ class Vic6560: public MOS::MOS6560 { }; class Machine: - public CPU::MOS6502::Processor, + public CPU::MOS6502::BusHandler, public CRTMachine::Machine, public MOS::MOS6522IRQDelegate::Delegate, public Utility::TypeRecipient, @@ -174,7 +174,7 @@ class Machine: virtual void close_output(); virtual std::shared_ptr get_crt() { return mos6560_->get_crt(); } virtual std::shared_ptr get_speaker() { return mos6560_->get_speaker(); } - virtual void run_for(const Cycles cycles) { CPU::MOS6502::Processor::run_for(cycles); } + virtual void run_for(const Cycles cycles); // to satisfy MOS::MOS6522::Delegate virtual void mos6522_did_change_interrupt_status(void *mos6522); @@ -187,6 +187,8 @@ class Machine: virtual void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape); private: + CPU::MOS6502::Processor m6502_; + uint8_t character_rom_[0x1000]; uint8_t basic_rom_[0x2000]; uint8_t kernel_rom_[0x2000]; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index a3f578b63..adf3c4571 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -15,6 +15,7 @@ using namespace Electron; #pragma mark - Lifecycle Machine::Machine() : + m6502_(*this), interrupt_control_(0), interrupt_status_(Interrupt::PowerOnReset | Interrupt::TransmitDataEmpty | 0x80), cycles_since_audio_update_(0), @@ -61,7 +62,7 @@ void Machine::clear_all_keys() { void Machine::set_key_state(uint16_t key, bool isPressed) { if(key == KeyBreak) { - set_reset_line(isPressed); + m6502_.set_reset_line(isPressed); } else { if(isPressed) key_states_[key >> 4] |= key&0xf; @@ -269,7 +270,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint // allow the PC read to return an RTS. ) ) { - uint8_t service_call = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X); + uint8_t service_call = (uint8_t)m6502_.get_value_of_register(CPU::MOS6502::Register::X); if(address == 0xf0a8) { if(!ram_[0x247] && service_call == 14) { tape_.set_delegate(nullptr); @@ -291,8 +292,8 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint interrupt_status_ |= tape_.get_interrupt_status(); fast_load_is_in_data_ = true; - set_value_of_register(CPU::MOS6502::Register::A, 0); - set_value_of_register(CPU::MOS6502::Register::Y, tape_.get_data_register()); + m6502_.set_value_of_register(CPU::MOS6502::Register::A, 0); + m6502_.set_value_of_register(CPU::MOS6502::Register::Y, tape_.get_data_register()); *value = 0x60; // 0x60 is RTS } else *value = os_[address & 16383]; @@ -340,7 +341,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint shift_restart_counter_ -= cycles; if(shift_restart_counter_ <= 0) { shift_restart_counter_ = 0; - set_power_on(true); + m6502_.set_power_on(true); set_key_state(KeyShift, true); is_holding_shift_ = true; } @@ -355,6 +356,10 @@ void Machine::flush() { speaker_->flush(); } +void Machine::run_for(const Cycles cycles) { + m6502_.run_for(cycles); +} + #pragma mark - Deferred scheduling inline void Machine::update_display() { @@ -393,7 +398,7 @@ inline void Machine::evaluate_interrupts() { } else { interrupt_status_ &= ~1; } - set_irq_line(interrupt_status_ & 1); + m6502_.set_irq_line(interrupt_status_ & 1); } #pragma mark - Tape::Delegate @@ -406,7 +411,7 @@ void Machine::tape_did_change_interrupt_status(Tape *tape) { #pragma mark - Typer timing HalfCycles Electron::Machine::get_typer_delay() { - return get_is_resetting() ? Cycles(625*25*128) : Cycles(0); // wait one second if resetting + return m6502_.get_is_resetting() ? Cycles(625*25*128) : Cycles(0); // wait one second if resetting } HalfCycles Electron::Machine::get_typer_frequency() { diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index 8ce40b044..b99398b5f 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -67,7 +67,7 @@ enum Key: uint16_t { Acorn Electron. */ class Machine: - public CPU::MOS6502::Processor, + public CPU::MOS6502::BusHandler, public CRTMachine::Machine, public Tape::Delegate, public Utility::TypeRecipient, @@ -95,7 +95,7 @@ class Machine: virtual void close_output(); virtual std::shared_ptr get_crt(); virtual std::shared_ptr get_speaker(); - virtual void run_for(const Cycles cycles) { CPU::MOS6502::Processor::run_for(cycles); } + virtual void run_for(const Cycles cycles); // to satisfy Tape::Delegate virtual void tape_did_change_interrupt_status(Tape *tape); @@ -114,6 +114,8 @@ class Machine: inline void clear_interrupt(Interrupt interrupt); inline void evaluate_interrupts(); + CPU::MOS6502::Processor m6502_; + // Things that directly constitute the memory map. uint8_t roms_[16][16384]; bool rom_write_masks_[16]; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 11038a440..bf90d3fd1 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -16,6 +16,7 @@ using namespace Oric; Machine::Machine() : + m6502_(*this), use_fast_tape_hack_(false), typer_delay_(2500000), keyboard_read_count_(0), @@ -94,8 +95,8 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint // E6C9 = read byte: return byte in A if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) { uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]); - set_value_of_register(CPU::MOS6502::A, next_byte); - set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero); + m6502_.set_value_of_register(CPU::MOS6502::A, next_byte); + m6502_.set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero); *value = 0x60; // i.e. RTS } } else { @@ -171,7 +172,7 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522) { void Machine::set_key_state(uint16_t key, bool isPressed) { if(key == KeyNMI) { - set_nmi_line(isPressed); + m6502_.set_nmi_line(isPressed); } else { if(isPressed) keyboard_->rows[key >> 8] |= (key & 0xff); @@ -206,7 +207,7 @@ std::shared_ptr Machine::get_speaker() { } void Machine::run_for(const Cycles cycles) { - CPU::MOS6502::Processor::run_for(cycles); + m6502_.run_for(cycles); } #pragma mark - The 6522 @@ -287,7 +288,7 @@ void Machine::wd1770_did_change_output(WD::WD1770 *wd1770) { } void Machine::set_interrupt_line() { - set_irq_line( + m6502_.set_irq_line( via_.get_interrupt_line() || (microdisc_is_enabled_ && microdisc_.get_interrupt_request_line())); } diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 4da1a312e..7aefbb8a9 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -55,7 +55,7 @@ enum ROM { }; class Machine: - public CPU::MOS6502::Processor, + public CPU::MOS6502::BusHandler, public CRTMachine::Machine, public ConfigurationTarget::Machine, public MOS::MOS6522IRQDelegate::Delegate, @@ -101,6 +101,8 @@ class Machine: void wd1770_did_change_output(WD::WD1770 *wd1770); private: + CPU::MOS6502::Processor m6502_; + // RAM and ROM std::vector basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_; uint8_t ram_[65536], rom_[16384]; diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index b2a06fa72..e1f9706e2 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -117,6 +117,14 @@ class ProcessorBase { static const MicroOp operations[256][10]; }; +class BusHandler { + public: + void flush() {} + Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { + return Cycles(0); + } +}; + /*! @abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism. @@ -130,6 +138,7 @@ class ProcessorBase { */ template class Processor: public ProcessorBase { private: + T &bus_handler_; const MicroOp *scheduled_program_counter_; /* @@ -261,8 +270,11 @@ template class Processor: public ProcessorBase { return reset; } - protected: - Processor() : + public: + /*! + Constructs an instance of the 6502 that will use @c bus_handler for all bus communications. + */ + Processor(T &bus_handler) : is_jammed_(false), ready_line_is_enabled_(false), ready_is_active_(false), @@ -274,7 +286,8 @@ template class Processor: public ProcessorBase { irq_line_(0), nmi_line_is_enabled_(false), set_overflow_line_is_enabled_(false), - scheduled_program_counter_(nullptr) { + scheduled_program_counter_(nullptr), + bus_handler_(bus_handler) { // only the interrupt flag is defined upon reset but get_flags isn't going to // mask the other flags so we need to do that, at least carry_flag_ &= Flag::Carry; @@ -282,7 +295,6 @@ template class Processor: public ProcessorBase { overflow_flag_ &= Flag::Overflow; } - public: /*! Runs the 6502 for a supplied number of cycles. @@ -334,7 +346,7 @@ template class Processor: public ProcessorBase { #define bus_access() \ interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \ irq_request_history_ = irq_line_ & inverse_interrupt_flag_; \ - number_of_cycles -= static_cast(this)->perform_bus_operation(nextBusOperation, busAddress, busValue); \ + number_of_cycles -= bus_handler_.perform_bus_operation(nextBusOperation, busAddress, busValue); \ nextBusOperation = BusOperation::None; \ if(number_of_cycles <= Cycles(0)) break; @@ -344,7 +356,7 @@ template class Processor: public ProcessorBase { while(number_of_cycles > Cycles(0)) { while (ready_is_active_ && number_of_cycles > Cycles(0)) { - number_of_cycles -= static_cast(this)->perform_bus_operation(BusOperation::Ready, busAddress, busValue); + number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue); } if(!ready_is_active_) { @@ -825,16 +837,9 @@ template class Processor: public ProcessorBase { bus_address_ = busAddress; bus_value_ = busValue; - static_cast(this)->flush(); + bus_handler_.flush(); } - /*! - Called to announce the end of a run_for period, allowing deferred work to take place. - - Users of the 6502 template may override this. - */ - void flush() {} - /*! Gets the value of a register. @@ -884,8 +889,8 @@ template class Processor: public ProcessorBase { */ void return_from_subroutine() { s_++; - static_cast(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++; - static_cast(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high); + 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_) {