mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-26 08:29:33 +00:00
Remove the 6502's use of runtime polymorphism in favour of ordinary templating.
This commit is contained in:
parent
27018ba64e
commit
42b5b66305
@ -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<uint8_t> &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;
|
||||
}
|
||||
|
@ -13,17 +13,19 @@
|
||||
#include "../Bus.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
template<class T> class Cartridge:
|
||||
public CPU::MOS6502::Processor<Cartridge<T>>,
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public Bus {
|
||||
|
||||
public:
|
||||
Cartridge(const std::vector<uint8_t> &rom) :
|
||||
m6502_(*this),
|
||||
rom_(rom) {}
|
||||
|
||||
void run_for(const Cycles cycles) { CPU::MOS6502::Processor<Cartridge<T>>::run_for(cycles); }
|
||||
void set_reset_line(bool state) { CPU::MOS6502::Processor<Cartridge<T>>::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 T> 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<Cartridge<T>>::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 T> class Cartridge:
|
||||
}
|
||||
}
|
||||
|
||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) CPU::MOS6502::Processor<Cartridge<T>>::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 T> class Cartridge:
|
||||
}
|
||||
|
||||
protected:
|
||||
CPU::MOS6502::Processor<Cartridge<T>> m6502_;
|
||||
std::vector<uint8_t> rom_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_Cartridge_hpp */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define Atari2600_CartridgeActivisionStack_hpp
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
public:
|
||||
@ -45,6 +46,7 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
uint8_t last_opcode_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeActivisionStack_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> {
|
||||
public:
|
||||
@ -61,6 +62,7 @@ class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> {
|
||||
uint8_t ram_[128];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeAtari16k_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> {
|
||||
public:
|
||||
@ -61,6 +62,7 @@ class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> {
|
||||
uint8_t ram_[128];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeAtari32k_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> {
|
||||
public:
|
||||
@ -63,6 +64,7 @@ class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> {
|
||||
uint8_t ram_[128];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeAtari8k_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
|
||||
public:
|
||||
@ -39,6 +40,7 @@ class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
|
||||
uint8_t ram_[256];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeCBSRAMPlus_hpp */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define Atari2600_CartridgeCommaVid_hpp
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> {
|
||||
public:
|
||||
@ -37,6 +38,7 @@ class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> {
|
||||
uint8_t ram_[1024];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeCommaVid_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
public:
|
||||
@ -63,6 +64,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
uint8_t low_ram_[1024], high_ram_[1024];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeMNetwork_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
|
||||
public:
|
||||
@ -40,6 +41,7 @@ class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
|
||||
uint8_t current_page_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CartridgeMegaBoy_h */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
public:
|
||||
@ -41,6 +42,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
uint8_t *rom_ptr_[4];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeParkerBros_hpp */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define Atari2600_CartridgePitfall2_hpp
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
public:
|
||||
@ -128,6 +129,7 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
Cycles cycles_since_audio_update_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgePitfall2_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
|
||||
public:
|
||||
@ -35,6 +36,7 @@ class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
|
||||
uint8_t *rom_ptr_[2];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeTigervision_hpp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeUnpaged: public Cartridge<CartridgeUnpaged> {
|
||||
public:
|
||||
@ -25,6 +26,7 @@ class CartridgeUnpaged: public Cartridge<CartridgeUnpaged> {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeUnpaged_hpp */
|
||||
|
@ -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<Storage::Disk::Disk> disk) {
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
CPU::MOS6502::Processor<Machine>::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
|
||||
|
@ -120,7 +120,7 @@ class SerialPort : public ::Commodore::Serial::Port {
|
||||
Provides an emulation of the C1540.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
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<Machine> m6502_;
|
||||
|
||||
uint8_t ram_[0x800];
|
||||
uint8_t rom_[0x4000];
|
||||
|
||||
|
@ -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<Storage::Tape::Commodore::Data> 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
|
||||
|
@ -139,7 +139,7 @@ class Vic6560: public MOS::MOS6560<Vic6560> {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
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<Outputs::CRT::CRT> get_crt() { return mos6560_->get_crt(); }
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return mos6560_->get_speaker(); }
|
||||
virtual void run_for(const Cycles cycles) { CPU::MOS6502::Processor<Machine>::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<Machine> m6502_;
|
||||
|
||||
uint8_t character_rom_[0x1000];
|
||||
uint8_t basic_rom_[0x2000];
|
||||
uint8_t kernel_rom_[0x2000];
|
||||
|
@ -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() {
|
||||
|
@ -67,7 +67,7 @@ enum Key: uint16_t {
|
||||
Acorn Electron.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
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<Outputs::CRT::CRT> get_crt();
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker();
|
||||
virtual void run_for(const Cycles cycles) { CPU::MOS6502::Processor<Machine>::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<Machine> m6502_;
|
||||
|
||||
// Things that directly constitute the memory map.
|
||||
uint8_t roms_[16][16384];
|
||||
bool rom_write_masks_[16];
|
||||
|
@ -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<Outputs::Speaker> Machine::get_speaker() {
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
CPU::MOS6502::Processor<Machine>::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()));
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ enum ROM {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
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<Machine> m6502_;
|
||||
|
||||
// RAM and ROM
|
||||
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
|
||||
uint8_t ram_[65536], rom_[16384];
|
||||
|
@ -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 T> class Processor: public ProcessorBase {
|
||||
private:
|
||||
T &bus_handler_;
|
||||
const MicroOp *scheduled_program_counter_;
|
||||
|
||||
/*
|
||||
@ -261,8 +270,11 @@ template <class T> 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 T> 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 T> class Processor: public ProcessorBase {
|
||||
overflow_flag_ &= Flag::Overflow;
|
||||
}
|
||||
|
||||
public:
|
||||
/*!
|
||||
Runs the 6502 for a supplied number of cycles.
|
||||
|
||||
@ -334,7 +346,7 @@ template <class T> 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<T *>(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 T> class Processor: public ProcessorBase {
|
||||
while(number_of_cycles > Cycles(0)) {
|
||||
|
||||
while (ready_is_active_ && number_of_cycles > Cycles(0)) {
|
||||
number_of_cycles -= static_cast<T *>(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 T> class Processor: public ProcessorBase {
|
||||
bus_address_ = busAddress;
|
||||
bus_value_ = busValue;
|
||||
|
||||
static_cast<T *>(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 T> class Processor: public ProcessorBase {
|
||||
*/
|
||||
void return_from_subroutine() {
|
||||
s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++;
|
||||
static_cast<T *>(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_) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user