mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +00:00
Pulled the 6502 into a CPU namespace, making it an instance of something that has micro-opcodes and schedules them, and factoring out the formulation of a register pair.
This commit is contained in:
parent
b81a2cc273
commit
0808e9b6fb
@ -11,7 +11,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "Bus.hpp"
|
||||
#include "PIA.hpp"
|
||||
|
@ -9,25 +9,25 @@
|
||||
#ifndef Atari2600_Cartridge_hpp
|
||||
#define Atari2600_Cartridge_hpp
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
#include "../Bus.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
template<class T> class Cartridge:
|
||||
public CPU6502::Processor<Cartridge<T>>,
|
||||
public CPU::MOS6502::Processor<Cartridge<T>>,
|
||||
public Bus {
|
||||
|
||||
public:
|
||||
Cartridge(const std::vector<uint8_t> &rom) :
|
||||
rom_(rom) {}
|
||||
|
||||
void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Cartridge<T>>::run_for_cycles(number_of_cycles); }
|
||||
void set_reset_line(bool state) { CPU6502::Processor<Cartridge<T>>::set_reset_line(state); }
|
||||
void run_for_cycles(int number_of_cycles) { CPU::MOS6502::Processor<Cartridge<T>>::run_for_cycles(number_of_cycles); }
|
||||
void set_reset_line(bool state) { CPU::MOS6502::Processor<Cartridge<T>>::set_reset_line(state); }
|
||||
void advance_cycles(unsigned int cycles) {}
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
uint8_t returnValue = 0xff;
|
||||
unsigned int cycles_run_for = 3;
|
||||
|
||||
@ -35,7 +35,7 @@ template<class T> class Cartridge:
|
||||
// leap to the end of ready only once ready is signalled — because on a 6502 ready doesn't take
|
||||
// effect until the next read; therefore it isn't safe to assume that signalling ready immediately
|
||||
// skips to the end of the line.
|
||||
if(operation == CPU6502::BusOperation::Ready)
|
||||
if(operation == CPU::MOS6502::BusOperation::Ready)
|
||||
cycles_run_for = (unsigned int)tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_);
|
||||
|
||||
cycles_since_speaker_update_ += cycles_run_for;
|
||||
@ -43,7 +43,7 @@ template<class T> class Cartridge:
|
||||
cycles_since_6532_update_ += (cycles_run_for / 3);
|
||||
static_cast<T *>(this)->advance_cycles(cycles_run_for / 3);
|
||||
|
||||
if(operation != CPU6502::BusOperation::Ready) {
|
||||
if(operation != CPU::MOS6502::BusOperation::Ready) {
|
||||
// give the cartridge a chance to respond to the bus access
|
||||
static_cast<T *>(this)->perform_bus_operation(operation, address, value);
|
||||
|
||||
@ -91,7 +91,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: CPU6502::Processor<Cartridge<T>>::set_ready_line(true); break;
|
||||
case 0x02: CPU::MOS6502::Processor<Cartridge<T>>::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 +156,7 @@ template<class T> class Cartridge:
|
||||
}
|
||||
}
|
||||
|
||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) CPU6502::Processor<Cartridge<T>>::set_ready_line(false);
|
||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) CPU::MOS6502::Processor<Cartridge<T>>::set_ready_line(false);
|
||||
|
||||
return cycles_run_for / 3;
|
||||
}
|
||||
|
@ -19,13 +19,13 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
// This is a bit of a hack; a real cartridge can't see either the sync or read lines, and can't see
|
||||
// address line 13. Instead it looks for a pattern in recent address accesses that would imply an
|
||||
// RST or JSR.
|
||||
if(operation == CPU6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) {
|
||||
if(operation == CPU::MOS6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) {
|
||||
if(address & 0x2000) {
|
||||
rom_ptr_ = rom_.data();
|
||||
} else {
|
||||
@ -37,7 +37,7 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
}
|
||||
|
||||
if(operation == CPU6502::BusOperation::ReadOpcode) last_opcode_ = *value;
|
||||
if(operation == CPU::MOS6502::BusOperation::ReadOpcode) last_opcode_ = *value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -20,7 +20,7 @@ class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
@ -42,7 +42,7 @@ class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
@ -42,7 +42,7 @@ class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
@ -43,7 +43,7 @@ class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -16,7 +16,7 @@ class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> {
|
||||
CartridgeCommaVid(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(!(address & 0x1000)) return;
|
||||
address &= 0x1fff;
|
||||
|
||||
|
@ -22,7 +22,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
high_ram_ptr_ = high_ram_;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -21,7 +21,7 @@ class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -23,7 +23,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
rom_ptr_[3] = rom_ptr_[2] + 1024;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -26,7 +26,7 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
cycles_since_audio_update_ += cycles;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -21,7 +21,7 @@ class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
|
||||
rom_ptr_[1] = rom_ptr_[0] + 2048;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if((address&0x1fff) == 0x3f) {
|
||||
int offset = ((*value) * 2048) & (rom_.size() - 1);
|
||||
rom_ptr_[0] = rom_.data() + offset;
|
||||
|
@ -18,7 +18,7 @@ class CartridgeUnpaged: public Cartridge<CartridgeUnpaged> {
|
||||
CartridgeUnpaged(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(isReadOperation(operation) && (address & 0x1000)) {
|
||||
*value = rom_[address & (rom_.size() - 1)];
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bu
|
||||
Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus);
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
/*
|
||||
Memory map (given that I'm unsure yet on any potential mirroring):
|
||||
|
||||
@ -80,7 +80,7 @@ void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk) {
|
||||
}
|
||||
|
||||
void Machine::run_for_cycles(int number_of_cycles) {
|
||||
CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_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(number_of_cycles);
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef Commodore1540_hpp
|
||||
#define Commodore1540_hpp
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
#include "../../../Components/6522/6522.hpp"
|
||||
|
||||
#include "../SerialBus.hpp"
|
||||
@ -120,7 +120,7 @@ class SerialPort : public ::Commodore::Serial::Port {
|
||||
Provides an emulation of the C1540.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public DriveVIA::Delegate,
|
||||
public Storage::Disk::Controller {
|
||||
@ -141,8 +141,8 @@ class Machine:
|
||||
void run_for_cycles(int number_of_cycles);
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
|
||||
// to satisfy MOS::MOS6522::Delegate
|
||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
|
@ -97,7 +97,7 @@ Machine::~Machine() {
|
||||
delete[] rom_;
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::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);
|
||||
|
||||
@ -115,7 +115,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
// PC hits the start of the loop that just waits for an interesting tape interrupt to have
|
||||
// occurred then skip both 6522s and the tape ahead to the next interrupt without any further
|
||||
// CPU or 6560 costs.
|
||||
if(use_fast_tape_hack_ && tape_->has_tape() && operation == CPU6502::BusOperation::ReadOpcode) {
|
||||
if(use_fast_tape_hack_ && tape_->has_tape() && operation == CPU::MOS6502::BusOperation::ReadOpcode) {
|
||||
if(address == 0xf7b2) {
|
||||
// Address 0xf7b2 contains a JSR to 0xf8c0 that will fill the tape buffer with the next header.
|
||||
// So cancel that via a double NOP and fill in the next header programmatically.
|
||||
@ -137,7 +137,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
*value = 0x0c; // i.e. NOP abs
|
||||
} else if(address == 0xf90b) {
|
||||
uint8_t x = (uint8_t)get_value_of_register(CPU6502::Register::X);
|
||||
uint8_t x = (uint8_t)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());
|
||||
@ -158,13 +158,13 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
// set tape status, carry and flag
|
||||
user_basic_memory_[0x90] |= 0x40;
|
||||
uint8_t flags = (uint8_t)get_value_of_register(CPU6502::Register::Flags);
|
||||
flags &= ~(uint8_t)(CPU6502::Flag::Carry | CPU6502::Flag::Interrupt);
|
||||
set_value_of_register(CPU6502::Register::Flags, flags);
|
||||
uint8_t flags = (uint8_t)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);
|
||||
|
||||
// to ensure that execution proceeds to 0xfccf, pretend a NOP was here and
|
||||
// ensure that the PC leaps to 0xfccf
|
||||
set_value_of_register(CPU6502::Register::ProgramCounter, 0xfccf);
|
||||
set_value_of_register(CPU::MOS6502::Register::ProgramCounter, 0xfccf);
|
||||
*value = 0xea; // i.e. NOP implied
|
||||
}
|
||||
}
|
||||
@ -181,7 +181,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
user_port_via_->run_for_cycles(1);
|
||||
keyboard_via_->run_for_cycles(1);
|
||||
if(typer_ && operation == CPU6502::BusOperation::ReadOpcode && address == 0xEB1E) {
|
||||
if(typer_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && address == 0xEB1E) {
|
||||
if(!typer_->type_next_character()) {
|
||||
clear_all_keys();
|
||||
typer_.reset();
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "../../CRTMachine.hpp"
|
||||
#include "../../Typer.hpp"
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
#include "../../../Components/6560/6560.hpp"
|
||||
#include "../../../Components/6522/6522.hpp"
|
||||
|
||||
@ -141,7 +141,7 @@ class Vic6560: public MOS::MOS6560<Vic6560> {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CRTMachine::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
@ -167,8 +167,8 @@ class Machine:
|
||||
|
||||
inline void set_use_fast_tape_hack(bool activate) { use_fast_tape_hack_ = activate; }
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void synchronise() { mos6560_->synchronise(); }
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
@ -176,7 +176,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_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
|
||||
// to satisfy MOS::MOS6522::Delegate
|
||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
|
@ -123,7 +123,7 @@ void Machine::set_rom(ROMSlot slot, std::vector<uint8_t> data, bool is_writeable
|
||||
|
||||
#pragma mark - The bus
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int cycles = 1;
|
||||
|
||||
if(address < 0x8000) {
|
||||
@ -246,7 +246,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
if(
|
||||
use_fast_tape_hack_ &&
|
||||
tape_.has_tape() &&
|
||||
(operation == CPU6502::BusOperation::ReadOpcode) &&
|
||||
(operation == CPU::MOS6502::BusOperation::ReadOpcode) &&
|
||||
(
|
||||
(address == 0xf4e5) || (address == 0xf4e6) || // double NOPs at 0xf4e5, 0xf6de, 0xf6fa and 0xfa51
|
||||
(address == 0xf6de) || (address == 0xf6df) || // act to disable the normal branch into tape-handling
|
||||
@ -263,7 +263,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
// allow the PC read to return an RTS.
|
||||
)
|
||||
) {
|
||||
uint8_t service_call = (uint8_t)get_value_of_register(CPU6502::Register::X);
|
||||
uint8_t service_call = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X);
|
||||
if(address == 0xf0a8) {
|
||||
if(!ram_[0x247] && service_call == 14) {
|
||||
tape_.set_delegate(nullptr);
|
||||
@ -285,8 +285,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
interrupt_status_ |= tape_.get_interrupt_status();
|
||||
|
||||
fast_load_is_in_data_ = true;
|
||||
set_value_of_register(CPU6502::Register::A, 0);
|
||||
set_value_of_register(CPU6502::Register::Y, tape_.get_data_register());
|
||||
set_value_of_register(CPU::MOS6502::Register::A, 0);
|
||||
set_value_of_register(CPU::MOS6502::Register::Y, tape_.get_data_register());
|
||||
*value = 0x60; // 0x60 is RTS
|
||||
}
|
||||
else *value = os_[address & 16383];
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef Electron_hpp
|
||||
#define Electron_hpp
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Storage/Tape/Tape.hpp"
|
||||
|
||||
#include "../ConfigurationTarget.hpp"
|
||||
@ -68,7 +68,7 @@ enum Key: uint16_t {
|
||||
Acorn Electron.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CRTMachine::Machine,
|
||||
public Tape::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
@ -87,8 +87,8 @@ class Machine:
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void synchronise();
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
@ -96,7 +96,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_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
|
||||
// to satisfy Tape::Delegate
|
||||
virtual void tape_did_change_interrupt_status(Tape *tape);
|
||||
|
@ -78,16 +78,16 @@ void Machine::set_rom(ROM rom, const std::vector<uint8_t> &data) {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::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];
|
||||
|
||||
// 024D = 0 => fast; otherwise slow
|
||||
// E6C9 = read byte: return byte in A
|
||||
if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) {
|
||||
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(CPU6502::A, next_byte);
|
||||
set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero);
|
||||
set_value_of_register(CPU::MOS6502::A, next_byte);
|
||||
set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
|
||||
*value = 0x60; // i.e. RTS
|
||||
}
|
||||
} else {
|
||||
@ -120,7 +120,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
}
|
||||
}
|
||||
|
||||
if(typer_ && address == scan_keyboard_address_ && operation == CPU6502::BusOperation::ReadOpcode) {
|
||||
if(typer_ && address == scan_keyboard_address_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) {
|
||||
// the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't
|
||||
// do anything until at least the second, regardless of machine
|
||||
if(!keyboard_read_count_) keyboard_read_count_++;
|
||||
@ -199,7 +199,7 @@ std::shared_ptr<Outputs::Speaker> Machine::get_speaker() {
|
||||
}
|
||||
|
||||
void Machine::run_for_cycles(int number_of_cycles) {
|
||||
CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
}
|
||||
|
||||
#pragma mark - The 6522
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "../Typer.hpp"
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Components/6522/6522.hpp"
|
||||
#include "../../Components/AY38910/AY38910.hpp"
|
||||
#include "../../Storage/Tape/Parsers/Oric.hpp"
|
||||
@ -57,7 +57,7 @@ enum ROM {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CRTMachine::Machine,
|
||||
public ConfigurationTarget::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
@ -78,8 +78,8 @@ class Machine:
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void synchronise();
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
|
@ -12,9 +12,9 @@
|
||||
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; };
|
||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; };
|
||||
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */; };
|
||||
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
|
||||
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
|
||||
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */; };
|
||||
4B14145B1B58879D00E04248 /* 6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* 6502.cpp */; };
|
||||
4B14145D1B5887A600E04248 /* 6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* 6502.cpp */; };
|
||||
4B14145E1B5887AA00E04248 /* 6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* 6502AllRAM.cpp */; };
|
||||
4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */; };
|
||||
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; };
|
||||
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D08051E0F7A1100763741 /* TimeTests.mm */; };
|
||||
@ -33,6 +33,7 @@
|
||||
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */; };
|
||||
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */; };
|
||||
4B2C45421E3C3896002A2389 /* cartridge.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B2C45411E3C3896002A2389 /* cartridge.png */; };
|
||||
4B2C455D1EC9442600FC74DD /* RegisterSizes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2C455B1EC9442600FC74DD /* RegisterSizes.cpp */; };
|
||||
4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; };
|
||||
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; };
|
||||
4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B30512B1D989E2200B4FED8 /* Drive.cpp */; };
|
||||
@ -443,10 +444,10 @@
|
||||
4B121F971E060CF000BFDA12 /* PCMSegment.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMSegment.hpp; sourceTree = "<group>"; };
|
||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMSegmentEventSourceTests.mm; sourceTree = "<group>"; };
|
||||
4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ClockSignal-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4B1414571B58879D00E04248 /* CPU6502.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPU6502.cpp; sourceTree = "<group>"; };
|
||||
4B1414581B58879D00E04248 /* CPU6502.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502.hpp; sourceTree = "<group>"; };
|
||||
4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPU6502AllRAM.cpp; sourceTree = "<group>"; };
|
||||
4B14145A1B58879D00E04248 /* CPU6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502AllRAM.hpp; sourceTree = "<group>"; };
|
||||
4B1414571B58879D00E04248 /* 6502.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502.cpp; sourceTree = "<group>"; };
|
||||
4B1414581B58879D00E04248 /* 6502.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502.hpp; sourceTree = "<group>"; };
|
||||
4B1414591B58879D00E04248 /* 6502AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502AllRAM.cpp; sourceTree = "<group>"; };
|
||||
4B14145A1B58879D00E04248 /* 6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502AllRAM.hpp; sourceTree = "<group>"; };
|
||||
4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WolfgangLorenzTests.swift; sourceTree = "<group>"; };
|
||||
4B1414611B58888700E04248 /* KlausDormannTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KlausDormannTests.swift; sourceTree = "<group>"; };
|
||||
4B1D08051E0F7A1100763741 /* TimeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TimeTests.mm; sourceTree = "<group>"; };
|
||||
@ -480,6 +481,8 @@
|
||||
4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Oric/Video.cpp; sourceTree = "<group>"; };
|
||||
4B2BFDB11DAEF5FF001A68B8 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Oric/Video.hpp; sourceTree = "<group>"; };
|
||||
4B2C45411E3C3896002A2389 /* cartridge.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cartridge.png; sourceTree = "<group>"; };
|
||||
4B2C455B1EC9442600FC74DD /* RegisterSizes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterSizes.cpp; sourceTree = "<group>"; };
|
||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RegisterSizes.hpp; sourceTree = "<group>"; };
|
||||
4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = "<group>"; };
|
||||
4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = "<group>"; };
|
||||
4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = "<group>"; };
|
||||
@ -547,6 +550,7 @@
|
||||
4B6C73BC1D387AE500AFCFCA /* DiskController.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = "<group>"; };
|
||||
4B77069B1EC904570053B588 /* Z80.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80.cpp; path = Z80/Z80.cpp; sourceTree = "<group>"; };
|
||||
4B77069C1EC904570053B588 /* Z80.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80.hpp; path = Z80/Z80.hpp; sourceTree = "<group>"; };
|
||||
4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MicroOpScheduler.hpp; sourceTree = "<group>"; };
|
||||
4B7913CA1DFCD80E00175A82 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Electron/Video.cpp; sourceTree = "<group>"; };
|
||||
4B7913CB1DFCD80E00175A82 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Electron/Video.hpp; sourceTree = "<group>"; };
|
||||
4B79E4411E3AF38600141F11 /* cassette.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cassette.png; sourceTree = "<group>"; };
|
||||
@ -1014,10 +1018,10 @@
|
||||
4B1414561B58879D00E04248 /* 6502 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B1414571B58879D00E04248 /* CPU6502.cpp */,
|
||||
4B1414581B58879D00E04248 /* CPU6502.hpp */,
|
||||
4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */,
|
||||
4B14145A1B58879D00E04248 /* CPU6502AllRAM.hpp */,
|
||||
4B1414571B58879D00E04248 /* 6502.cpp */,
|
||||
4B1414581B58879D00E04248 /* 6502.hpp */,
|
||||
4B1414591B58879D00E04248 /* 6502AllRAM.cpp */,
|
||||
4B14145A1B58879D00E04248 /* 6502AllRAM.hpp */,
|
||||
);
|
||||
path = 6502;
|
||||
sourceTree = "<group>";
|
||||
@ -1804,6 +1808,9 @@
|
||||
children = (
|
||||
4B1414561B58879D00E04248 /* 6502 */,
|
||||
4B77069E1EC9045B0053B588 /* Z80 */,
|
||||
4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */,
|
||||
4B2C455B1EC9442600FC74DD /* RegisterSizes.cpp */,
|
||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
|
||||
);
|
||||
name = Processors;
|
||||
path = ../../Processors;
|
||||
@ -2509,6 +2516,7 @@
|
||||
4B9CCDA11DA279CA0098B625 /* Vic20OptionsPanel.swift in Sources */,
|
||||
4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */,
|
||||
4B3051301D98ACC600B4FED8 /* Plus3.cpp in Sources */,
|
||||
4B2C455D1EC9442600FC74DD /* RegisterSizes.cpp in Sources */,
|
||||
4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */,
|
||||
4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */,
|
||||
4BA22B071D8817CE0008C640 /* Disk.cpp in Sources */,
|
||||
@ -2516,7 +2524,7 @@
|
||||
4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */,
|
||||
4B4C83701D4F623200CD541F /* D64.cpp in Sources */,
|
||||
4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */,
|
||||
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */,
|
||||
4B14145B1B58879D00E04248 /* 6502.cpp in Sources */,
|
||||
4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */,
|
||||
4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */,
|
||||
4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */,
|
||||
@ -2536,8 +2544,8 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */,
|
||||
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */,
|
||||
4B14145E1B5887AA00E04248 /* 6502AllRAM.cpp in Sources */,
|
||||
4B14145D1B5887A600E04248 /* 6502.cpp in Sources */,
|
||||
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */,
|
||||
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */,
|
||||
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */,
|
||||
|
@ -8,15 +8,15 @@
|
||||
|
||||
#import "TestMachine.h"
|
||||
#include <stdint.h>
|
||||
#include "CPU6502AllRAM.hpp"
|
||||
#include "6502AllRAM.hpp"
|
||||
|
||||
const uint8_t CSTestMachineJamOpcode = CPU6502::JamOpcode;
|
||||
const uint8_t CSTestMachineJamOpcode = CPU::MOS6502::JamOpcode;
|
||||
|
||||
class MachineJamHandler: public CPU6502::AllRAMProcessor::JamHandler {
|
||||
class MachineJamHandler: public CPU::MOS6502::AllRAMProcessor::JamHandler {
|
||||
public:
|
||||
MachineJamHandler(CSTestMachine *targetMachine) : _targetMachine(targetMachine) {}
|
||||
|
||||
void processor_did_jam(CPU6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
|
||||
void processor_did_jam(CPU::MOS6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
|
||||
[_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address];
|
||||
}
|
||||
|
||||
@ -25,33 +25,33 @@ class MachineJamHandler: public CPU6502::AllRAMProcessor::JamHandler {
|
||||
};
|
||||
|
||||
@implementation CSTestMachine {
|
||||
CPU6502::AllRAMProcessor _processor;
|
||||
CPU::MOS6502::AllRAMProcessor _processor;
|
||||
MachineJamHandler *_cppJamHandler;
|
||||
}
|
||||
|
||||
- (uint8_t)valueForAddress:(uint16_t)address {
|
||||
uint8_t value;
|
||||
_processor.perform_bus_operation(CPU6502::BusOperation::Read, address, &value);
|
||||
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Read, address, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address {
|
||||
_processor.perform_bus_operation(CPU6502::BusOperation::Write, address, &value);
|
||||
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Write, address, &value);
|
||||
}
|
||||
|
||||
- (void)returnFromSubroutine {
|
||||
_processor.return_from_subroutine();
|
||||
}
|
||||
|
||||
- (CPU6502::Register)registerForRegister:(CSTestMachineRegister)reg {
|
||||
- (CPU::MOS6502::Register)registerForRegister:(CSTestMachineRegister)reg {
|
||||
switch (reg) {
|
||||
case CSTestMachineRegisterProgramCounter: return CPU6502::Register::ProgramCounter;
|
||||
case CSTestMachineRegisterLastOperationAddress: return CPU6502::Register::LastOperationAddress;
|
||||
case CSTestMachineRegisterFlags: return CPU6502::Register::Flags;
|
||||
case CSTestMachineRegisterA: return CPU6502::Register::A;
|
||||
case CSTestMachineRegisterX: return CPU6502::Register::X;
|
||||
case CSTestMachineRegisterY: return CPU6502::Register::Y;
|
||||
case CSTestMachineRegisterStackPointer: return CPU6502::Register::S;
|
||||
case CSTestMachineRegisterProgramCounter: return CPU::MOS6502::Register::ProgramCounter;
|
||||
case CSTestMachineRegisterLastOperationAddress: return CPU::MOS6502::Register::LastOperationAddress;
|
||||
case CSTestMachineRegisterFlags: return CPU::MOS6502::Register::Flags;
|
||||
case CSTestMachineRegisterA: return CPU::MOS6502::Register::A;
|
||||
case CSTestMachineRegisterX: return CPU::MOS6502::Register::X;
|
||||
case CSTestMachineRegisterY: return CPU::MOS6502::Register::Y;
|
||||
case CSTestMachineRegisterStackPointer: return CPU::MOS6502::Register::S;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
//
|
||||
// CPU6502.cpp
|
||||
// 6502.cpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "CPU6502.hpp"
|
||||
#include "6502.hpp"
|
||||
|
||||
const uint8_t CPU6502::JamOpcode = 0xf2;
|
||||
const uint8_t CPU::MOS6502::JamOpcode = 0xf2;
|
@ -1,18 +1,22 @@
|
||||
//
|
||||
// CPU6502.hpp
|
||||
// 6502.hpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPU6502_cpp
|
||||
#define CPU6502_cpp
|
||||
#ifndef MOS6502_cpp
|
||||
#define MOS6502_cpp
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
namespace CPU6502 {
|
||||
#include "../MicroOpScheduler.hpp"
|
||||
#include "../RegisterSizes.hpp"
|
||||
|
||||
namespace CPU {
|
||||
namespace MOS6502 {
|
||||
|
||||
/*
|
||||
The list of registers that can be accessed via @c set_value_of_register and @c set_value_of_register.
|
||||
@ -56,13 +60,58 @@ enum BusOperation {
|
||||
/*!
|
||||
Evaluates to `true` if the operation is a read; `false` if it is a write.
|
||||
*/
|
||||
#define isReadOperation(v) (v == CPU6502::BusOperation::Read || v == CPU6502::BusOperation::ReadOpcode)
|
||||
#define isReadOperation(v) (v == CPU::MOS6502::BusOperation::Read || v == CPU::MOS6502::BusOperation::ReadOpcode)
|
||||
|
||||
/*!
|
||||
An opcode that is guaranteed to cause the CPU to jam.
|
||||
*/
|
||||
extern const uint8_t JamOpcode;
|
||||
|
||||
/*
|
||||
This emulation functions by decomposing instructions into micro programs, consisting of the micro operations
|
||||
as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle
|
||||
to perform whereas those called OperationX occur for free (so, in effect, their cost is loaded onto the next cycle).
|
||||
*/
|
||||
enum MicroOp {
|
||||
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
|
||||
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
|
||||
OperationSetI,
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead,
|
||||
OperationMoveToNextProgram, OperationIncrementPC,
|
||||
CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA,
|
||||
CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand,
|
||||
OperationIncrementOperand, OperationORA, OperationAND, OperationEOR,
|
||||
OperationINS, OperationADC, OperationSBC, OperationLDA,
|
||||
OperationLDX, OperationLDY, OperationLAX, OperationSTA,
|
||||
OperationSTX, OperationSTY, OperationSAX, OperationSHA,
|
||||
OperationSHX, OperationSHY, OperationSHS, OperationCMP,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationASL,
|
||||
OperationASO, OperationROL, OperationRLA, OperationLSR,
|
||||
OperationLSE, OperationASR, OperationROR, OperationRRA,
|
||||
OperationCLC, OperationCLI, OperationCLV, OperationCLD,
|
||||
OperationSEC, OperationSEI, OperationSED, OperationINC,
|
||||
OperationDEC, OperationINX, OperationDEX, OperationINY,
|
||||
OperationDEY, OperationBPL, OperationBMI, OperationBVC,
|
||||
OperationBVS, OperationBCC, OperationBCS, OperationBNE,
|
||||
OperationBEQ, OperationTXA, OperationTYA, OperationTXS,
|
||||
OperationTAY, OperationTAX, OperationTSX, OperationARR,
|
||||
OperationSBX, OperationLXA, OperationANE, OperationANC,
|
||||
OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA,
|
||||
CycleScheduleJam
|
||||
};
|
||||
|
||||
/*!
|
||||
@abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism.
|
||||
|
||||
@ -74,7 +123,7 @@ extern const uint8_t JamOpcode;
|
||||
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 T> class Processor {
|
||||
template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
||||
public:
|
||||
|
||||
class JamHandler {
|
||||
@ -84,60 +133,8 @@ template <class T> class Processor {
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
This emulation funcitons by decomposing instructions into micro programs, consisting of the micro operations
|
||||
as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle
|
||||
to perform whereas those called OperationX occur for free (so, in effect, their cost is loaded onto the next cycle).
|
||||
*/
|
||||
enum MicroOp {
|
||||
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
|
||||
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
|
||||
OperationSetI,
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead,
|
||||
OperationMoveToNextProgram, OperationIncrementPC,
|
||||
CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA,
|
||||
CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand,
|
||||
OperationIncrementOperand, OperationORA, OperationAND, OperationEOR,
|
||||
OperationINS, OperationADC, OperationSBC, OperationLDA,
|
||||
OperationLDX, OperationLDY, OperationLAX, OperationSTA,
|
||||
OperationSTX, OperationSTY, OperationSAX, OperationSHA,
|
||||
OperationSHX, OperationSHY, OperationSHS, OperationCMP,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationASL,
|
||||
OperationASO, OperationROL, OperationRLA, OperationLSR,
|
||||
OperationLSE, OperationASR, OperationROR, OperationRRA,
|
||||
OperationCLC, OperationCLI, OperationCLV, OperationCLD,
|
||||
OperationSEC, OperationSEI, OperationSED, OperationINC,
|
||||
OperationDEC, OperationINX, OperationDEX, OperationINY,
|
||||
OperationDEY, OperationBPL, OperationBMI, OperationBVC,
|
||||
OperationBVS, OperationBCC, OperationBCS, OperationBNE,
|
||||
OperationBEQ, OperationTXA, OperationTYA, OperationTXS,
|
||||
OperationTAY, OperationTAX, OperationTSX, OperationARR,
|
||||
OperationSBX, OperationLXA, OperationANE, OperationANC,
|
||||
OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA,
|
||||
CycleScheduleJam
|
||||
};
|
||||
|
||||
#define JAM {CycleFetchOperand, CycleScheduleJam, OperationMoveToNextProgram}
|
||||
|
||||
union RegisterPair {
|
||||
uint16_t full;
|
||||
struct {
|
||||
uint8_t low, high;
|
||||
} bytes;
|
||||
};
|
||||
|
||||
/*
|
||||
Storage for the 6502 registers; F is stored as individual flags.
|
||||
*/
|
||||
@ -151,16 +148,6 @@ template <class T> class Processor {
|
||||
uint8_t operation_, operand_;
|
||||
RegisterPair address_, next_address_;
|
||||
|
||||
/*
|
||||
Up to four programs can be scheduled; each will be carried out in turn. This
|
||||
storage maintains pointers to the scheduled list of programs.
|
||||
|
||||
Programs should be terminated by an OperationMoveToNextProgram, causing this
|
||||
queue to take that step.
|
||||
*/
|
||||
const MicroOp *scheduled_programs_[4];
|
||||
unsigned int schedule_programs_write_pointer_, schedule_programs_read_pointer_, schedule_program_program_counter_;
|
||||
|
||||
/*
|
||||
Temporary storage allowing a common dispatch point for calling perform_bus_operation;
|
||||
possibly deferring is no longer of value.
|
||||
@ -169,18 +156,6 @@ template <class T> class Processor {
|
||||
uint16_t bus_address_;
|
||||
uint8_t *bus_value_;
|
||||
|
||||
/*!
|
||||
Schedules a new program, adding it to the end of the queue. Programs should be
|
||||
terminated with a OperationMoveToNextProgram. No attempt to copy the program
|
||||
is made; a non-owning reference is kept.
|
||||
|
||||
@param program The program to schedule.
|
||||
*/
|
||||
inline void schedule_program(const MicroOp *program) {
|
||||
scheduled_programs_[schedule_programs_write_pointer_] = program;
|
||||
schedule_programs_write_pointer_ = (schedule_programs_write_pointer_+1)&3;
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the flags register.
|
||||
|
||||
@ -535,14 +510,11 @@ template <class T> class Processor {
|
||||
|
||||
protected:
|
||||
Processor() :
|
||||
schedule_programs_read_pointer_(0),
|
||||
schedule_programs_write_pointer_(0),
|
||||
is_jammed_(false),
|
||||
jam_handler_(nullptr),
|
||||
cycles_left_to_run_(0),
|
||||
ready_line_is_enabled_(false),
|
||||
ready_is_active_(false),
|
||||
scheduled_programs_{nullptr, nullptr, nullptr, nullptr},
|
||||
inverse_interrupt_flag_(0),
|
||||
irq_request_history_(0),
|
||||
s_(0),
|
||||
@ -1176,8 +1148,8 @@ template <class T> class Processor {
|
||||
*/
|
||||
void return_from_subroutine() {
|
||||
s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(CPU6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(CPU6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high);
|
||||
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);
|
||||
pc_.full++;
|
||||
|
||||
if(is_jammed_) {
|
||||
@ -1278,6 +1250,7 @@ template <class T> class Processor {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CPU6502_cpp */
|
||||
#endif /* MOS6502_cpp */
|
@ -1,22 +1,22 @@
|
||||
//
|
||||
// CPU6502AllRAM.cpp
|
||||
// 6502AllRAM.cpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 13/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "CPU6502AllRAM.hpp"
|
||||
#include "6502AllRAM.hpp"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
using namespace CPU6502;
|
||||
using namespace CPU::MOS6502;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor() : _timestamp(0) {
|
||||
set_power_on(false);
|
||||
}
|
||||
|
||||
int AllRAMProcessor::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
int AllRAMProcessor::perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
_timestamp++;
|
||||
|
||||
if(isReadOperation(operation)) {
|
@ -1,17 +1,18 @@
|
||||
//
|
||||
// CPU6502AllRAM.hpp
|
||||
// 6502AllRAM.hpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 13/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPU6502AllRAM_cpp
|
||||
#define CPU6502AllRAM_cpp
|
||||
#ifndef MOS6502AllRAM_cpp
|
||||
#define MOS6502AllRAM_cpp
|
||||
|
||||
#include "CPU6502.hpp"
|
||||
#include "6502.hpp"
|
||||
|
||||
namespace CPU6502 {
|
||||
namespace CPU {
|
||||
namespace MOS6502 {
|
||||
|
||||
class AllRAMProcessor: public Processor<AllRAMProcessor> {
|
||||
|
||||
@ -19,7 +20,7 @@ class AllRAMProcessor: public Processor<AllRAMProcessor> {
|
||||
|
||||
AllRAMProcessor();
|
||||
|
||||
int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
int perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
|
||||
void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data);
|
||||
uint32_t get_timestamp();
|
||||
@ -29,6 +30,7 @@ class AllRAMProcessor: public Processor<AllRAMProcessor> {
|
||||
uint32_t _timestamp;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CPU6502AllRAM_cpp */
|
||||
#endif /* MOS6502AllRAM_cpp */
|
48
Processors/MicroOpScheduler.hpp
Normal file
48
Processors/MicroOpScheduler.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// MicroOpScheduler.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MicroOpScheduler_hpp
|
||||
#define MicroOpScheduler_hpp
|
||||
|
||||
namespace CPU {
|
||||
|
||||
template <class T> class MicroOpScheduler {
|
||||
public:
|
||||
MicroOpScheduler() :
|
||||
scheduled_programs_{nullptr, nullptr, nullptr, nullptr},
|
||||
schedule_programs_write_pointer_(0),
|
||||
schedule_programs_read_pointer_(0),
|
||||
schedule_program_program_counter_(0) {}
|
||||
|
||||
protected:
|
||||
/*
|
||||
Up to four programs can be scheduled; each will be carried out in turn. This
|
||||
storage maintains pointers to the scheduled list of programs.
|
||||
|
||||
Programs should be terminated by an OperationMoveToNextProgram, causing this
|
||||
queue to take that step.
|
||||
*/
|
||||
const T *scheduled_programs_[4];
|
||||
unsigned int schedule_programs_write_pointer_, schedule_programs_read_pointer_, schedule_program_program_counter_;
|
||||
|
||||
/*!
|
||||
Schedules a new program, adding it to the end of the queue. Programs should be
|
||||
terminated with a OperationMoveToNextProgram. No attempt to copy the program
|
||||
is made; a non-owning reference is kept.
|
||||
|
||||
@param program The program to schedule.
|
||||
*/
|
||||
inline void schedule_program(const T *program) {
|
||||
scheduled_programs_[schedule_programs_write_pointer_] = program;
|
||||
schedule_programs_write_pointer_ = (schedule_programs_write_pointer_+1)&3;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MicroOpScheduler_hpp */
|
9
Processors/RegisterSizes.cpp
Normal file
9
Processors/RegisterSizes.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
// RegisterSizes.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "RegisterSizes.hpp"
|
25
Processors/RegisterSizes.hpp
Normal file
25
Processors/RegisterSizes.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// RegisterSizes.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef RegisterSizes_hpp
|
||||
#define RegisterSizes_hpp
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace CPU {
|
||||
|
||||
union RegisterPair {
|
||||
uint16_t full;
|
||||
struct {
|
||||
uint8_t low, high;
|
||||
} bytes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* RegisterSizes_hpp */
|
@ -54,11 +54,49 @@ enum Flag: uint8_t {
|
||||
Subclasses will be given the task of performing bus operations, allowing them to provide whatever interface they like
|
||||
between a Z80 and the rest of the system. @c BusOperation lists the types of bus operation that may be requested.
|
||||
|
||||
@c None is reserved for internal use. It will never be requested from a subclass. It is safe always to use the
|
||||
isReadOperation macro to make a binary choice between reading and writing.
|
||||
@c None is reserved for internal use. It will never be requested from a subclass.
|
||||
*/
|
||||
enum BusOperation {
|
||||
Read, ReadOpcode, Write, Input, Output, Interrupt, BusRequest, None
|
||||
ReadOpcode,
|
||||
Read, Write,
|
||||
Input, Output,
|
||||
Interrupt,
|
||||
BusRequest, BusAcknowledge,
|
||||
None
|
||||
};
|
||||
|
||||
/*!
|
||||
@abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism.
|
||||
|
||||
@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 synchronise(), 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 T> class Processor {
|
||||
private:
|
||||
struct MicroOp {
|
||||
enum {
|
||||
} type;
|
||||
void *source;
|
||||
void *destination;
|
||||
};
|
||||
|
||||
union RegisterPair {
|
||||
uint16_t full;
|
||||
struct {
|
||||
uint8_t low, high;
|
||||
} bytes;
|
||||
};
|
||||
|
||||
RegisterPair bc_, de_, hl_, afDash_, bcDash_, hlDash_, ix_, iy_;
|
||||
uint8_t a, i, r;
|
||||
|
||||
const MicroOp *scheduled_programs_[4];
|
||||
unsigned int schedule_programs_write_pointer_, schedule_programs_read_pointer_, schedule_program_program_counter_;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user