mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +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:
commit
fba6ac2b4c
@ -9,6 +9,7 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.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 */; };
|
||||
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1198,12 +1202,15 @@
|
||||
4BEF6AA81D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.h */,
|
||||
4B3BA0C81D318B44005DD7A7 /* MOS6522Bridge.h */,
|
||||
4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */,
|
||||
4B08A2761EE39306008B7065 /* TestMachine.h */,
|
||||
4B08A2791EE3957B008B7065 /* TestMachine+ForSubclassEyesOnly.h */,
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine6502.h */,
|
||||
4BFCA1251ECBE33200AC40C1 /* TestMachineZ80.h */,
|
||||
4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */,
|
||||
4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */,
|
||||
4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */,
|
||||
4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */,
|
||||
4B08A2771EE39306008B7065 /* TestMachine.mm */,
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */,
|
||||
4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */,
|
||||
);
|
||||
@ -2623,6 +2630,7 @@
|
||||
4BD4A8D01E077FD20020D856 /* PCMTrackTests.mm in Sources */,
|
||||
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */,
|
||||
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
|
||||
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
|
||||
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
|
||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */,
|
||||
);
|
||||
|
@ -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
|
22
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine.h
Normal file
22
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine.h
Normal 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
|
57
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine.mm
Normal file
57
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine.mm
Normal 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
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TestMachine.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSTestMachine6502Register) {
|
||||
CSTestMachine6502RegisterLastOperationAddress,
|
||||
@ -25,7 +26,7 @@ extern const uint8_t CSTestMachine6502JamOpcode;
|
||||
- (void)testMachine:(CSTestMachine6502 *)machine didJamAtAddress:(uint16_t)address;
|
||||
@end
|
||||
|
||||
@interface CSTestMachine6502 : NSObject
|
||||
@interface CSTestMachine6502 : CSTestMachine
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (void)runForNumberOfCycles:(int)cycles;
|
||||
|
@ -9,22 +9,23 @@
|
||||
#import "TestMachine6502.h"
|
||||
#include <stdint.h>
|
||||
#include "6502AllRAM.hpp"
|
||||
#import "TestMachine+ForSubclassEyesOnly.h"
|
||||
|
||||
const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode;
|
||||
|
||||
#pragma mark - C++ jam handler
|
||||
|
||||
class MachineJamHandler: public CPU::MOS6502::AllRAMProcessor::JamHandler {
|
||||
public:
|
||||
MachineJamHandler(CSTestMachine6502 *targetMachine) : _targetMachine(targetMachine) {}
|
||||
|
||||
void processor_did_jam(CPU::MOS6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
|
||||
[_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address];
|
||||
}
|
||||
|
||||
private:
|
||||
CSTestMachine6502 *_targetMachine;
|
||||
};
|
||||
//class MachineJamHandler: public CPU::MOS6502::AllRAMProcessor::JamHandler {
|
||||
// public:
|
||||
// MachineJamHandler(CSTestMachine6502 *targetMachine) : _targetMachine(targetMachine) {}
|
||||
//
|
||||
// void processor_did_jam(CPU::MOS6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
|
||||
// [_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address];
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// CSTestMachine6502 *_targetMachine;
|
||||
//};
|
||||
|
||||
#pragma mark - Register enum map
|
||||
|
||||
@ -43,8 +44,8 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
|
||||
#pragma mark - Test class
|
||||
|
||||
@implementation CSTestMachine6502 {
|
||||
CPU::MOS6502::AllRAMProcessor _processor;
|
||||
MachineJamHandler *_cppJamHandler;
|
||||
CPU::MOS6502::AllRAMProcessor *_processor;
|
||||
// MachineJamHandler *_cppJamHandler;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
@ -53,67 +54,70 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
|
||||
self = [super init];
|
||||
|
||||
if(self) {
|
||||
_cppJamHandler = new MachineJamHandler(self);
|
||||
_processor.set_jam_handler(_cppJamHandler);
|
||||
_processor = CPU::MOS6502::AllRAMProcessor::Processor();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete _cppJamHandler;
|
||||
delete _processor;
|
||||
}
|
||||
|
||||
#pragma mark - Accessors
|
||||
|
||||
- (uint8_t)valueForAddress:(uint16_t)address {
|
||||
uint8_t value;
|
||||
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Read, address, &value);
|
||||
_processor->get_data_at_address(address, 1, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
- (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 {
|
||||
_processor.set_value_of_register(registerForRegister(reg), value);
|
||||
_processor->set_value_of_register(registerForRegister(reg), value);
|
||||
}
|
||||
|
||||
- (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 {
|
||||
_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 {
|
||||
return _processor.is_jammed();
|
||||
return _processor->is_jammed();
|
||||
}
|
||||
|
||||
- (uint32_t)timestamp {
|
||||
return _processor.get_timestamp();
|
||||
return _processor->get_timestamp();
|
||||
}
|
||||
|
||||
- (void)setIrqLine:(BOOL)irqLine {
|
||||
_irqLine = irqLine;
|
||||
_processor.set_irq_line(irqLine);
|
||||
_processor->set_irq_line(irqLine);
|
||||
}
|
||||
|
||||
- (void)setNmiLine:(BOOL)nmiLine {
|
||||
_nmiLine = nmiLine;
|
||||
_processor.set_nmi_line(nmiLine);
|
||||
_processor->set_nmi_line(nmiLine);
|
||||
}
|
||||
|
||||
- (CPU::AllRAMProcessor *)processor {
|
||||
return _processor;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)returnFromSubroutine {
|
||||
_processor.return_from_subroutine();
|
||||
_processor->return_from_subroutine();
|
||||
}
|
||||
|
||||
- (void)runForNumberOfCycles:(int)cycles {
|
||||
_processor.run_for_cycles(cycles);
|
||||
_processor->run_for_cycles(cycles);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -8,13 +8,10 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <stdint.h>
|
||||
#import "TestMachine.h"
|
||||
|
||||
@class CSTestMachineZ80;
|
||||
|
||||
@protocol CSTestMachineTrapHandler
|
||||
- (void)testMachine:(nonnull CSTestMachineZ80 *)testMachine didTrapAtAddress:(uint16_t)address;
|
||||
@end
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSTestMachineZ80BusOperationCaptureOperation) {
|
||||
CSTestMachineZ80BusOperationCaptureOperationRead,
|
||||
CSTestMachineZ80BusOperationCaptureOperationWrite,
|
||||
@ -46,7 +43,7 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
|
||||
CSTestMachineZ80RegisterIFF1, CSTestMachineZ80RegisterIFF2, CSTestMachineZ80RegisterIM
|
||||
};
|
||||
|
||||
@interface CSTestMachineZ80 : NSObject
|
||||
@interface CSTestMachineZ80 : CSTestMachine
|
||||
|
||||
- (void)setData:(nonnull NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (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;
|
||||
- (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg;
|
||||
|
||||
@property(nonatomic, weak, nullable) id<CSTestMachineTrapHandler> trapHandler;
|
||||
- (void)addTrapAddress:(uint16_t)trapAddress;
|
||||
|
||||
@property(nonatomic, assign) BOOL captureBusActivity;
|
||||
@property(nonatomic, readonly, nonnull) NSArray<CSTestMachineZ80BusOperationCapture *> *busOperationCaptures;
|
||||
|
||||
|
@ -8,26 +8,14 @@
|
||||
|
||||
#import "TestMachineZ80.h"
|
||||
#include "Z80AllRAM.hpp"
|
||||
#import "TestMachine+ForSubclassEyesOnly.h"
|
||||
|
||||
@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;
|
||||
@end
|
||||
|
||||
#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 {
|
||||
public:
|
||||
BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {}
|
||||
@ -105,7 +93,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
||||
|
||||
@implementation CSTestMachineZ80 {
|
||||
CPU::Z80::AllRAMProcessor *_processor;
|
||||
MachineTrapHandler *_cppTrapHandler;
|
||||
BusOperationHandler *_busOperationHandler;
|
||||
|
||||
NSMutableArray<CSTestMachineZ80BusOperationCapture *> *_busOperationCaptures;
|
||||
@ -120,7 +107,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
||||
if(self = [super init]) {
|
||||
_processor = CPU::Z80::AllRAMProcessor::Processor();
|
||||
_processor->reset_power_on();
|
||||
_cppTrapHandler = new MachineTrapHandler(self);
|
||||
_busOperationHandler = new BusOperationHandler(self);
|
||||
_busOperationCaptures = [[NSMutableArray alloc] init];
|
||||
}
|
||||
@ -128,7 +114,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete _cppTrapHandler;
|
||||
delete _busOperationHandler;
|
||||
}
|
||||
|
||||
@ -160,15 +145,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
- (CPU::AllRAMProcessor *)processor {
|
||||
return _processor;
|
||||
}
|
||||
|
||||
#pragma mark - Z80-specific Runner
|
||||
|
||||
- (void)runToNextInstruction {
|
||||
|
@ -9,7 +9,7 @@
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
class WolfgangLorenzTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
|
||||
func testWolfgangLorenzStart() {
|
||||
self.runWolfgangLorenzTest(" start")
|
||||
@ -201,7 +201,7 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
|
||||
machine = CSTestMachine6502()
|
||||
machine.jamHandler = self
|
||||
machine.trapHandler = self
|
||||
// machine.logActivity = true
|
||||
output = ""
|
||||
|
||||
@ -225,11 +225,18 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
] as [UInt8]), count: 19)
|
||||
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:0xffe4) // scan keyboard
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0x8000) // exit
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xa474) // exit
|
||||
|
||||
machine.setValue(0x0801, for: CSTestMachine6502Register.programCounter)
|
||||
machine.setValue(0xfd, for: CSTestMachine6502Register.stackPointer)
|
||||
@ -296,19 +303,17 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
return result
|
||||
}
|
||||
|
||||
func testMachine(_ machine: CSTestMachine6502!, didJamAtAddress address: UInt16) {
|
||||
func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) {
|
||||
let testMachine6502 = testMachine as! CSTestMachine6502
|
||||
switch address {
|
||||
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)!))
|
||||
|
||||
machine.returnFromSubroutine()
|
||||
|
||||
case 0xffe4:
|
||||
machine.setValue(0x3, for:CSTestMachine6502Register.A)
|
||||
machine.returnFromSubroutine()
|
||||
testMachine6502.setValue(0x3, for:CSTestMachine6502Register.A)
|
||||
|
||||
case 0x8000, 0xa474:
|
||||
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: self.petsciiToString(output), userInfo: nil).raise()
|
||||
@ -316,9 +321,6 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
case 0x0000:
|
||||
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:
|
||||
let hexAddress = String(format:"%04x", address)
|
||||
NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()
|
||||
|
@ -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 {
|
||||
case 0x0005:
|
||||
let cRegister = testMachine.value(for: .C)
|
||||
let cRegister = testMachineZ80.value(for: .C)
|
||||
var textToAppend = ""
|
||||
switch cRegister {
|
||||
case 9:
|
||||
var address = testMachine.value(for: .DE)
|
||||
var address = testMachineZ80.value(for: .DE)
|
||||
var character: Character = " "
|
||||
while true {
|
||||
character = Character(UnicodeScalar(testMachine.value(atAddress: address)))
|
||||
character = Character(UnicodeScalar(testMachineZ80.value(atAddress: address)))
|
||||
if character == "$" {
|
||||
break
|
||||
}
|
||||
@ -149,7 +150,7 @@ class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
address = address + 1
|
||||
}
|
||||
case 5:
|
||||
textToAppend = String(describing: UnicodeScalar(testMachine.value(for: .E)))
|
||||
textToAppend = String(describing: UnicodeScalar(testMachineZ80.value(for: .E)))
|
||||
case 0:
|
||||
done = true
|
||||
default:
|
||||
|
@ -9,3 +9,237 @@
|
||||
#include "6502.hpp"
|
||||
|
||||
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
|
||||
|
@ -66,27 +66,8 @@ enum BusOperation {
|
||||
*/
|
||||
extern const uint8_t JamOpcode;
|
||||
|
||||
/*!
|
||||
@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:
|
||||
|
||||
class JamHandler {
|
||||
public:
|
||||
virtual void processor_did_jam(Processor *processor, uint16_t address) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
class ProcessorBase {
|
||||
protected:
|
||||
/*
|
||||
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
|
||||
@ -131,9 +112,24 @@ template <class T> class Processor {
|
||||
OperationSetFlagsFromA,
|
||||
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.
|
||||
@ -183,251 +179,7 @@ template <class T> class Processor {
|
||||
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_;
|
||||
JamHandler *jam_handler_;
|
||||
|
||||
int cycles_left_to_run_;
|
||||
|
||||
enum InterruptRequestFlags: uint8_t {
|
||||
@ -511,7 +263,6 @@ template <class T> class Processor {
|
||||
protected:
|
||||
Processor() :
|
||||
is_jammed_(false),
|
||||
jam_handler_(nullptr),
|
||||
cycles_left_to_run_(0),
|
||||
ready_line_is_enabled_(false),
|
||||
ready_is_active_(false),
|
||||
@ -639,7 +390,7 @@ template <class T> class Processor {
|
||||
|
||||
case OperationDecodeOperation:
|
||||
// printf("d %02x\n", operation_);
|
||||
decode_operation(operation_);
|
||||
scheduled_program_counter_ = operations[operation_];
|
||||
continue;
|
||||
|
||||
case OperationMoveToNextProgram:
|
||||
@ -702,13 +453,7 @@ template <class T> class Processor {
|
||||
|
||||
case CycleScheduleJam: {
|
||||
is_jammed_ = true;
|
||||
static const MicroOp jam[] = JAM;
|
||||
scheduled_program_counter_ = jam;
|
||||
|
||||
if(jam_handler_) {
|
||||
jam_handler_->processor_did_jam(this, pc_.full - 1);
|
||||
checkSchedule(is_jammed_ = false;);
|
||||
}
|
||||
scheduled_program_counter_ = operations[CPU::MOS6502::JamOpcode];
|
||||
} continue;
|
||||
|
||||
#pragma mark - Bitwise
|
||||
@ -1230,15 +975,6 @@ template <class T> class Processor {
|
||||
inline bool 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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,20 +12,61 @@
|
||||
|
||||
using namespace CPU::MOS6502;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) {
|
||||
set_power_on(false);
|
||||
namespace {
|
||||
|
||||
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) {
|
||||
timestamp_++;
|
||||
|
||||
// if(operation == MOS6502::BusOperation::ReadOpcode) printf("%04x\n", address);
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
*value = memory_[address];
|
||||
} else {
|
||||
memory_[address] = *value;
|
||||
}
|
||||
|
||||
return 1;
|
||||
AllRAMProcessor *AllRAMProcessor::Processor() {
|
||||
return new ConcreteAllRAMProcessor;
|
||||
}
|
||||
|
@ -16,13 +16,22 @@ namespace CPU {
|
||||
namespace MOS6502 {
|
||||
|
||||
class AllRAMProcessor:
|
||||
public ::CPU::AllRAMProcessor,
|
||||
public Processor<AllRAMProcessor> {
|
||||
public ::CPU::AllRAMProcessor {
|
||||
|
||||
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) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using namespace CPU;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor(size_t memory_size) :
|
||||
memory_(memory_size),
|
||||
traps_(memory_size, false),
|
||||
timestamp_(0) {}
|
||||
|
||||
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) {
|
||||
trap_addresses_.insert(address);
|
||||
traps_[address] = true;
|
||||
}
|
||||
|
@ -34,14 +34,14 @@ class AllRAMProcessor {
|
||||
uint32_t timestamp_;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<uint16_t> trap_addresses_;
|
||||
TrapHandler *trap_handler_;
|
||||
std::vector<bool> traps_;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user