1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-18 16:30:29 +00:00

Merge pull request #200 from TomHarte/6502BusHandler

Converts the 6502 into a bus-handler-type template, and makes appropriate adjustments to all 6502 machines
This commit is contained in:
Thomas Harte 2017-08-16 14:10:08 -04:00 committed by GitHub
commit 2105597910
24 changed files with 249 additions and 199 deletions

View File

@ -10,18 +10,18 @@
#include <algorithm> #include <algorithm>
#include <stdio.h> #include <stdio.h>
#include "Cartridges/CartridgeAtari8k.hpp" #include "Cartridges/Atari8k.hpp"
#include "Cartridges/CartridgeAtari16k.hpp" #include "Cartridges/Atari16k.hpp"
#include "Cartridges/CartridgeAtari32k.hpp" #include "Cartridges/Atari32k.hpp"
#include "Cartridges/CartridgeActivisionStack.hpp" #include "Cartridges/ActivisionStack.hpp"
#include "Cartridges/CartridgeCBSRAMPlus.hpp" #include "Cartridges/CBSRAMPlus.hpp"
#include "Cartridges/CartridgeCommaVid.hpp" #include "Cartridges/CommaVid.hpp"
#include "Cartridges/CartridgeMegaBoy.hpp" #include "Cartridges/MegaBoy.hpp"
#include "Cartridges/CartridgeMNetwork.hpp" #include "Cartridges/MNetwork.hpp"
#include "Cartridges/CartridgeParkerBros.hpp" #include "Cartridges/ParkerBros.hpp"
#include "Cartridges/CartridgePitfall2.hpp" #include "Cartridges/Pitfall2.hpp"
#include "Cartridges/CartridgeTigervision.hpp" #include "Cartridges/Tigervision.hpp"
#include "Cartridges/CartridgeUnpaged.hpp" #include "Cartridges/Unpaged.hpp"
using namespace Atari2600; using namespace Atari2600;
namespace { namespace {
@ -83,35 +83,35 @@ void Machine::set_switch_is_enabled(Atari2600Switch input, bool state) {
void Machine::configure_as_target(const StaticAnalyser::Target &target) { void Machine::configure_as_target(const StaticAnalyser::Target &target) {
const std::vector<uint8_t> &rom = target.cartridges.front()->get_segments().front().data; const std::vector<uint8_t> &rom = target.cartridges.front()->get_segments().front().data;
switch(target.atari.paging_model) { switch(target.atari.paging_model) {
case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new CartridgeActivisionStack(rom)); break; case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::Cartridge<Cartridge::ActivisionStack>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new CartridgeCBSRAMPlus(rom)); break; case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new Cartridge::Cartridge<Cartridge::CBSRAMPlus>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new CartridgeCommaVid(rom)); break; case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new Cartridge::Cartridge<Cartridge::CommaVid>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new CartridgeMegaBoy(rom)); break; case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new Cartridge::Cartridge<Cartridge::MegaBoy>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new CartridgeMNetwork(rom)); break; case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new Cartridge::Cartridge<Cartridge::MNetwork>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new CartridgeUnpaged(rom)); break; case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new Cartridge::Cartridge<Cartridge::Unpaged>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new CartridgeParkerBros(rom)); break; case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new Cartridge::Cartridge<Cartridge::ParkerBros>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new CartridgePitfall2(rom)); break; case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new Cartridge::Cartridge<Cartridge::Pitfall2>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new CartridgeTigervision(rom)); break; case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new Cartridge::Cartridge<Cartridge::Tigervision>(rom)); break;
case StaticAnalyser::Atari2600PagingModel::Atari8k: case StaticAnalyser::Atari2600PagingModel::Atari8k:
if(target.atari.uses_superchip) { if(target.atari.uses_superchip) {
bus_.reset(new CartridgeAtari8kSuperChip(rom)); bus_.reset(new Cartridge::Cartridge<Cartridge::Atari8kSuperChip>(rom));
} else { } else {
bus_.reset(new CartridgeAtari8k(rom)); bus_.reset(new Cartridge::Cartridge<Cartridge::Atari8k>(rom));
} }
break; break;
case StaticAnalyser::Atari2600PagingModel::Atari16k: case StaticAnalyser::Atari2600PagingModel::Atari16k:
if(target.atari.uses_superchip) { if(target.atari.uses_superchip) {
bus_.reset(new CartridgeAtari16kSuperChip(rom)); bus_.reset(new Cartridge::Cartridge<Cartridge::Atari16kSuperChip>(rom));
} else { } else {
bus_.reset(new CartridgeAtari16k(rom)); bus_.reset(new Cartridge::Cartridge<Cartridge::Atari16k>(rom));
} }
break; break;
case StaticAnalyser::Atari2600PagingModel::Atari32k: case StaticAnalyser::Atari2600PagingModel::Atari32k:
if(target.atari.uses_superchip) { if(target.atari.uses_superchip) {
bus_.reset(new CartridgeAtari32kSuperChip(rom)); bus_.reset(new Cartridge::Cartridge<Cartridge::Atari32kSuperChip>(rom));
} else { } else {
bus_.reset(new CartridgeAtari32k(rom)); bus_.reset(new Cartridge::Cartridge<Cartridge::Atari32k>(rom));
} }
break; break;
} }

View File

@ -6,18 +6,18 @@
// Copyright © 2017 Thomas Harte. All rights reserved. // Copyright © 2017 Thomas Harte. All rights reserved.
// //
#ifndef Atari2600_CartridgeActivisionStack_hpp #ifndef Atari2600_ActivisionStack_hpp
#define Atari2600_CartridgeActivisionStack_hpp #define Atari2600_ActivisionStack_hpp
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> { class ActivisionStack: public BusExtender {
public: public:
CartridgeActivisionStack(const std::vector<uint8_t> &rom) : ActivisionStack(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom), BusExtender(rom_base, rom_size),
last_opcode_(0x00) { rom_ptr_(rom_base),
rom_ptr_ = rom_.data(); last_opcode_(0x00) {}
}
void perform_bus_operation(CPU::MOS6502::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; if(!(address & 0x1000)) return;
@ -27,9 +27,9 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
// RST or JSR. // RST or JSR.
if(operation == CPU::MOS6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) { if(operation == CPU::MOS6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) {
if(address & 0x2000) { if(address & 0x2000) {
rom_ptr_ = rom_.data(); rom_ptr_ = rom_base_;
} else { } else {
rom_ptr_ = rom_.data() + 4096; rom_ptr_ = rom_base_ + 4096;
} }
} }
@ -45,6 +45,7 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
uint8_t last_opcode_; uint8_t last_opcode_;
}; };
}
} }
#endif /* Atari2600_CartridgeActivisionStack_hpp */ #endif /* Atari2600_CartridgeActivisionStack_hpp */

View File

@ -12,19 +12,19 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> { class Atari16k: public BusExtender {
public: public:
CartridgeAtari16k(const std::vector<uint8_t> &rom) : Atari16k(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom) { BusExtender(rom_base, rom_size),
rom_ptr_ = rom_.data(); rom_ptr_(rom_base) {}
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address >= 0x1ff6 && address <= 0x1ff9) rom_ptr_ = rom_.data() + (address - 0x1ff6) * 4096; if(address >= 0x1ff6 && address <= 0x1ff9) rom_ptr_ = rom_base_ + (address - 0x1ff6) * 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -35,18 +35,17 @@ class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> {
uint8_t *rom_ptr_; uint8_t *rom_ptr_;
}; };
class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> { class Atari16kSuperChip: public BusExtender {
public: public:
CartridgeAtari16kSuperChip(const std::vector<uint8_t> &rom) : Atari16kSuperChip(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom) { BusExtender(rom_base, rom_size),
rom_ptr_ = rom_.data(); rom_ptr_(rom_base) {}
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address >= 0x1ff6 && address <= 0x1ff9) rom_ptr_ = rom_.data() + (address - 0x1ff6) * 4096; if(address >= 0x1ff6 && address <= 0x1ff9) rom_ptr_ = rom_base_ + (address - 0x1ff6) * 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -61,6 +60,7 @@ class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> {
uint8_t ram_[128]; uint8_t ram_[128];
}; };
}
} }
#endif /* Atari2600_CartridgeAtari16k_hpp */ #endif /* Atari2600_CartridgeAtari16k_hpp */

View File

@ -12,19 +12,17 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> { class Atari32k: public BusExtender {
public: public:
CartridgeAtari32k(const std::vector<uint8_t> &rom) : Atari32k(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
Cartridge(rom) {
rom_ptr_ = rom_.data();
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address >= 0x1ff4 && address <= 0x1ffb) rom_ptr_ = rom_.data() + (address - 0x1ff4) * 4096; if(address >= 0x1ff4 && address <= 0x1ffb) rom_ptr_ = rom_base_ + (address - 0x1ff4) * 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -35,18 +33,15 @@ class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> {
uint8_t *rom_ptr_; uint8_t *rom_ptr_;
}; };
class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> { class Atari32kSuperChip: public BusExtender {
public: public:
CartridgeAtari32kSuperChip(const std::vector<uint8_t> &rom) : Atari32kSuperChip(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
Cartridge(rom) {
rom_ptr_ = rom_.data();
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address >= 0x1ff4 && address <= 0x1ffb) rom_ptr_ = rom_.data() + (address - 0x1ff4) * 4096; if(address >= 0x1ff4 && address <= 0x1ffb) rom_ptr_ = rom_base_ + (address - 0x1ff4) * 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -61,6 +56,7 @@ class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> {
uint8_t ram_[128]; uint8_t ram_[128];
}; };
}
} }
#endif /* Atari2600_CartridgeAtari32k_hpp */ #endif /* Atari2600_CartridgeAtari32k_hpp */

View File

@ -12,20 +12,18 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> { class Atari8k: public BusExtender {
public: public:
CartridgeAtari8k(const std::vector<uint8_t> &rom) : Atari8k(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
Cartridge(rom) {
rom_ptr_ = rom_.data();
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address == 0x1ff8) rom_ptr_ = rom_.data(); if(address == 0x1ff8) rom_ptr_ = rom_base_;
else if(address == 0x1ff9) rom_ptr_ = rom_.data() + 4096; else if(address == 0x1ff9) rom_ptr_ = rom_base_ + 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -36,19 +34,16 @@ class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> {
uint8_t *rom_ptr_; uint8_t *rom_ptr_;
}; };
class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> { class Atari8kSuperChip: public BusExtender {
public: public:
CartridgeAtari8kSuperChip(const std::vector<uint8_t> &rom) : Atari8kSuperChip(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
Cartridge(rom) {
rom_ptr_ = rom_.data();
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address == 0x1ff8) rom_ptr_ = rom_.data(); if(address == 0x1ff8) rom_ptr_ = rom_base_;
if(address == 0x1ff9) rom_ptr_ = rom_.data() + 4096; if(address == 0x1ff9) rom_ptr_ = rom_base_ + 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -63,6 +58,7 @@ class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> {
uint8_t ram_[128]; uint8_t ram_[128];
}; };
}
} }
#endif /* Atari2600_CartridgeAtari8k_hpp */ #endif /* Atari2600_CartridgeAtari8k_hpp */

View File

@ -12,19 +12,17 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> { class CBSRAMPlus: public BusExtender {
public: public:
CartridgeCBSRAMPlus(const std::vector<uint8_t> &rom) : CBSRAMPlus(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
Cartridge(rom) {
rom_ptr_ = rom_.data();
}
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
address &= 0x1fff; address &= 0x1fff;
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address >= 0x1ff8 && address <= 0x1ffa) rom_ptr_ = rom_.data() + (address - 0x1ff8) * 4096; if(address >= 0x1ff8 && address <= 0x1ffa) rom_ptr_ = rom_base_ + (address - 0x1ff8) * 4096;
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
*value = rom_ptr_[address & 4095]; *value = rom_ptr_[address & 4095];
@ -39,6 +37,7 @@ class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
uint8_t ram_[256]; uint8_t ram_[256];
}; };
}
} }
#endif /* Atari2600_CartridgeCBSRAMPlus_hpp */ #endif /* Atari2600_CartridgeCBSRAMPlus_hpp */

View File

@ -13,18 +13,34 @@
#include "../Bus.hpp" #include "../Bus.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class BusExtender: public CPU::MOS6502::BusHandler {
public:
BusExtender(uint8_t *rom_base, size_t rom_size) : rom_base_(rom_base), rom_size_(rom_size) {}
void advance_cycles(int cycles) {}
protected:
uint8_t *rom_base_;
size_t rom_size_;
};
template<class T> class Cartridge: template<class T> class Cartridge:
public CPU::MOS6502::Processor<Cartridge<T>>, public CPU::MOS6502::BusHandler,
public Bus { public Bus {
public: public:
Cartridge(const std::vector<uint8_t> &rom) : Cartridge(const std::vector<uint8_t> &rom) :
rom_(rom) {} m6502_(*this),
rom_(rom),
bus_extender_(rom_.data(), rom.size()) {
// The above works because bus_extender_ is declared after rom_ in the instance storage list;
// consider doing something less fragile.
}
void run_for(const Cycles cycles) { CPU::MOS6502::Processor<Cartridge<T>>::run_for(cycles); } void run_for(const Cycles cycles) { m6502_.run_for(cycles); }
void set_reset_line(bool state) { CPU::MOS6502::Processor<Cartridge<T>>::set_reset_line(state); } void set_reset_line(bool state) { m6502_.set_reset_line(state); }
void advance_cycles(int cycles) {}
// to satisfy CPU::MOS6502::Processor // to satisfy CPU::MOS6502::Processor
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
@ -41,11 +57,11 @@ template<class T> class Cartridge:
cycles_since_speaker_update_ += Cycles(cycles_run_for); cycles_since_speaker_update_ += Cycles(cycles_run_for);
cycles_since_video_update_ += Cycles(cycles_run_for); cycles_since_video_update_ += Cycles(cycles_run_for);
cycles_since_6532_update_ += Cycles(cycles_run_for / 3); cycles_since_6532_update_ += Cycles(cycles_run_for / 3);
static_cast<T *>(this)->advance_cycles(cycles_run_for / 3); bus_extender_.advance_cycles(cycles_run_for / 3);
if(operation != CPU::MOS6502::BusOperation::Ready) { if(operation != CPU::MOS6502::BusOperation::Ready) {
// give the cartridge a chance to respond to the bus access // give the cartridge a chance to respond to the bus access
static_cast<T *>(this)->perform_bus_operation(operation, address, value); bus_extender_.perform_bus_operation(operation, address, value);
// check for a RIOT RAM access // check for a RIOT RAM access
if((address&0x1280) == 0x80) { if((address&0x1280) == 0x80) {
@ -91,7 +107,7 @@ template<class T> class Cartridge:
case 0x00: update_video(); tia_->set_sync(*value & 0x02); break; case 0x00: update_video(); tia_->set_sync(*value & 0x02); break;
case 0x01: update_video(); tia_->set_blank(*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; case 0x03: update_video(); tia_->reset_horizontal_counter(); break;
// TODO: audio will now be out of synchronisation — fix // TODO: audio will now be out of synchronisation — fix
@ -156,7 +172,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); return Cycles(cycles_run_for / 3);
} }
@ -168,9 +184,14 @@ template<class T> class Cartridge:
} }
protected: protected:
CPU::MOS6502::Processor<Cartridge<T>> m6502_;
std::vector<uint8_t> rom_; std::vector<uint8_t> rom_;
private:
T bus_extender_;
}; };
}
} }
#endif /* Atari2600_Cartridge_hpp */ #endif /* Atari2600_Cartridge_hpp */

View File

@ -9,12 +9,14 @@
#ifndef Atari2600_CartridgeCommaVid_hpp #ifndef Atari2600_CartridgeCommaVid_hpp
#define Atari2600_CartridgeCommaVid_hpp #define Atari2600_CartridgeCommaVid_hpp
namespace Atari2600 { #include "Cartridge.hpp"
class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> { namespace Atari2600 {
namespace Cartridge {
class CommaVid: public BusExtender {
public: public:
CartridgeCommaVid(const std::vector<uint8_t> &rom) : CommaVid(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size) {}
Cartridge(rom) {}
void perform_bus_operation(CPU::MOS6502::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; if(!(address & 0x1000)) return;
@ -30,13 +32,14 @@ class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> {
return; return;
} }
if(isReadOperation(operation)) *value = rom_[address & 2047]; if(isReadOperation(operation)) *value = rom_base_[address & 2047];
} }
private: private:
uint8_t ram_[1024]; uint8_t ram_[1024];
}; };
}
} }
#endif /* Atari2600_CartridgeCommaVid_hpp */ #endif /* Atari2600_CartridgeCommaVid_hpp */

View File

@ -12,12 +12,13 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> { class MNetwork: public BusExtender {
public: public:
CartridgeMNetwork(const std::vector<uint8_t> &rom) : MNetwork(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom) { BusExtender(rom_base, rom_size) {
rom_ptr_[0] = rom_.data() + rom_.size() - 4096; rom_ptr_[0] = rom_base + rom_size_ - 4096;
rom_ptr_[1] = rom_ptr_[0] + 2048; rom_ptr_[1] = rom_ptr_[0] + 2048;
high_ram_ptr_ = high_ram_; high_ram_ptr_ = high_ram_;
} }
@ -27,7 +28,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
if(!(address & 0x1000)) return; if(!(address & 0x1000)) return;
if(address >= 0x1fe0 && address <= 0x1fe6) { if(address >= 0x1fe0 && address <= 0x1fe6) {
rom_ptr_[0] = rom_.data() + (address - 0x1fe0) * 2048; rom_ptr_[0] = rom_base_ + (address - 0x1fe0) * 2048;
} else if(address == 0x1fe7) { } else if(address == 0x1fe7) {
rom_ptr_[0] = nullptr; rom_ptr_[0] = nullptr;
} else if(address >= 0x1ff8 && address <= 0x1ffb) { } else if(address >= 0x1ff8 && address <= 0x1ffb) {
@ -54,7 +55,6 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
} }
} }
} }
} }
private: private:
@ -63,6 +63,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
uint8_t low_ram_[1024], high_ram_[1024]; uint8_t low_ram_[1024], high_ram_[1024];
}; };
}
} }
#endif /* Atari2600_CartridgeMNetwork_hpp */ #endif /* Atari2600_CartridgeMNetwork_hpp */

View File

@ -12,13 +12,14 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> { class MegaBoy: public BusExtender {
public: public:
CartridgeMegaBoy(const std::vector<uint8_t> &rom) : MegaBoy(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom), BusExtender(rom_base, rom_size),
rom_ptr_(rom_base),
current_page_(0) { current_page_(0) {
rom_ptr_ = rom_.data();
} }
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
@ -27,7 +28,7 @@ class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
if(address == 0x1ff0) { if(address == 0x1ff0) {
current_page_ = (current_page_ + 1) & 15; current_page_ = (current_page_ + 1) & 15;
rom_ptr_ = rom_.data() + current_page_ * 4096; rom_ptr_ = rom_base_ + current_page_ * 4096;
} }
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
@ -40,6 +41,7 @@ class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
uint8_t current_page_; uint8_t current_page_;
}; };
}
} }
#endif /* CartridgeMegaBoy_h */ #endif /* CartridgeMegaBoy_h */

View File

@ -12,12 +12,13 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> { class ParkerBros: public BusExtender {
public: public:
CartridgeParkerBros(const std::vector<uint8_t> &rom) : ParkerBros(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom) { BusExtender(rom_base, rom_size) {
rom_ptr_[0] = rom_.data() + 4096; rom_ptr_[0] = rom_base + 4096;
rom_ptr_[1] = rom_ptr_[0] + 1024; rom_ptr_[1] = rom_ptr_[0] + 1024;
rom_ptr_[2] = rom_ptr_[1] + 1024; rom_ptr_[2] = rom_ptr_[1] + 1024;
rom_ptr_[3] = rom_ptr_[2] + 1024; rom_ptr_[3] = rom_ptr_[2] + 1024;
@ -29,7 +30,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
if(address >= 0x1fe0 && address < 0x1ff8) { if(address >= 0x1fe0 && address < 0x1ff8) {
int slot = (address >> 3)&3; int slot = (address >> 3)&3;
rom_ptr_[slot] = rom_.data() + ((address & 7) * 1024); rom_ptr_[slot] = rom_base_ + ((address & 7) * 1024);
} }
if(isReadOperation(operation)) { if(isReadOperation(operation)) {
@ -41,6 +42,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
uint8_t *rom_ptr_[4]; uint8_t *rom_ptr_[4];
}; };
}
} }
#endif /* Atari2600_CartridgeParkerBros_hpp */ #endif /* Atari2600_CartridgeParkerBros_hpp */

View File

@ -10,17 +10,17 @@
#define Atari2600_CartridgePitfall2_hpp #define Atari2600_CartridgePitfall2_hpp
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgePitfall2: public Cartridge<CartridgePitfall2> { class Pitfall2: public BusExtender {
public: public:
CartridgePitfall2(const std::vector<uint8_t> &rom) : Pitfall2(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom), BusExtender(rom_base, rom_size),
rom_ptr_(rom_base),
random_number_generator_(0), random_number_generator_(0),
featcher_address_{0, 0, 0, 0, 0, 0, 0, 0}, featcher_address_{0, 0, 0, 0, 0, 0, 0, 0},
mask_{0, 0, 0, 0, 0, 0, 0, 0}, mask_{0, 0, 0, 0, 0, 0, 0, 0},
cycles_since_audio_update_(0) { cycles_since_audio_update_(0) {}
rom_ptr_ = rom_.data();
}
void advance_cycles(int cycles) { void advance_cycles(int cycles) {
cycles_since_audio_update_ += cycles; cycles_since_audio_update_ += cycles;
@ -53,11 +53,11 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
break; break;
case 0x1008: case 0x1009: case 0x100a: case 0x100b: case 0x100c: case 0x100d: case 0x100e: case 0x100f: case 0x1008: case 0x1009: case 0x100a: case 0x100b: case 0x100c: case 0x100d: case 0x100e: case 0x100f:
*value = rom_[8192 + address_for_counter(address & 7)]; *value = rom_base_[8192 + address_for_counter(address & 7)];
break; break;
case 0x1010: case 0x1011: case 0x1012: case 0x1013: case 0x1014: case 0x1015: case 0x1016: case 0x1017: case 0x1010: case 0x1011: case 0x1012: case 0x1013: case 0x1014: case 0x1015: case 0x1016: case 0x1017:
*value = rom_[8192 + address_for_counter(address & 7)] & mask_[address & 7]; *value = rom_base_[8192 + address_for_counter(address & 7)] & mask_[address & 7];
break; break;
#pragma mark - Writes #pragma mark - Writes
@ -81,8 +81,8 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
#pragma mark - Paging #pragma mark - Paging
case 0x1ff8: rom_ptr_ = rom_.data(); break; case 0x1ff8: rom_ptr_ = rom_base_; break;
case 0x1ff9: rom_ptr_ = rom_.data() + 4096; break; case 0x1ff9: rom_ptr_ = rom_base_ + 4096; break;
#pragma mark - Business as usual #pragma mark - Business as usual
@ -128,6 +128,7 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
Cycles cycles_since_audio_update_; Cycles cycles_since_audio_update_;
}; };
}
} }
#endif /* Atari2600_CartridgePitfall2_hpp */ #endif /* Atari2600_CartridgePitfall2_hpp */

View File

@ -12,19 +12,20 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeTigervision: public Cartridge<CartridgeTigervision> { class Tigervision: public BusExtender {
public: public:
CartridgeTigervision(const std::vector<uint8_t> &rom) : Tigervision(uint8_t *rom_base, size_t rom_size) :
Cartridge(rom) { BusExtender(rom_base, rom_size) {
rom_ptr_[0] = rom_.data() + rom_.size() - 4096; rom_ptr_[0] = rom_base + rom_size - 4096;
rom_ptr_[1] = rom_ptr_[0] + 2048; rom_ptr_[1] = rom_ptr_[0] + 2048;
} }
void perform_bus_operation(CPU::MOS6502::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) { if((address&0x1fff) == 0x3f) {
int offset = ((*value) * 2048) & (rom_.size() - 1); int offset = ((*value) * 2048) & (rom_size_ - 1);
rom_ptr_[0] = rom_.data() + offset; rom_ptr_[0] = rom_base_ + offset;
return; return;
} else if((address&0x1000) && isReadOperation(operation)) { } else if((address&0x1000) && isReadOperation(operation)) {
*value = rom_ptr_[(address >> 11)&1][address & 2047]; *value = rom_ptr_[(address >> 11)&1][address & 2047];
@ -35,6 +36,7 @@ class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
uint8_t *rom_ptr_[2]; uint8_t *rom_ptr_[2];
}; };
}
} }
#endif /* Atari2600_CartridgeTigervision_hpp */ #endif /* Atari2600_CartridgeTigervision_hpp */

View File

@ -12,19 +12,20 @@
#include "Cartridge.hpp" #include "Cartridge.hpp"
namespace Atari2600 { namespace Atari2600 {
namespace Cartridge {
class CartridgeUnpaged: public Cartridge<CartridgeUnpaged> { class Unpaged: public BusExtender {
public: public:
CartridgeUnpaged(const std::vector<uint8_t> &rom) : Unpaged(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size) {}
Cartridge(rom) {}
void perform_bus_operation(CPU::MOS6502::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)) { if(isReadOperation(operation) && (address & 0x1000)) {
*value = rom_[address & (rom_.size() - 1)]; *value = rom_base_[address & (rom_size_ - 1)];
} }
} }
}; };
}
} }
#endif /* Atari2600_CartridgeUnpaged_hpp */ #endif /* Atari2600_CartridgeUnpaged_hpp */

View File

@ -13,6 +13,7 @@
using namespace Commodore::C1540; using namespace Commodore::C1540;
Machine::Machine() : Machine::Machine() :
m6502_(*this),
shift_register_(0), shift_register_(0),
Storage::Disk::Controller(1000000, 4, 300), Storage::Disk::Controller(1000000, 4, 300),
serial_port_(new SerialPort), 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) { 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()); set_motor_on(drive_VIA_.get_motor_enabled());
if(drive_VIA_.get_motor_enabled()) // TODO: motor speed up/down if(drive_VIA_.get_motor_enabled()) // TODO: motor speed up/down
Storage::Disk::Controller::run_for(cycles); 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) { void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
// both VIAs are connected to the IRQ line // 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 #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_); drive_VIA_.set_data_input((uint8_t)shift_register_);
bit_window_offset_ = 0; bit_window_offset_ = 0;
if(drive_VIA_.get_should_set_overflow()) { 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 // 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. Provides an emulation of the C1540.
*/ */
class Machine: class Machine:
public CPU::MOS6502::Processor<Machine>, public CPU::MOS6502::BusHandler,
public MOS::MOS6522IRQDelegate::Delegate, public MOS::MOS6522IRQDelegate::Delegate,
public DriveVIA::Delegate, public DriveVIA::Delegate,
public Storage::Disk::Controller { public Storage::Disk::Controller {
@ -152,6 +152,8 @@ class Machine:
void drive_via_did_set_data_density(void *driveVIA, int density); void drive_via_did_set_data_density(void *driveVIA, int density);
private: private:
CPU::MOS6502::Processor<Machine> m6502_;
uint8_t ram_[0x800]; uint8_t ram_[0x800];
uint8_t rom_[0x4000]; uint8_t rom_[0x4000];

View File

@ -17,6 +17,7 @@
using namespace Commodore::Vic20; using namespace Commodore::Vic20;
Machine::Machine() : Machine::Machine() :
m6502_(*this),
rom_(nullptr), rom_(nullptr),
is_running_at_zero_cost_(false), is_running_at_zero_cost_(false),
tape_(new Storage::Tape::BinaryTapePlayer(1022727)), 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 *value = 0x0c; // i.e. NOP abs
} else if(address == 0xf90b) { } 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) { if(x == 0xe) {
Storage::Tape::Commodore::Parser parser; Storage::Tape::Commodore::Parser parser;
std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(tape_->get_tape()); 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 // set tape status, carry and flag
user_basic_memory_[0x90] |= 0x40; 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); 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 // to ensure that execution proceeds to 0xfccf, pretend a NOP was here and
// ensure that the PC leaps to 0xfccf // 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 *value = 0xea; // i.e. NOP implied
} }
} }
@ -194,11 +195,15 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
return Cycles(1); return Cycles(1);
} }
void Machine::run_for(const Cycles cycles) {
m6502_.run_for(cycles);
}
#pragma mark - 6522 delegate #pragma mark - 6522 delegate
void Machine::mos6522_did_change_interrupt_status(void *mos6522) { void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
set_nmi_line(user_port_via_->get_interrupt_line()); m6502_.set_nmi_line(user_port_via_->get_interrupt_line());
set_irq_line(keyboard_via_->get_interrupt_line()); m6502_.set_irq_line(keyboard_via_->get_interrupt_line());
} }
#pragma mark - Setup #pragma mark - Setup

View File

@ -139,7 +139,7 @@ class Vic6560: public MOS::MOS6560<Vic6560> {
}; };
class Machine: class Machine:
public CPU::MOS6502::Processor<Machine>, public CPU::MOS6502::BusHandler,
public CRTMachine::Machine, public CRTMachine::Machine,
public MOS::MOS6522IRQDelegate::Delegate, public MOS::MOS6522IRQDelegate::Delegate,
public Utility::TypeRecipient, public Utility::TypeRecipient,
@ -174,7 +174,7 @@ class Machine:
virtual void close_output(); virtual void close_output();
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return mos6560_->get_crt(); } 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 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 // to satisfy MOS::MOS6522::Delegate
virtual void mos6522_did_change_interrupt_status(void *mos6522); 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); virtual void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape);
private: private:
CPU::MOS6502::Processor<Machine> m6502_;
uint8_t character_rom_[0x1000]; uint8_t character_rom_[0x1000];
uint8_t basic_rom_[0x2000]; uint8_t basic_rom_[0x2000];
uint8_t kernel_rom_[0x2000]; uint8_t kernel_rom_[0x2000];

View File

@ -15,6 +15,7 @@ using namespace Electron;
#pragma mark - Lifecycle #pragma mark - Lifecycle
Machine::Machine() : Machine::Machine() :
m6502_(*this),
interrupt_control_(0), interrupt_control_(0),
interrupt_status_(Interrupt::PowerOnReset | Interrupt::TransmitDataEmpty | 0x80), interrupt_status_(Interrupt::PowerOnReset | Interrupt::TransmitDataEmpty | 0x80),
cycles_since_audio_update_(0), cycles_since_audio_update_(0),
@ -61,7 +62,7 @@ void Machine::clear_all_keys() {
void Machine::set_key_state(uint16_t key, bool isPressed) { void Machine::set_key_state(uint16_t key, bool isPressed) {
if(key == KeyBreak) { if(key == KeyBreak) {
set_reset_line(isPressed); m6502_.set_reset_line(isPressed);
} else { } else {
if(isPressed) if(isPressed)
key_states_[key >> 4] |= key&0xf; 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. // 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(address == 0xf0a8) {
if(!ram_[0x247] && service_call == 14) { if(!ram_[0x247] && service_call == 14) {
tape_.set_delegate(nullptr); tape_.set_delegate(nullptr);
@ -291,8 +292,8 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
interrupt_status_ |= tape_.get_interrupt_status(); interrupt_status_ |= tape_.get_interrupt_status();
fast_load_is_in_data_ = true; fast_load_is_in_data_ = true;
set_value_of_register(CPU::MOS6502::Register::A, 0); m6502_.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::Y, tape_.get_data_register());
*value = 0x60; // 0x60 is RTS *value = 0x60; // 0x60 is RTS
} }
else *value = os_[address & 16383]; else *value = os_[address & 16383];
@ -340,7 +341,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
shift_restart_counter_ -= cycles; shift_restart_counter_ -= cycles;
if(shift_restart_counter_ <= 0) { if(shift_restart_counter_ <= 0) {
shift_restart_counter_ = 0; shift_restart_counter_ = 0;
set_power_on(true); m6502_.set_power_on(true);
set_key_state(KeyShift, true); set_key_state(KeyShift, true);
is_holding_shift_ = true; is_holding_shift_ = true;
} }
@ -355,6 +356,10 @@ void Machine::flush() {
speaker_->flush(); speaker_->flush();
} }
void Machine::run_for(const Cycles cycles) {
m6502_.run_for(cycles);
}
#pragma mark - Deferred scheduling #pragma mark - Deferred scheduling
inline void Machine::update_display() { inline void Machine::update_display() {
@ -393,7 +398,7 @@ inline void Machine::evaluate_interrupts() {
} else { } else {
interrupt_status_ &= ~1; interrupt_status_ &= ~1;
} }
set_irq_line(interrupt_status_ & 1); m6502_.set_irq_line(interrupt_status_ & 1);
} }
#pragma mark - Tape::Delegate #pragma mark - Tape::Delegate
@ -406,7 +411,7 @@ void Machine::tape_did_change_interrupt_status(Tape *tape) {
#pragma mark - Typer timing #pragma mark - Typer timing
HalfCycles Electron::Machine::get_typer_delay() { 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() { HalfCycles Electron::Machine::get_typer_frequency() {

View File

@ -67,7 +67,7 @@ enum Key: uint16_t {
Acorn Electron. Acorn Electron.
*/ */
class Machine: class Machine:
public CPU::MOS6502::Processor<Machine>, public CPU::MOS6502::BusHandler,
public CRTMachine::Machine, public CRTMachine::Machine,
public Tape::Delegate, public Tape::Delegate,
public Utility::TypeRecipient, public Utility::TypeRecipient,
@ -95,7 +95,7 @@ class Machine:
virtual void close_output(); virtual void close_output();
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt(); virtual std::shared_ptr<Outputs::CRT::CRT> get_crt();
virtual std::shared_ptr<Outputs::Speaker> get_speaker(); 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 // to satisfy Tape::Delegate
virtual void tape_did_change_interrupt_status(Tape *tape); virtual void tape_did_change_interrupt_status(Tape *tape);
@ -114,6 +114,8 @@ class Machine:
inline void clear_interrupt(Interrupt interrupt); inline void clear_interrupt(Interrupt interrupt);
inline void evaluate_interrupts(); inline void evaluate_interrupts();
CPU::MOS6502::Processor<Machine> m6502_;
// Things that directly constitute the memory map. // Things that directly constitute the memory map.
uint8_t roms_[16][16384]; uint8_t roms_[16][16384];
bool rom_write_masks_[16]; bool rom_write_masks_[16];

View File

@ -16,6 +16,7 @@
using namespace Oric; using namespace Oric;
Machine::Machine() : Machine::Machine() :
m6502_(*this),
use_fast_tape_hack_(false), use_fast_tape_hack_(false),
typer_delay_(2500000), typer_delay_(2500000),
keyboard_read_count_(0), 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 // 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()) { 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_]); uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
set_value_of_register(CPU::MOS6502::A, next_byte); m6502_.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::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
*value = 0x60; // i.e. RTS *value = 0x60; // i.e. RTS
} }
} else { } else {
@ -171,7 +172,7 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
void Machine::set_key_state(uint16_t key, bool isPressed) { void Machine::set_key_state(uint16_t key, bool isPressed) {
if(key == KeyNMI) { if(key == KeyNMI) {
set_nmi_line(isPressed); m6502_.set_nmi_line(isPressed);
} else { } else {
if(isPressed) if(isPressed)
keyboard_->rows[key >> 8] |= (key & 0xff); 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) { void Machine::run_for(const Cycles cycles) {
CPU::MOS6502::Processor<Machine>::run_for(cycles); m6502_.run_for(cycles);
} }
#pragma mark - The 6522 #pragma mark - The 6522
@ -287,7 +288,7 @@ void Machine::wd1770_did_change_output(WD::WD1770 *wd1770) {
} }
void Machine::set_interrupt_line() { void Machine::set_interrupt_line() {
set_irq_line( m6502_.set_irq_line(
via_.get_interrupt_line() || via_.get_interrupt_line() ||
(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line())); (microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
} }

View File

@ -55,7 +55,7 @@ enum ROM {
}; };
class Machine: class Machine:
public CPU::MOS6502::Processor<Machine>, public CPU::MOS6502::BusHandler,
public CRTMachine::Machine, public CRTMachine::Machine,
public ConfigurationTarget::Machine, public ConfigurationTarget::Machine,
public MOS::MOS6522IRQDelegate::Delegate, public MOS::MOS6522IRQDelegate::Delegate,
@ -101,6 +101,8 @@ class Machine:
void wd1770_did_change_output(WD::WD1770 *wd1770); void wd1770_did_change_output(WD::WD1770 *wd1770);
private: private:
CPU::MOS6502::Processor<Machine> m6502_;
// RAM and ROM // RAM and ROM
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_; std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
uint8_t ram_[65536], rom_[16384]; uint8_t ram_[65536], rom_[16384];

View File

@ -1036,19 +1036,19 @@
4BEA52651DF3472B007E74F2 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Speaker.hpp; sourceTree = "<group>"; }; 4BEA52651DF3472B007E74F2 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Speaker.hpp; sourceTree = "<group>"; };
4BEA52671DF34909007E74F2 /* PIA.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PIA.hpp; sourceTree = "<group>"; }; 4BEA52671DF34909007E74F2 /* PIA.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PIA.hpp; sourceTree = "<group>"; };
4BEAC0811E7E0DF800EE56B2 /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; }; 4BEAC0811E7E0DF800EE56B2 /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
4BEAC0821E7E0DF800EE56B2 /* CartridgeActivisionStack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeActivisionStack.hpp; sourceTree = "<group>"; }; 4BEAC0821E7E0DF800EE56B2 /* ActivisionStack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ActivisionStack.hpp; sourceTree = "<group>"; };
4BEAC0831E7E0DF800EE56B2 /* CartridgeAtari16k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeAtari16k.hpp; sourceTree = "<group>"; }; 4BEAC0831E7E0DF800EE56B2 /* Atari16k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari16k.hpp; sourceTree = "<group>"; };
4BEAC0841E7E0DF800EE56B2 /* CartridgeAtari32k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeAtari32k.hpp; sourceTree = "<group>"; }; 4BEAC0841E7E0DF800EE56B2 /* Atari32k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari32k.hpp; sourceTree = "<group>"; };
4BEAC0851E7E0DF800EE56B2 /* CartridgeAtari8k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeAtari8k.hpp; sourceTree = "<group>"; }; 4BEAC0851E7E0DF800EE56B2 /* Atari8k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari8k.hpp; sourceTree = "<group>"; };
4BEAC0861E7E0DF800EE56B2 /* CartridgeCBSRAMPlus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeCBSRAMPlus.hpp; sourceTree = "<group>"; }; 4BEAC0861E7E0DF800EE56B2 /* CBSRAMPlus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CBSRAMPlus.hpp; sourceTree = "<group>"; };
4BEAC0871E7E0DF800EE56B2 /* CartridgeCommaVid.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeCommaVid.hpp; sourceTree = "<group>"; }; 4BEAC0871E7E0DF800EE56B2 /* CommaVid.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CommaVid.hpp; sourceTree = "<group>"; };
4BEAC0881E7E0DF800EE56B2 /* CartridgeMegaBoy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeMegaBoy.hpp; sourceTree = "<group>"; }; 4BEAC0881E7E0DF800EE56B2 /* MegaBoy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MegaBoy.hpp; sourceTree = "<group>"; };
4BEAC0891E7E0DF800EE56B2 /* CartridgeMNetwork.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeMNetwork.hpp; sourceTree = "<group>"; }; 4BEAC0891E7E0DF800EE56B2 /* MNetwork.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MNetwork.hpp; sourceTree = "<group>"; };
4BEAC08A1E7E0DF800EE56B2 /* CartridgeParkerBros.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeParkerBros.hpp; sourceTree = "<group>"; }; 4BEAC08A1E7E0DF800EE56B2 /* ParkerBros.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkerBros.hpp; sourceTree = "<group>"; };
4BEAC08B1E7E0DF800EE56B2 /* CartridgeTigervision.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeTigervision.hpp; sourceTree = "<group>"; }; 4BEAC08B1E7E0DF800EE56B2 /* Tigervision.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Tigervision.hpp; sourceTree = "<group>"; };
4BEAC08C1E7E0DF800EE56B2 /* CartridgeUnpaged.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeUnpaged.hpp; sourceTree = "<group>"; }; 4BEAC08C1E7E0DF800EE56B2 /* Unpaged.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Unpaged.hpp; sourceTree = "<group>"; };
4BEAC08D1E7E0E1A00EE56B2 /* Bus.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Bus.hpp; sourceTree = "<group>"; }; 4BEAC08D1E7E0E1A00EE56B2 /* Bus.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Bus.hpp; sourceTree = "<group>"; };
4BEAC08E1E7E110500EE56B2 /* CartridgePitfall2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CartridgePitfall2.hpp; sourceTree = "<group>"; }; 4BEAC08E1E7E110500EE56B2 /* Pitfall2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pitfall2.hpp; sourceTree = "<group>"; };
4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = "<group>"; }; 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = "<group>"; };
4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; }; 4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = "<group>"; }; 4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = "<group>"; };
@ -2216,18 +2216,18 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4BEAC0811E7E0DF800EE56B2 /* Cartridge.hpp */, 4BEAC0811E7E0DF800EE56B2 /* Cartridge.hpp */,
4BEAC0821E7E0DF800EE56B2 /* CartridgeActivisionStack.hpp */, 4BEAC0821E7E0DF800EE56B2 /* ActivisionStack.hpp */,
4BEAC0831E7E0DF800EE56B2 /* CartridgeAtari16k.hpp */, 4BEAC0851E7E0DF800EE56B2 /* Atari8k.hpp */,
4BEAC0841E7E0DF800EE56B2 /* CartridgeAtari32k.hpp */, 4BEAC0831E7E0DF800EE56B2 /* Atari16k.hpp */,
4BEAC0851E7E0DF800EE56B2 /* CartridgeAtari8k.hpp */, 4BEAC0841E7E0DF800EE56B2 /* Atari32k.hpp */,
4BEAC0861E7E0DF800EE56B2 /* CartridgeCBSRAMPlus.hpp */, 4BEAC0861E7E0DF800EE56B2 /* CBSRAMPlus.hpp */,
4BEAC0871E7E0DF800EE56B2 /* CartridgeCommaVid.hpp */, 4BEAC0871E7E0DF800EE56B2 /* CommaVid.hpp */,
4BEAC0881E7E0DF800EE56B2 /* CartridgeMegaBoy.hpp */, 4BEAC0881E7E0DF800EE56B2 /* MegaBoy.hpp */,
4BEAC0891E7E0DF800EE56B2 /* CartridgeMNetwork.hpp */, 4BEAC0891E7E0DF800EE56B2 /* MNetwork.hpp */,
4BEAC08A1E7E0DF800EE56B2 /* CartridgeParkerBros.hpp */, 4BEAC08A1E7E0DF800EE56B2 /* ParkerBros.hpp */,
4BEAC08B1E7E0DF800EE56B2 /* CartridgeTigervision.hpp */, 4BEAC08E1E7E110500EE56B2 /* Pitfall2.hpp */,
4BEAC08C1E7E0DF800EE56B2 /* CartridgeUnpaged.hpp */, 4BEAC08B1E7E0DF800EE56B2 /* Tigervision.hpp */,
4BEAC08E1E7E110500EE56B2 /* CartridgePitfall2.hpp */, 4BEAC08C1E7E0DF800EE56B2 /* Unpaged.hpp */,
); );
path = Cartridges; path = Cartridges;
sourceTree = "<group>"; sourceTree = "<group>";

View File

@ -117,6 +117,14 @@ class ProcessorBase {
static const MicroOp operations[256][10]; 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. @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 { template <class T> class Processor: public ProcessorBase {
private: private:
T &bus_handler_;
const MicroOp *scheduled_program_counter_; const MicroOp *scheduled_program_counter_;
/* /*
@ -261,8 +270,11 @@ template <class T> class Processor: public ProcessorBase {
return reset; return reset;
} }
protected: public:
Processor() : /*!
Constructs an instance of the 6502 that will use @c bus_handler for all bus communications.
*/
Processor(T &bus_handler) :
is_jammed_(false), is_jammed_(false),
ready_line_is_enabled_(false), ready_line_is_enabled_(false),
ready_is_active_(false), ready_is_active_(false),
@ -274,7 +286,8 @@ template <class T> class Processor: public ProcessorBase {
irq_line_(0), irq_line_(0),
nmi_line_is_enabled_(false), nmi_line_is_enabled_(false),
set_overflow_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 // 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 // mask the other flags so we need to do that, at least
carry_flag_ &= Flag::Carry; carry_flag_ &= Flag::Carry;
@ -282,7 +295,6 @@ template <class T> class Processor: public ProcessorBase {
overflow_flag_ &= Flag::Overflow; overflow_flag_ &= Flag::Overflow;
} }
public:
/*! /*!
Runs the 6502 for a supplied number of cycles. Runs the 6502 for a supplied number of cycles.
@ -334,7 +346,7 @@ template <class T> class Processor: public ProcessorBase {
#define bus_access() \ #define bus_access() \
interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \ interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \
irq_request_history_ = irq_line_ & inverse_interrupt_flag_; \ 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; \ nextBusOperation = BusOperation::None; \
if(number_of_cycles <= Cycles(0)) break; 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(number_of_cycles > Cycles(0)) {
while (ready_is_active_ && 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_) { if(!ready_is_active_) {
@ -825,16 +837,9 @@ template <class T> class Processor: public ProcessorBase {
bus_address_ = busAddress; bus_address_ = busAddress;
bus_value_ = busValue; 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. Gets the value of a register.
@ -884,8 +889,8 @@ template <class T> class Processor: public ProcessorBase {
*/ */
void return_from_subroutine() { void return_from_subroutine() {
s_++; s_++;
static_cast<T *>(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++; bus_handler_.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.high);
pc_.full++; pc_.full++;
if(is_jammed_) { if(is_jammed_) {