1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Attempted to bring a common hierarchy to the Z80 and 6502 test machines, particularly with a view to eliminating the special-case Jam stuff on the 6502.

This commit is contained in:
Thomas Harte 2017-06-03 21:22:16 -04:00
parent 0b2a3f18bc
commit fd6623b5a5
11 changed files with 214 additions and 84 deletions

View File

@ -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 */,
);

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 "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;

View File

@ -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

View File

@ -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;

View File

@ -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 {

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 {
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:

View File

@ -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);
}
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;
}

View File

@ -16,13 +16,21 @@ namespace CPU {
namespace MOS6502 {
class AllRAMProcessor:
public ::CPU::AllRAMProcessor,
public Processor<AllRAMProcessor> {
public ::CPU::AllRAMProcessor {
public:
AllRAMProcessor();
static AllRAMProcessor *Processor();
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) {}
};
}