mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +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:
commit
2105597910
@ -10,18 +10,18 @@
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Cartridges/CartridgeAtari8k.hpp"
|
||||
#include "Cartridges/CartridgeAtari16k.hpp"
|
||||
#include "Cartridges/CartridgeAtari32k.hpp"
|
||||
#include "Cartridges/CartridgeActivisionStack.hpp"
|
||||
#include "Cartridges/CartridgeCBSRAMPlus.hpp"
|
||||
#include "Cartridges/CartridgeCommaVid.hpp"
|
||||
#include "Cartridges/CartridgeMegaBoy.hpp"
|
||||
#include "Cartridges/CartridgeMNetwork.hpp"
|
||||
#include "Cartridges/CartridgeParkerBros.hpp"
|
||||
#include "Cartridges/CartridgePitfall2.hpp"
|
||||
#include "Cartridges/CartridgeTigervision.hpp"
|
||||
#include "Cartridges/CartridgeUnpaged.hpp"
|
||||
#include "Cartridges/Atari8k.hpp"
|
||||
#include "Cartridges/Atari16k.hpp"
|
||||
#include "Cartridges/Atari32k.hpp"
|
||||
#include "Cartridges/ActivisionStack.hpp"
|
||||
#include "Cartridges/CBSRAMPlus.hpp"
|
||||
#include "Cartridges/CommaVid.hpp"
|
||||
#include "Cartridges/MegaBoy.hpp"
|
||||
#include "Cartridges/MNetwork.hpp"
|
||||
#include "Cartridges/ParkerBros.hpp"
|
||||
#include "Cartridges/Pitfall2.hpp"
|
||||
#include "Cartridges/Tigervision.hpp"
|
||||
#include "Cartridges/Unpaged.hpp"
|
||||
|
||||
using namespace Atari2600;
|
||||
namespace {
|
||||
@ -83,35 +83,35 @@ void Machine::set_switch_is_enabled(Atari2600Switch input, bool state) {
|
||||
void Machine::configure_as_target(const StaticAnalyser::Target &target) {
|
||||
const std::vector<uint8_t> &rom = target.cartridges.front()->get_segments().front().data;
|
||||
switch(target.atari.paging_model) {
|
||||
case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new CartridgeActivisionStack(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new CartridgeCBSRAMPlus(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new CartridgeCommaVid(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new CartridgeMegaBoy(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new CartridgeMNetwork(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new CartridgeUnpaged(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new CartridgeParkerBros(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new CartridgePitfall2(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new CartridgeTigervision(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::Cartridge<Cartridge::ActivisionStack>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new Cartridge::Cartridge<Cartridge::CBSRAMPlus>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::CommaVid: bus_.reset(new Cartridge::Cartridge<Cartridge::CommaVid>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::MegaBoy: bus_.reset(new Cartridge::Cartridge<Cartridge::MegaBoy>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::MNetwork: bus_.reset(new Cartridge::Cartridge<Cartridge::MNetwork>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::None: bus_.reset(new Cartridge::Cartridge<Cartridge::Unpaged>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::ParkerBros: bus_.reset(new Cartridge::Cartridge<Cartridge::ParkerBros>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::Pitfall2: bus_.reset(new Cartridge::Cartridge<Cartridge::Pitfall2>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::Tigervision: bus_.reset(new Cartridge::Cartridge<Cartridge::Tigervision>(rom)); break;
|
||||
|
||||
case StaticAnalyser::Atari2600PagingModel::Atari8k:
|
||||
if(target.atari.uses_superchip) {
|
||||
bus_.reset(new CartridgeAtari8kSuperChip(rom));
|
||||
bus_.reset(new Cartridge::Cartridge<Cartridge::Atari8kSuperChip>(rom));
|
||||
} else {
|
||||
bus_.reset(new CartridgeAtari8k(rom));
|
||||
bus_.reset(new Cartridge::Cartridge<Cartridge::Atari8k>(rom));
|
||||
}
|
||||
break;
|
||||
case StaticAnalyser::Atari2600PagingModel::Atari16k:
|
||||
if(target.atari.uses_superchip) {
|
||||
bus_.reset(new CartridgeAtari16kSuperChip(rom));
|
||||
bus_.reset(new Cartridge::Cartridge<Cartridge::Atari16kSuperChip>(rom));
|
||||
} else {
|
||||
bus_.reset(new CartridgeAtari16k(rom));
|
||||
bus_.reset(new Cartridge::Cartridge<Cartridge::Atari16k>(rom));
|
||||
}
|
||||
break;
|
||||
case StaticAnalyser::Atari2600PagingModel::Atari32k:
|
||||
if(target.atari.uses_superchip) {
|
||||
bus_.reset(new CartridgeAtari32kSuperChip(rom));
|
||||
bus_.reset(new Cartridge::Cartridge<Cartridge::Atari32kSuperChip>(rom));
|
||||
} else {
|
||||
bus_.reset(new CartridgeAtari32k(rom));
|
||||
bus_.reset(new Cartridge::Cartridge<Cartridge::Atari32k>(rom));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -6,18 +6,18 @@
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Atari2600_CartridgeActivisionStack_hpp
|
||||
#define Atari2600_CartridgeActivisionStack_hpp
|
||||
#ifndef Atari2600_ActivisionStack_hpp
|
||||
#define Atari2600_ActivisionStack_hpp
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
class ActivisionStack: public BusExtender {
|
||||
public:
|
||||
CartridgeActivisionStack(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom),
|
||||
last_opcode_(0x00) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
ActivisionStack(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size),
|
||||
rom_ptr_(rom_base),
|
||||
last_opcode_(0x00) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(!(address & 0x1000)) return;
|
||||
@ -27,9 +27,9 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
// RST or JSR.
|
||||
if(operation == CPU::MOS6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) {
|
||||
if(address & 0x2000) {
|
||||
rom_ptr_ = rom_.data();
|
||||
rom_ptr_ = rom_base_;
|
||||
} else {
|
||||
rom_ptr_ = rom_.data() + 4096;
|
||||
rom_ptr_ = rom_base_ + 4096;
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
uint8_t last_opcode_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeActivisionStack_hpp */
|
@ -12,19 +12,19 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> {
|
||||
class Atari16k: public BusExtender {
|
||||
public:
|
||||
CartridgeAtari16k(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
Atari16k(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size),
|
||||
rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
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)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -35,18 +35,17 @@ class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> {
|
||||
uint8_t *rom_ptr_;
|
||||
};
|
||||
|
||||
class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> {
|
||||
class Atari16kSuperChip: public BusExtender {
|
||||
public:
|
||||
CartridgeAtari16kSuperChip(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
Atari16kSuperChip(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size),
|
||||
rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
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)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -61,6 +60,7 @@ class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> {
|
||||
uint8_t ram_[128];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeAtari16k_hpp */
|
@ -12,19 +12,17 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> {
|
||||
class Atari32k: public BusExtender {
|
||||
public:
|
||||
CartridgeAtari32k(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
Atari32k(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
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)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -35,18 +33,15 @@ class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> {
|
||||
uint8_t *rom_ptr_;
|
||||
};
|
||||
|
||||
class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> {
|
||||
class Atari32kSuperChip: public BusExtender {
|
||||
public:
|
||||
CartridgeAtari32kSuperChip(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
Atari32kSuperChip(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
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)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -61,6 +56,7 @@ class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> {
|
||||
uint8_t ram_[128];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeAtari32k_hpp */
|
@ -12,20 +12,18 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> {
|
||||
class Atari8k: public BusExtender {
|
||||
public:
|
||||
CartridgeAtari8k(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
Atari8k(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
if(address == 0x1ff8) rom_ptr_ = rom_.data();
|
||||
else if(address == 0x1ff9) rom_ptr_ = rom_.data() + 4096;
|
||||
if(address == 0x1ff8) rom_ptr_ = rom_base_;
|
||||
else if(address == 0x1ff9) rom_ptr_ = rom_base_ + 4096;
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -36,19 +34,16 @@ class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> {
|
||||
uint8_t *rom_ptr_;
|
||||
};
|
||||
|
||||
class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> {
|
||||
class Atari8kSuperChip: public BusExtender {
|
||||
public:
|
||||
CartridgeAtari8kSuperChip(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
Atari8kSuperChip(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
if(address == 0x1ff8) rom_ptr_ = rom_.data();
|
||||
if(address == 0x1ff9) rom_ptr_ = rom_.data() + 4096;
|
||||
if(address == 0x1ff8) rom_ptr_ = rom_base_;
|
||||
if(address == 0x1ff9) rom_ptr_ = rom_base_ + 4096;
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -63,6 +58,7 @@ class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> {
|
||||
uint8_t ram_[128];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeAtari8k_hpp */
|
@ -12,19 +12,17 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
|
||||
class CBSRAMPlus: public BusExtender {
|
||||
public:
|
||||
CartridgeCBSRAMPlus(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
CBSRAMPlus(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size), rom_ptr_(rom_base) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
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)) {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
@ -39,6 +37,7 @@ class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
|
||||
uint8_t ram_[256];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeCBSRAMPlus_hpp */
|
@ -13,18 +13,34 @@
|
||||
#include "../Bus.hpp"
|
||||
|
||||
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:
|
||||
public CPU::MOS6502::Processor<Cartridge<T>>,
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public Bus {
|
||||
|
||||
public:
|
||||
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 set_reset_line(bool state) { CPU::MOS6502::Processor<Cartridge<T>>::set_reset_line(state); }
|
||||
void advance_cycles(int cycles) {}
|
||||
void run_for(const Cycles cycles) { m6502_.run_for(cycles); }
|
||||
void set_reset_line(bool state) { m6502_.set_reset_line(state); }
|
||||
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
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_video_update_ += Cycles(cycles_run_for);
|
||||
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) {
|
||||
// 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
|
||||
if((address&0x1280) == 0x80) {
|
||||
@ -91,7 +107,7 @@ template<class T> class Cartridge:
|
||||
case 0x00: update_video(); tia_->set_sync(*value & 0x02); break;
|
||||
case 0x01: update_video(); tia_->set_blank(*value & 0x02); break;
|
||||
|
||||
case 0x02: CPU::MOS6502::Processor<Cartridge<T>>::set_ready_line(true); break;
|
||||
case 0x02: m6502_.set_ready_line(true); break;
|
||||
case 0x03: update_video(); tia_->reset_horizontal_counter(); break;
|
||||
// TODO: audio will now be out of synchronisation — fix
|
||||
|
||||
@ -156,7 +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);
|
||||
}
|
||||
@ -168,9 +184,14 @@ template<class T> class Cartridge:
|
||||
}
|
||||
|
||||
protected:
|
||||
CPU::MOS6502::Processor<Cartridge<T>> m6502_;
|
||||
std::vector<uint8_t> rom_;
|
||||
|
||||
private:
|
||||
T bus_extender_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_Cartridge_hpp */
|
||||
|
@ -9,12 +9,14 @@
|
||||
#ifndef 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:
|
||||
CartridgeCommaVid(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {}
|
||||
CommaVid(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size) {}
|
||||
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(!(address & 0x1000)) return;
|
||||
@ -30,13 +32,14 @@ class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> {
|
||||
return;
|
||||
}
|
||||
|
||||
if(isReadOperation(operation)) *value = rom_[address & 2047];
|
||||
if(isReadOperation(operation)) *value = rom_base_[address & 2047];
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t ram_[1024];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeCommaVid_hpp */
|
@ -12,12 +12,13 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
class MNetwork: public BusExtender {
|
||||
public:
|
||||
CartridgeMNetwork(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_[0] = rom_.data() + rom_.size() - 4096;
|
||||
MNetwork(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size) {
|
||||
rom_ptr_[0] = rom_base + rom_size_ - 4096;
|
||||
rom_ptr_[1] = rom_ptr_[0] + 2048;
|
||||
high_ram_ptr_ = high_ram_;
|
||||
}
|
||||
@ -27,7 +28,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
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) {
|
||||
rom_ptr_[0] = nullptr;
|
||||
} else if(address >= 0x1ff8 && address <= 0x1ffb) {
|
||||
@ -54,7 +55,6 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
@ -63,6 +63,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
uint8_t low_ram_[1024], high_ram_[1024];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeMNetwork_hpp */
|
@ -12,13 +12,14 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
|
||||
class MegaBoy: public BusExtender {
|
||||
public:
|
||||
CartridgeMegaBoy(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom),
|
||||
MegaBoy(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size),
|
||||
rom_ptr_(rom_base),
|
||||
current_page_(0) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
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) {
|
||||
current_page_ = (current_page_ + 1) & 15;
|
||||
rom_ptr_ = rom_.data() + current_page_ * 4096;
|
||||
rom_ptr_ = rom_base_ + current_page_ * 4096;
|
||||
}
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
@ -40,6 +41,7 @@ class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
|
||||
uint8_t current_page_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CartridgeMegaBoy_h */
|
@ -12,12 +12,13 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
class ParkerBros: public BusExtender {
|
||||
public:
|
||||
CartridgeParkerBros(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_[0] = rom_.data() + 4096;
|
||||
ParkerBros(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size) {
|
||||
rom_ptr_[0] = rom_base + 4096;
|
||||
rom_ptr_[1] = rom_ptr_[0] + 1024;
|
||||
rom_ptr_[2] = rom_ptr_[1] + 1024;
|
||||
rom_ptr_[3] = rom_ptr_[2] + 1024;
|
||||
@ -29,7 +30,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
|
||||
if(address >= 0x1fe0 && address < 0x1ff8) {
|
||||
int slot = (address >> 3)&3;
|
||||
rom_ptr_[slot] = rom_.data() + ((address & 7) * 1024);
|
||||
rom_ptr_[slot] = rom_base_ + ((address & 7) * 1024);
|
||||
}
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
@ -41,6 +42,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
uint8_t *rom_ptr_[4];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeParkerBros_hpp */
|
@ -10,17 +10,17 @@
|
||||
#define Atari2600_CartridgePitfall2_hpp
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
class Pitfall2: public BusExtender {
|
||||
public:
|
||||
CartridgePitfall2(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom),
|
||||
Pitfall2(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size),
|
||||
rom_ptr_(rom_base),
|
||||
random_number_generator_(0),
|
||||
featcher_address_{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
mask_{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
cycles_since_audio_update_(0) {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
cycles_since_audio_update_(0) {}
|
||||
|
||||
void advance_cycles(int cycles) {
|
||||
cycles_since_audio_update_ += cycles;
|
||||
@ -53,11 +53,11 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
#pragma mark - Writes
|
||||
@ -81,8 +81,8 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
|
||||
#pragma mark - Paging
|
||||
|
||||
case 0x1ff8: rom_ptr_ = rom_.data(); break;
|
||||
case 0x1ff9: rom_ptr_ = rom_.data() + 4096; break;
|
||||
case 0x1ff8: rom_ptr_ = rom_base_; break;
|
||||
case 0x1ff9: rom_ptr_ = rom_base_ + 4096; break;
|
||||
|
||||
#pragma mark - Business as usual
|
||||
|
||||
@ -128,6 +128,7 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
Cycles cycles_since_audio_update_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgePitfall2_hpp */
|
@ -12,19 +12,20 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
|
||||
class Tigervision: public BusExtender {
|
||||
public:
|
||||
CartridgeTigervision(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {
|
||||
rom_ptr_[0] = rom_.data() + rom_.size() - 4096;
|
||||
Tigervision(uint8_t *rom_base, size_t rom_size) :
|
||||
BusExtender(rom_base, rom_size) {
|
||||
rom_ptr_[0] = rom_base + rom_size - 4096;
|
||||
rom_ptr_[1] = rom_ptr_[0] + 2048;
|
||||
}
|
||||
|
||||
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;
|
||||
int offset = ((*value) * 2048) & (rom_size_ - 1);
|
||||
rom_ptr_[0] = rom_base_ + offset;
|
||||
return;
|
||||
} else if((address&0x1000) && isReadOperation(operation)) {
|
||||
*value = rom_ptr_[(address >> 11)&1][address & 2047];
|
||||
@ -35,6 +36,7 @@ class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
|
||||
uint8_t *rom_ptr_[2];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeTigervision_hpp */
|
@ -12,19 +12,20 @@
|
||||
#include "Cartridge.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
namespace Cartridge {
|
||||
|
||||
class CartridgeUnpaged: public Cartridge<CartridgeUnpaged> {
|
||||
class Unpaged: public BusExtender {
|
||||
public:
|
||||
CartridgeUnpaged(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {}
|
||||
Unpaged(uint8_t *rom_base, size_t rom_size) : BusExtender(rom_base, rom_size) {}
|
||||
|
||||
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)];
|
||||
*value = rom_base_[address & (rom_size_ - 1)];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Atari2600_CartridgeUnpaged_hpp */
|
@ -13,6 +13,7 @@
|
||||
using namespace Commodore::C1540;
|
||||
|
||||
Machine::Machine() :
|
||||
m6502_(*this),
|
||||
shift_register_(0),
|
||||
Storage::Disk::Controller(1000000, 4, 300),
|
||||
serial_port_(new SerialPort),
|
||||
@ -80,7 +81,7 @@ void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk) {
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
CPU::MOS6502::Processor<Machine>::run_for(cycles);
|
||||
m6502_.run_for(cycles);
|
||||
set_motor_on(drive_VIA_.get_motor_enabled());
|
||||
if(drive_VIA_.get_motor_enabled()) // TODO: motor speed up/down
|
||||
Storage::Disk::Controller::run_for(cycles);
|
||||
@ -90,7 +91,7 @@ void Machine::run_for(const Cycles cycles) {
|
||||
|
||||
void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
|
||||
// both VIAs are connected to the IRQ line
|
||||
set_irq_line(serial_port_VIA_->get_interrupt_line() || drive_VIA_.get_interrupt_line());
|
||||
m6502_.set_irq_line(serial_port_VIA_->get_interrupt_line() || drive_VIA_.get_interrupt_line());
|
||||
}
|
||||
|
||||
#pragma mark - Disk drive
|
||||
@ -108,10 +109,10 @@ void Machine::process_input_bit(int value, unsigned int cycles_since_index_hole)
|
||||
drive_VIA_.set_data_input((uint8_t)shift_register_);
|
||||
bit_window_offset_ = 0;
|
||||
if(drive_VIA_.get_should_set_overflow()) {
|
||||
set_overflow_line(true);
|
||||
m6502_.set_overflow_line(true);
|
||||
}
|
||||
}
|
||||
else set_overflow_line(false);
|
||||
else m6502_.set_overflow_line(false);
|
||||
}
|
||||
|
||||
// the 1540 does not recognise index holes
|
||||
|
@ -120,7 +120,7 @@ class SerialPort : public ::Commodore::Serial::Port {
|
||||
Provides an emulation of the C1540.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public DriveVIA::Delegate,
|
||||
public Storage::Disk::Controller {
|
||||
@ -152,6 +152,8 @@ class Machine:
|
||||
void drive_via_did_set_data_density(void *driveVIA, int density);
|
||||
|
||||
private:
|
||||
CPU::MOS6502::Processor<Machine> m6502_;
|
||||
|
||||
uint8_t ram_[0x800];
|
||||
uint8_t rom_[0x4000];
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
using namespace Commodore::Vic20;
|
||||
|
||||
Machine::Machine() :
|
||||
m6502_(*this),
|
||||
rom_(nullptr),
|
||||
is_running_at_zero_cost_(false),
|
||||
tape_(new Storage::Tape::BinaryTapePlayer(1022727)),
|
||||
@ -138,7 +139,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
|
||||
*value = 0x0c; // i.e. NOP abs
|
||||
} else if(address == 0xf90b) {
|
||||
uint8_t x = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X);
|
||||
uint8_t x = (uint8_t)m6502_.get_value_of_register(CPU::MOS6502::Register::X);
|
||||
if(x == 0xe) {
|
||||
Storage::Tape::Commodore::Parser parser;
|
||||
std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(tape_->get_tape());
|
||||
@ -159,13 +160,13 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
|
||||
// set tape status, carry and flag
|
||||
user_basic_memory_[0x90] |= 0x40;
|
||||
uint8_t flags = (uint8_t)get_value_of_register(CPU::MOS6502::Register::Flags);
|
||||
uint8_t flags = (uint8_t)m6502_.get_value_of_register(CPU::MOS6502::Register::Flags);
|
||||
flags &= ~(uint8_t)(CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Interrupt);
|
||||
set_value_of_register(CPU::MOS6502::Register::Flags, flags);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Register::Flags, flags);
|
||||
|
||||
// to ensure that execution proceeds to 0xfccf, pretend a NOP was here and
|
||||
// ensure that the PC leaps to 0xfccf
|
||||
set_value_of_register(CPU::MOS6502::Register::ProgramCounter, 0xfccf);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Register::ProgramCounter, 0xfccf);
|
||||
*value = 0xea; // i.e. NOP implied
|
||||
}
|
||||
}
|
||||
@ -194,11 +195,15 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
return Cycles(1);
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
#pragma mark - 6522 delegate
|
||||
|
||||
void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
|
||||
set_nmi_line(user_port_via_->get_interrupt_line());
|
||||
set_irq_line(keyboard_via_->get_interrupt_line());
|
||||
m6502_.set_nmi_line(user_port_via_->get_interrupt_line());
|
||||
m6502_.set_irq_line(keyboard_via_->get_interrupt_line());
|
||||
}
|
||||
|
||||
#pragma mark - Setup
|
||||
|
@ -139,7 +139,7 @@ class Vic6560: public MOS::MOS6560<Vic6560> {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public CRTMachine::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
@ -174,7 +174,7 @@ class Machine:
|
||||
virtual void close_output();
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return mos6560_->get_crt(); }
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return mos6560_->get_speaker(); }
|
||||
virtual void run_for(const Cycles cycles) { CPU::MOS6502::Processor<Machine>::run_for(cycles); }
|
||||
virtual void run_for(const Cycles cycles);
|
||||
|
||||
// to satisfy MOS::MOS6522::Delegate
|
||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
@ -187,6 +187,8 @@ class Machine:
|
||||
virtual void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape);
|
||||
|
||||
private:
|
||||
CPU::MOS6502::Processor<Machine> m6502_;
|
||||
|
||||
uint8_t character_rom_[0x1000];
|
||||
uint8_t basic_rom_[0x2000];
|
||||
uint8_t kernel_rom_[0x2000];
|
||||
|
@ -15,6 +15,7 @@ using namespace Electron;
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
Machine::Machine() :
|
||||
m6502_(*this),
|
||||
interrupt_control_(0),
|
||||
interrupt_status_(Interrupt::PowerOnReset | Interrupt::TransmitDataEmpty | 0x80),
|
||||
cycles_since_audio_update_(0),
|
||||
@ -61,7 +62,7 @@ void Machine::clear_all_keys() {
|
||||
|
||||
void Machine::set_key_state(uint16_t key, bool isPressed) {
|
||||
if(key == KeyBreak) {
|
||||
set_reset_line(isPressed);
|
||||
m6502_.set_reset_line(isPressed);
|
||||
} else {
|
||||
if(isPressed)
|
||||
key_states_[key >> 4] |= key&0xf;
|
||||
@ -269,7 +270,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
// allow the PC read to return an RTS.
|
||||
)
|
||||
) {
|
||||
uint8_t service_call = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X);
|
||||
uint8_t service_call = (uint8_t)m6502_.get_value_of_register(CPU::MOS6502::Register::X);
|
||||
if(address == 0xf0a8) {
|
||||
if(!ram_[0x247] && service_call == 14) {
|
||||
tape_.set_delegate(nullptr);
|
||||
@ -291,8 +292,8 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
interrupt_status_ |= tape_.get_interrupt_status();
|
||||
|
||||
fast_load_is_in_data_ = true;
|
||||
set_value_of_register(CPU::MOS6502::Register::A, 0);
|
||||
set_value_of_register(CPU::MOS6502::Register::Y, tape_.get_data_register());
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Register::A, 0);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Register::Y, tape_.get_data_register());
|
||||
*value = 0x60; // 0x60 is RTS
|
||||
}
|
||||
else *value = os_[address & 16383];
|
||||
@ -340,7 +341,7 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
shift_restart_counter_ -= cycles;
|
||||
if(shift_restart_counter_ <= 0) {
|
||||
shift_restart_counter_ = 0;
|
||||
set_power_on(true);
|
||||
m6502_.set_power_on(true);
|
||||
set_key_state(KeyShift, true);
|
||||
is_holding_shift_ = true;
|
||||
}
|
||||
@ -355,6 +356,10 @@ void Machine::flush() {
|
||||
speaker_->flush();
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
#pragma mark - Deferred scheduling
|
||||
|
||||
inline void Machine::update_display() {
|
||||
@ -393,7 +398,7 @@ inline void Machine::evaluate_interrupts() {
|
||||
} else {
|
||||
interrupt_status_ &= ~1;
|
||||
}
|
||||
set_irq_line(interrupt_status_ & 1);
|
||||
m6502_.set_irq_line(interrupt_status_ & 1);
|
||||
}
|
||||
|
||||
#pragma mark - Tape::Delegate
|
||||
@ -406,7 +411,7 @@ void Machine::tape_did_change_interrupt_status(Tape *tape) {
|
||||
#pragma mark - Typer timing
|
||||
|
||||
HalfCycles Electron::Machine::get_typer_delay() {
|
||||
return get_is_resetting() ? Cycles(625*25*128) : Cycles(0); // wait one second if resetting
|
||||
return m6502_.get_is_resetting() ? Cycles(625*25*128) : Cycles(0); // wait one second if resetting
|
||||
}
|
||||
|
||||
HalfCycles Electron::Machine::get_typer_frequency() {
|
||||
|
@ -67,7 +67,7 @@ enum Key: uint16_t {
|
||||
Acorn Electron.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public CRTMachine::Machine,
|
||||
public Tape::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
@ -95,7 +95,7 @@ class Machine:
|
||||
virtual void close_output();
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt();
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker();
|
||||
virtual void run_for(const Cycles cycles) { CPU::MOS6502::Processor<Machine>::run_for(cycles); }
|
||||
virtual void run_for(const Cycles cycles);
|
||||
|
||||
// to satisfy Tape::Delegate
|
||||
virtual void tape_did_change_interrupt_status(Tape *tape);
|
||||
@ -114,6 +114,8 @@ class Machine:
|
||||
inline void clear_interrupt(Interrupt interrupt);
|
||||
inline void evaluate_interrupts();
|
||||
|
||||
CPU::MOS6502::Processor<Machine> m6502_;
|
||||
|
||||
// Things that directly constitute the memory map.
|
||||
uint8_t roms_[16][16384];
|
||||
bool rom_write_masks_[16];
|
||||
|
@ -16,6 +16,7 @@
|
||||
using namespace Oric;
|
||||
|
||||
Machine::Machine() :
|
||||
m6502_(*this),
|
||||
use_fast_tape_hack_(false),
|
||||
typer_delay_(2500000),
|
||||
keyboard_read_count_(0),
|
||||
@ -94,8 +95,8 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
||||
// E6C9 = read byte: return byte in A
|
||||
if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) {
|
||||
uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
|
||||
set_value_of_register(CPU::MOS6502::A, next_byte);
|
||||
set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::A, next_byte);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
|
||||
*value = 0x60; // i.e. RTS
|
||||
}
|
||||
} else {
|
||||
@ -171,7 +172,7 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
|
||||
|
||||
void Machine::set_key_state(uint16_t key, bool isPressed) {
|
||||
if(key == KeyNMI) {
|
||||
set_nmi_line(isPressed);
|
||||
m6502_.set_nmi_line(isPressed);
|
||||
} else {
|
||||
if(isPressed)
|
||||
keyboard_->rows[key >> 8] |= (key & 0xff);
|
||||
@ -206,7 +207,7 @@ std::shared_ptr<Outputs::Speaker> Machine::get_speaker() {
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
CPU::MOS6502::Processor<Machine>::run_for(cycles);
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
#pragma mark - The 6522
|
||||
@ -287,7 +288,7 @@ void Machine::wd1770_did_change_output(WD::WD1770 *wd1770) {
|
||||
}
|
||||
|
||||
void Machine::set_interrupt_line() {
|
||||
set_irq_line(
|
||||
m6502_.set_irq_line(
|
||||
via_.get_interrupt_line() ||
|
||||
(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ enum ROM {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public CRTMachine::Machine,
|
||||
public ConfigurationTarget::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
@ -101,6 +101,8 @@ class Machine:
|
||||
void wd1770_did_change_output(WD::WD1770 *wd1770);
|
||||
|
||||
private:
|
||||
CPU::MOS6502::Processor<Machine> m6502_;
|
||||
|
||||
// RAM and ROM
|
||||
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
|
||||
uint8_t ram_[65536], rom_[16384];
|
||||
|
@ -1036,19 +1036,19 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
4BEAC0831E7E0DF800EE56B2 /* CartridgeAtari16k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeAtari16k.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0841E7E0DF800EE56B2 /* CartridgeAtari32k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeAtari32k.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0851E7E0DF800EE56B2 /* CartridgeAtari8k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeAtari8k.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0861E7E0DF800EE56B2 /* CartridgeCBSRAMPlus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeCBSRAMPlus.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0871E7E0DF800EE56B2 /* CartridgeCommaVid.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeCommaVid.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0881E7E0DF800EE56B2 /* CartridgeMegaBoy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeMegaBoy.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0891E7E0DF800EE56B2 /* CartridgeMNetwork.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeMNetwork.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08A1E7E0DF800EE56B2 /* CartridgeParkerBros.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeParkerBros.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08B1E7E0DF800EE56B2 /* CartridgeTigervision.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeTigervision.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08C1E7E0DF800EE56B2 /* CartridgeUnpaged.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartridgeUnpaged.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0821E7E0DF800EE56B2 /* ActivisionStack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ActivisionStack.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0831E7E0DF800EE56B2 /* Atari16k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari16k.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0841E7E0DF800EE56B2 /* Atari32k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari32k.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0851E7E0DF800EE56B2 /* Atari8k.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari8k.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0861E7E0DF800EE56B2 /* CBSRAMPlus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CBSRAMPlus.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0871E7E0DF800EE56B2 /* CommaVid.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CommaVid.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0881E7E0DF800EE56B2 /* MegaBoy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MegaBoy.hpp; sourceTree = "<group>"; };
|
||||
4BEAC0891E7E0DF800EE56B2 /* MNetwork.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MNetwork.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08A1E7E0DF800EE56B2 /* ParkerBros.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ParkerBros.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08B1E7E0DF800EE56B2 /* Tigervision.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Tigervision.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -2216,18 +2216,18 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BEAC0811E7E0DF800EE56B2 /* Cartridge.hpp */,
|
||||
4BEAC0821E7E0DF800EE56B2 /* CartridgeActivisionStack.hpp */,
|
||||
4BEAC0831E7E0DF800EE56B2 /* CartridgeAtari16k.hpp */,
|
||||
4BEAC0841E7E0DF800EE56B2 /* CartridgeAtari32k.hpp */,
|
||||
4BEAC0851E7E0DF800EE56B2 /* CartridgeAtari8k.hpp */,
|
||||
4BEAC0861E7E0DF800EE56B2 /* CartridgeCBSRAMPlus.hpp */,
|
||||
4BEAC0871E7E0DF800EE56B2 /* CartridgeCommaVid.hpp */,
|
||||
4BEAC0881E7E0DF800EE56B2 /* CartridgeMegaBoy.hpp */,
|
||||
4BEAC0891E7E0DF800EE56B2 /* CartridgeMNetwork.hpp */,
|
||||
4BEAC08A1E7E0DF800EE56B2 /* CartridgeParkerBros.hpp */,
|
||||
4BEAC08B1E7E0DF800EE56B2 /* CartridgeTigervision.hpp */,
|
||||
4BEAC08C1E7E0DF800EE56B2 /* CartridgeUnpaged.hpp */,
|
||||
4BEAC08E1E7E110500EE56B2 /* CartridgePitfall2.hpp */,
|
||||
4BEAC0821E7E0DF800EE56B2 /* ActivisionStack.hpp */,
|
||||
4BEAC0851E7E0DF800EE56B2 /* Atari8k.hpp */,
|
||||
4BEAC0831E7E0DF800EE56B2 /* Atari16k.hpp */,
|
||||
4BEAC0841E7E0DF800EE56B2 /* Atari32k.hpp */,
|
||||
4BEAC0861E7E0DF800EE56B2 /* CBSRAMPlus.hpp */,
|
||||
4BEAC0871E7E0DF800EE56B2 /* CommaVid.hpp */,
|
||||
4BEAC0881E7E0DF800EE56B2 /* MegaBoy.hpp */,
|
||||
4BEAC0891E7E0DF800EE56B2 /* MNetwork.hpp */,
|
||||
4BEAC08A1E7E0DF800EE56B2 /* ParkerBros.hpp */,
|
||||
4BEAC08E1E7E110500EE56B2 /* Pitfall2.hpp */,
|
||||
4BEAC08B1E7E0DF800EE56B2 /* Tigervision.hpp */,
|
||||
4BEAC08C1E7E0DF800EE56B2 /* Unpaged.hpp */,
|
||||
);
|
||||
path = Cartridges;
|
||||
sourceTree = "<group>";
|
||||
|
@ -117,6 +117,14 @@ class ProcessorBase {
|
||||
static const MicroOp operations[256][10];
|
||||
};
|
||||
|
||||
class BusHandler {
|
||||
public:
|
||||
void flush() {}
|
||||
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
return Cycles(0);
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
@abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism.
|
||||
|
||||
@ -130,6 +138,7 @@ class ProcessorBase {
|
||||
*/
|
||||
template <class T> class Processor: public ProcessorBase {
|
||||
private:
|
||||
T &bus_handler_;
|
||||
const MicroOp *scheduled_program_counter_;
|
||||
|
||||
/*
|
||||
@ -261,8 +270,11 @@ template <class T> class Processor: public ProcessorBase {
|
||||
return reset;
|
||||
}
|
||||
|
||||
protected:
|
||||
Processor() :
|
||||
public:
|
||||
/*!
|
||||
Constructs an instance of the 6502 that will use @c bus_handler for all bus communications.
|
||||
*/
|
||||
Processor(T &bus_handler) :
|
||||
is_jammed_(false),
|
||||
ready_line_is_enabled_(false),
|
||||
ready_is_active_(false),
|
||||
@ -274,7 +286,8 @@ template <class T> class Processor: public ProcessorBase {
|
||||
irq_line_(0),
|
||||
nmi_line_is_enabled_(false),
|
||||
set_overflow_line_is_enabled_(false),
|
||||
scheduled_program_counter_(nullptr) {
|
||||
scheduled_program_counter_(nullptr),
|
||||
bus_handler_(bus_handler) {
|
||||
// only the interrupt flag is defined upon reset but get_flags isn't going to
|
||||
// mask the other flags so we need to do that, at least
|
||||
carry_flag_ &= Flag::Carry;
|
||||
@ -282,7 +295,6 @@ template <class T> class Processor: public ProcessorBase {
|
||||
overflow_flag_ &= Flag::Overflow;
|
||||
}
|
||||
|
||||
public:
|
||||
/*!
|
||||
Runs the 6502 for a supplied number of cycles.
|
||||
|
||||
@ -334,7 +346,7 @@ template <class T> class Processor: public ProcessorBase {
|
||||
#define bus_access() \
|
||||
interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \
|
||||
irq_request_history_ = irq_line_ & inverse_interrupt_flag_; \
|
||||
number_of_cycles -= static_cast<T *>(this)->perform_bus_operation(nextBusOperation, busAddress, busValue); \
|
||||
number_of_cycles -= bus_handler_.perform_bus_operation(nextBusOperation, busAddress, busValue); \
|
||||
nextBusOperation = BusOperation::None; \
|
||||
if(number_of_cycles <= Cycles(0)) break;
|
||||
|
||||
@ -344,7 +356,7 @@ template <class T> class Processor: public ProcessorBase {
|
||||
while(number_of_cycles > Cycles(0)) {
|
||||
|
||||
while (ready_is_active_ && number_of_cycles > Cycles(0)) {
|
||||
number_of_cycles -= static_cast<T *>(this)->perform_bus_operation(BusOperation::Ready, busAddress, busValue);
|
||||
number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue);
|
||||
}
|
||||
|
||||
if(!ready_is_active_) {
|
||||
@ -825,16 +837,9 @@ template <class T> class Processor: public ProcessorBase {
|
||||
bus_address_ = busAddress;
|
||||
bus_value_ = busValue;
|
||||
|
||||
static_cast<T *>(this)->flush();
|
||||
bus_handler_.flush();
|
||||
}
|
||||
|
||||
/*!
|
||||
Called to announce the end of a run_for period, allowing deferred work to take place.
|
||||
|
||||
Users of the 6502 template may override this.
|
||||
*/
|
||||
void flush() {}
|
||||
|
||||
/*!
|
||||
Gets the value of a register.
|
||||
|
||||
@ -884,8 +889,8 @@ template <class T> class Processor: public ProcessorBase {
|
||||
*/
|
||||
void return_from_subroutine() {
|
||||
s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high);
|
||||
bus_handler_.perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++;
|
||||
bus_handler_.perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high);
|
||||
pc_.full++;
|
||||
|
||||
if(is_jammed_) {
|
||||
|
Loading…
Reference in New Issue
Block a user