1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Started working on a shell for the Electron emulation, including factoring out the common CRT delegate -> Objective-C bridging, serial dispatch queue and frameskipping logic from the Atari 2600 shell.

This commit is contained in:
Thomas Harte 2016-01-04 23:12:47 -05:00
parent 22fa024546
commit ab45c1d530
14 changed files with 304 additions and 144 deletions

View File

@ -9,8 +9,8 @@
#ifndef Atari2600_cpp
#define Atari2600_cpp
#include "../Processors/6502/CPU6502.hpp"
#include "../Outputs/CRT.hpp"
#include "../../Processors/6502/CPU6502.hpp"
#include "../../Outputs/CRT.hpp"
#include <stdint.h>
#include "Atari2600Inputs.h"

View File

@ -0,0 +1,24 @@
//
// Electron.cpp
// Clock Signal
//
// Created by Thomas Harte on 03/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "Electron.hpp"
using namespace Electron;
Machine::Machine()
{
}
Machine::~Machine()
{
}
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
{
return 1;
}

View File

@ -0,0 +1,32 @@
//
// Electron.hpp
// Clock Signal
//
// Created by Thomas Harte on 03/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef Electron_hpp
#define Electron_hpp
#include "../../Processors/6502/CPU6502.hpp"
#include "../../Outputs/CRT.hpp"
#include <stdint.h>
#include "Atari2600Inputs.h"
namespace Electron {
class Machine: public CPU6502::Processor<Machine> {
public:
Machine();
~Machine();
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
};
}
#endif /* Electron_hpp */

View File

@ -7,9 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
4B14144E1B5883E500E04248 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B14144B1B5883E500E04248 /* CSAtari2600.mm */; };
4B14144F1B5883E500E04248 /* CSCathodeRayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B14144D1B5883E500E04248 /* CSCathodeRayView.m */; };
4B1414511B5885DF00E04248 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6D7F921B58822000787C9A /* Atari2600.cpp */; };
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */; };
@ -17,7 +15,11 @@
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; };
4B2E2D921C399B9900138695 /* ElectronDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D911C399B9900138695 /* ElectronDocument.swift */; };
4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2E2D931C399D1200138695 /* ElectronDocument.xib */; };
4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; };
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; };
4B366DFC1B5C165A0026627B /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B366DFA1B5C165A0026627B /* CRT.cpp */; };
4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */; };
4B55CE4E1C3B3BDA0093A61B /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */; };
4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; };
4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; };
4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; };
@ -314,8 +316,6 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
4B14144A1B5883E500E04248 /* CSAtari2600.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSAtari2600.h; sourceTree = "<group>"; };
4B14144B1B5883E500E04248 /* CSAtari2600.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSAtari2600.mm; sourceTree = "<group>"; };
4B14144C1B5883E500E04248 /* CSCathodeRayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSCathodeRayView.h; sourceTree = "<group>"; };
4B14144D1B5883E500E04248 /* CSCathodeRayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSCathodeRayView.m; sourceTree = "<group>"; };
4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ClockSignal-Bridging-Header.h"; sourceTree = "<group>"; };
@ -328,12 +328,19 @@
4B2632551B631A510082A461 /* CRTFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CRTFrame.h; path = ../../Outputs/CRTFrame.h; sourceTree = "<group>"; };
4B2E2D911C399B9900138695 /* ElectronDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElectronDocument.swift; sourceTree = "<group>"; };
4B2E2D941C399D1200138695 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ElectronDocument.xib; sourceTree = "<group>"; };
4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = "<group>"; };
4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = "<group>"; };
4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = "<group>"; };
4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = "<group>"; };
4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = "<group>"; };
4B366DFA1B5C165A0026627B /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRT.cpp; path = ../../Outputs/CRT.cpp; sourceTree = "<group>"; };
4B366DFB1B5C165A0026627B /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRT.hpp; path = ../../Outputs/CRT.hpp; sourceTree = "<group>"; };
4B6D7F921B58822000787C9A /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = "<group>"; };
4B6D7F931B58822000787C9A /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = "<group>"; };
4B55CE491C3B3B0C0093A61B /* CSAtari2600.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSAtari2600.h; sourceTree = "<group>"; };
4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSAtari2600.mm; sourceTree = "<group>"; };
4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSMachine.h; sourceTree = "<group>"; };
4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSMachine.mm; sourceTree = "<group>"; };
4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Subclassing.h"; sourceTree = "<group>"; };
4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = "<group>"; };
4BA3921C1B8402B3007FBF0E /* Atari2600Inputs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = "<group>"; };
4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = "<group>"; };
4BB297E01B587D8300A49093 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = "<group>"; };
4BB297E11B587D8300A49093 /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = AllSuiteA.bin; sourceTree = "<group>"; };
@ -666,6 +673,25 @@
name = "Test Binaries";
sourceTree = "<group>";
};
4B2E2D961C3A06EC00138695 /* Atari2600 */ = {
isa = PBXGroup;
children = (
4B2E2D971C3A06EC00138695 /* Atari2600.cpp */,
4B2E2D981C3A06EC00138695 /* Atari2600.hpp */,
4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */,
);
path = Atari2600;
sourceTree = "<group>";
};
4B2E2D9E1C3A070900138695 /* Electron */ = {
isa = PBXGroup;
children = (
4B2E2D9B1C3A070400138695 /* Electron.cpp */,
4B2E2D9C1C3A070400138695 /* Electron.hpp */,
);
name = Electron;
sourceTree = "<group>";
};
4B366DFD1B5C165F0026627B /* Outputs */ = {
isa = PBXGroup;
children = (
@ -676,6 +702,18 @@
name = Outputs;
sourceTree = "<group>";
};
4B55CE481C3B3B0C0093A61B /* Wrappers */ = {
isa = PBXGroup;
children = (
4B55CE491C3B3B0C0093A61B /* CSAtari2600.h */,
4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */,
4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */,
4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */,
4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */,
);
path = Wrappers;
sourceTree = "<group>";
};
4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */ = {
isa = PBXGroup;
children = (
@ -974,10 +1012,9 @@
4BB73EA01B587A5100552FC2 /* Clock Signal */ = {
isa = PBXGroup;
children = (
4B55CE481C3B3B0C0093A61B /* Wrappers */,
4B2E2D931C399D1200138695 /* ElectronDocument.xib */,
4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */,
4B14144A1B5883E500E04248 /* CSAtari2600.h */,
4B14144B1B5883E500E04248 /* CSAtari2600.mm */,
4B14144C1B5883E500E04248 /* CSCathodeRayView.h */,
4B14144D1B5883E500E04248 /* CSCathodeRayView.m */,
4BB73ECF1B587A6700552FC2 /* Clock Signal.entitlements */,
@ -1020,9 +1057,8 @@
4BB73EDC1B587CA500552FC2 /* Machines */ = {
isa = PBXGroup;
children = (
4B6D7F921B58822000787C9A /* Atari2600.cpp */,
4B6D7F931B58822000787C9A /* Atari2600.hpp */,
4BA3921C1B8402B3007FBF0E /* Atari2600Inputs.h */,
4B2E2D961C3A06EC00138695 /* Atari2600 */,
4B2E2D9E1C3A070900138695 /* Electron */,
);
name = Machines;
path = ../../Machines;
@ -1441,10 +1477,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B1414511B5885DF00E04248 /* Atari2600.cpp in Sources */,
4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */,
4B55CE4E1C3B3BDA0093A61B /* CSMachine.mm in Sources */,
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,
4B366DFC1B5C165A0026627B /* CRT.cpp in Sources */,
4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */,
4BB73EA41B587A5100552FC2 /* Atari2600Document.swift in Sources */,
4B14144E1B5883E500E04248 /* CSAtari2600.mm in Sources */,
4B2E2D921C399B9900138695 /* ElectronDocument.swift in Sources */,
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */,
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */,

View File

@ -16,10 +16,10 @@ class Atari2600Document: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewR
openGLView.delegate = self
openGLView.responderDelegate = self
atari2600!.view = openGLView!
atari2600.view = openGLView
// bind the content aspect ratio to remain 4:3 from now on
aController.window!.contentAspectRatio = NSSize(width: 4.0, height: 3.0)
aController.window?.contentAspectRatio = NSSize(width: 4.0, height: 3.0)
}
override class func autosavesInPlace() -> Bool {
@ -32,7 +32,7 @@ class Atari2600Document: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewR
return "Atari2600Document"
}
private var atari2600: CSAtari2600? = nil
private var atari2600: CSAtari2600! = nil
override func dataOfType(typeName: String) throws -> NSData {
// Insert code here to write your document to data of the specified type. If outError != nil, ensure that you create and set an appropriate error when returning nil.
// You can also choose to override fileWrapperOfType:error:, writeToURL:ofType:error:, or writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
@ -41,7 +41,7 @@ class Atari2600Document: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewR
override func readFromData(data: NSData, ofType typeName: String) throws {
atari2600 = CSAtari2600()
atari2600!.setROM(data)
atari2600.setROM(data)
}
override func close() {
@ -66,7 +66,7 @@ class Atari2600Document: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewR
let cycleCount = cycleCountLow + cycleCountHigh
if let lastCycleCount = lastCycleCount {
let elapsedTime = cycleCount - lastCycleCount
atari2600!.runForNumberOfCycles(Int32(elapsedTime))
atari2600.runForNumberOfCycles(Int32(elapsedTime))
}
lastCycleCount = cycleCount
}
@ -86,21 +86,21 @@ class Atari2600Document: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewR
func keyDown(event: NSEvent) {
if let input = inputForKey(event) {
atari2600!.setState(true, forDigitalInput: input)
atari2600.setState(true, forDigitalInput: input)
}
if event.keyCode == 36 {
atari2600!.setResetLineEnabled(true)
atari2600.setResetLineEnabled(true)
}
}
func keyUp(event: NSEvent) {
if let input = inputForKey(event) {
atari2600!.setState(false, forDigitalInput: input)
atari2600.setState(false, forDigitalInput: input)
}
if event.keyCode == 36 {
atari2600!.setResetLineEnabled(false)
atari2600.setResetLineEnabled(false)
}
}

View File

@ -1,114 +0,0 @@
//
// Atari2600.m
// CLK
//
// Created by Thomas Harte on 14/07/2015.
// Copyright © 2015 Thomas Harte. All rights reserved.
//
#import "CSAtari2600.h"
#import "Atari2600.hpp"
@interface CSAtari2600 (Callbacks)
- (void)crtDidEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync;
@end
struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate {
__weak CSAtari2600 *atari;
void crt_did_end_frame(Outputs::CRT *crt, CRTFrame *frame, bool did_detect_vsync) { [atari crtDidEndFrame:frame didDetectVSync:did_detect_vsync]; }
};
typedef NS_ENUM(NSInteger, CSAtari2600RunningState) {
CSAtari2600RunningStateRunning,
CSAtari2600RunningStateStopped
};
@implementation CSAtari2600 {
Atari2600::Machine _atari2600;
Atari2600CRTDelegate _crtDelegate;
dispatch_queue_t _serialDispatchQueue;
int _frameCount;
int _hitCount;
BOOL _didDecideRegion;
NSConditionLock *_runningLock;
}
- (void)crtDidEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync {
if(!_didDecideRegion)
{
_frameCount++;
_hitCount += didDetectVSync ? 1 : 0;
if(_frameCount > 30)
{
if(_hitCount < _frameCount >> 1)
{
_atari2600.switch_region();
_didDecideRegion = YES;
}
if(_hitCount > (_frameCount * 7) >> 3)
{
_didDecideRegion = YES;
}
}
}
BOOL hasReturn = [self.view pushFrame:frame];
if(hasReturn)
_atari2600.get_crt()->return_frame();
}
- (void)runForNumberOfCycles:(int)cycles {
if([_runningLock tryLockWhenCondition:CSAtari2600RunningStateStopped]) {
[_runningLock unlockWithCondition:CSAtari2600RunningStateRunning];
dispatch_async(_serialDispatchQueue, ^{
[_runningLock lockWhenCondition:CSAtari2600RunningStateRunning];
_atari2600.run_for_cycles(cycles);
[_runningLock unlockWithCondition:CSAtari2600RunningStateStopped];
});
}
}
- (void)setROM:(NSData *)rom {
dispatch_async(_serialDispatchQueue, ^{
_atari2600.set_rom(rom.length, (const uint8_t *)rom.bytes);
});
}
- (void)setState:(BOOL)state forDigitalInput:(Atari2600DigitalInput)digitalInput {
dispatch_async(_serialDispatchQueue, ^{
_atari2600.set_digital_input(digitalInput, state ? true : false);
});
}
- (void)setResetLineEnabled:(BOOL)enabled {
dispatch_async(_serialDispatchQueue, ^{
_atari2600.set_reset_line(enabled ? true : false);
});
}
- (void)setView:(CSCathodeRayView *)view {
_view = view;
[_view setSignalDecoder:[NSString stringWithUTF8String:_atari2600.get_signal_decoder()] type:CSCathodeRayViewSignalTypeNTSC];
}
- (instancetype)init {
self = [super init];
if (self) {
_crtDelegate.atari = self;
_atari2600.get_crt()->set_delegate(&_crtDelegate);
_serialDispatchQueue = dispatch_queue_create("Atari 2600 queue", DISPATCH_QUEUE_SERIAL);
_runningLock = [[NSConditionLock alloc] initWithCondition:CSAtari2600RunningStateStopped];
}
return self;
}
@end

View File

@ -10,6 +10,10 @@ import Foundation
class ElectronDocument: NSDocument, CSCathodeRayViewResponderDelegate, CSCathodeRayViewDelegate {
override init() {
super.init()
}
@IBOutlet weak var openGLView: CSCathodeRayView!
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
@ -27,6 +31,7 @@ class ElectronDocument: NSDocument, CSCathodeRayViewResponderDelegate, CSCathode
}
override func readFromData(data: NSData, ofType typeName: String) throws {
print("H")
}
override func close() {

View File

@ -9,14 +9,11 @@
#import <Foundation/Foundation.h>
#import "CSCathodeRayView.h"
#include "Atari2600Inputs.h"
#include "CSMachine.h"
@interface CSAtari2600 : NSObject
@interface CSAtari2600 : CSMachine
@property (nonatomic, weak) CSCathodeRayView *view;
- (void)runForNumberOfCycles:(int)cycles;
- (void)setROM:(nonnull NSData *)rom;
- (void)setState:(BOOL)state forDigitalInput:(Atari2600DigitalInput)digitalInput;
- (void)setResetLineEnabled:(BOOL)enabled;

View File

@ -0,0 +1,77 @@
//
// Atari2600.m
// CLK
//
// Created by Thomas Harte on 14/07/2015.
// Copyright © 2015 Thomas Harte. All rights reserved.
//
#import "CSAtari2600.h"
#import "Atari2600.hpp"
#import "CSMachine+Subclassing.h"
@implementation CSAtari2600 {
Atari2600::Machine _atari2600;
int _frameCount;
int _hitCount;
BOOL _didDecideRegion;
}
- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync {
if(!_didDecideRegion)
{
_frameCount++;
_hitCount += didDetectVSync ? 1 : 0;
if(_frameCount > 30)
{
if(_hitCount < _frameCount >> 1)
{
_atari2600.switch_region();
_didDecideRegion = YES;
}
if(_hitCount > (_frameCount * 7) >> 3)
{
_didDecideRegion = YES;
}
}
}
[super crt:crt didEndFrame:frame didDetectVSync:didDetectVSync];
}
- (void)doRunForNumberOfCycles:(int)numberOfCycles {
_atari2600.run_for_cycles(numberOfCycles);
}
- (void)setROM:(NSData *)rom {
[self perform:^{
_atari2600.set_rom(rom.length, (const uint8_t *)rom.bytes);
}];
}
- (void)setState:(BOOL)state forDigitalInput:(Atari2600DigitalInput)digitalInput {
[self perform:^{
_atari2600.set_digital_input(digitalInput, state ? true : false);
}];
}
- (void)setResetLineEnabled:(BOOL)enabled {
[self perform:^{
_atari2600.set_reset_line(enabled ? true : false);
}];
}
- (void)setView:(CSCathodeRayView *)view {
[super setView:view];
[view setSignalDecoder:[NSString stringWithUTF8String:_atari2600.get_signal_decoder()] type:CSCathodeRayViewSignalTypeNTSC];
}
- (void)setCRTDelegate:(Outputs::CRT::CRTDelegate *)delegate{
_atari2600.get_crt()->set_delegate(delegate);
}
@end

View File

@ -0,0 +1,20 @@
//
// CSMachine+Subclassing.h
// Clock Signal
//
// Created by Thomas Harte on 04/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#import "CSMachine.h"
#include "../../../../Outputs/CRT.hpp"
@interface CSMachine (Subclassing)
- (void)setCRTDelegate:(Outputs::CRT::CRTDelegate *)delegate;
- (void)doRunForNumberOfCycles:(int)numberOfCycles;
- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync;
- (void)perform:(dispatch_block_t)action;
@end

View File

@ -0,0 +1,18 @@
//
// CSMachine.h
// Clock Signal
//
// Created by Thomas Harte on 04/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "CSCathodeRayView.h"
@interface CSMachine : NSObject
- (void)runForNumberOfCycles:(int)numberOfCycles;
@property (nonatomic, weak) CSCathodeRayView *view;
@end

View File

@ -0,0 +1,63 @@
//
// CSMachine.m
// Clock Signal
//
// Created by Thomas Harte on 04/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#import "CSMachine.h"
#import "CSMachine+Subclassing.h"
struct CRTDelegate: public Outputs::CRT::CRTDelegate {
__weak CSMachine *machine;
void crt_did_end_frame(Outputs::CRT *crt, CRTFrame *frame, bool did_detect_vsync) {
[machine crt:crt didEndFrame:frame didDetectVSync:did_detect_vsync];
}
};
typedef NS_ENUM(NSInteger, CSAtari2600RunningState) {
CSMachineRunningStateRunning,
CSMachineRunningStateStopped
};
@implementation CSMachine {
CRTDelegate _crtDelegate;
dispatch_queue_t _serialDispatchQueue;
NSConditionLock *_runningLock;
}
- (void)perform:(dispatch_block_t)action {
dispatch_async(_serialDispatchQueue, action);
}
- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync {
if([self.view pushFrame:frame]) crt->return_frame();
}
- (void)runForNumberOfCycles:(int)cycles {
if([_runningLock tryLockWhenCondition:CSMachineRunningStateStopped]) {
[_runningLock unlockWithCondition:CSMachineRunningStateRunning];
dispatch_async(_serialDispatchQueue, ^{
[_runningLock lockWhenCondition:CSMachineRunningStateRunning];
[self doRunForNumberOfCycles:cycles];
[_runningLock unlockWithCondition:CSMachineRunningStateStopped];
});
}
}
- (instancetype)init {
self = [super init];
if (self) {
_crtDelegate.machine = self;
[self setCRTDelegate:&_crtDelegate];
_serialDispatchQueue = dispatch_queue_create("Machine queue", DISPATCH_QUEUE_SERIAL);
_runningLock = [[NSConditionLock alloc] initWithCondition:CSMachineRunningStateStopped];
}
return self;
}
@end