mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge pull request #519 from TomHarte/65C02
Makes an initial pass at 65C02 emulation
This commit is contained in:
commit
f46d52364c
@ -298,7 +298,7 @@ template <bool is_iie> class ConcreteMachine:
|
||||
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::AppleII::Target &target, const ROMMachine::ROMFetcher &rom_fetcher):
|
||||
m6502_(*this),
|
||||
m6502_(CPU::MOS6502::Personality::P6502, *this),
|
||||
video_bus_handler_(ram_, aux_ram_),
|
||||
audio_toggle_(audio_queue_),
|
||||
speaker_(audio_toggle_) {
|
||||
|
@ -32,7 +32,7 @@ template<class T> class Cartridge:
|
||||
|
||||
public:
|
||||
Cartridge(const std::vector<uint8_t> &rom) :
|
||||
m6502_(*this),
|
||||
m6502_(CPU::MOS6502::Personality::P6502, *this),
|
||||
rom_(rom),
|
||||
bus_extender_(rom_.data(), rom.size()) {
|
||||
// The above works because bus_extender_ is declared after rom_ in the instance storage list;
|
||||
|
@ -18,7 +18,7 @@ using namespace Commodore::C1540;
|
||||
|
||||
MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
Storage::Disk::Controller(1000000),
|
||||
m6502_(*this),
|
||||
m6502_(CPU::MOS6502::Personality::P6502, *this),
|
||||
drive_(new Storage::Disk::Drive(1000000, 300, 2)),
|
||||
serial_port_VIA_port_handler_(new SerialPortVIA(serial_port_VIA_)),
|
||||
serial_port_(new SerialPort),
|
||||
|
@ -293,7 +293,7 @@ class ConcreteMachine:
|
||||
public Activity::Source {
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
m6502_(*this),
|
||||
m6502_(CPU::MOS6502::Personality::P6502, *this),
|
||||
user_port_via_port_handler_(new UserPortVIA),
|
||||
keyboard_via_port_handler_(new KeyboardVIA),
|
||||
serial_port_(new SerialPort),
|
||||
|
@ -50,7 +50,7 @@ class ConcreteMachine:
|
||||
public Activity::Source {
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Acorn::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
m6502_(*this),
|
||||
m6502_(CPU::MOS6502::Personality::P6502, *this),
|
||||
sound_generator_(audio_queue_),
|
||||
speaker_(sound_generator_) {
|
||||
memset(key_states_, 0, sizeof(key_states_));
|
||||
|
@ -207,7 +207,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Oric::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
m6502_(*this),
|
||||
m6502_(CPU::MOS6502::Personality::P6502, *this),
|
||||
ay8910_(audio_queue_),
|
||||
speaker_(ay8910_),
|
||||
via_port_handler_(audio_queue_, ay8910_, speaker_, tape_player_, keyboard_),
|
||||
|
@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
4B018B89211930DE002A3937 /* 65C02_extended_opcodes_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */; };
|
||||
4B01A6881F22F0DB001FD6E3 /* Z80MemptrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */; };
|
||||
4B0333AF2094081A0050B93D /* AppleDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0333AD2094081A0050B93D /* AppleDSK.cpp */; };
|
||||
4B0333B02094081A0050B93D /* AppleDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0333AD2094081A0050B93D /* AppleDSK.cpp */; };
|
||||
@ -690,6 +691,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 65C02_extended_opcodes_test.bin; path = "Klaus Dormann/65C02_extended_opcodes_test.bin"; sourceTree = "<group>"; };
|
||||
4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MemptrTests.swift; sourceTree = "<group>"; };
|
||||
4B0333AD2094081A0050B93D /* AppleDSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AppleDSK.cpp; sourceTree = "<group>"; };
|
||||
4B0333AE2094081A0050B93D /* AppleDSK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AppleDSK.hpp; sourceTree = "<group>"; };
|
||||
@ -1545,14 +1547,15 @@
|
||||
4B1414631B588A1100E04248 /* Test Binaries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B98A1CD1FFADEC400ADF63B /* MSX ROMs */,
|
||||
4B9252CD1E74D28200B76AF1 /* Atari ROMs */,
|
||||
4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */,
|
||||
4B98A1CD1FFADEC400ADF63B /* MSX ROMs */,
|
||||
4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */,
|
||||
4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */,
|
||||
4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */,
|
||||
4BE9A6B21EDE294200CBCB47 /* Zexall */,
|
||||
4BBF49B41ED2881600AB3669 /* FUSE */,
|
||||
4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */,
|
||||
4BE9A6B21EDE294200CBCB47 /* Zexall */,
|
||||
);
|
||||
name = "Test Binaries";
|
||||
sourceTree = "<group>";
|
||||
@ -3330,6 +3333,7 @@
|
||||
4BB2998A1B587D8400A49093 /* lseix in Resources */,
|
||||
4BB2994E1B587D8400A49093 /* dexn in Resources */,
|
||||
4BB299971B587D8400A49093 /* nopa in Resources */,
|
||||
4B018B89211930DE002A3937 /* 65C02_extended_opcodes_test.bin in Resources */,
|
||||
4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */,
|
||||
4BB299521B587D8400A49093 /* eoray in Resources */,
|
||||
4BB299411B587D8400A49093 /* cpyb in Resources */,
|
||||
|
@ -15,7 +15,7 @@ class MOS6502InterruptTests: XCTestCase {
|
||||
super.setUp()
|
||||
|
||||
// create a machine full of NOPs
|
||||
machine = CSTestMachine6502()
|
||||
machine = CSTestMachine6502(is65C02: false)
|
||||
for c in 0...65535 {
|
||||
machine.setValue(0xea, forAddress: UInt16(c))
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import XCTest
|
||||
class MOS6502TimingTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
|
||||
private var endTime: UInt32 = 0
|
||||
private let machine = CSTestMachine6502()
|
||||
private let machine = CSTestMachine6502(is65C02: false)
|
||||
|
||||
func testImplied() {
|
||||
let code: [UInt8] = [
|
||||
|
@ -13,7 +13,7 @@ class AllSuiteATests: XCTestCase {
|
||||
func testAllSuiteA() {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "AllSuiteA", ofType: "bin") {
|
||||
if let allSuiteA = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine6502()
|
||||
let machine = CSTestMachine6502(is65C02: false)
|
||||
|
||||
machine.setData(allSuiteA, atAddress: 0x4000)
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0x45c0); // end
|
||||
|
@ -14,7 +14,7 @@ class BCDTest: XCTestCase, CSTestMachineTrapHandler {
|
||||
func testBCD() {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "BCDTEST_beeb", ofType: nil) {
|
||||
if let bcdTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine6502()
|
||||
let machine = CSTestMachine6502(is65C02: false)
|
||||
machine.trapHandler = self
|
||||
|
||||
machine.setData(bcdTest, atAddress: 0x2900)
|
||||
|
@ -32,8 +32,8 @@ class VanillaSerialPort: public Commodore::Serial::Port {
|
||||
_serialBus.reset(new ::Commodore::Serial::Bus);
|
||||
_serialPort.reset(new VanillaSerialPort);
|
||||
|
||||
_c1540.reset(new Commodore::C1540::Machine(Commodore::C1540::Machine::C1540));
|
||||
_c1540->set_rom_fetcher(CSROMFetcher());
|
||||
auto rom_fetcher = CSROMFetcher();
|
||||
_c1540.reset(new Commodore::C1540::Machine(Commodore::C1540::Personality::C1540, rom_fetcher));
|
||||
_c1540->set_serial_bus(_serialBus);
|
||||
Commodore::Serial::AttachPortAndBus(_serialPort, _serialBus);
|
||||
}
|
||||
|
@ -23,7 +23,11 @@ extern const uint8_t CSTestMachine6502JamOpcode;
|
||||
|
||||
@interface CSTestMachine6502 : CSTestMachine
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (nonnull instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (nonnull instancetype)initIs65C02:(BOOL)is65C02;
|
||||
|
||||
- (void)setData:(nonnull NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (void)runForNumberOfCycles:(int)cycles;
|
||||
|
||||
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#import "TestMachine6502.h"
|
||||
#include <stdint.h>
|
||||
#include "6502AllRAM.hpp"
|
||||
#include "../../../../Processors/6502/AllRAM/6502AllRAM.hpp"
|
||||
#import "TestMachine+ForSubclassEyesOnly.h"
|
||||
|
||||
const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode;
|
||||
@ -35,11 +35,12 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init {
|
||||
- (instancetype)initIs65C02:(BOOL)is65C02 {
|
||||
self = [super init];
|
||||
|
||||
if(self) {
|
||||
_processor = CPU::MOS6502::AllRAMProcessor::Processor();
|
||||
_processor = CPU::MOS6502::AllRAMProcessor::Processor(
|
||||
is65C02 ? CPU::MOS6502::Personality::P65C02 : CPU::MOS6502::Personality::P6502);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
Binary file not shown.
@ -11,10 +11,37 @@ import XCTest
|
||||
|
||||
class KlausDormannTests: XCTestCase {
|
||||
|
||||
func testKlausDormann() {
|
||||
fileprivate func runTest(resource: String, is65C02: Bool) -> UInt16 {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: resource, ofType: "bin") {
|
||||
if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine6502(is65C02: is65C02)
|
||||
|
||||
machine.setData(functionalTest, atAddress: 0)
|
||||
machine.setValue(0x400, for: .programCounter)
|
||||
|
||||
while true {
|
||||
let oldPC = machine.value(for: .lastOperationAddress)
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
let newPC = machine.value(for: .lastOperationAddress)
|
||||
|
||||
if newPC == oldPC {
|
||||
machine.runForNumber(ofCycles: 7)
|
||||
|
||||
let retestPC = machine.value(for: .lastOperationAddress)
|
||||
if retestPC == oldPC {
|
||||
return newPC
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/// Runs Klaus Dorman's 6502 tests.
|
||||
func test6502() {
|
||||
func errorForTrapAddress(_ address: UInt16) -> String? {
|
||||
let hexAddress = String(format:"%04x", address)
|
||||
switch address {
|
||||
case 0x3399: return nil // success!
|
||||
|
||||
@ -28,29 +55,63 @@ class KlausDormannTests: XCTestCase {
|
||||
case 0x26d2: return "ASL zpg,x produced incorrect flags"
|
||||
case 0x36c6: return "Unexpected RESET"
|
||||
|
||||
default: return "Unknown error at \(hexAddress)"
|
||||
case 0: return "Didn't find tests"
|
||||
|
||||
default: return "Unknown error at \(String(format:"%04x", address))"
|
||||
}
|
||||
}
|
||||
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "6502_functional_test", ofType: "bin") {
|
||||
if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine6502()
|
||||
let destination = runTest(resource: "6502_functional_test", is65C02: false)
|
||||
let error = errorForTrapAddress(destination)
|
||||
XCTAssert(error == nil, "Failed with error \(error!)")
|
||||
}
|
||||
|
||||
machine.setData(functionalTest, atAddress: 0)
|
||||
machine.setValue(0x400, for: .programCounter)
|
||||
/// Runs Klaus Dorman's 65C02 tests.
|
||||
func test65C02() {
|
||||
func errorForTrapAddress(_ address: UInt16) -> String? {
|
||||
switch address {
|
||||
case 0x24f1: return nil // success!
|
||||
|
||||
while true {
|
||||
let oldPC = machine.value(for: .lastOperationAddress)
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
let newPC = machine.value(for: .lastOperationAddress)
|
||||
case 0x0423: return "PHX: value of X not on stack page"
|
||||
case 0x0428: return "PHX: stack pointer not decremented"
|
||||
case 0x042d: return "PLY: didn't acquire value 0xaa from stack"
|
||||
case 0x0432: return "PLY: didn't acquire value 0x55 from stack"
|
||||
case 0x0437: return "PLY: stack pointer not incremented"
|
||||
case 0x043c: return "PLY: stack pointer not incremented"
|
||||
|
||||
if newPC == oldPC {
|
||||
let error = errorForTrapAddress(oldPC)
|
||||
XCTAssert(error == nil, "Failed with error \(error!)")
|
||||
return
|
||||
}
|
||||
}
|
||||
case 0x066a: return "BRA: branch not taken"
|
||||
case 0x0730: return "BBS: branch not taken"
|
||||
case 0x0733: return "BBR: branch taken"
|
||||
|
||||
case 0x2884: return "JMP (abs) exhibited 6502 page-crossing bug"
|
||||
case 0x16ca: return "JMP (abs, x) failed"
|
||||
|
||||
case 0x2785: return "BRK didn't clear the decimal mode flag"
|
||||
|
||||
case 0x177b: return "INC A didn't function"
|
||||
|
||||
case 0x1834: return "LDA (zp) acted as JAM"
|
||||
case 0x183a: return "STA (zp) acted as JAM"
|
||||
case 0x1849: return "LDA/STA (zp) left flags in incorrect state"
|
||||
|
||||
case 0x1983: return "STZ didn't store zero"
|
||||
|
||||
case 0x1b03: return "BIT didn't set flags correctly"
|
||||
case 0x1c6c: return "BIT immediate didn't set flags correctly"
|
||||
|
||||
case 0x1d88: return "TRB set Z flag incorrectly"
|
||||
case 0x1e7c: return "RMB set flags incorrectly"
|
||||
|
||||
case 0x2245: return "CMP (zero) didn't work"
|
||||
case 0x2506: return "Decimal ADC set flags incorrectly"
|
||||
|
||||
case 0: return "Didn't find tests"
|
||||
default: return "Unknown error at \(String(format:"%04x", address))"
|
||||
}
|
||||
}
|
||||
|
||||
let destination = runTest(resource: "65C02_extended_opcodes_test", is65C02: true)
|
||||
let error = errorForTrapAddress(destination)
|
||||
XCTAssert(error == nil, "Failed with error \(error!)")
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: name, ofType: nil) {
|
||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
|
||||
machine = CSTestMachine6502()
|
||||
machine = CSTestMachine6502(is65C02: false)
|
||||
machine.trapHandler = self
|
||||
// machine.logActivity = true
|
||||
output = ""
|
||||
|
@ -33,6 +33,15 @@ enum Register {
|
||||
S
|
||||
};
|
||||
|
||||
/*
|
||||
The list of 6502 variants supported by this implementation.
|
||||
*/
|
||||
enum Personality {
|
||||
P6502, // the original 6502, replete with various undocumented instructions
|
||||
P65C02, // the 65C02; an extended 6502 with a few extra instructions and addressing modes for existing instructions
|
||||
P65SC02, // like the 65C02, but lacking bit instructions
|
||||
};
|
||||
|
||||
/*
|
||||
Flags as defined on the 6502; can be used to decode the result of @c get_value_of_register(Flags) or to form a value for
|
||||
the corresponding set.
|
||||
@ -110,6 +119,8 @@ class BusHandler {
|
||||
*/
|
||||
class ProcessorBase: public ProcessorStorage {
|
||||
public:
|
||||
ProcessorBase(Personality personality) : ProcessorStorage(personality) {}
|
||||
|
||||
/*!
|
||||
Gets the value of a register.
|
||||
|
||||
@ -193,7 +204,7 @@ template <typename T, bool uses_ready_line> class Processor: public ProcessorBas
|
||||
/*!
|
||||
Constructs an instance of the 6502 that will use @c bus_handler for all bus communications.
|
||||
*/
|
||||
Processor(T &bus_handler) : bus_handler_(bus_handler) {}
|
||||
Processor(Personality personality, T &bus_handler) : ProcessorBase(personality), personality_(personality), bus_handler_(bus_handler) {}
|
||||
|
||||
/*!
|
||||
Runs the 6502 for a supplied number of cycles.
|
||||
@ -210,6 +221,7 @@ template <typename T, bool uses_ready_line> class Processor: public ProcessorBas
|
||||
void set_ready_line(bool active);
|
||||
|
||||
private:
|
||||
Personality personality_;
|
||||
T &bus_handler_;
|
||||
};
|
||||
|
||||
|
@ -17,8 +17,8 @@ namespace {
|
||||
|
||||
class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler {
|
||||
public:
|
||||
ConcreteAllRAMProcessor() :
|
||||
mos6502_(*this) {
|
||||
ConcreteAllRAMProcessor(Personality personality) :
|
||||
mos6502_(personality, *this) {
|
||||
mos6502_.set_power_on(false);
|
||||
}
|
||||
|
||||
@ -68,6 +68,6 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler {
|
||||
|
||||
}
|
||||
|
||||
AllRAMProcessor *AllRAMProcessor::Processor() {
|
||||
return new ConcreteAllRAMProcessor;
|
||||
AllRAMProcessor *AllRAMProcessor::Processor(Personality personality) {
|
||||
return new ConcreteAllRAMProcessor(personality);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class AllRAMProcessor:
|
||||
public ::CPU::AllRAMProcessor {
|
||||
|
||||
public:
|
||||
static AllRAMProcessor *Processor();
|
||||
static AllRAMProcessor *Processor(Personality personality);
|
||||
virtual ~AllRAMProcessor() {}
|
||||
|
||||
virtual void run_for(const Cycles cycles) = 0;
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
template <typename T, bool uses_ready_line> void Processor<T, uses_ready_line>::run_for(const Cycles cycles) {
|
||||
static const MicroOp doBranch[] = {
|
||||
static const MicroOp do_branch[] = {
|
||||
CycleReadFromPC,
|
||||
CycleAddSignedOperandToPC,
|
||||
OperationMoveToNextProgram
|
||||
@ -93,11 +93,25 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
} break;
|
||||
|
||||
case CycleFetchOperand:
|
||||
read_mem(operand_, pc_.full);
|
||||
// This is supposed to produce the 65C02's 1-cycle NOPs; they're
|
||||
// treated as a special case because they break the rule that
|
||||
// governs everything else on the 6502: that two bytes will always
|
||||
// be fetched.
|
||||
if(
|
||||
personality_ == P6502 ||
|
||||
(operation_&7) != 3 ||
|
||||
operation_ == 0xcb ||
|
||||
operation_ == 0xdb
|
||||
) {
|
||||
read_mem(operand_, pc_.full);
|
||||
}
|
||||
break;
|
||||
|
||||
case OperationDecodeOperation:
|
||||
scheduled_program_counter_ = operations[operation_];
|
||||
if(operation_ == 0x89) {
|
||||
printf("");
|
||||
}
|
||||
scheduled_program_counter_ = operations_[operation_];
|
||||
continue;
|
||||
|
||||
case OperationMoveToNextProgram:
|
||||
@ -115,6 +129,8 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case CyclePushPCL: push(pc_.bytes.low); break;
|
||||
case CyclePushOperand: push(operand_); break;
|
||||
case CyclePushA: push(a_); break;
|
||||
case CyclePushX: push(x_); break;
|
||||
case CyclePushY: push(y_); break;
|
||||
case CycleNoWritePush: {
|
||||
uint16_t targetAddress = s_ | 0x100; s_--;
|
||||
read_mem(operand_, targetAddress);
|
||||
@ -135,20 +151,29 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case OperationRSTPickVector: nextAddress.full = 0xfffc; continue;
|
||||
case CycleReadVectorLow: read_mem(pc_.bytes.low, nextAddress.full); break;
|
||||
case CycleReadVectorHigh: read_mem(pc_.bytes.high, nextAddress.full+1); break;
|
||||
case OperationSetI: inverse_interrupt_flag_ = 0; continue;
|
||||
case OperationSetI:
|
||||
inverse_interrupt_flag_ = 0;
|
||||
if(personality_ != P6502) decimal_flag_ = false;
|
||||
continue;
|
||||
|
||||
case CyclePullPCL: s_++; read_mem(pc_.bytes.low, s_ | 0x100); break;
|
||||
case CyclePullPCH: s_++; read_mem(pc_.bytes.high, s_ | 0x100); break;
|
||||
case CyclePullA: s_++; read_mem(a_, s_ | 0x100); break;
|
||||
case CyclePullX: s_++; read_mem(x_, s_ | 0x100); break;
|
||||
case CyclePullY: s_++; read_mem(y_, s_ | 0x100); break;
|
||||
case CyclePullOperand: s_++; read_mem(operand_, s_ | 0x100); break;
|
||||
case OperationSetFlagsFromOperand: set_flags(operand_); continue;
|
||||
case OperationSetOperandFromFlagsWithBRKSet: operand_ = get_flags() | Flag::Break; continue;
|
||||
case OperationSetOperandFromFlags: operand_ = get_flags(); continue;
|
||||
case OperationSetFlagsFromA: zero_result_ = negative_result_ = a_; continue;
|
||||
case OperationSetFlagsFromX: zero_result_ = negative_result_ = x_; continue;
|
||||
case OperationSetFlagsFromY: zero_result_ = negative_result_ = y_; continue;
|
||||
|
||||
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
|
||||
case CycleReadPCLFromAddress: read_mem(pc_.bytes.low, address_.full); break;
|
||||
case CycleReadPCHFromAddress: address_.bytes.low++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
|
||||
case CycleReadPCLFromAddress: read_mem(pc_.bytes.low, address_.full); break;
|
||||
case CycleReadPCHFromAddressLowInc: address_.bytes.low++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressFixed: if(!address_.bytes.low) address_.bytes.high++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressInc: address_.full++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
|
||||
case CycleReadAndIncrementPC: {
|
||||
uint16_t oldPC = pc_.full;
|
||||
@ -160,7 +185,7 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
|
||||
case CycleScheduleJam: {
|
||||
is_jammed_ = true;
|
||||
scheduled_program_counter_ = operations[CPU::MOS6502::JamOpcode];
|
||||
scheduled_program_counter_ = operations_[CPU::MOS6502::JamOpcode];
|
||||
} continue;
|
||||
|
||||
// MARK: - Bitwise
|
||||
@ -179,6 +204,7 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case OperationSTA: operand_ = a_; continue;
|
||||
case OperationSTX: operand_ = x_; continue;
|
||||
case OperationSTY: operand_ = y_; continue;
|
||||
case OperationSTZ: operand_ = 0; continue;
|
||||
case OperationSAX: operand_ = a_ & x_; continue;
|
||||
case OperationSHA: operand_ = a_ & x_ & (address_.bytes.high+1); continue;
|
||||
case OperationSHX: operand_ = x_ & (address_.bytes.high+1); continue;
|
||||
@ -208,13 +234,33 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
carry_flag_ = ((~temp16) >> 8)&1;
|
||||
} continue;
|
||||
|
||||
// MARK: - BIT
|
||||
// MARK: - BIT, TSB, TRB
|
||||
|
||||
case OperationBIT:
|
||||
zero_result_ = operand_ & a_;
|
||||
negative_result_ = operand_;
|
||||
overflow_flag_ = operand_&Flag::Overflow;
|
||||
continue;
|
||||
case OperationBITNoNV:
|
||||
zero_result_ = operand_ & a_;
|
||||
continue;
|
||||
case OperationTRB:
|
||||
zero_result_ = operand_ & a_;
|
||||
operand_ &= ~a_;
|
||||
continue;
|
||||
case OperationTSB:
|
||||
zero_result_ = operand_ & a_;
|
||||
operand_ |= a_;
|
||||
continue;
|
||||
|
||||
// MARK: - RMB and SMB
|
||||
|
||||
case OperationRMB:
|
||||
operand_ &= ~(1 << (operation_ >> 4));
|
||||
continue;
|
||||
case OperationSMB:
|
||||
operand_ |= 1 << ((operation_ >> 4)&7);
|
||||
continue;
|
||||
|
||||
// MARK: - ADC/SBC (and INS)
|
||||
|
||||
@ -239,6 +285,12 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
|
||||
carry_flag_ = (temp16 > 0xff) ? 0 : Flag::Carry;
|
||||
a_ = static_cast<uint8_t>(temp16);
|
||||
|
||||
if(personality_ != P6502) {
|
||||
negative_result_ = zero_result_ = a_;
|
||||
read_mem(operand_, address_.full);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
operand_ = ~operand_;
|
||||
@ -259,6 +311,12 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
carry_flag_ = (result >> 8) ? 1 : 0;
|
||||
a_ = static_cast<uint8_t>(result);
|
||||
zero_result_ = static_cast<uint8_t>(decimalResult);
|
||||
|
||||
if(personality_ != P6502) {
|
||||
negative_result_ = zero_result_ = a_;
|
||||
read_mem(operand_, address_.full);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
const uint16_t result = static_cast<uint16_t>(a_) + static_cast<uint16_t>(operand_) + static_cast<uint16_t>(carry_flag_);
|
||||
overflow_flag_ = (( (result^a_)&(result^operand_) )&0x80) >> 1;
|
||||
@ -345,6 +403,8 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
|
||||
case OperationINC: operand_++; negative_result_ = zero_result_ = operand_; continue;
|
||||
case OperationDEC: operand_--; negative_result_ = zero_result_ = operand_; continue;
|
||||
case OperationINA: a_++; negative_result_ = zero_result_ = a_; continue;
|
||||
case OperationDEA: a_--; negative_result_ = zero_result_ = a_; continue;
|
||||
case OperationINX: x_++; negative_result_ = zero_result_ = x_; continue;
|
||||
case OperationDEX: x_--; negative_result_ = zero_result_ = x_; continue;
|
||||
case OperationINY: y_++; negative_result_ = zero_result_ = y_; continue;
|
||||
@ -405,6 +465,9 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
operand_ += x_;
|
||||
read_mem(address_.bytes.low, operand_);
|
||||
break;
|
||||
case CycleFetchAddressLowFromOperand:
|
||||
read_mem(address_.bytes.low, operand_);
|
||||
break;
|
||||
case CycleIncrementOperandFetchAddressHigh:
|
||||
operand_++;
|
||||
read_mem(address_.bytes.high, operand_);
|
||||
@ -454,7 +517,7 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
|
||||
// MARK: - Branching
|
||||
|
||||
#define BRA(condition) pc_.full++; if(condition) scheduled_program_counter_ = doBranch
|
||||
#define BRA(condition) pc_.full++; if(condition) scheduled_program_counter_ = do_branch
|
||||
|
||||
case OperationBPL: BRA(!(negative_result_&0x80)); continue;
|
||||
case OperationBMI: BRA(negative_result_&0x80); continue;
|
||||
@ -464,6 +527,7 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
case OperationBCS: BRA(carry_flag_); continue;
|
||||
case OperationBNE: BRA(zero_result_); continue;
|
||||
case OperationBEQ: BRA(!zero_result_); continue;
|
||||
case OperationBRA: BRA(true); continue;
|
||||
|
||||
case CycleAddSignedOperandToPC:
|
||||
nextAddress.full = static_cast<uint16_t>(pc_.full + (int8_t)operand_);
|
||||
@ -476,6 +540,39 @@ if(number_of_cycles <= Cycles(0)) break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case CycleFetchFromHalfUpdatedPC: {
|
||||
uint16_t halfUpdatedPc = static_cast<uint16_t>(((pc_.bytes.low + (int8_t)operand_) & 0xff) | (pc_.bytes.high << 8));
|
||||
throwaway_read(halfUpdatedPc);
|
||||
} break;
|
||||
|
||||
case OperationAddSignedOperandToPC16:
|
||||
pc_.full = static_cast<uint16_t>(pc_.full + (int8_t)operand_);
|
||||
continue;
|
||||
|
||||
case OperationBBRBBS: {
|
||||
// To reach here, the 6502 has (i) read the operation; (ii) read the first operand;
|
||||
// and (iii) read from the corresponding zero page.
|
||||
const uint8_t mask = static_cast<uint8_t>(1 << ((operation_ >> 4)&7));
|
||||
if((operand_ & mask) == ((operation_ & 0x80) ? mask : 0)) {
|
||||
static const MicroOp do_branch[] = {
|
||||
CycleFetchOperand, // Fetch offset.
|
||||
OperationIncrementPC,
|
||||
CycleFetchFromHalfUpdatedPC,
|
||||
OperationAddSignedOperandToPC16,
|
||||
OperationMoveToNextProgram
|
||||
};
|
||||
scheduled_program_counter_ = do_branch;
|
||||
} else {
|
||||
static const MicroOp do_not_branch[] = {
|
||||
CycleFetchOperand,
|
||||
OperationIncrementPC,
|
||||
CycleFetchFromHalfUpdatedPC,
|
||||
OperationMoveToNextProgram
|
||||
};
|
||||
scheduled_program_counter_ = do_not_branch;
|
||||
}
|
||||
} break;
|
||||
|
||||
#undef BRA
|
||||
|
||||
// MARK: - Transfers
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "../6502.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace CPU::MOS6502;
|
||||
|
||||
#define Program(...) {__VA_ARGS__, OperationMoveToNextProgram}
|
||||
@ -20,13 +22,14 @@ using namespace CPU::MOS6502;
|
||||
#define Zero OperationLoadAddressZeroPage
|
||||
#define ZeroX CycleLoadAddessZeroX
|
||||
#define ZeroY CycleLoadAddessZeroY
|
||||
#define ZeroIndirect OperationLoadAddressZeroPage, CycleFetchAddressLowFromOperand, CycleIncrementOperandFetchAddressHigh
|
||||
#define IndexedIndirect CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh
|
||||
#define IndirectIndexedr CycleIncrementPCFetchAddressLowFromOperand, CycleIncrementOperandFetchAddressHigh, CycleAddYToAddressLow, OperationCorrectAddressHigh
|
||||
#define IndirectIndexed CycleIncrementPCFetchAddressLowFromOperand, CycleIncrementOperandFetchAddressHigh, CycleAddYToAddressLowRead, OperationCorrectAddressHigh
|
||||
|
||||
#define Read(...) CycleFetchOperandFromAddress, __VA_ARGS__
|
||||
#define Write(...) __VA_ARGS__, CycleWriteOperandToAddress
|
||||
#define ReadModifyWrite(...) CycleFetchOperandFromAddress, CycleWriteOperandToAddress, __VA_ARGS__, CycleWriteOperandToAddress
|
||||
#define ReadModifyWrite(...) CycleFetchOperandFromAddress, (personality == P6502) ? CycleWriteOperandToAddress : CycleFetchOperandFromAddress, __VA_ARGS__, CycleWriteOperandToAddress
|
||||
|
||||
#define AbsoluteRead(op) Program(Absolute, Read(op))
|
||||
#define AbsoluteXRead(op) Program(AbsoluteXr, Read(op))
|
||||
@ -34,6 +37,7 @@ using namespace CPU::MOS6502;
|
||||
#define ZeroRead(...) Program(Zero, Read(__VA_ARGS__))
|
||||
#define ZeroXRead(op) Program(ZeroX, Read(op))
|
||||
#define ZeroYRead(op) Program(ZeroY, Read(op))
|
||||
#define ZeroIndirectRead(op) Program(ZeroIndirect, Read(op))
|
||||
#define IndexedIndirectRead(op) Program(IndexedIndirect, Read(op))
|
||||
#define IndirectIndexedRead(op) Program(IndirectIndexedr, Read(op))
|
||||
|
||||
@ -43,6 +47,7 @@ using namespace CPU::MOS6502;
|
||||
#define ZeroWrite(op) Program(Zero, Write(op))
|
||||
#define ZeroXWrite(op) Program(ZeroX, Write(op))
|
||||
#define ZeroYWrite(op) Program(ZeroY, Write(op))
|
||||
#define ZeroIndirectWrite(op) Program(ZeroIndirect, Write(op))
|
||||
#define IndexedIndirectWrite(op) Program(IndexedIndirect, Write(op))
|
||||
#define IndirectIndexedWrite(op) Program(IndirectIndexed, Write(op))
|
||||
|
||||
@ -67,143 +72,248 @@ using namespace CPU::MOS6502;
|
||||
|
||||
#define JAM {CycleFetchOperand, CycleScheduleJam}
|
||||
|
||||
const ProcessorStorage::MicroOp ProcessorStorage::operations[256][10] = {
|
||||
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetI, CycleReadVectorLow, CycleReadVectorHigh),
|
||||
/* 0x01 ORA x, ind */ IndexedIndirectRead(OperationORA),
|
||||
/* 0x02 JAM */ JAM, /* 0x03 ASO x, ind */ IndexedIndirectReadModifyWrite(OperationASO),
|
||||
/* 0x04 NOP zpg */ ZeroNop(), /* 0x05 ORA zpg */ ZeroRead(OperationORA),
|
||||
/* 0x06 ASL zpg */ ZeroReadModifyWrite(OperationASL), /* 0x07 ASO zpg */ ZeroReadModifyWrite(OperationASO),
|
||||
/* 0x08 PHP */ Program(OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand),
|
||||
/* 0x09 ORA # */ Immediate(OperationORA),
|
||||
/* 0x0a ASL A */ Implied(OperationASL), /* 0x0b ANC # */ Immediate(OperationANC),
|
||||
/* 0x0c NOP abs */ AbsoluteNop(), /* 0x0d ORA abs */ AbsoluteRead(OperationORA),
|
||||
/* 0x0e ASL abs */ AbsoluteReadModifyWrite(OperationASL), /* 0x0f ASO abs */ AbsoluteReadModifyWrite(OperationASO),
|
||||
/* 0x10 BPL */ Program(OperationBPL), /* 0x11 ORA ind, y */ IndirectIndexedRead(OperationORA),
|
||||
/* 0x12 JAM */ JAM, /* 0x13 ASO ind, y */ IndirectIndexedReadModifyWrite(OperationASO),
|
||||
/* 0x14 NOP zpg, x */ ZeroXNop(), /* 0x15 ORA zpg, x */ ZeroXRead(OperationORA),
|
||||
/* 0x16 ASL zpg, x */ ZeroXReadModifyWrite(OperationASL), /* 0x17 ASO zpg, x */ ZeroXReadModifyWrite(OperationASO),
|
||||
/* 0x18 CLC */ Program(OperationCLC), /* 0x19 ORA abs, y */ AbsoluteYRead(OperationORA),
|
||||
/* 0x1a NOP # */ ImpliedNop(), /* 0x1b ASO abs, y */ AbsoluteYReadModifyWrite(OperationASO),
|
||||
/* 0x1c NOP abs, x */ AbsoluteXNop(), /* 0x1d ORA abs, x */ AbsoluteXRead(OperationORA),
|
||||
/* 0x1e ASL abs, x */ AbsoluteXReadModifyWrite(OperationASL), /* 0x1f ASO abs, x */ AbsoluteXReadModifyWrite(OperationASO),
|
||||
/* 0x20 JSR abs */ Program(CycleIncrementPCAndReadStack, CyclePushPCH, CyclePushPCL, CycleReadPCHLoadPCL),
|
||||
/* 0x21 AND x, ind */ IndexedIndirectRead(OperationAND),
|
||||
/* 0x22 JAM */ JAM, /* 0x23 RLA x, ind */ IndexedIndirectReadModifyWrite(OperationRLA),
|
||||
/* 0x24 BIT zpg */ ZeroRead(OperationBIT), /* 0x25 AND zpg */ ZeroRead(OperationAND),
|
||||
/* 0x26 ROL zpg */ ZeroReadModifyWrite(OperationROL), /* 0x27 RLA zpg */ ZeroReadModifyWrite(OperationRLA),
|
||||
/* 0x28 PLP */ Program(CycleReadFromS, CyclePullOperand, OperationSetFlagsFromOperand),
|
||||
/* 0x29 AND A # */ Immediate(OperationAND),
|
||||
/* 0x2a ROL A */ Implied(OperationROL), /* 0x2b ANC # */ Immediate(OperationANC),
|
||||
/* 0x2c BIT abs */ AbsoluteRead(OperationBIT), /* 0x2d AND abs */ AbsoluteRead(OperationAND),
|
||||
/* 0x2e ROL abs */ AbsoluteReadModifyWrite(OperationROL), /* 0x2f RLA abs */ AbsoluteReadModifyWrite(OperationRLA),
|
||||
/* 0x30 BMI */ Program(OperationBMI), /* 0x31 AND ind, y */ IndirectIndexedRead(OperationAND),
|
||||
/* 0x32 JAM */ JAM, /* 0x33 RLA ind, y */ IndirectIndexedReadModifyWrite(OperationRLA),
|
||||
/* 0x34 NOP zpg, x */ ZeroXNop(), /* 0x35 AND zpg, x */ ZeroXRead(OperationAND),
|
||||
/* 0x36 ROL zpg, x */ ZeroXReadModifyWrite(OperationROL), /* 0x37 RLA zpg, x */ ZeroXReadModifyWrite(OperationRLA),
|
||||
/* 0x38 SEC */ Program(OperationSEC), /* 0x39 AND abs, y */ AbsoluteYRead(OperationAND),
|
||||
/* 0x3a NOP # */ ImpliedNop(), /* 0x3b RLA abs, y */ AbsoluteYReadModifyWrite(OperationRLA),
|
||||
/* 0x3c NOP abs, x */ AbsoluteXNop(), /* 0x3d AND abs, x */ AbsoluteXRead(OperationAND),
|
||||
/* 0x3e ROL abs, x */ AbsoluteXReadModifyWrite(OperationROL), /* 0x3f RLA abs, x */ AbsoluteXReadModifyWrite(OperationRLA),
|
||||
/* 0x40 RTI */ Program(CycleReadFromS, CyclePullOperand, OperationSetFlagsFromOperand, CyclePullPCL, CyclePullPCH),
|
||||
/* 0x41 EOR x, ind */ IndexedIndirectRead(OperationEOR),
|
||||
/* 0x42 JAM */ JAM, /* 0x43 LSE x, ind */ IndexedIndirectReadModifyWrite(OperationLSE),
|
||||
/* 0x44 NOP zpg */ ZeroNop(), /* 0x45 EOR zpg */ ZeroRead(OperationEOR),
|
||||
/* 0x46 LSR zpg */ ZeroReadModifyWrite(OperationLSR), /* 0x47 LSE zpg */ ZeroReadModifyWrite(OperationLSE),
|
||||
/* 0x48 PHA */ Program(CyclePushA), /* 0x49 EOR # */ Immediate(OperationEOR),
|
||||
/* 0x4a LSR A */ Implied(OperationLSR), /* 0x4b ASR A */ Immediate(OperationASR),
|
||||
/* 0x4c JMP abs */ Program(CycleIncrementPCReadPCHLoadPCL), /* 0x4d EOR abs */ AbsoluteRead(OperationEOR),
|
||||
/* 0x4e LSR abs */ AbsoluteReadModifyWrite(OperationLSR), /* 0x4f LSE abs */ AbsoluteReadModifyWrite(OperationLSE),
|
||||
/* 0x50 BVC */ Program(OperationBVC), /* 0x51 EOR ind, y */ IndirectIndexedRead(OperationEOR),
|
||||
/* 0x52 JAM */ JAM, /* 0x53 LSE ind, y */ IndirectIndexedReadModifyWrite(OperationLSE),
|
||||
/* 0x54 NOP zpg, x */ ZeroXNop(), /* 0x55 EOR zpg, x */ ZeroXRead(OperationEOR),
|
||||
/* 0x56 LSR zpg, x */ ZeroXReadModifyWrite(OperationLSR), /* 0x57 LSE zpg, x */ ZeroXReadModifyWrite(OperationLSE),
|
||||
/* 0x58 CLI */ Program(OperationCLI), /* 0x59 EOR abs, y */ AbsoluteYRead(OperationEOR),
|
||||
/* 0x5a NOP # */ ImpliedNop(), /* 0x5b LSE abs, y */ AbsoluteYReadModifyWrite(OperationLSE),
|
||||
/* 0x5c NOP abs, x */ AbsoluteXNop(), /* 0x5d EOR abs, x */ AbsoluteXRead(OperationEOR),
|
||||
/* 0x5e LSR abs, x */ AbsoluteXReadModifyWrite(OperationLSR), /* 0x5f LSE abs, x */ AbsoluteXReadModifyWrite(OperationLSE),
|
||||
/* 0x60 RTS */ Program(CycleReadFromS, CyclePullPCL, CyclePullPCH, CycleReadAndIncrementPC),
|
||||
/* 0x61 ADC x, ind */ IndexedIndirectRead(OperationADC),
|
||||
/* 0x62 JAM */ JAM, /* 0x63 RRA x, ind */ IndexedIndirectReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x64 NOP zpg */ ZeroNop(), /* 0x65 ADC zpg */ ZeroRead(OperationADC),
|
||||
/* 0x66 ROR zpg */ ZeroReadModifyWrite(OperationROR), /* 0x67 RRA zpg */ ZeroReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x68 PLA */ Program(CycleReadFromS, CyclePullA, OperationSetFlagsFromA), /* 0x69 ADC # */ Immediate(OperationADC),
|
||||
/* 0x6a ROR A */ Implied(OperationROR), /* 0x6b ARR # */ Immediate(OperationARR),
|
||||
/* 0x6c JMP (abs) */ Program(CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress),
|
||||
/* 0x6d ADC abs */ AbsoluteRead(OperationADC),
|
||||
/* 0x6e ROR abs */ AbsoluteReadModifyWrite(OperationROR), /* 0x6f RRA abs */ AbsoluteReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x70 BVS */ Program(OperationBVS), /* 0x71 ADC ind, y */ IndirectIndexedRead(OperationADC),
|
||||
/* 0x72 JAM */ JAM, /* 0x73 RRA ind, y */ IndirectIndexedReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x74 NOP zpg, x */ ZeroXNop(), /* 0x75 ADC zpg, x */ ZeroXRead(OperationADC),
|
||||
/* 0x76 ROR zpg, x */ ZeroXReadModifyWrite(OperationROR), /* 0x77 RRA zpg, x */ ZeroXReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x78 SEI */ Program(OperationSEI), /* 0x79 ADC abs, y */ AbsoluteYRead(OperationADC),
|
||||
/* 0x7a NOP # */ ImpliedNop(), /* 0x7b RRA abs, y */ AbsoluteYReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x7c NOP abs, x */ AbsoluteXNop(), /* 0x7d ADC abs, x */ AbsoluteXRead(OperationADC),
|
||||
/* 0x7e ROR abs, x */ AbsoluteXReadModifyWrite(OperationROR), /* 0x7f RRA abs, x */ AbsoluteXReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x80 NOP # */ ImmediateNop(), /* 0x81 STA x, ind */ IndexedIndirectWrite(OperationSTA),
|
||||
/* 0x82 NOP # */ ImmediateNop(), /* 0x83 SAX x, ind */ IndexedIndirectWrite(OperationSAX),
|
||||
/* 0x84 STY zpg */ ZeroWrite(OperationSTY), /* 0x85 STA zpg */ ZeroWrite(OperationSTA),
|
||||
/* 0x86 STX zpg */ ZeroWrite(OperationSTX), /* 0x87 SAX zpg */ ZeroWrite(OperationSAX),
|
||||
/* 0x88 DEY */ Program(OperationDEY), /* 0x89 NOP # */ ImmediateNop(),
|
||||
/* 0x8a TXA */ Program(OperationTXA), /* 0x8b ANE # */ Immediate(OperationANE),
|
||||
/* 0x8c STY abs */ AbsoluteWrite(OperationSTY), /* 0x8d STA abs */ AbsoluteWrite(OperationSTA),
|
||||
/* 0x8e STX abs */ AbsoluteWrite(OperationSTX), /* 0x8f SAX abs */ AbsoluteWrite(OperationSAX),
|
||||
/* 0x90 BCC */ Program(OperationBCC), /* 0x91 STA ind, y */ IndirectIndexedWrite(OperationSTA),
|
||||
/* 0x92 JAM */ JAM, /* 0x93 SHA ind, y */ IndirectIndexedWrite(OperationSHA),
|
||||
/* 0x94 STY zpg, x */ ZeroXWrite(OperationSTY), /* 0x95 STA zpg, x */ ZeroXWrite(OperationSTA),
|
||||
/* 0x96 STX zpg, y */ ZeroYWrite(OperationSTX), /* 0x97 SAX zpg, y */ ZeroYWrite(OperationSAX),
|
||||
/* 0x98 TYA */ Program(OperationTYA), /* 0x99 STA abs, y */ AbsoluteYWrite(OperationSTA),
|
||||
/* 0x9a TXS */ Program(OperationTXS), /* 0x9b SHS abs, y */ AbsoluteYWrite(OperationSHS),
|
||||
/* 0x9c SHY abs, x */ AbsoluteXWrite(OperationSHY), /* 0x9d STA abs, x */ AbsoluteXWrite(OperationSTA),
|
||||
/* 0x9e SHX abs, y */ AbsoluteYWrite(OperationSHX), /* 0x9f SHA abs, y */ AbsoluteYWrite(OperationSHA),
|
||||
/* 0xa0 LDY # */ Immediate(OperationLDY), /* 0xa1 LDA x, ind */ IndexedIndirectRead(OperationLDA),
|
||||
/* 0xa2 LDX # */ Immediate(OperationLDX), /* 0xa3 LAX x, ind */ IndexedIndirectRead(OperationLAX),
|
||||
/* 0xa4 LDY zpg */ ZeroRead(OperationLDY), /* 0xa5 LDA zpg */ ZeroRead(OperationLDA),
|
||||
/* 0xa6 LDX zpg */ ZeroRead(OperationLDX), /* 0xa7 LAX zpg */ ZeroRead(OperationLAX),
|
||||
/* 0xa8 TAY */ Program(OperationTAY), /* 0xa9 LDA # */ Immediate(OperationLDA),
|
||||
/* 0xaa TAX */ Program(OperationTAX), /* 0xab LXA # */ Immediate(OperationLXA),
|
||||
/* 0xac LDY abs */ AbsoluteRead(OperationLDY), /* 0xad LDA abs */ AbsoluteRead(OperationLDA),
|
||||
/* 0xae LDX abs */ AbsoluteRead(OperationLDX), /* 0xaf LAX abs */ AbsoluteRead(OperationLAX),
|
||||
/* 0xb0 BCS */ Program(OperationBCS), /* 0xb1 LDA ind, y */ IndirectIndexedRead(OperationLDA),
|
||||
/* 0xb2 JAM */ JAM, /* 0xb3 LAX ind, y */ IndirectIndexedRead(OperationLAX),
|
||||
/* 0xb4 LDY zpg, x */ ZeroXRead(OperationLDY), /* 0xb5 LDA zpg, x */ ZeroXRead(OperationLDA),
|
||||
/* 0xb6 LDX zpg, y */ ZeroYRead(OperationLDX), /* 0xb7 LAX zpg, x */ ZeroYRead(OperationLAX),
|
||||
/* 0xb8 CLV */ Program(OperationCLV), /* 0xb9 LDA abs, y */ AbsoluteYRead(OperationLDA),
|
||||
/* 0xba TSX */ Program(OperationTSX), /* 0xbb LAS abs, y */ AbsoluteYRead(OperationLAS),
|
||||
/* 0xbc LDY abs, x */ AbsoluteXRead(OperationLDY), /* 0xbd LDA abs, x */ AbsoluteXRead(OperationLDA),
|
||||
/* 0xbe LDX abs, y */ AbsoluteYRead(OperationLDX), /* 0xbf LAX abs, y */ AbsoluteYRead(OperationLAX),
|
||||
/* 0xc0 CPY # */ Immediate(OperationCPY), /* 0xc1 CMP x, ind */ IndexedIndirectRead(OperationCMP),
|
||||
/* 0xc2 NOP # */ ImmediateNop(), /* 0xc3 DCP x, ind */ IndexedIndirectReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xc4 CPY zpg */ ZeroRead(OperationCPY), /* 0xc5 CMP zpg */ ZeroRead(OperationCMP),
|
||||
/* 0xc6 DEC zpg */ ZeroReadModifyWrite(OperationDEC), /* 0xc7 DCP zpg */ ZeroReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xc8 INY */ Program(OperationINY), /* 0xc9 CMP # */ Immediate(OperationCMP),
|
||||
/* 0xca DEX */ Program(OperationDEX), /* 0xcb ARR # */ Immediate(OperationSBX),
|
||||
/* 0xcc CPY abs */ AbsoluteRead(OperationCPY), /* 0xcd CMP abs */ AbsoluteRead(OperationCMP),
|
||||
/* 0xce DEC abs */ AbsoluteReadModifyWrite(OperationDEC), /* 0xcf DCP abs */ AbsoluteReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xd0 BNE */ Program(OperationBNE), /* 0xd1 CMP ind, y */ IndirectIndexedRead(OperationCMP),
|
||||
/* 0xd2 JAM */ JAM, /* 0xd3 DCP ind, y */ IndirectIndexedReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xd4 NOP zpg, x */ ZeroXNop(), /* 0xd5 CMP zpg, x */ ZeroXRead(OperationCMP),
|
||||
/* 0xd6 DEC zpg, x */ ZeroXReadModifyWrite(OperationDEC), /* 0xd7 DCP zpg, x */ ZeroXReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xd8 CLD */ Program(OperationCLD), /* 0xd9 CMP abs, y */ AbsoluteYRead(OperationCMP),
|
||||
/* 0xda NOP # */ ImpliedNop(), /* 0xdb DCP abs, y */ AbsoluteYReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xdc NOP abs, x */ AbsoluteXNop(), /* 0xdd CMP abs, x */ AbsoluteXRead(OperationCMP),
|
||||
/* 0xde DEC abs, x */ AbsoluteXReadModifyWrite(OperationDEC), /* 0xdf DCP abs, x */ AbsoluteXReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xe0 CPX # */ Immediate(OperationCPX), /* 0xe1 SBC x, ind */ IndexedIndirectRead(OperationSBC),
|
||||
/* 0xe2 NOP # */ ImmediateNop(), /* 0xe3 INS x, ind */ IndexedIndirectReadModifyWrite(OperationINS),
|
||||
/* 0xe4 CPX zpg */ ZeroRead(OperationCPX), /* 0xe5 SBC zpg */ ZeroRead(OperationSBC),
|
||||
/* 0xe6 INC zpg */ ZeroReadModifyWrite(OperationINC), /* 0xe7 INS zpg */ ZeroReadModifyWrite(OperationINS),
|
||||
/* 0xe8 INX */ Program(OperationINX), /* 0xe9 SBC # */ Immediate(OperationSBC),
|
||||
/* 0xea NOP # */ ImpliedNop(), /* 0xeb SBC # */ Immediate(OperationSBC),
|
||||
/* 0xec CPX abs */ AbsoluteRead(OperationCPX), /* 0xed SBC abs */ AbsoluteRead(OperationSBC),
|
||||
/* 0xee INC abs */ AbsoluteReadModifyWrite(OperationINC), /* 0xef INS abs */ AbsoluteReadModifyWrite(OperationINS),
|
||||
/* 0xf0 BEQ */ Program(OperationBEQ), /* 0xf1 SBC ind, y */ IndirectIndexedRead(OperationSBC),
|
||||
/* 0xf2 JAM */ JAM, /* 0xf3 INS ind, y */ IndirectIndexedReadModifyWrite(OperationINS),
|
||||
/* 0xf4 NOP zpg, x */ ZeroXNop(), /* 0xf5 SBC zpg, x */ ZeroXRead(OperationSBC),
|
||||
/* 0xf6 INC zpg, x */ ZeroXReadModifyWrite(OperationINC), /* 0xf7 INS zpg, x */ ZeroXReadModifyWrite(OperationINS),
|
||||
/* 0xf8 SED */ Program(OperationSED), /* 0xf9 SBC abs, y */ AbsoluteYRead(OperationSBC),
|
||||
/* 0xfa NOP # */ ImpliedNop(), /* 0xfb INS abs, y */ AbsoluteYReadModifyWrite(OperationINS),
|
||||
/* 0xfc NOP abs, x */ AbsoluteXNop(), /* 0xfd SBC abs, x */ AbsoluteXRead(OperationSBC),
|
||||
/* 0xfe INC abs, x */ AbsoluteXReadModifyWrite(OperationINC), /* 0xff INS abs, x */ AbsoluteXReadModifyWrite(OperationINS),
|
||||
};
|
||||
ProcessorStorage::ProcessorStorage(Personality personality) {
|
||||
// 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;
|
||||
decimal_flag_ &= Flag::Decimal;
|
||||
overflow_flag_ &= Flag::Overflow;
|
||||
|
||||
const InstructionList operations_6502[256] = {
|
||||
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetI, CycleReadVectorLow, CycleReadVectorHigh),
|
||||
/* 0x01 ORA x, ind */ IndexedIndirectRead(OperationORA),
|
||||
/* 0x02 JAM */ JAM, /* 0x03 ASO x, ind */ IndexedIndirectReadModifyWrite(OperationASO),
|
||||
/* 0x04 NOP zpg */ ZeroNop(), /* 0x05 ORA zpg */ ZeroRead(OperationORA),
|
||||
/* 0x06 ASL zpg */ ZeroReadModifyWrite(OperationASL), /* 0x07 ASO zpg */ ZeroReadModifyWrite(OperationASO),
|
||||
/* 0x08 PHP */ Program(OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand),
|
||||
/* 0x09 ORA # */ Immediate(OperationORA),
|
||||
/* 0x0a ASL A */ Implied(OperationASL), /* 0x0b ANC # */ Immediate(OperationANC),
|
||||
/* 0x0c NOP abs */ AbsoluteNop(), /* 0x0d ORA abs */ AbsoluteRead(OperationORA),
|
||||
/* 0x0e ASL abs */ AbsoluteReadModifyWrite(OperationASL), /* 0x0f ASO abs */ AbsoluteReadModifyWrite(OperationASO),
|
||||
/* 0x10 BPL */ Program(OperationBPL), /* 0x11 ORA ind, y */ IndirectIndexedRead(OperationORA),
|
||||
/* 0x12 JAM */ JAM, /* 0x13 ASO ind, y */ IndirectIndexedReadModifyWrite(OperationASO),
|
||||
/* 0x14 NOP zpg, x */ ZeroXNop(), /* 0x15 ORA zpg, x */ ZeroXRead(OperationORA),
|
||||
/* 0x16 ASL zpg, x */ ZeroXReadModifyWrite(OperationASL), /* 0x17 ASO zpg, x */ ZeroXReadModifyWrite(OperationASO),
|
||||
/* 0x18 CLC */ Program(OperationCLC), /* 0x19 ORA abs, y */ AbsoluteYRead(OperationORA),
|
||||
/* 0x1a NOP # */ ImpliedNop(), /* 0x1b ASO abs, y */ AbsoluteYReadModifyWrite(OperationASO),
|
||||
/* 0x1c NOP abs, x */ AbsoluteXNop(), /* 0x1d ORA abs, x */ AbsoluteXRead(OperationORA),
|
||||
/* 0x1e ASL abs, x */ AbsoluteXReadModifyWrite(OperationASL), /* 0x1f ASO abs, x */ AbsoluteXReadModifyWrite(OperationASO),
|
||||
/* 0x20 JSR abs */ Program(CycleIncrementPCAndReadStack, CyclePushPCH, CyclePushPCL, CycleReadPCHLoadPCL),
|
||||
/* 0x21 AND x, ind */ IndexedIndirectRead(OperationAND),
|
||||
/* 0x22 JAM */ JAM, /* 0x23 RLA x, ind */ IndexedIndirectReadModifyWrite(OperationRLA),
|
||||
/* 0x24 BIT zpg */ ZeroRead(OperationBIT), /* 0x25 AND zpg */ ZeroRead(OperationAND),
|
||||
/* 0x26 ROL zpg */ ZeroReadModifyWrite(OperationROL), /* 0x27 RLA zpg */ ZeroReadModifyWrite(OperationRLA),
|
||||
/* 0x28 PLP */ Program(CycleReadFromS, CyclePullOperand, OperationSetFlagsFromOperand),
|
||||
/* 0x29 AND A # */ Immediate(OperationAND),
|
||||
/* 0x2a ROL A */ Implied(OperationROL), /* 0x2b ANC # */ Immediate(OperationANC),
|
||||
/* 0x2c BIT abs */ AbsoluteRead(OperationBIT), /* 0x2d AND abs */ AbsoluteRead(OperationAND),
|
||||
/* 0x2e ROL abs */ AbsoluteReadModifyWrite(OperationROL), /* 0x2f RLA abs */ AbsoluteReadModifyWrite(OperationRLA),
|
||||
/* 0x30 BMI */ Program(OperationBMI), /* 0x31 AND ind, y */ IndirectIndexedRead(OperationAND),
|
||||
/* 0x32 JAM */ JAM, /* 0x33 RLA ind, y */ IndirectIndexedReadModifyWrite(OperationRLA),
|
||||
/* 0x34 NOP zpg, x */ ZeroXNop(), /* 0x35 AND zpg, x */ ZeroXRead(OperationAND),
|
||||
/* 0x36 ROL zpg, x */ ZeroXReadModifyWrite(OperationROL), /* 0x37 RLA zpg, x */ ZeroXReadModifyWrite(OperationRLA),
|
||||
/* 0x38 SEC */ Program(OperationSEC), /* 0x39 AND abs, y */ AbsoluteYRead(OperationAND),
|
||||
/* 0x3a NOP # */ ImpliedNop(), /* 0x3b RLA abs, y */ AbsoluteYReadModifyWrite(OperationRLA),
|
||||
/* 0x3c NOP abs, x */ AbsoluteXNop(), /* 0x3d AND abs, x */ AbsoluteXRead(OperationAND),
|
||||
/* 0x3e ROL abs, x */ AbsoluteXReadModifyWrite(OperationROL), /* 0x3f RLA abs, x */ AbsoluteXReadModifyWrite(OperationRLA),
|
||||
/* 0x40 RTI */ Program(CycleReadFromS, CyclePullOperand, OperationSetFlagsFromOperand, CyclePullPCL, CyclePullPCH),
|
||||
/* 0x41 EOR x, ind */ IndexedIndirectRead(OperationEOR),
|
||||
/* 0x42 JAM */ JAM, /* 0x43 LSE x, ind */ IndexedIndirectReadModifyWrite(OperationLSE),
|
||||
/* 0x44 NOP zpg */ ZeroNop(), /* 0x45 EOR zpg */ ZeroRead(OperationEOR),
|
||||
/* 0x46 LSR zpg */ ZeroReadModifyWrite(OperationLSR), /* 0x47 LSE zpg */ ZeroReadModifyWrite(OperationLSE),
|
||||
/* 0x48 PHA */ Program(CyclePushA), /* 0x49 EOR # */ Immediate(OperationEOR),
|
||||
/* 0x4a LSR A */ Implied(OperationLSR), /* 0x4b ASR A */ Immediate(OperationASR),
|
||||
/* 0x4c JMP abs */ Program(CycleIncrementPCReadPCHLoadPCL), /* 0x4d EOR abs */ AbsoluteRead(OperationEOR),
|
||||
/* 0x4e LSR abs */ AbsoluteReadModifyWrite(OperationLSR), /* 0x4f LSE abs */ AbsoluteReadModifyWrite(OperationLSE),
|
||||
/* 0x50 BVC */ Program(OperationBVC), /* 0x51 EOR ind, y */ IndirectIndexedRead(OperationEOR),
|
||||
/* 0x52 JAM */ JAM, /* 0x53 LSE ind, y */ IndirectIndexedReadModifyWrite(OperationLSE),
|
||||
/* 0x54 NOP zpg, x */ ZeroXNop(), /* 0x55 EOR zpg, x */ ZeroXRead(OperationEOR),
|
||||
/* 0x56 LSR zpg, x */ ZeroXReadModifyWrite(OperationLSR), /* 0x57 LSE zpg, x */ ZeroXReadModifyWrite(OperationLSE),
|
||||
/* 0x58 CLI */ Program(OperationCLI), /* 0x59 EOR abs, y */ AbsoluteYRead(OperationEOR),
|
||||
/* 0x5a NOP # */ ImpliedNop(), /* 0x5b LSE abs, y */ AbsoluteYReadModifyWrite(OperationLSE),
|
||||
/* 0x5c NOP abs, x */ AbsoluteXNop(), /* 0x5d EOR abs, x */ AbsoluteXRead(OperationEOR),
|
||||
/* 0x5e LSR abs, x */ AbsoluteXReadModifyWrite(OperationLSR), /* 0x5f LSE abs, x */ AbsoluteXReadModifyWrite(OperationLSE),
|
||||
/* 0x60 RTS */ Program(CycleReadFromS, CyclePullPCL, CyclePullPCH, CycleReadAndIncrementPC),
|
||||
/* 0x61 ADC x, ind */ IndexedIndirectRead(OperationADC),
|
||||
/* 0x62 JAM */ JAM, /* 0x63 RRA x, ind */ IndexedIndirectReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x64 NOP zpg */ ZeroNop(), /* 0x65 ADC zpg */ ZeroRead(OperationADC),
|
||||
/* 0x66 ROR zpg */ ZeroReadModifyWrite(OperationROR), /* 0x67 RRA zpg */ ZeroReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x68 PLA */ Program(CycleReadFromS, CyclePullA, OperationSetFlagsFromA), /* 0x69 ADC # */ Immediate(OperationADC),
|
||||
/* 0x6a ROR A */ Implied(OperationROR), /* 0x6b ARR # */ Immediate(OperationARR),
|
||||
/* 0x6c JMP (abs) */ Program(CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddressLowInc),
|
||||
/* 0x6d ADC abs */ AbsoluteRead(OperationADC),
|
||||
/* 0x6e ROR abs */ AbsoluteReadModifyWrite(OperationROR), /* 0x6f RRA abs */ AbsoluteReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x70 BVS */ Program(OperationBVS), /* 0x71 ADC ind, y */ IndirectIndexedRead(OperationADC),
|
||||
/* 0x72 JAM */ JAM, /* 0x73 RRA ind, y */ IndirectIndexedReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x74 NOP zpg, x */ ZeroXNop(), /* 0x75 ADC zpg, x */ ZeroXRead(OperationADC),
|
||||
/* 0x76 ROR zpg, x */ ZeroXReadModifyWrite(OperationROR), /* 0x77 RRA zpg, x */ ZeroXReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x78 SEI */ Program(OperationSEI), /* 0x79 ADC abs, y */ AbsoluteYRead(OperationADC),
|
||||
/* 0x7a NOP # */ ImpliedNop(), /* 0x7b RRA abs, y */ AbsoluteYReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x7c NOP abs, x */ AbsoluteXNop(), /* 0x7d ADC abs, x */ AbsoluteXRead(OperationADC),
|
||||
/* 0x7e ROR abs, x */ AbsoluteXReadModifyWrite(OperationROR), /* 0x7f RRA abs, x */ AbsoluteXReadModifyWrite(OperationRRA, OperationADC),
|
||||
/* 0x80 NOP # */ ImmediateNop(), /* 0x81 STA x, ind */ IndexedIndirectWrite(OperationSTA),
|
||||
/* 0x82 NOP # */ ImmediateNop(), /* 0x83 SAX x, ind */ IndexedIndirectWrite(OperationSAX),
|
||||
/* 0x84 STY zpg */ ZeroWrite(OperationSTY), /* 0x85 STA zpg */ ZeroWrite(OperationSTA),
|
||||
/* 0x86 STX zpg */ ZeroWrite(OperationSTX), /* 0x87 SAX zpg */ ZeroWrite(OperationSAX),
|
||||
/* 0x88 DEY */ Program(OperationDEY), /* 0x89 NOP # */ ImmediateNop(),
|
||||
/* 0x8a TXA */ Program(OperationTXA), /* 0x8b ANE # */ Immediate(OperationANE),
|
||||
/* 0x8c STY abs */ AbsoluteWrite(OperationSTY), /* 0x8d STA abs */ AbsoluteWrite(OperationSTA),
|
||||
/* 0x8e STX abs */ AbsoluteWrite(OperationSTX), /* 0x8f SAX abs */ AbsoluteWrite(OperationSAX),
|
||||
/* 0x90 BCC */ Program(OperationBCC), /* 0x91 STA ind, y */ IndirectIndexedWrite(OperationSTA),
|
||||
/* 0x92 JAM */ JAM, /* 0x93 SHA ind, y */ IndirectIndexedWrite(OperationSHA),
|
||||
/* 0x94 STY zpg, x */ ZeroXWrite(OperationSTY), /* 0x95 STA zpg, x */ ZeroXWrite(OperationSTA),
|
||||
/* 0x96 STX zpg, y */ ZeroYWrite(OperationSTX), /* 0x97 SAX zpg, y */ ZeroYWrite(OperationSAX),
|
||||
/* 0x98 TYA */ Program(OperationTYA), /* 0x99 STA abs, y */ AbsoluteYWrite(OperationSTA),
|
||||
/* 0x9a TXS */ Program(OperationTXS), /* 0x9b SHS abs, y */ AbsoluteYWrite(OperationSHS),
|
||||
/* 0x9c SHY abs, x */ AbsoluteXWrite(OperationSHY), /* 0x9d STA abs, x */ AbsoluteXWrite(OperationSTA),
|
||||
/* 0x9e SHX abs, y */ AbsoluteYWrite(OperationSHX), /* 0x9f SHA abs, y */ AbsoluteYWrite(OperationSHA),
|
||||
/* 0xa0 LDY # */ Immediate(OperationLDY), /* 0xa1 LDA x, ind */ IndexedIndirectRead(OperationLDA),
|
||||
/* 0xa2 LDX # */ Immediate(OperationLDX), /* 0xa3 LAX x, ind */ IndexedIndirectRead(OperationLAX),
|
||||
/* 0xa4 LDY zpg */ ZeroRead(OperationLDY), /* 0xa5 LDA zpg */ ZeroRead(OperationLDA),
|
||||
/* 0xa6 LDX zpg */ ZeroRead(OperationLDX), /* 0xa7 LAX zpg */ ZeroRead(OperationLAX),
|
||||
/* 0xa8 TAY */ Program(OperationTAY), /* 0xa9 LDA # */ Immediate(OperationLDA),
|
||||
/* 0xaa TAX */ Program(OperationTAX), /* 0xab LXA # */ Immediate(OperationLXA),
|
||||
/* 0xac LDY abs */ AbsoluteRead(OperationLDY), /* 0xad LDA abs */ AbsoluteRead(OperationLDA),
|
||||
/* 0xae LDX abs */ AbsoluteRead(OperationLDX), /* 0xaf LAX abs */ AbsoluteRead(OperationLAX),
|
||||
/* 0xb0 BCS */ Program(OperationBCS), /* 0xb1 LDA ind, y */ IndirectIndexedRead(OperationLDA),
|
||||
/* 0xb2 JAM */ JAM, /* 0xb3 LAX ind, y */ IndirectIndexedRead(OperationLAX),
|
||||
/* 0xb4 LDY zpg, x */ ZeroXRead(OperationLDY), /* 0xb5 LDA zpg, x */ ZeroXRead(OperationLDA),
|
||||
/* 0xb6 LDX zpg, y */ ZeroYRead(OperationLDX), /* 0xb7 LAX zpg, x */ ZeroYRead(OperationLAX),
|
||||
/* 0xb8 CLV */ Program(OperationCLV), /* 0xb9 LDA abs, y */ AbsoluteYRead(OperationLDA),
|
||||
/* 0xba TSX */ Program(OperationTSX), /* 0xbb LAS abs, y */ AbsoluteYRead(OperationLAS),
|
||||
/* 0xbc LDY abs, x */ AbsoluteXRead(OperationLDY), /* 0xbd LDA abs, x */ AbsoluteXRead(OperationLDA),
|
||||
/* 0xbe LDX abs, y */ AbsoluteYRead(OperationLDX), /* 0xbf LAX abs, y */ AbsoluteYRead(OperationLAX),
|
||||
/* 0xc0 CPY # */ Immediate(OperationCPY), /* 0xc1 CMP x, ind */ IndexedIndirectRead(OperationCMP),
|
||||
/* 0xc2 NOP # */ ImmediateNop(), /* 0xc3 DCP x, ind */ IndexedIndirectReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xc4 CPY zpg */ ZeroRead(OperationCPY), /* 0xc5 CMP zpg */ ZeroRead(OperationCMP),
|
||||
/* 0xc6 DEC zpg */ ZeroReadModifyWrite(OperationDEC), /* 0xc7 DCP zpg */ ZeroReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xc8 INY */ Program(OperationINY), /* 0xc9 CMP # */ Immediate(OperationCMP),
|
||||
/* 0xca DEX */ Program(OperationDEX), /* 0xcb ARR # */ Immediate(OperationSBX),
|
||||
/* 0xcc CPY abs */ AbsoluteRead(OperationCPY), /* 0xcd CMP abs */ AbsoluteRead(OperationCMP),
|
||||
/* 0xce DEC abs */ AbsoluteReadModifyWrite(OperationDEC), /* 0xcf DCP abs */ AbsoluteReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xd0 BNE */ Program(OperationBNE), /* 0xd1 CMP ind, y */ IndirectIndexedRead(OperationCMP),
|
||||
/* 0xd2 JAM */ JAM, /* 0xd3 DCP ind, y */ IndirectIndexedReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xd4 NOP zpg, x */ ZeroXNop(), /* 0xd5 CMP zpg, x */ ZeroXRead(OperationCMP),
|
||||
/* 0xd6 DEC zpg, x */ ZeroXReadModifyWrite(OperationDEC), /* 0xd7 DCP zpg, x */ ZeroXReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xd8 CLD */ Program(OperationCLD), /* 0xd9 CMP abs, y */ AbsoluteYRead(OperationCMP),
|
||||
/* 0xda NOP # */ ImpliedNop(), /* 0xdb DCP abs, y */ AbsoluteYReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xdc NOP abs, x */ AbsoluteXNop(), /* 0xdd CMP abs, x */ AbsoluteXRead(OperationCMP),
|
||||
/* 0xde DEC abs, x */ AbsoluteXReadModifyWrite(OperationDEC), /* 0xdf DCP abs, x */ AbsoluteXReadModifyWrite(OperationDecrementOperand, OperationCMP),
|
||||
/* 0xe0 CPX # */ Immediate(OperationCPX), /* 0xe1 SBC x, ind */ IndexedIndirectRead(OperationSBC),
|
||||
/* 0xe2 NOP # */ ImmediateNop(), /* 0xe3 INS x, ind */ IndexedIndirectReadModifyWrite(OperationINS),
|
||||
/* 0xe4 CPX zpg */ ZeroRead(OperationCPX), /* 0xe5 SBC zpg */ ZeroRead(OperationSBC),
|
||||
/* 0xe6 INC zpg */ ZeroReadModifyWrite(OperationINC), /* 0xe7 INS zpg */ ZeroReadModifyWrite(OperationINS),
|
||||
/* 0xe8 INX */ Program(OperationINX), /* 0xe9 SBC # */ Immediate(OperationSBC),
|
||||
/* 0xea NOP # */ ImpliedNop(), /* 0xeb SBC # */ Immediate(OperationSBC),
|
||||
/* 0xec CPX abs */ AbsoluteRead(OperationCPX), /* 0xed SBC abs */ AbsoluteRead(OperationSBC),
|
||||
/* 0xee INC abs */ AbsoluteReadModifyWrite(OperationINC), /* 0xef INS abs */ AbsoluteReadModifyWrite(OperationINS),
|
||||
/* 0xf0 BEQ */ Program(OperationBEQ), /* 0xf1 SBC ind, y */ IndirectIndexedRead(OperationSBC),
|
||||
/* 0xf2 JAM */ JAM, /* 0xf3 INS ind, y */ IndirectIndexedReadModifyWrite(OperationINS),
|
||||
/* 0xf4 NOP zpg, x */ ZeroXNop(), /* 0xf5 SBC zpg, x */ ZeroXRead(OperationSBC),
|
||||
/* 0xf6 INC zpg, x */ ZeroXReadModifyWrite(OperationINC), /* 0xf7 INS zpg, x */ ZeroXReadModifyWrite(OperationINS),
|
||||
/* 0xf8 SED */ Program(OperationSED), /* 0xf9 SBC abs, y */ AbsoluteYRead(OperationSBC),
|
||||
/* 0xfa NOP # */ ImpliedNop(), /* 0xfb INS abs, y */ AbsoluteYReadModifyWrite(OperationINS),
|
||||
/* 0xfc NOP abs, x */ AbsoluteXNop(), /* 0xfd SBC abs, x */ AbsoluteXRead(OperationSBC),
|
||||
/* 0xfe INC abs, x */ AbsoluteXReadModifyWrite(OperationINC), /* 0xff INS abs, x */ AbsoluteXReadModifyWrite(OperationINS),
|
||||
};
|
||||
|
||||
// Install the basic 6502 table.
|
||||
memcpy(operations_, operations_6502, sizeof(operations_));
|
||||
|
||||
// Patch the table according to the chip's personality.
|
||||
#define Install(location, instructions) {\
|
||||
const InstructionList code = instructions; \
|
||||
memcpy(&operations_[location], code, sizeof(InstructionList)); \
|
||||
}
|
||||
if(personality != P6502) {
|
||||
// Add P[L/H][X/Y].
|
||||
Install(0x5a, Program(CyclePushY));
|
||||
Install(0xda, Program(CyclePushX));
|
||||
Install(0x7a, Program(CycleReadFromS, CyclePullY, OperationSetFlagsFromY));
|
||||
Install(0xfa, Program(CycleReadFromS, CyclePullX, OperationSetFlagsFromX));
|
||||
|
||||
// Add BRA.
|
||||
Install(0x80, Program(OperationBRA));
|
||||
|
||||
// Add BBS and BBR. These take five cycles. My guessed breakdown is:
|
||||
// 1. read opcode
|
||||
// 2. read operand
|
||||
// 3. read zero page
|
||||
// 4. read second operand
|
||||
// 5. read from PC without top byte fixed yet
|
||||
// ... with the caveat that (3) and (4) could be the other way around.
|
||||
for(int location = 0x0f; location <= 0xff; location += 0x10) {
|
||||
Install(location, Program(OperationLoadAddressZeroPage, CycleFetchOperandFromAddress, OperationBBRBBS));
|
||||
}
|
||||
|
||||
// Add NOPs.
|
||||
|
||||
// The 1-byte, 1-cycle (!) NOPs.
|
||||
for(int c = 0x03; c <= 0xf3; c += 0x10) {
|
||||
Install(c, ImpliedNop());
|
||||
}
|
||||
for(int c = 0x0b; c <= 0xbb; c += 0x10) {
|
||||
Install(c, ImpliedNop());
|
||||
}
|
||||
for(int c = 0xeb; c <= 0xfb; c += 0x10) {
|
||||
Install(c, ImpliedNop());
|
||||
}
|
||||
|
||||
// The 2-byte, 2-cycle NOPs that the 6502 doesn't have.
|
||||
for(int c = 0x02; c <= 0x62; c += 0x10) {
|
||||
Install(c, ImmediateNop());
|
||||
}
|
||||
|
||||
// Correct JMP (abs) and install JMP (abs, x).
|
||||
Install(0x6c, Program(CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddressLowInc, CycleReadPCHFromAddressFixed));
|
||||
Install(0x7c, Program(
|
||||
CycleReadAddressHLoadAddressL, // (3) read second byte of (addr)
|
||||
CycleAddXToAddressLowRead, // (4) calculate addr+x, read from (addr+x) with high byte not yet calculated
|
||||
OperationCorrectAddressHigh, CycleReadPCLFromAddress, // (5) read from real (addr+x)
|
||||
CycleReadPCHFromAddressInc // (6) read from addr+x+1
|
||||
));
|
||||
|
||||
// Add INA and DEA.
|
||||
Install(0x1a, Program(OperationINA));
|
||||
Install(0x3a, Program(OperationDEA));
|
||||
|
||||
// Add (zp) operations.
|
||||
Install(0x12, ZeroIndirectRead(OperationORA));
|
||||
Install(0x32, ZeroIndirectRead(OperationAND));
|
||||
Install(0x52, ZeroIndirectRead(OperationEOR));
|
||||
Install(0x72, ZeroIndirectRead(OperationADC));
|
||||
Install(0x92, ZeroIndirectWrite(OperationSTA));
|
||||
Install(0xb2, ZeroIndirectRead(OperationLDA));
|
||||
Install(0xd2, ZeroIndirectRead(OperationCMP));
|
||||
Install(0xf2, ZeroIndirectRead(OperationSBC));
|
||||
|
||||
// Add STZ.
|
||||
Install(0x9c, AbsoluteWrite(OperationSTZ));
|
||||
Install(0x9e, AbsoluteXWrite(OperationSTZ));
|
||||
Install(0x64, ZeroWrite(OperationSTZ));
|
||||
Install(0x74, ZeroXWrite(OperationSTZ));
|
||||
|
||||
// Add the extra BITs.
|
||||
Install(0x34, ZeroXRead(OperationBIT));
|
||||
Install(0x3c, AbsoluteXRead(OperationBIT));
|
||||
Install(0x89, Immediate(OperationBITNoNV));
|
||||
|
||||
// Add TRB and TSB.
|
||||
Install(0x04, ZeroReadModifyWrite(OperationTSB));
|
||||
Install(0x0c, AbsoluteReadModifyWrite(OperationTSB));
|
||||
Install(0x14, ZeroReadModifyWrite(OperationTRB));
|
||||
Install(0x1c, AbsoluteReadModifyWrite(OperationTRB));
|
||||
|
||||
// Add RMB and SMB.
|
||||
for(int c = 0x07; c <= 0x77; c += 0x10) {
|
||||
Install(c, ZeroReadModifyWrite(OperationRMB));
|
||||
}
|
||||
for(int c = 0x87; c <= 0xf7; c += 0x10) {
|
||||
Install(c, ZeroReadModifyWrite(OperationSMB));
|
||||
}
|
||||
}
|
||||
#undef Install
|
||||
}
|
||||
|
||||
#undef Program
|
||||
#undef Absolute
|
||||
@ -243,11 +353,3 @@ const ProcessorStorage::MicroOp ProcessorStorage::operations[256][10] = {
|
||||
#undef IndirectIndexedReadModify
|
||||
#undef Immediate
|
||||
#undef Implied
|
||||
|
||||
ProcessorStorage::ProcessorStorage() {
|
||||
// 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;
|
||||
decimal_flag_ &= Flag::Decimal;
|
||||
overflow_flag_ &= Flag::Overflow;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
class ProcessorStorage {
|
||||
protected:
|
||||
ProcessorStorage();
|
||||
ProcessorStorage(Personality);
|
||||
|
||||
/*
|
||||
This emulation functions by decomposing instructions into micro programs, consisting of the micro operations
|
||||
@ -25,44 +25,64 @@ class ProcessorStorage {
|
||||
enum MicroOp {
|
||||
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
|
||||
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
|
||||
OperationSetI,
|
||||
CyclePushX, CyclePushY, OperationSetI,
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CyclePullX, CyclePullY,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute,
|
||||
CycleReadAddressHLoadAddressL,
|
||||
|
||||
CycleReadPCLFromAddress, CycleReadPCHFromAddressLowInc, CycleReadPCHFromAddressFixed, CycleReadPCHFromAddressInc,
|
||||
|
||||
CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead,
|
||||
OperationMoveToNextProgram, OperationIncrementPC,
|
||||
CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA,
|
||||
CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand,
|
||||
CycleFetchAddressLowFromOperand,
|
||||
OperationIncrementOperand, OperationORA, OperationAND, OperationEOR,
|
||||
OperationINS, OperationADC, OperationSBC, OperationLDA,
|
||||
OperationLDX, OperationLDY, OperationLAX, OperationSTA,
|
||||
OperationSTX, OperationSTY, OperationSAX, OperationSHA,
|
||||
OperationSTX, OperationSTY, OperationSTZ,
|
||||
OperationSAX, OperationSHA,
|
||||
OperationSHX, OperationSHY, OperationSHS, OperationCMP,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationASL,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationBITNoNV,
|
||||
OperationASL, OperationRMB, OperationSMB,
|
||||
OperationASO, OperationROL, OperationRLA, OperationLSR,
|
||||
OperationLSE, OperationASR, OperationROR, OperationRRA,
|
||||
OperationCLC, OperationCLI, OperationCLV, OperationCLD,
|
||||
OperationSEC, OperationSEI, OperationSED, OperationINC,
|
||||
OperationDEC, OperationINX, OperationDEX, OperationINY,
|
||||
OperationDEY, OperationBPL, OperationBMI, OperationBVC,
|
||||
OperationBVS, OperationBCC, OperationBCS, OperationBNE,
|
||||
OperationBEQ, OperationTXA, OperationTYA, OperationTXS,
|
||||
OperationTAY, OperationTAX, OperationTSX, OperationARR,
|
||||
OperationSBX, OperationLXA, OperationANE, OperationANC,
|
||||
OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSEC, OperationSEI, OperationSED,
|
||||
OperationTRB, OperationTSB,
|
||||
|
||||
OperationINC, OperationDEC, OperationINX, OperationDEX,
|
||||
OperationINY, OperationDEY, OperationINA, OperationDEA,
|
||||
|
||||
OperationBPL, OperationBMI, OperationBVC, OperationBVS,
|
||||
OperationBCC, OperationBCS, OperationBNE, OperationBEQ,
|
||||
OperationBRA, OperationBBRBBS,
|
||||
|
||||
OperationTXA, OperationTYA, OperationTXS, OperationTAY,
|
||||
OperationTAX, OperationTSX,
|
||||
|
||||
OperationARR, OperationSBX, OperationLXA, OperationANE,
|
||||
OperationANC, OperationLAS,
|
||||
|
||||
CycleFetchFromHalfUpdatedPC, CycleAddSignedOperandToPC, OperationAddSignedOperandToPC16,
|
||||
|
||||
OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA,
|
||||
OperationSetFlagsFromA, OperationSetFlagsFromX, OperationSetFlagsFromY,
|
||||
CycleScheduleJam
|
||||
};
|
||||
|
||||
static const MicroOp operations[256][10];
|
||||
using InstructionList = MicroOp[10];
|
||||
InstructionList operations_[256];
|
||||
|
||||
const MicroOp *scheduled_program_counter_ = nullptr;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user