From ab45c1d530649e89a9b1c4709617f1c4c24367c0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 4 Jan 2016 23:12:47 -0500 Subject: [PATCH] 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. --- Machines/{ => Atari2600}/Atari2600.cpp | 0 Machines/{ => Atari2600}/Atari2600.hpp | 4 +- Machines/{ => Atari2600}/Atari2600Inputs.h | 0 Machines/Electron/Electron.cpp | 24 ++++ Machines/Electron/Electron.hpp | 32 +++++ .../Clock Signal.xcodeproj/project.pbxproj | 66 +++++++--- .../Mac/Clock Signal/Atari2600Document.swift | 18 +-- OSBindings/Mac/Clock Signal/CSAtari2600.mm | 114 ------------------ .../Mac/Clock Signal/ElectronDocument.swift | 5 + .../Clock Signal/{ => Wrappers}/CSAtari2600.h | 7 +- .../Mac/Clock Signal/Wrappers/CSAtari2600.mm | 77 ++++++++++++ .../Wrappers/CSMachine+Subclassing.h | 20 +++ .../Mac/Clock Signal/Wrappers/CSMachine.h | 18 +++ .../Mac/Clock Signal/Wrappers/CSMachine.mm | 63 ++++++++++ 14 files changed, 304 insertions(+), 144 deletions(-) rename Machines/{ => Atari2600}/Atari2600.cpp (100%) rename Machines/{ => Atari2600}/Atari2600.hpp (96%) rename Machines/{ => Atari2600}/Atari2600Inputs.h (100%) create mode 100644 Machines/Electron/Electron.cpp create mode 100644 Machines/Electron/Electron.hpp delete mode 100644 OSBindings/Mac/Clock Signal/CSAtari2600.mm rename OSBindings/Mac/Clock Signal/{ => Wrappers}/CSAtari2600.h (75%) create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm diff --git a/Machines/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp similarity index 100% rename from Machines/Atari2600.cpp rename to Machines/Atari2600/Atari2600.cpp diff --git a/Machines/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp similarity index 96% rename from Machines/Atari2600.hpp rename to Machines/Atari2600/Atari2600.hpp index 0e53f801b..7b65b9db2 100644 --- a/Machines/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -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 #include "Atari2600Inputs.h" diff --git a/Machines/Atari2600Inputs.h b/Machines/Atari2600/Atari2600Inputs.h similarity index 100% rename from Machines/Atari2600Inputs.h rename to Machines/Atari2600/Atari2600Inputs.h diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp new file mode 100644 index 000000000..808bff52b --- /dev/null +++ b/Machines/Electron/Electron.cpp @@ -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; +} diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp new file mode 100644 index 000000000..23f5930c7 --- /dev/null +++ b/Machines/Electron/Electron.hpp @@ -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 +#include "Atari2600Inputs.h" + +namespace Electron { + +class Machine: public CPU6502::Processor { + + public: + + Machine(); + ~Machine(); + + unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); + +}; + +} + +#endif /* Electron_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 915068d5c..eb1964c7d 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -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 = ""; }; - 4B14144B1B5883E500E04248 /* CSAtari2600.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSAtari2600.mm; sourceTree = ""; }; 4B14144C1B5883E500E04248 /* CSCathodeRayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSCathodeRayView.h; sourceTree = ""; }; 4B14144D1B5883E500E04248 /* CSCathodeRayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSCathodeRayView.m; sourceTree = ""; }; 4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ClockSignal-Bridging-Header.h"; sourceTree = ""; }; @@ -328,12 +328,19 @@ 4B2632551B631A510082A461 /* CRTFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CRTFrame.h; path = ../../Outputs/CRTFrame.h; sourceTree = ""; }; 4B2E2D911C399B9900138695 /* ElectronDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElectronDocument.swift; sourceTree = ""; }; 4B2E2D941C399D1200138695 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ElectronDocument.xib; sourceTree = ""; }; + 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = ""; }; + 4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = ""; }; + 4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = ""; }; + 4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = ""; }; + 4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = ""; }; 4B366DFA1B5C165A0026627B /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRT.cpp; path = ../../Outputs/CRT.cpp; sourceTree = ""; }; 4B366DFB1B5C165A0026627B /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRT.hpp; path = ../../Outputs/CRT.hpp; sourceTree = ""; }; - 4B6D7F921B58822000787C9A /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = ""; }; - 4B6D7F931B58822000787C9A /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = ""; }; + 4B55CE491C3B3B0C0093A61B /* CSAtari2600.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSAtari2600.h; sourceTree = ""; }; + 4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSAtari2600.mm; sourceTree = ""; }; + 4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSMachine.h; sourceTree = ""; }; + 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSMachine.mm; sourceTree = ""; }; + 4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Subclassing.h"; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; - 4BA3921C1B8402B3007FBF0E /* Atari2600Inputs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = ""; }; 4BB297E11B587D8300A49093 /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = AllSuiteA.bin; sourceTree = ""; }; @@ -666,6 +673,25 @@ name = "Test Binaries"; sourceTree = ""; }; + 4B2E2D961C3A06EC00138695 /* Atari2600 */ = { + isa = PBXGroup; + children = ( + 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */, + 4B2E2D981C3A06EC00138695 /* Atari2600.hpp */, + 4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */, + ); + path = Atari2600; + sourceTree = ""; + }; + 4B2E2D9E1C3A070900138695 /* Electron */ = { + isa = PBXGroup; + children = ( + 4B2E2D9B1C3A070400138695 /* Electron.cpp */, + 4B2E2D9C1C3A070400138695 /* Electron.hpp */, + ); + name = Electron; + sourceTree = ""; + }; 4B366DFD1B5C165F0026627B /* Outputs */ = { isa = PBXGroup; children = ( @@ -676,6 +702,18 @@ name = Outputs; sourceTree = ""; }; + 4B55CE481C3B3B0C0093A61B /* Wrappers */ = { + isa = PBXGroup; + children = ( + 4B55CE491C3B3B0C0093A61B /* CSAtari2600.h */, + 4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */, + 4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */, + 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */, + 4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */, + ); + path = Wrappers; + sourceTree = ""; + }; 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 */, diff --git a/OSBindings/Mac/Clock Signal/Atari2600Document.swift b/OSBindings/Mac/Clock Signal/Atari2600Document.swift index f3edcd55d..ffa7ce5d6 100644 --- a/OSBindings/Mac/Clock Signal/Atari2600Document.swift +++ b/OSBindings/Mac/Clock Signal/Atari2600Document.swift @@ -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) } } diff --git a/OSBindings/Mac/Clock Signal/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/CSAtari2600.mm deleted file mode 100644 index 07b3ac646..000000000 --- a/OSBindings/Mac/Clock Signal/CSAtari2600.mm +++ /dev/null @@ -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 diff --git a/OSBindings/Mac/Clock Signal/ElectronDocument.swift b/OSBindings/Mac/Clock Signal/ElectronDocument.swift index 0fbd05563..8d3f8ae66 100644 --- a/OSBindings/Mac/Clock Signal/ElectronDocument.swift +++ b/OSBindings/Mac/Clock Signal/ElectronDocument.swift @@ -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() { diff --git a/OSBindings/Mac/Clock Signal/CSAtari2600.h b/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.h similarity index 75% rename from OSBindings/Mac/Clock Signal/CSAtari2600.h rename to OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.h index ffa4191c9..38dc12c78 100644 --- a/OSBindings/Mac/Clock Signal/CSAtari2600.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.h @@ -9,14 +9,11 @@ #import #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; diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm new file mode 100644 index 000000000..d7006d766 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm @@ -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 diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h new file mode 100644 index 000000000..1aa88b268 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h @@ -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 diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h new file mode 100644 index 000000000..dbce321a3 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h @@ -0,0 +1,18 @@ +// +// CSMachine.h +// Clock Signal +// +// Created by Thomas Harte on 04/01/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import +#import "CSCathodeRayView.h" + +@interface CSMachine : NSObject + +- (void)runForNumberOfCycles:(int)numberOfCycles; + +@property (nonatomic, weak) CSCathodeRayView *view; + +@end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm new file mode 100644 index 000000000..fa5b80452 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm @@ -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