1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 16:31:31 +00:00

Merge pull request #129 from TomHarte/TestMachineCommonality

Generalises the Z80 test machine's trap handler also to cover the 6502
This commit is contained in:
Thomas Harte 2017-06-03 22:27:55 -04:00 committed by GitHub
commit fba6ac2b4c
16 changed files with 492 additions and 388 deletions

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.swift */; }; 4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.swift */; };
4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; }; 4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; };
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2771EE39306008B7065 /* TestMachine.mm */; };
4B0BE4281D3481E700D5256B /* DigitalPhaseLockedLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */; }; 4B0BE4281D3481E700D5256B /* DigitalPhaseLockedLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */; };
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; }; 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; };
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; }; 4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; };
@ -444,6 +445,9 @@
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTMachine.hpp; sourceTree = "<group>"; }; 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTMachine.hpp; sourceTree = "<group>"; };
4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = "<group>"; }; 4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = "<group>"; };
4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = "<group>"; }; 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = "<group>"; };
4B08A2761EE39306008B7065 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = "<group>"; };
4B08A2771EE39306008B7065 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = "<group>"; };
4B08A2791EE3957B008B7065 /* TestMachine+ForSubclassEyesOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TestMachine+ForSubclassEyesOnly.h"; sourceTree = "<group>"; };
4B0B6E121C9DBD5D00FFB60D /* CRTConstants.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CRTConstants.hpp; sourceTree = "<group>"; }; 4B0B6E121C9DBD5D00FFB60D /* CRTConstants.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CRTConstants.hpp; sourceTree = "<group>"; };
4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DigitalPhaseLockedLoop.cpp; sourceTree = "<group>"; }; 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DigitalPhaseLockedLoop.cpp; sourceTree = "<group>"; };
4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DigitalPhaseLockedLoop.hpp; sourceTree = "<group>"; }; 4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DigitalPhaseLockedLoop.hpp; sourceTree = "<group>"; };
@ -1198,12 +1202,15 @@
4BEF6AA81D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.h */, 4BEF6AA81D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.h */,
4B3BA0C81D318B44005DD7A7 /* MOS6522Bridge.h */, 4B3BA0C81D318B44005DD7A7 /* MOS6522Bridge.h */,
4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */, 4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */,
4B08A2761EE39306008B7065 /* TestMachine.h */,
4B08A2791EE3957B008B7065 /* TestMachine+ForSubclassEyesOnly.h */,
4B3BA0CC1D318B44005DD7A7 /* TestMachine6502.h */, 4B3BA0CC1D318B44005DD7A7 /* TestMachine6502.h */,
4BFCA1251ECBE33200AC40C1 /* TestMachineZ80.h */, 4BFCA1251ECBE33200AC40C1 /* TestMachineZ80.h */,
4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */, 4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */,
4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */, 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */,
4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */, 4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */,
4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */, 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */,
4B08A2771EE39306008B7065 /* TestMachine.mm */,
4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */, 4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */,
4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */, 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */,
); );
@ -2623,6 +2630,7 @@
4BD4A8D01E077FD20020D856 /* PCMTrackTests.mm in Sources */, 4BD4A8D01E077FD20020D856 /* PCMTrackTests.mm in Sources */,
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */, 4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */,
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */, 4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */, 4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */, 4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */,
); );

View File

@ -0,0 +1,14 @@
//
// TestMachine+ForSubclassEyesOnly.h
// Clock Signal
//
// Created by Thomas Harte on 03/06/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#import "TestMachine.h"
#include "AllRAMProcessor.hpp"
@interface CSTestMachine (ForSubclassEyesOnly)
- (CPU::AllRAMProcessor *)processor;
@end

View File

@ -0,0 +1,22 @@
//
// TestMachine.h
// Clock Signal
//
// Created by Thomas Harte on 03/06/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#import <Foundation/Foundation.h>
@class CSTestMachine;
@protocol CSTestMachineTrapHandler
- (void)testMachine:(nonnull CSTestMachine *)testMachine didTrapAtAddress:(uint16_t)address;
@end
@interface CSTestMachine : NSObject
@property(nonatomic, weak, nullable) id<CSTestMachineTrapHandler> trapHandler;
- (void)addTrapAddress:(uint16_t)trapAddress;
@end

View File

@ -0,0 +1,57 @@
//
// TestMachine.m
// Clock Signal
//
// Created by Thomas Harte on 03/06/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#import "TestMachine.h"
#import "TestMachine+ForSubclassEyesOnly.h"
#include "AllRAMProcessor.hpp"
@interface CSTestMachine ()
- (void)testMachineDidTrapAtAddress:(uint16_t)address;
@end
#pragma mark - C++ delegate handlers
class MachineTrapHandler: public CPU::AllRAMProcessor::TrapHandler {
public:
MachineTrapHandler(CSTestMachine *targetMachine) : target_(targetMachine) {}
void processor_did_trap(CPU::AllRAMProcessor &, uint16_t address) {
[target_ testMachineDidTrapAtAddress:address];
}
private:
CSTestMachine *target_;
};
#pragma mark - The test machine
@implementation CSTestMachine {
MachineTrapHandler *_cppTrapHandler;
}
- (instancetype)init {
if(self = [super init]) {
_cppTrapHandler = new MachineTrapHandler(self);
}
return self;
}
- (void)dealloc {
delete _cppTrapHandler;
}
- (void)addTrapAddress:(uint16_t)trapAddress {
self.processor->set_trap_handler(_cppTrapHandler);
self.processor->add_trap_address(trapAddress);
}
- (void)testMachineDidTrapAtAddress:(uint16_t)address {
[self.trapHandler testMachine:self didTrapAtAddress:address];
}
@end

View File

@ -7,6 +7,7 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "TestMachine.h"
typedef NS_ENUM(NSInteger, CSTestMachine6502Register) { typedef NS_ENUM(NSInteger, CSTestMachine6502Register) {
CSTestMachine6502RegisterLastOperationAddress, CSTestMachine6502RegisterLastOperationAddress,
@ -25,7 +26,7 @@ extern const uint8_t CSTestMachine6502JamOpcode;
- (void)testMachine:(CSTestMachine6502 *)machine didJamAtAddress:(uint16_t)address; - (void)testMachine:(CSTestMachine6502 *)machine didJamAtAddress:(uint16_t)address;
@end @end
@interface CSTestMachine6502 : NSObject @interface CSTestMachine6502 : CSTestMachine
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress; - (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
- (void)runForNumberOfCycles:(int)cycles; - (void)runForNumberOfCycles:(int)cycles;

View File

@ -9,22 +9,23 @@
#import "TestMachine6502.h" #import "TestMachine6502.h"
#include <stdint.h> #include <stdint.h>
#include "6502AllRAM.hpp" #include "6502AllRAM.hpp"
#import "TestMachine+ForSubclassEyesOnly.h"
const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode; const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode;
#pragma mark - C++ jam handler #pragma mark - C++ jam handler
class MachineJamHandler: public CPU::MOS6502::AllRAMProcessor::JamHandler { //class MachineJamHandler: public CPU::MOS6502::AllRAMProcessor::JamHandler {
public: // public:
MachineJamHandler(CSTestMachine6502 *targetMachine) : _targetMachine(targetMachine) {} // MachineJamHandler(CSTestMachine6502 *targetMachine) : _targetMachine(targetMachine) {}
//
void processor_did_jam(CPU::MOS6502::AllRAMProcessor::Processor *processor, uint16_t address) override { // void processor_did_jam(CPU::MOS6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
[_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address]; // [_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address];
} // }
//
private: // private:
CSTestMachine6502 *_targetMachine; // CSTestMachine6502 *_targetMachine;
}; //};
#pragma mark - Register enum map #pragma mark - Register enum map
@ -43,8 +44,8 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
#pragma mark - Test class #pragma mark - Test class
@implementation CSTestMachine6502 { @implementation CSTestMachine6502 {
CPU::MOS6502::AllRAMProcessor _processor; CPU::MOS6502::AllRAMProcessor *_processor;
MachineJamHandler *_cppJamHandler; // MachineJamHandler *_cppJamHandler;
} }
#pragma mark - Lifecycle #pragma mark - Lifecycle
@ -53,67 +54,70 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
self = [super init]; self = [super init];
if(self) { if(self) {
_cppJamHandler = new MachineJamHandler(self); _processor = CPU::MOS6502::AllRAMProcessor::Processor();
_processor.set_jam_handler(_cppJamHandler);
} }
return self; return self;
} }
- (void)dealloc { - (void)dealloc {
delete _cppJamHandler; delete _processor;
} }
#pragma mark - Accessors #pragma mark - Accessors
- (uint8_t)valueForAddress:(uint16_t)address { - (uint8_t)valueForAddress:(uint16_t)address {
uint8_t value; uint8_t value;
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Read, address, &value); _processor->get_data_at_address(address, 1, &value);
return value; return value;
} }
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address { - (void)setValue:(uint8_t)value forAddress:(uint16_t)address {
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Write, address, &value); _processor->set_data_at_address(address, 1, &value);
} }
- (void)setValue:(uint16_t)value forRegister:(CSTestMachine6502Register)reg { - (void)setValue:(uint16_t)value forRegister:(CSTestMachine6502Register)reg {
_processor.set_value_of_register(registerForRegister(reg), value); _processor->set_value_of_register(registerForRegister(reg), value);
} }
- (uint16_t)valueForRegister:(CSTestMachine6502Register)reg { - (uint16_t)valueForRegister:(CSTestMachine6502Register)reg {
return _processor.get_value_of_register(registerForRegister(reg)); return _processor->get_value_of_register(registerForRegister(reg));
} }
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress { - (void)setData:(NSData *)data atAddress:(uint16_t)startAddress {
_processor.set_data_at_address(startAddress, data.length, (const uint8_t *)data.bytes); _processor->set_data_at_address(startAddress, data.length, (const uint8_t *)data.bytes);
} }
- (BOOL)isJammed { - (BOOL)isJammed {
return _processor.is_jammed(); return _processor->is_jammed();
} }
- (uint32_t)timestamp { - (uint32_t)timestamp {
return _processor.get_timestamp(); return _processor->get_timestamp();
} }
- (void)setIrqLine:(BOOL)irqLine { - (void)setIrqLine:(BOOL)irqLine {
_irqLine = irqLine; _irqLine = irqLine;
_processor.set_irq_line(irqLine); _processor->set_irq_line(irqLine);
} }
- (void)setNmiLine:(BOOL)nmiLine { - (void)setNmiLine:(BOOL)nmiLine {
_nmiLine = nmiLine; _nmiLine = nmiLine;
_processor.set_nmi_line(nmiLine); _processor->set_nmi_line(nmiLine);
}
- (CPU::AllRAMProcessor *)processor {
return _processor;
} }
#pragma mark - Actions #pragma mark - Actions
- (void)returnFromSubroutine { - (void)returnFromSubroutine {
_processor.return_from_subroutine(); _processor->return_from_subroutine();
} }
- (void)runForNumberOfCycles:(int)cycles { - (void)runForNumberOfCycles:(int)cycles {
_processor.run_for_cycles(cycles); _processor->run_for_cycles(cycles);
} }
@end @end

View File

@ -8,13 +8,10 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <stdint.h> #import <stdint.h>
#import "TestMachine.h"
@class CSTestMachineZ80; @class CSTestMachineZ80;
@protocol CSTestMachineTrapHandler
- (void)testMachine:(nonnull CSTestMachineZ80 *)testMachine didTrapAtAddress:(uint16_t)address;
@end
typedef NS_ENUM(NSInteger, CSTestMachineZ80BusOperationCaptureOperation) { typedef NS_ENUM(NSInteger, CSTestMachineZ80BusOperationCaptureOperation) {
CSTestMachineZ80BusOperationCaptureOperationRead, CSTestMachineZ80BusOperationCaptureOperationRead,
CSTestMachineZ80BusOperationCaptureOperationWrite, CSTestMachineZ80BusOperationCaptureOperationWrite,
@ -46,7 +43,7 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
CSTestMachineZ80RegisterIFF1, CSTestMachineZ80RegisterIFF2, CSTestMachineZ80RegisterIM CSTestMachineZ80RegisterIFF1, CSTestMachineZ80RegisterIFF2, CSTestMachineZ80RegisterIM
}; };
@interface CSTestMachineZ80 : NSObject @interface CSTestMachineZ80 : CSTestMachine
- (void)setData:(nonnull NSData *)data atAddress:(uint16_t)startAddress; - (void)setData:(nonnull NSData *)data atAddress:(uint16_t)startAddress;
- (void)setValue:(uint8_t)value atAddress:(uint16_t)address; - (void)setValue:(uint8_t)value atAddress:(uint16_t)address;
@ -58,9 +55,6 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg; - (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg;
- (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg; - (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg;
@property(nonatomic, weak, nullable) id<CSTestMachineTrapHandler> trapHandler;
- (void)addTrapAddress:(uint16_t)trapAddress;
@property(nonatomic, assign) BOOL captureBusActivity; @property(nonatomic, assign) BOOL captureBusActivity;
@property(nonatomic, readonly, nonnull) NSArray<CSTestMachineZ80BusOperationCapture *> *busOperationCaptures; @property(nonatomic, readonly, nonnull) NSArray<CSTestMachineZ80BusOperationCapture *> *busOperationCaptures;

View File

@ -8,26 +8,14 @@
#import "TestMachineZ80.h" #import "TestMachineZ80.h"
#include "Z80AllRAM.hpp" #include "Z80AllRAM.hpp"
#import "TestMachine+ForSubclassEyesOnly.h"
@interface CSTestMachineZ80 () @interface CSTestMachineZ80 ()
- (void)testMachineDidTrapAtAddress:(uint16_t)address;
- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp; - (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp;
@end @end
#pragma mark - C++ delegate handlers #pragma mark - C++ delegate handlers
class MachineTrapHandler: public CPU::AllRAMProcessor::TrapHandler {
public:
MachineTrapHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {}
void processor_did_trap(CPU::AllRAMProcessor &, uint16_t address) {
[target_ testMachineDidTrapAtAddress:address];
}
private:
CSTestMachineZ80 *target_;
};
class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegate { class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegate {
public: public:
BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {} BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {}
@ -105,7 +93,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
@implementation CSTestMachineZ80 { @implementation CSTestMachineZ80 {
CPU::Z80::AllRAMProcessor *_processor; CPU::Z80::AllRAMProcessor *_processor;
MachineTrapHandler *_cppTrapHandler;
BusOperationHandler *_busOperationHandler; BusOperationHandler *_busOperationHandler;
NSMutableArray<CSTestMachineZ80BusOperationCapture *> *_busOperationCaptures; NSMutableArray<CSTestMachineZ80BusOperationCapture *> *_busOperationCaptures;
@ -120,7 +107,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
if(self = [super init]) { if(self = [super init]) {
_processor = CPU::Z80::AllRAMProcessor::Processor(); _processor = CPU::Z80::AllRAMProcessor::Processor();
_processor->reset_power_on(); _processor->reset_power_on();
_cppTrapHandler = new MachineTrapHandler(self);
_busOperationHandler = new BusOperationHandler(self); _busOperationHandler = new BusOperationHandler(self);
_busOperationCaptures = [[NSMutableArray alloc] init]; _busOperationCaptures = [[NSMutableArray alloc] init];
} }
@ -128,7 +114,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
} }
- (void)dealloc { - (void)dealloc {
delete _cppTrapHandler;
delete _busOperationHandler; delete _busOperationHandler;
} }
@ -160,15 +145,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
return _processor->get_value_of_register(registerForRegister(reg)); return _processor->get_value_of_register(registerForRegister(reg));
} }
- (void)addTrapAddress:(uint16_t)trapAddress {
_processor->set_trap_handler(_cppTrapHandler);
_processor->add_trap_address(trapAddress);
}
- (void)testMachineDidTrapAtAddress:(uint16_t)address {
[self.trapHandler testMachine:self didTrapAtAddress:address];
}
- (BOOL)isHalted { - (BOOL)isHalted {
return _processor->get_halt_line() ? YES : NO; return _processor->get_halt_line() ? YES : NO;
} }
@ -183,6 +159,10 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
_processor->set_interrupt_line(irqLine ? true : false); _processor->set_interrupt_line(irqLine ? true : false);
} }
- (CPU::AllRAMProcessor *)processor {
return _processor;
}
#pragma mark - Z80-specific Runner #pragma mark - Z80-specific Runner
- (void)runToNextInstruction { - (void)runToNextInstruction {

View File

@ -9,7 +9,7 @@
import XCTest import XCTest
import Foundation import Foundation
class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler { class WolfgangLorenzTests: XCTestCase, CSTestMachineTrapHandler {
func testWolfgangLorenzStart() { func testWolfgangLorenzStart() {
self.runWolfgangLorenzTest(" start") self.runWolfgangLorenzTest(" start")
@ -201,7 +201,7 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) { if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
machine = CSTestMachine6502() machine = CSTestMachine6502()
machine.jamHandler = self machine.trapHandler = self
// machine.logActivity = true // machine.logActivity = true
output = "" output = ""
@ -225,11 +225,18 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
] as [UInt8]), count: 19) ] as [UInt8]), count: 19)
machine.setData( irqHandler, atAddress: 0xff48) machine.setData( irqHandler, atAddress: 0xff48)
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffd2) // print character machine.addTrapAddress(0xffd2) // print character
machine.addTrapAddress(0xffe4) // scan keyboard
machine.addTrapAddress(0x8000) // exit
machine.addTrapAddress(0xa474) // exit
machine.setValue(0x60, forAddress:0xffd2) // 0x60 is RTS
machine.setValue(0x60, forAddress:0xffe4)
machine.setValue(0x60, forAddress:0x8000)
machine.setValue(0x60, forAddress:0xa474)
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xe16f) // load machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xe16f) // load
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffe4) // scan keyboard
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0x8000) // exit
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xa474) // exit
machine.setValue(0x0801, for: CSTestMachine6502Register.programCounter) machine.setValue(0x0801, for: CSTestMachine6502Register.programCounter)
machine.setValue(0xfd, for: CSTestMachine6502Register.stackPointer) machine.setValue(0xfd, for: CSTestMachine6502Register.stackPointer)
@ -296,19 +303,17 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
return result return result
} }
func testMachine(_ machine: CSTestMachine6502!, didJamAtAddress address: UInt16) { func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) {
let testMachine6502 = testMachine as! CSTestMachine6502
switch address { switch address {
case 0xffd2: case 0xffd2:
machine.setValue(0x00, forAddress: 0x030c) testMachine6502.setValue(0x00, forAddress: 0x030c)
let character = machine.value(for: CSTestMachine6502Register.A) let character = testMachine6502.value(for: CSTestMachine6502Register.A)
output.append(Character(UnicodeScalar(character)!)) output.append(Character(UnicodeScalar(character)!))
machine.returnFromSubroutine()
case 0xffe4: case 0xffe4:
machine.setValue(0x3, for:CSTestMachine6502Register.A) testMachine6502.setValue(0x3, for:CSTestMachine6502Register.A)
machine.returnFromSubroutine()
case 0x8000, 0xa474: case 0x8000, 0xa474:
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: self.petsciiToString(output), userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed test"), reason: self.petsciiToString(output), userInfo: nil).raise()
@ -316,9 +321,6 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
case 0x0000: case 0x0000:
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: "Execution hit 0000", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed test"), reason: "Execution hit 0000", userInfo: nil).raise()
case 0xe16f: // load next (which we consider to be success)
break;
default: default:
let hexAddress = String(format:"%04x", address) let hexAddress = String(format:"%04x", address)
NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()

View File

@ -131,17 +131,18 @@ class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
} }
} }
func testMachine(_ testMachine: CSTestMachineZ80, didTrapAtAddress address: UInt16) { func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) {
let testMachineZ80 = testMachine as! CSTestMachineZ80
switch address { switch address {
case 0x0005: case 0x0005:
let cRegister = testMachine.value(for: .C) let cRegister = testMachineZ80.value(for: .C)
var textToAppend = "" var textToAppend = ""
switch cRegister { switch cRegister {
case 9: case 9:
var address = testMachine.value(for: .DE) var address = testMachineZ80.value(for: .DE)
var character: Character = " " var character: Character = " "
while true { while true {
character = Character(UnicodeScalar(testMachine.value(atAddress: address))) character = Character(UnicodeScalar(testMachineZ80.value(atAddress: address)))
if character == "$" { if character == "$" {
break break
} }
@ -149,7 +150,7 @@ class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
address = address + 1 address = address + 1
} }
case 5: case 5:
textToAppend = String(describing: UnicodeScalar(testMachine.value(for: .E))) textToAppend = String(describing: UnicodeScalar(testMachineZ80.value(for: .E)))
case 0: case 0:
done = true done = true
default: default:

View File

@ -9,3 +9,237 @@
#include "6502.hpp" #include "6502.hpp"
const uint8_t CPU::MOS6502::JamOpcode = 0xf2; const uint8_t CPU::MOS6502::JamOpcode = 0xf2;
#define Program(...) {__VA_ARGS__, OperationMoveToNextProgram}
#define Absolute CycleLoadAddressAbsolute
#define AbsoluteXr CycleLoadAddressAbsolute, CycleAddXToAddressLow, OperationCorrectAddressHigh
#define AbsoluteYr CycleLoadAddressAbsolute, CycleAddYToAddressLow, OperationCorrectAddressHigh
#define AbsoluteX CycleLoadAddressAbsolute, CycleAddXToAddressLowRead, OperationCorrectAddressHigh
#define AbsoluteY CycleLoadAddressAbsolute, CycleAddYToAddressLowRead, OperationCorrectAddressHigh
#define Zero OperationLoadAddressZeroPage
#define ZeroX CycleLoadAddessZeroX
#define ZeroY CycleLoadAddessZeroY
#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 AbsoluteRead(op) Program(Absolute, Read(op))
#define AbsoluteXRead(op) Program(AbsoluteXr, Read(op))
#define AbsoluteYRead(op) Program(AbsoluteYr, Read(op))
#define ZeroRead(...) Program(Zero, Read(__VA_ARGS__))
#define ZeroXRead(op) Program(ZeroX, Read(op))
#define ZeroYRead(op) Program(ZeroY, Read(op))
#define IndexedIndirectRead(op) Program(IndexedIndirect, Read(op))
#define IndirectIndexedRead(op) Program(IndirectIndexedr, Read(op))
#define AbsoluteWrite(op) Program(Absolute, Write(op))
#define AbsoluteXWrite(op) Program(AbsoluteX, Write(op))
#define AbsoluteYWrite(op) Program(AbsoluteY, Write(op))
#define ZeroWrite(op) Program(Zero, Write(op))
#define ZeroXWrite(op) Program(ZeroX, Write(op))
#define ZeroYWrite(op) Program(ZeroY, Write(op))
#define IndexedIndirectWrite(op) Program(IndexedIndirect, Write(op))
#define IndirectIndexedWrite(op) Program(IndirectIndexed, Write(op))
#define AbsoluteReadModifyWrite(...) Program(Absolute, ReadModifyWrite(__VA_ARGS__))
#define AbsoluteXReadModifyWrite(...) Program(AbsoluteX, ReadModifyWrite(__VA_ARGS__))
#define AbsoluteYReadModifyWrite(...) Program(AbsoluteY, ReadModifyWrite(__VA_ARGS__))
#define ZeroReadModifyWrite(...) Program(Zero, ReadModifyWrite(__VA_ARGS__))
#define ZeroXReadModifyWrite(...) Program(ZeroX, ReadModifyWrite(__VA_ARGS__))
#define ZeroYReadModifyWrite(...) Program(ZeroY, ReadModifyWrite(__VA_ARGS__))
#define IndexedIndirectReadModifyWrite(...) Program(IndexedIndirect, ReadModifyWrite(__VA_ARGS__))
#define IndirectIndexedReadModifyWrite(...) Program(IndirectIndexed, ReadModifyWrite(__VA_ARGS__))
#define Immediate(op) Program(OperationIncrementPC, op)
#define Implied(op) Program(OperationCopyOperandFromA, op, OperationCopyOperandToA)
#define ZeroNop() Program(Zero, CycleFetchOperandFromAddress)
#define ZeroXNop() Program(ZeroX, CycleFetchOperandFromAddress)
#define AbsoluteNop() Program(Absolute)
#define AbsoluteXNop() Program(AbsoluteX)
#define ImpliedNop() {OperationMoveToNextProgram}
#define ImmediateNop() Program(OperationIncrementPC)
#define JAM {CycleFetchOperand, CycleScheduleJam}
const CPU::MOS6502::ProcessorBase::MicroOp CPU::MOS6502::ProcessorBase::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),
};
#undef Program
#undef Absolute
#undef AbsoluteX
#undef AbsoluteY
#undef Zero
#undef ZeroX
#undef ZeroY
#undef IndexedIndirect
#undef IndirectIndexed
#undef Read
#undef Write
#undef ReadModifyWrite
#undef AbsoluteRead
#undef AbsoluteXRead
#undef AbsoluteYRead
#undef ZeroRead
#undef ZeroXRead
#undef ZeroYRead
#undef IndexedIndirectRead
#undef IndirectIndexedRead
#undef AbsoluteWrite
#undef AbsoluteXWrite
#undef AbsoluteYWrite
#undef ZeroWrite
#undef ZeroXWrite
#undef ZeroYWrite
#undef IndexedIndirectWrite
#undef IndirectIndexedWrite
#undef AbsoluteReadModifyWrite
#undef AbsoluteXReadModifyWrite
#undef AbsoluteYReadModifyWrite
#undef ZeroReadModifyWrite
#undef ZeroXReadModifyWrite
#undef ZeroYReadModify
#undef IndexedIndirectReadModify
#undef IndirectIndexedReadModify
#undef Immediate
#undef Implied

View File

@ -66,27 +66,8 @@ enum BusOperation {
*/ */
extern const uint8_t JamOpcode; extern const uint8_t JamOpcode;
/*! class ProcessorBase {
@abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism. protected:
@discussion Subclasses should implement @c perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) in
order to provide the bus on which the 6502 operates and @c flush(), which is called upon completion of a continuous run
of cycles to allow a subclass to bring any on-demand activities up to date.
Additional functionality can be provided by the host machine by providing a jam handler and inserting jam opcodes where appropriate;
that will cause call outs when the program counter reaches those addresses. @c return_from_subroutine can be used to exit from a
jammed state.
*/
template <class T> class Processor {
public:
class JamHandler {
public:
virtual void processor_did_jam(Processor *processor, uint16_t address) = 0;
};
private:
/* /*
This emulation functions by decomposing instructions into micro programs, consisting of the micro operations This emulation functions by decomposing instructions into micro programs, consisting of the micro operations
as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle
@ -131,9 +112,24 @@ template <class T> class Processor {
OperationSetFlagsFromA, OperationSetFlagsFromA,
CycleScheduleJam CycleScheduleJam
}; };
const MicroOp *scheduled_program_counter_;
#define JAM {CycleFetchOperand, CycleScheduleJam} static const MicroOp operations[256][10];
};
/*!
@abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism.
@discussion Subclasses should implement @c perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) in
order to provide the bus on which the 6502 operates and @c flush(), which is called upon completion of a continuous run
of cycles to allow a subclass to bring any on-demand activities up to date.
Additional functionality can be provided by the host machine by providing a jam handler and inserting jam opcodes where appropriate;
that will cause call outs when the program counter reaches those addresses. @c return_from_subroutine can be used to exit from a
jammed state.
*/
template <class T> class Processor: public ProcessorBase {
private:
const MicroOp *scheduled_program_counter_;
/* /*
Storage for the 6502 registers; F is stored as individual flags. Storage for the 6502 registers; F is stored as individual flags.
@ -183,251 +179,7 @@ template <class T> class Processor {
decimal_flag_ = flags & Flag::Decimal; decimal_flag_ = flags & Flag::Decimal;
} }
/*!
Schedules the program corresponding to the specified operation.
@param operation The operation code for which to schedule a program.
*/
inline void decode_operation(uint8_t operation) {
#define Program(...) {__VA_ARGS__, OperationMoveToNextProgram}
#define Absolute CycleLoadAddressAbsolute
#define AbsoluteXr CycleLoadAddressAbsolute, CycleAddXToAddressLow, OperationCorrectAddressHigh
#define AbsoluteYr CycleLoadAddressAbsolute, CycleAddYToAddressLow, OperationCorrectAddressHigh
#define AbsoluteX CycleLoadAddressAbsolute, CycleAddXToAddressLowRead, OperationCorrectAddressHigh
#define AbsoluteY CycleLoadAddressAbsolute, CycleAddYToAddressLowRead, OperationCorrectAddressHigh
#define Zero OperationLoadAddressZeroPage
#define ZeroX CycleLoadAddessZeroX
#define ZeroY CycleLoadAddessZeroY
#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 AbsoluteRead(op) Program(Absolute, Read(op))
#define AbsoluteXRead(op) Program(AbsoluteXr, Read(op))
#define AbsoluteYRead(op) Program(AbsoluteYr, Read(op))
#define ZeroRead(...) Program(Zero, Read(__VA_ARGS__))
#define ZeroXRead(op) Program(ZeroX, Read(op))
#define ZeroYRead(op) Program(ZeroY, Read(op))
#define IndexedIndirectRead(op) Program(IndexedIndirect, Read(op))
#define IndirectIndexedRead(op) Program(IndirectIndexedr, Read(op))
#define AbsoluteWrite(op) Program(Absolute, Write(op))
#define AbsoluteXWrite(op) Program(AbsoluteX, Write(op))
#define AbsoluteYWrite(op) Program(AbsoluteY, Write(op))
#define ZeroWrite(op) Program(Zero, Write(op))
#define ZeroXWrite(op) Program(ZeroX, Write(op))
#define ZeroYWrite(op) Program(ZeroY, Write(op))
#define IndexedIndirectWrite(op) Program(IndexedIndirect, Write(op))
#define IndirectIndexedWrite(op) Program(IndirectIndexed, Write(op))
#define AbsoluteReadModifyWrite(...) Program(Absolute, ReadModifyWrite(__VA_ARGS__))
#define AbsoluteXReadModifyWrite(...) Program(AbsoluteX, ReadModifyWrite(__VA_ARGS__))
#define AbsoluteYReadModifyWrite(...) Program(AbsoluteY, ReadModifyWrite(__VA_ARGS__))
#define ZeroReadModifyWrite(...) Program(Zero, ReadModifyWrite(__VA_ARGS__))
#define ZeroXReadModifyWrite(...) Program(ZeroX, ReadModifyWrite(__VA_ARGS__))
#define ZeroYReadModifyWrite(...) Program(ZeroY, ReadModifyWrite(__VA_ARGS__))
#define IndexedIndirectReadModifyWrite(...) Program(IndexedIndirect, ReadModifyWrite(__VA_ARGS__))
#define IndirectIndexedReadModifyWrite(...) Program(IndirectIndexed, ReadModifyWrite(__VA_ARGS__))
#define Immediate(op) Program(OperationIncrementPC, op)
#define Implied(op) Program(OperationCopyOperandFromA, op, OperationCopyOperandToA)
#define ZeroNop() Program(Zero, CycleFetchOperandFromAddress)
#define ZeroXNop() Program(ZeroX, CycleFetchOperandFromAddress)
#define AbsoluteNop() Program(Absolute)
#define AbsoluteXNop() Program(AbsoluteX)
#define ImpliedNop() {OperationMoveToNextProgram}
#define ImmediateNop() Program(OperationIncrementPC)
static const MicroOp 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),
};
#undef Program
#undef Absolute
#undef AbsoluteX
#undef AbsoluteY
#undef Zero
#undef ZeroX
#undef ZeroY
#undef IndexedIndirect
#undef IndirectIndexed
#undef Read
#undef Write
#undef ReadModifyWrite
#undef AbsoluteRead
#undef AbsoluteXRead
#undef AbsoluteYRead
#undef ZeroRead
#undef ZeroXRead
#undef ZeroYRead
#undef IndexedIndirectRead
#undef IndirectIndexedRead
#undef AbsoluteWrite
#undef AbsoluteXWrite
#undef AbsoluteYWrite
#undef ZeroWrite
#undef ZeroXWrite
#undef ZeroYWrite
#undef IndexedIndirectWrite
#undef IndirectIndexedWrite
#undef AbsoluteReadModifyWrite
#undef AbsoluteXReadModifyWrite
#undef AbsoluteYReadModifyWrite
#undef ZeroReadModifyWrite
#undef ZeroXReadModifyWrite
#undef ZeroYReadModify
#undef IndexedIndirectReadModify
#undef IndirectIndexedReadModify
#undef Immediate
#undef Implied
scheduled_program_counter_ = operations[operation];
}
bool is_jammed_; bool is_jammed_;
JamHandler *jam_handler_;
int cycles_left_to_run_; int cycles_left_to_run_;
enum InterruptRequestFlags: uint8_t { enum InterruptRequestFlags: uint8_t {
@ -511,7 +263,6 @@ template <class T> class Processor {
protected: protected:
Processor() : Processor() :
is_jammed_(false), is_jammed_(false),
jam_handler_(nullptr),
cycles_left_to_run_(0), cycles_left_to_run_(0),
ready_line_is_enabled_(false), ready_line_is_enabled_(false),
ready_is_active_(false), ready_is_active_(false),
@ -639,7 +390,7 @@ template <class T> class Processor {
case OperationDecodeOperation: case OperationDecodeOperation:
// printf("d %02x\n", operation_); // printf("d %02x\n", operation_);
decode_operation(operation_); scheduled_program_counter_ = operations[operation_];
continue; continue;
case OperationMoveToNextProgram: case OperationMoveToNextProgram:
@ -702,13 +453,7 @@ template <class T> class Processor {
case CycleScheduleJam: { case CycleScheduleJam: {
is_jammed_ = true; is_jammed_ = true;
static const MicroOp jam[] = JAM; scheduled_program_counter_ = operations[CPU::MOS6502::JamOpcode];
scheduled_program_counter_ = jam;
if(jam_handler_) {
jam_handler_->processor_did_jam(this, pc_.full - 1);
checkSchedule(is_jammed_ = false;);
}
} continue; } continue;
#pragma mark - Bitwise #pragma mark - Bitwise
@ -1230,15 +975,6 @@ template <class T> class Processor {
inline bool is_jammed() { inline bool is_jammed() {
return is_jammed_; return is_jammed_;
} }
/*!
Installs a jam handler. Jam handlers are notified if a running 6502 jams.
@param handler The class instance that will be this 6502's jam handler from now on.
*/
inline void set_jam_handler(JamHandler *handler) {
jam_handler_ = handler;
}
}; };
} }

View File

@ -12,20 +12,61 @@
using namespace CPU::MOS6502; using namespace CPU::MOS6502;
AllRAMProcessor::AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) { namespace {
set_power_on(false);
class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<ConcreteAllRAMProcessor> {
public:
ConcreteAllRAMProcessor() {
set_power_on(false);
}
inline int perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) {
timestamp_++;
if(operation == BusOperation::ReadOpcode) {
check_address_for_trap(address);
}
if(isReadOperation(operation)) {
*value = memory_[address];
} else {
memory_[address] = *value;
}
return 1;
}
void run_for_cycles(int number_of_cycles) {
Processor<ConcreteAllRAMProcessor>::run_for_cycles(number_of_cycles);
}
bool is_jammed() {
return Processor<ConcreteAllRAMProcessor>::is_jammed();
}
void set_irq_line(bool value) {
Processor<ConcreteAllRAMProcessor>::set_irq_line(value);
}
void set_nmi_line(bool value) {
Processor<ConcreteAllRAMProcessor>::set_nmi_line(value);
}
void return_from_subroutine() {
Processor<ConcreteAllRAMProcessor>::return_from_subroutine();
}
uint16_t get_value_of_register(Register r) {
return Processor<ConcreteAllRAMProcessor>::get_value_of_register(r);
}
void set_value_of_register(Register r, uint16_t value) {
Processor<ConcreteAllRAMProcessor>::set_value_of_register(r, value);
}
};
} }
int AllRAMProcessor::perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { AllRAMProcessor *AllRAMProcessor::Processor() {
timestamp_++; return new ConcreteAllRAMProcessor;
// if(operation == MOS6502::BusOperation::ReadOpcode) printf("%04x\n", address);
if(isReadOperation(operation)) {
*value = memory_[address];
} else {
memory_[address] = *value;
}
return 1;
} }

View File

@ -16,13 +16,22 @@ namespace CPU {
namespace MOS6502 { namespace MOS6502 {
class AllRAMProcessor: class AllRAMProcessor:
public ::CPU::AllRAMProcessor, public ::CPU::AllRAMProcessor {
public Processor<AllRAMProcessor> {
public: public:
AllRAMProcessor(); static AllRAMProcessor *Processor();
virtual ~AllRAMProcessor() {}
int perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value); virtual void run_for_cycles(int number_of_cycles) = 0;
virtual bool is_jammed() = 0;
virtual void set_irq_line(bool value) = 0;
virtual void set_nmi_line(bool value) = 0;
virtual void return_from_subroutine() = 0;
virtual uint16_t get_value_of_register(Register r) = 0;
virtual void set_value_of_register(Register r, uint16_t value) = 0;
protected:
AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) {}
}; };
} }

View File

@ -12,6 +12,7 @@ using namespace CPU;
AllRAMProcessor::AllRAMProcessor(size_t memory_size) : AllRAMProcessor::AllRAMProcessor(size_t memory_size) :
memory_(memory_size), memory_(memory_size),
traps_(memory_size, false),
timestamp_(0) {} timestamp_(0) {}
void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data) { void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data) {
@ -33,5 +34,5 @@ void AllRAMProcessor::set_trap_handler(TrapHandler *trap_handler) {
} }
void AllRAMProcessor::add_trap_address(uint16_t address) { void AllRAMProcessor::add_trap_address(uint16_t address) {
trap_addresses_.insert(address); traps_[address] = true;
} }

View File

@ -34,14 +34,14 @@ class AllRAMProcessor {
uint32_t timestamp_; uint32_t timestamp_;
inline void check_address_for_trap(uint16_t address) { inline void check_address_for_trap(uint16_t address) {
if(trap_addresses_.find(address) != trap_addresses_.end()) { if(traps_[address]) {
trap_handler_->processor_did_trap(*this, address); trap_handler_->processor_did_trap(*this, address);
} }
} }
private: private:
std::set<uint16_t> trap_addresses_;
TrapHandler *trap_handler_; TrapHandler *trap_handler_;
std::vector<bool> traps_;
}; };
} }