1
0
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:
Thomas Harte 2017-08-16 11:56:52 -04:00
parent 27018ba64e
commit 42b5b66305
23 changed files with 117 additions and 64 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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];

View File

@ -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() {

View File

@ -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];

View File

@ -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()));
}

View File

@ -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];

View File

@ -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_) {