1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-25 04:29:09 +00:00

Merge pull request #49 from TomHarte/Xcode8

Migrated to Swift 3.
This commit is contained in:
Thomas Harte 2016-09-17 18:10:43 -04:00 committed by GitHub
commit 788df09f71
16 changed files with 243 additions and 241 deletions

View File

@ -1708,11 +1708,12 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0700; LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700; LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "Thomas Harte"; ORGANIZATIONNAME = "Thomas Harte";
TargetAttributes = { TargetAttributes = {
4BB73E9D1B587A5100552FC2 = { 4BB73E9D1B587A5100552FC2 = {
CreatedOnToolsVersion = 7.0; CreatedOnToolsVersion = 7.0;
LastSwiftMigration = 0800;
SystemCapabilities = { SystemCapabilities = {
com.apple.Sandbox = { com.apple.Sandbox = {
enabled = 1; enabled = 1;
@ -1721,10 +1722,12 @@
}; };
4BB73EB11B587A5100552FC2 = { 4BB73EB11B587A5100552FC2 = {
CreatedOnToolsVersion = 7.0; CreatedOnToolsVersion = 7.0;
LastSwiftMigration = 0800;
TestTargetID = 4BB73E9D1B587A5100552FC2; TestTargetID = 4BB73E9D1B587A5100552FC2;
}; };
4BB73EBC1B587A5100552FC2 = { 4BB73EBC1B587A5100552FC2 = {
CreatedOnToolsVersion = 7.0; CreatedOnToolsVersion = 7.0;
LastSwiftMigration = 0800;
TestTargetID = 4BB73E9D1B587A5100552FC2; TestTargetID = 4BB73E9D1B587A5100552FC2;
}; };
}; };
@ -2207,8 +2210,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
@ -2251,8 +2256,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
@ -2271,6 +2278,7 @@
MACOSX_DEPLOYMENT_TARGET = 10.10; MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
}; };
name = Release; name = Release;
}; };
@ -2289,6 +2297,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -2306,6 +2315,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-Signal"; PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-Signal";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h";
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -2321,6 +2331,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
}; };
name = Debug; name = Debug;
@ -2336,6 +2347,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalTests"; PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalTests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
}; };
name = Release; name = Release;
@ -2348,6 +2360,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests"; PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_TARGET_NAME = "Clock Signal"; TEST_TARGET_NAME = "Clock Signal";
USES_XCTRUNNER = YES; USES_XCTRUNNER = YES;
}; };
@ -2361,6 +2374,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests"; PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_TARGET_NAME = "Clock Signal"; TEST_TARGET_NAME = "Clock Signal";
USES_XCTRUNNER = YES; USES_XCTRUNNER = YES;
}; };

View File

@ -11,16 +11,16 @@ import Cocoa
@NSApplicationMain @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application // Insert code here to initialize your application
} }
func applicationWillTerminate(aNotification: NSNotification) { func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application // Insert code here to tear down your application
} }
// decline to open a new file unless the user explicitly requests it // decline to open a new file unless the user explicitly requests it
func applicationShouldOpenUntitledFile(sender: NSApplication) -> Bool { func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool {
return false return false
} }
} }

View File

@ -9,18 +9,18 @@
import Cocoa import Cocoa
class DocumentController: NSDocumentController { class DocumentController: NSDocumentController {
override func makeDocumentWithContentsOfURL(url: NSURL, ofType typeName: String) throws -> NSDocument { override func makeDocument(withContentsOf url: URL, ofType typeName: String) throws -> NSDocument {
if let analyser = CSStaticAnalyser(fileAtURL: url) { if let analyser = CSStaticAnalyser(fileAt: url) {
if let documentClass = analyser.documentClass as? NSDocument.Type { if let documentClass = analyser.documentClass as? NSDocument.Type {
let document = documentClass.init() let document = documentClass.init()
if let machineDocument = document as? MachineDocument { if let machineDocument = document as? MachineDocument {
machineDocument.setDisplayName(analyser.displayName) machineDocument.displayName = analyser.displayName
machineDocument.configureAs(analyser) machineDocument.configureAs(analyser)
return machineDocument return machineDocument
} }
} }
} }
return try! super.makeDocumentWithContentsOfURL(url, ofType: typeName) return try! super.makeDocument(withContentsOf: url, ofType: typeName)
} }
} }

View File

@ -10,7 +10,7 @@ import Cocoa
class Atari2600Document: MachineDocument { class Atari2600Document: MachineDocument {
private var atari2600 = CSAtari2600() fileprivate var atari2600 = CSAtari2600()
override var machine: CSMachine! { override var machine: CSMachine! {
get { get {
return atari2600 return atari2600
@ -31,7 +31,7 @@ class Atari2600Document: MachineDocument {
return "Atari2600Document" return "Atari2600Document"
} }
override func windowControllerDidLoadNib(aController: NSWindowController) { override func windowControllerDidLoadNib(_ aController: NSWindowController) {
super.windowControllerDidLoadNib(aController) super.windowControllerDidLoadNib(aController)
// push whatever settings the switches have in the NIB into the emulation // push whatever settings the switches have in the NIB into the emulation
@ -39,26 +39,28 @@ class Atari2600Document: MachineDocument {
// show the options window but ensure the OpenGL view is key // show the options window but ensure the OpenGL view is key
showOptions(self) showOptions(self)
self.openGLView.window?.makeKeyWindow() self.openGLView.window?.makeKey()
} }
// MARK: CSOpenGLViewResponderDelegate // MARK: CSOpenGLViewResponderDelegate
private func inputForKey(event: NSEvent) -> Atari2600DigitalInput? { fileprivate func inputForKey(_ event: NSEvent) -> Atari2600DigitalInput? {
switch event.keyCode { switch event.keyCode {
case 123: return Atari2600DigitalInputJoy1Left case 123: return Atari2600DigitalInputJoy1Left
case 126: return Atari2600DigitalInputJoy1Up case 126: return Atari2600DigitalInputJoy1Up
case 124: return Atari2600DigitalInputJoy1Right case 124: return Atari2600DigitalInputJoy1Right
case 125: return Atari2600DigitalInputJoy1Down case 125: return Atari2600DigitalInputJoy1Down
case 0: return Atari2600DigitalInputJoy1Fire case 0: return Atari2600DigitalInputJoy1Fire
default: print("\(event.keyCode)"); return nil default:
Swift.print("\(event.keyCode)")
return nil
} }
} }
override func keyDown(event: NSEvent) { override func keyDown(_ event: NSEvent) {
super.keyDown(event) super.keyDown(event)
if let input = inputForKey(event) { if let input = inputForKey(event) {
atari2600.setState(true, forDigitalInput: input) atari2600.setState(true, for: input)
} }
if event.keyCode == 36 { if event.keyCode == 36 {
@ -66,11 +68,11 @@ class Atari2600Document: MachineDocument {
} }
} }
override func keyUp(event: NSEvent) { override func keyUp(_ event: NSEvent) {
super.keyUp(event) super.keyUp(event)
if let input = inputForKey(event) { if let input = inputForKey(event) {
atari2600.setState(false, forDigitalInput: input) atari2600.setState(false, for: input)
} }
if event.keyCode == 36 { if event.keyCode == 36 {
@ -85,21 +87,21 @@ class Atari2600Document: MachineDocument {
@IBOutlet var leftPlayerDifficultyButton: NSButton! @IBOutlet var leftPlayerDifficultyButton: NSButton!
@IBOutlet var rightPlayerDifficultyButton: NSButton! @IBOutlet var rightPlayerDifficultyButton: NSButton!
@IBAction func optionDidChange(sender: AnyObject!) { @IBAction func optionDidChange(_ sender: AnyObject!) {
pushSwitchValues() pushSwitchValues()
} }
private func pushSwitchValues() { fileprivate func pushSwitchValues() {
atari2600.colourButton = colourButton.state == NSOnState atari2600.colourButton = colourButton.state == NSOnState
atari2600.leftPlayerDifficultyButton = leftPlayerDifficultyButton.state == NSOnState atari2600.leftPlayerDifficultyButton = leftPlayerDifficultyButton.state == NSOnState
atari2600.rightPlayerDifficultyButton = rightPlayerDifficultyButton.state == NSOnState atari2600.rightPlayerDifficultyButton = rightPlayerDifficultyButton.state == NSOnState
} }
@IBAction func optionWasPressed(sender: NSButton!) { @IBAction func optionWasPressed(_ sender: NSButton!) {
if sender == resetButton { if sender == resetButton {
atari2600.pressResetButton() atari2600.pressResetButton()
} else { } else {
atari2600.pressSelectButton() atari2600.pressSelectButton()
} }
} }
} }

View File

@ -11,7 +11,7 @@ import AudioToolbox
class ElectronDocument: MachineDocument { class ElectronDocument: MachineDocument {
private lazy var electron = CSElectron() fileprivate lazy var electron = CSElectron()
override var machine: CSMachine! { override var machine: CSMachine! {
get { get {
return electron return electron
@ -27,14 +27,14 @@ class ElectronDocument: MachineDocument {
return NSSize(width: 11.0, height: 10.0) return NSSize(width: 11.0, height: 10.0)
} }
private func rom(name: String) -> NSData? { fileprivate func rom(_ name: String) -> Data? {
return dataForResource(name, ofType: "rom", inDirectory: "ROMImages/Electron") return dataForResource(name, ofType: "rom", inDirectory: "ROMImages/Electron")
} }
override func windowControllerDidLoadNib(aController: NSWindowController) { override func windowControllerDidLoadNib(_ aController: NSWindowController) {
super.windowControllerDidLoadNib(aController) super.windowControllerDidLoadNib(aController)
if let os = rom("os"), basic = rom("basic") { if let os = rom("os"), let basic = rom("basic") {
self.electron.setOSROM(os) self.electron.setOSROM(os)
self.electron.setBASICROM(basic) self.electron.setBASICROM(basic)
} }
@ -67,21 +67,21 @@ class ElectronDocument: MachineDocument {
// MARK: IBActions // MARK: IBActions
@IBOutlet var displayTypeButton: NSPopUpButton? @IBOutlet var displayTypeButton: NSPopUpButton?
@IBAction func setDisplayType(sender: NSPopUpButton!) { @IBAction func setDisplayType(_ sender: NSPopUpButton!) {
electron.useTelevisionOutput = (sender.indexOfSelectedItem == 1) electron.useTelevisionOutput = (sender.indexOfSelectedItem == 1)
NSUserDefaults.standardUserDefaults().setInteger(sender.indexOfSelectedItem, forKey: self.displayTypeUserDefaultsKey) UserDefaults.standard.set(sender.indexOfSelectedItem, forKey: self.displayTypeUserDefaultsKey)
} }
private let displayTypeUserDefaultsKey = "electron.displayType" fileprivate let displayTypeUserDefaultsKey = "electron.displayType"
override func establishStoredOptions() { override func establishStoredOptions() {
super.establishStoredOptions() super.establishStoredOptions()
let standardUserDefaults = NSUserDefaults.standardUserDefaults() let standardUserDefaults = UserDefaults.standard
standardUserDefaults.registerDefaults([ standardUserDefaults.register(defaults: [
displayTypeUserDefaultsKey: 0, displayTypeUserDefaultsKey: 0,
]) ])
let displayType = standardUserDefaults.integerForKey(self.displayTypeUserDefaultsKey) let displayType = standardUserDefaults.integer(forKey: self.displayTypeUserDefaultsKey)
electron.useTelevisionOutput = (displayType == 1) electron.useTelevisionOutput = (displayType == 1)
self.displayTypeButton?.selectItemAtIndex(displayType) self.displayTypeButton?.selectItem(at: displayType)
} }
} }

View File

@ -43,24 +43,24 @@ class MachineDocument:
} }
@IBOutlet weak var optionsPanel: NSPanel! @IBOutlet weak var optionsPanel: NSPanel!
@IBAction func showOptions(sender: AnyObject!) { @IBAction func showOptions(_ sender: AnyObject!) {
optionsPanel?.setIsVisible(true) optionsPanel?.setIsVisible(true)
} }
private var audioQueue: CSAudioQueue! = nil fileprivate var audioQueue: CSAudioQueue! = nil
private lazy var bestEffortUpdater: CSBestEffortUpdater = { fileprivate lazy var bestEffortUpdater: CSBestEffortUpdater = {
let updater = CSBestEffortUpdater() let updater = CSBestEffortUpdater()
updater.delegate = self updater.delegate = self
return updater return updater
}() }()
override func windowControllerDidLoadNib(aController: NSWindowController) { override func windowControllerDidLoadNib(_ aController: NSWindowController) {
super.windowControllerDidLoadNib(aController) super.windowControllerDidLoadNib(aController)
// establish the output aspect ratio and audio // establish the output aspect ratio and audio
let displayAspectRatio = self.aspectRatio() let displayAspectRatio = self.aspectRatio()
aController.window?.contentAspectRatio = displayAspectRatio aController.window?.contentAspectRatio = displayAspectRatio
openGLView.performWithGLContext({ openGLView.perform(glContext: {
self.machine.setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height)) self.machine.setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height))
}) })
@ -69,18 +69,18 @@ class MachineDocument:
establishStoredOptions() establishStoredOptions()
} }
func machineDidChangeClockRate(machine: CSMachine!) { func machineDidChangeClockRate(_ machine: CSMachine!) {
setupClockRate() setupClockRate()
} }
func machineDidChangeClockIsUnlimited(machine: CSMachine!) { func machineDidChangeClockIsUnlimited(_ machine: CSMachine!) {
self.bestEffortUpdater.runAsUnlimited = machine.clockIsUnlimited self.bestEffortUpdater.runAsUnlimited = machine.clockIsUnlimited
} }
private func setupClockRate() { fileprivate func setupClockRate() {
// establish and provide the audio queue, taking advice as to an appropriate sampling rate // establish and provide the audio queue, taking advice as to an appropriate sampling rate
let maximumSamplingRate = CSAudioQueue.preferredSamplingRate() let maximumSamplingRate = CSAudioQueue.preferredSamplingRate()
let selectedSamplingRate = self.machine.idealSamplingRateFromRange(NSRange(location: 0, length: NSInteger(maximumSamplingRate))) let selectedSamplingRate = self.machine.idealSamplingRate(from: NSRange(location: 0, length: NSInteger(maximumSamplingRate)))
if selectedSamplingRate > 0 { if selectedSamplingRate > 0 {
audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate)) audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate))
audioQueue.delegate = self audioQueue.delegate = self
@ -103,89 +103,89 @@ class MachineDocument:
} }
// MARK: configuring // MARK: configuring
func configureAs(analysis: CSStaticAnalyser) { func configureAs(_ analysis: CSStaticAnalyser) {
analysis.applyToMachine(self.machine) analysis.apply(to: self.machine)
} }
// MARK: the pasteboard // MARK: the pasteboard
func paste(sender: AnyObject!) { func paste(_ sender: AnyObject!) {
let pasteboard = NSPasteboard.generalPasteboard() let pasteboard = NSPasteboard.general()
if let string = pasteboard.stringForType(NSPasteboardTypeString) { if let string = pasteboard.string(forType: NSPasteboardTypeString) {
self.machine.paste(string) self.machine.paste(string)
} }
} }
// MARK: CSBestEffortUpdaterDelegate // MARK: CSBestEffortUpdaterDelegate
final func bestEffortUpdater(bestEffortUpdater: CSBestEffortUpdater!, runForCycles cycles: UInt, didSkipPreviousUpdate: Bool) { final func bestEffortUpdater(_ bestEffortUpdater: CSBestEffortUpdater!, runForCycles cycles: UInt, didSkipPreviousUpdate: Bool) {
runForNumberOfCycles(Int32(cycles)) runForNumberOfCycles(Int32(cycles))
} }
func runForNumberOfCycles(numberOfCycles: Int32) { func runForNumberOfCycles(_ numberOfCycles: Int32) {
let cyclesToRunFor = min(numberOfCycles, Int32(bestEffortUpdater.clockRate / 10)) let cyclesToRunFor = min(numberOfCycles, Int32(bestEffortUpdater.clockRate / 10))
if actionLock.tryLock() { if actionLock.try() {
self.machine.runForNumberOfCycles(cyclesToRunFor) self.machine.runForNumber(ofCycles: cyclesToRunFor)
actionLock.unlock() actionLock.unlock()
} }
} }
// MARK: Utilities for children // MARK: Utilities for children
func dataForResource(name : String, ofType type: String, inDirectory directory: String) -> NSData? { func dataForResource(_ name : String, ofType type: String, inDirectory directory: String) -> Data? {
if let path = NSBundle.mainBundle().pathForResource(name, ofType: type, inDirectory: directory) { if let path = Bundle.main.path(forResource: name, ofType: type, inDirectory: directory) {
return NSData(contentsOfFile: path) return (try? Data(contentsOf: URL(fileURLWithPath: path)))
} }
return nil return nil
} }
// MARK: CSAudioQueueDelegate // MARK: CSAudioQueueDelegate
final func audioQueueDidCompleteBuffer(audioQueue: CSAudioQueue) { final func audioQueueDidCompleteBuffer(_ audioQueue: CSAudioQueue) {
bestEffortUpdater.update() bestEffortUpdater.update()
} }
// MARK: CSOpenGLViewDelegate // MARK: CSOpenGLViewDelegate
final func openGLView(view: CSOpenGLView, drawViewOnlyIfDirty onlyIfDirty: Bool) { final func openGLView(_ view: CSOpenGLView, drawViewOnlyIfDirty onlyIfDirty: Bool) {
bestEffortUpdater.update() bestEffortUpdater.update()
if drawLock.tryLock() { if drawLock.try() {
self.machine.drawViewForPixelSize(view.backingSize, onlyIfDirty: onlyIfDirty) self.machine.drawView(forPixelSize: view.backingSize, onlyIfDirty: onlyIfDirty)
drawLock.unlock() drawLock.unlock()
} }
} }
// MARK: NSDocument overrides // MARK: NSDocument overrides
override func dataOfType(typeName: String) throws -> NSData { override func data(ofType typeName: String) throws -> Data {
throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
} }
// MARK: Key forwarding // MARK: Key forwarding
private func withKeyboardMachine(action: (CSKeyboardMachine) -> ()) { fileprivate func withKeyboardMachine(_ action: (CSKeyboardMachine) -> ()) {
if let keyboardMachine = self.machine as? CSKeyboardMachine { if let keyboardMachine = self.machine as? CSKeyboardMachine {
action(keyboardMachine) action(keyboardMachine)
} }
} }
func windowDidResignKey(notification: NSNotification) { func windowDidResignKey(_ notification: Notification) {
self.withKeyboardMachine { $0.clearAllKeys() } self.withKeyboardMachine { $0.clearAllKeys() }
} }
func keyDown(event: NSEvent) { func keyDown(_ event: NSEvent) {
self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: true) } self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: true) }
} }
func keyUp(event: NSEvent) { func keyUp(_ event: NSEvent) {
self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: false) } self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: false) }
} }
func flagsChanged(newModifiers: NSEvent) { func flagsChanged(_ newModifiers: NSEvent) {
self.withKeyboardMachine { self.withKeyboardMachine {
$0.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.ShiftKeyMask)) $0.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.shift))
$0.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.ControlKeyMask)) $0.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.control))
$0.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.CommandKeyMask)) $0.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.command))
$0.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.AlternateKeyMask)) $0.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.option))
} }
} }
// MARK: IBActions // MARK: IBActions
final func prefixedUserDefaultsKey(key: String) -> String { final func prefixedUserDefaultsKey(_ key: String) -> String {
return "\(self.name).\(key)" return "\(self.name).\(key)"
} }
var fastLoadingUserDefaultsKey: String { var fastLoadingUserDefaultsKey: String {
@ -195,22 +195,22 @@ class MachineDocument:
} }
@IBOutlet var fastLoadingButton: NSButton? @IBOutlet var fastLoadingButton: NSButton?
@IBAction func setFastLoading(sender: NSButton!) { @IBAction func setFastLoading(_ sender: NSButton!) {
if let fastLoadingMachine = machine as? CSFastLoading { if let fastLoadingMachine = machine as? CSFastLoading {
let useFastLoadingHack = sender.state == NSOnState let useFastLoadingHack = sender.state == NSOnState
fastLoadingMachine.useFastLoadingHack = useFastLoadingHack fastLoadingMachine.useFastLoadingHack = useFastLoadingHack
NSUserDefaults.standardUserDefaults().setBool(useFastLoadingHack, forKey: fastLoadingUserDefaultsKey) UserDefaults.standard.set(useFastLoadingHack, forKey: fastLoadingUserDefaultsKey)
} }
} }
func establishStoredOptions() { func establishStoredOptions() {
let standardUserDefaults = NSUserDefaults.standardUserDefaults() let standardUserDefaults = UserDefaults.standard
standardUserDefaults.registerDefaults([ standardUserDefaults.register(defaults: [
fastLoadingUserDefaultsKey: true fastLoadingUserDefaultsKey: true
]) ])
if let fastLoadingMachine = machine as? CSFastLoading { if let fastLoadingMachine = machine as? CSFastLoading {
let useFastLoadingHack = standardUserDefaults.boolForKey(self.fastLoadingUserDefaultsKey) let useFastLoadingHack = standardUserDefaults.bool(forKey: self.fastLoadingUserDefaultsKey)
fastLoadingMachine.useFastLoadingHack = useFastLoadingHack fastLoadingMachine.useFastLoadingHack = useFastLoadingHack
self.fastLoadingButton?.state = useFastLoadingHack ? NSOnState : NSOffState self.fastLoadingButton?.state = useFastLoadingHack ? NSOnState : NSOffState
} }

View File

@ -10,7 +10,7 @@ import Foundation
class Vic20Document: MachineDocument { class Vic20Document: MachineDocument {
private lazy var vic20 = CSVic20() fileprivate lazy var vic20 = CSVic20()
override var machine: CSMachine! { override var machine: CSMachine! {
get { get {
return vic20 return vic20
@ -41,22 +41,8 @@ class Vic20Document: MachineDocument {
return "Vic20Document" return "Vic20Document"
} }
override func readFromURL(url: NSURL, ofType typeName: String) throws {
if let pathExtension = url.pathExtension {
switch pathExtension.lowercaseString {
case "tap": vic20.openTAPAtURL(url)
case "g64": vic20.openG64AtURL(url)
case "d64": vic20.openD64AtURL(url)
case "prg": vic20.openPRGAtURL(url)
default:
let fileWrapper = try NSFileWrapper(URL: url, options: NSFileWrapperReadingOptions(rawValue: 0))
try self.readFromFileWrapper(fileWrapper, ofType: typeName)
}
}
}
// MARK: machine setup // MARK: machine setup
private func rom(name: String) -> NSData? { fileprivate func rom(_ name: String) -> Data? {
return dataForResource(name, ofType: "bin", inDirectory: "ROMImages/Vic20") return dataForResource(name, ofType: "bin", inDirectory: "ROMImages/Vic20")
} }
@ -66,10 +52,10 @@ class Vic20Document: MachineDocument {
get { return prefixedUserDefaultsKey("autoload") } get { return prefixedUserDefaultsKey("autoload") }
} }
@IBAction func setShouldLoadAutomatically(sender: NSButton!) { @IBAction func setShouldLoadAutomatically(_ sender: NSButton!) {
let loadAutomatically = sender.state == NSOnState let loadAutomatically = sender.state == NSOnState
vic20.shouldLoadAutomatically = loadAutomatically vic20.shouldLoadAutomatically = loadAutomatically
NSUserDefaults.standardUserDefaults().setBool(loadAutomatically, forKey: self.autoloadingUserDefaultsKey) UserDefaults.standard.set(loadAutomatically, forKey: self.autoloadingUserDefaultsKey)
} }
// MARK: country selector // MARK: country selector
@ -78,12 +64,12 @@ class Vic20Document: MachineDocument {
get { return prefixedUserDefaultsKey("country") } get { return prefixedUserDefaultsKey("country") }
} }
@IBAction func setCountry(sender: NSPopUpButton!) { @IBAction func setCountry(_ sender: NSPopUpButton!) {
NSUserDefaults.standardUserDefaults().setInteger(sender.indexOfSelectedItem, forKey: self.countryUserDefaultsKey) UserDefaults.standard.set(sender.indexOfSelectedItem, forKey: self.countryUserDefaultsKey)
setCountry(sender.indexOfSelectedItem) setCountry(sender.indexOfSelectedItem)
} }
private func setCountry(countryID: Int) { fileprivate func setCountry(_ countryID: Int) {
var charactersROM: String? var charactersROM: String?
var kernelROM: String? var kernelROM: String?
switch countryID { switch countryID {
@ -110,8 +96,8 @@ class Vic20Document: MachineDocument {
default: break default: break
} }
if let charactersROM = charactersROM, kernelROM = kernelROM { if let charactersROM = charactersROM, let kernelROM = kernelROM {
if let kernel = rom(kernelROM), basic = rom("basic"), characters = rom(charactersROM) { if let kernel = rom(kernelROM), let basic = rom("basic"), let characters = rom(charactersROM) {
vic20.setKernelROM(kernel) vic20.setKernelROM(kernel)
vic20.setBASICROM(basic) vic20.setBASICROM(basic)
vic20.setCharactersROM(characters) vic20.setCharactersROM(characters)
@ -125,7 +111,7 @@ class Vic20Document: MachineDocument {
get { return prefixedUserDefaultsKey("memorySize") } get { return prefixedUserDefaultsKey("memorySize") }
} }
@IBAction func setMemorySize(sender: NSPopUpButton!) { @IBAction func setMemorySize(_ sender: NSPopUpButton!) {
var selectedSize: Int? var selectedSize: Int?
switch sender.indexOfSelectedItem { switch sender.indexOfSelectedItem {
case 0: selectedSize = 5 case 0: selectedSize = 5
@ -134,15 +120,15 @@ class Vic20Document: MachineDocument {
default: break default: break
} }
if let selectedSize = selectedSize { if let selectedSize = selectedSize {
NSUserDefaults.standardUserDefaults().setInteger(selectedSize, forKey: self.memorySizeUserDefaultsKey) UserDefaults.standard.set(selectedSize, forKey: self.memorySizeUserDefaultsKey)
setMemorySize(sender.indexOfSelectedItem) setMemorySize(sender.indexOfSelectedItem)
} }
} }
private func setMemorySize(sizeIndex: Int) { fileprivate func setMemorySize(_ sizeIndex: Int) {
switch sizeIndex { switch sizeIndex {
case 2: vic20.memorySize = .Size32Kb case 2: vic20.memorySize = .size32Kb
case 1: vic20.memorySize = .Size8Kb case 1: vic20.memorySize = .size8Kb
default: vic20.memorySize = .Size5Kb default: vic20.memorySize = .size5Kb
} }
} }
@ -150,19 +136,19 @@ class Vic20Document: MachineDocument {
override func establishStoredOptions() { override func establishStoredOptions() {
super.establishStoredOptions() super.establishStoredOptions()
let standardUserDefaults = NSUserDefaults.standardUserDefaults() let standardUserDefaults = UserDefaults.standard
standardUserDefaults.registerDefaults([ standardUserDefaults.register(defaults: [
self.autoloadingUserDefaultsKey: true, self.autoloadingUserDefaultsKey: true,
self.memorySizeUserDefaultsKey: 5, self.memorySizeUserDefaultsKey: 5,
self.countryUserDefaultsKey: 1 self.countryUserDefaultsKey: 1
]) ])
let loadAutomatically = standardUserDefaults.boolForKey(self.autoloadingUserDefaultsKey) let loadAutomatically = standardUserDefaults.bool(forKey: self.autoloadingUserDefaultsKey)
vic20.shouldLoadAutomatically = loadAutomatically vic20.shouldLoadAutomatically = loadAutomatically
self.loadAutomaticallyButton?.state = loadAutomatically ? NSOnState : NSOffState self.loadAutomaticallyButton?.state = loadAutomatically ? NSOnState : NSOffState
if !loadAutomatically { if !loadAutomatically {
let memorySize = standardUserDefaults.integerForKey(self.memorySizeUserDefaultsKey) let memorySize = standardUserDefaults.integer(forKey: self.memorySizeUserDefaultsKey)
var indexToSelect: Int? var indexToSelect: Int?
switch memorySize { switch memorySize {
case 32: indexToSelect = 2 case 32: indexToSelect = 2
@ -170,14 +156,14 @@ class Vic20Document: MachineDocument {
default: indexToSelect = 0 default: indexToSelect = 0
} }
if let indexToSelect = indexToSelect { if let indexToSelect = indexToSelect {
self.memorySizeButton?.selectItemAtIndex(indexToSelect) self.memorySizeButton?.selectItem(at: indexToSelect)
setMemorySize(indexToSelect) setMemorySize(indexToSelect)
} }
} }
// TODO: this should be part of the configuration // TODO: this should be part of the configuration
let country = standardUserDefaults.integerForKey(self.countryUserDefaultsKey) let country = standardUserDefaults.integer(forKey: self.countryUserDefaultsKey)
setCountry(country) setCountry(country)
self.countryButton?.selectItemAtIndex(country) self.countryButton?.selectItem(at: country)
} }
} }

View File

@ -28,31 +28,31 @@ class MOS6502InterruptTests: XCTestCase {
machine.setValue(0x58, forAddress: 0x4000) machine.setValue(0x58, forAddress: 0x4000)
// pick things off at 0x4000 // pick things off at 0x4000
machine.setValue(0x4000, forRegister: CSTestMachineRegister.ProgramCounter) machine.setValue(0x4000, for: CSTestMachineRegister.programCounter)
} }
func testIRQLine() { func testIRQLine() {
// run for six cycles; check that no interrupt has occurred // run for six cycles; check that no interrupt has occurred
machine.runForNumberOfCycles(6) machine.runForNumber(ofCycles: 6)
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4003, "No interrupt should have occurred with line low") XCTAssert(machine.value(for: .programCounter) == 0x4003, "No interrupt should have occurred with line low")
// enable the interrupt line, check that it was too late // enable the interrupt line, check that it was too late
machine.irqLine = true machine.irqLine = true
machine.runForNumberOfCycles(2) machine.runForNumber(ofCycles: 2)
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4004, "No interrupt should have occurred from interrupt raised between instructions") XCTAssert(machine.value(for: .programCounter) == 0x4004, "No interrupt should have occurred from interrupt raised between instructions")
// run for a further 7 cycles, confirm that the IRQ vector was jumped to // run for a further 7 cycles, confirm that the IRQ vector was jumped to
machine.runForNumberOfCycles(7) machine.runForNumber(ofCycles: 7)
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun") XCTAssert(machine.value(for: .programCounter) == 0x1234, "Interrupt routine should just have begun")
} }
func testIFlagSet() { func testIFlagSet() {
// enable the interrupt line, run for eleven cycles to get past the CLIP and the following NOP and into the interrupt routine // enable the interrupt line, run for eleven cycles to get past the CLIP and the following NOP and into the interrupt routine
machine.irqLine = true machine.irqLine = true
machine.runForNumberOfCycles(11) machine.runForNumber(ofCycles: 11)
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun") XCTAssert(machine.value(for: .programCounter) == 0x1234, "Interrupt routine should just have begun")
XCTAssert(machine.valueForRegister(.Flags) & 0x04 == 0x04, "Interrupt status flag should be set") XCTAssert(machine.value(for: .flags) & 0x04 == 0x04, "Interrupt status flag should be set")
} }
func testCLISEIFlagClear() { func testCLISEIFlagClear() {
@ -61,13 +61,13 @@ class MOS6502InterruptTests: XCTestCase {
machine.irqLine = true machine.irqLine = true
// run for four cycles; the CLI and SEI should have been performed // run for four cycles; the CLI and SEI should have been performed
machine.runForNumberOfCycles(4) machine.runForNumber(ofCycles: 4)
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4002, "CLI/SEI pair should have been performed in their entirety") XCTAssert(machine.value(for: .programCounter) == 0x4002, "CLI/SEI pair should have been performed in their entirety")
// run for seven more cycles // run for seven more cycles
machine.runForNumberOfCycles(7) machine.runForNumber(ofCycles: 7)
// interrupt should have taken place despite SEI // interrupt should have taken place despite SEI
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun") XCTAssert(machine.value(for: .programCounter) == 0x1234, "Interrupt routine should just have begun")
} }
} }

View File

@ -11,7 +11,7 @@ import XCTest
class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler { class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
private var endTime: UInt32 = 0 fileprivate var endTime: UInt32 = 0
func testImplied() { func testImplied() {
let code: [UInt8] = [ let code: [UInt8] = [
@ -195,12 +195,12 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
self.runTest(code, expectedRunLength: 43) self.runTest(code, expectedRunLength: 43)
} }
func runTest(code: [UInt8], expectedRunLength: UInt32) { func runTest(_ code: [UInt8], expectedRunLength: UInt32) {
let machine = CSTestMachine() let machine = CSTestMachine()
machine.jamHandler = self machine.jamHandler = self
let immediateCode = NSData(bytes: code, length: code.count) let immediateCode = Data(bytes: UnsafePointer<UInt8>(code), count: code.count)
machine.setData(immediateCode, atAddress: 0x200) machine.setData(immediateCode, atAddress: 0x200)
machine.setValue(0x00, forAddress: 0x0000) machine.setValue(0x00, forAddress: 0x0000)
machine.setValue(0x00, forAddress: 0x0001) machine.setValue(0x00, forAddress: 0x0001)
@ -208,19 +208,19 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
machine.setValue(0x00, forAddress: 0x0003) machine.setValue(0x00, forAddress: 0x0003)
machine.setValue(0x08, forAddress: 0x0004) machine.setValue(0x08, forAddress: 0x0004)
machine.setValue(0x02, forAddress: 0x0005) machine.setValue(0x02, forAddress: 0x0005)
machine.setValue(0x200, forRegister: CSTestMachineRegister.ProgramCounter) machine.setValue(0x200, for: CSTestMachineRegister.programCounter)
machine.setValue(0xff, forRegister: CSTestMachineRegister.X) machine.setValue(0xff, for: CSTestMachineRegister.X)
machine.setValue(0xfe, forRegister: CSTestMachineRegister.Y) machine.setValue(0xfe, for: CSTestMachineRegister.Y)
self.endTime = 0 self.endTime = 0
while self.endTime == 0 { while self.endTime == 0 {
machine.runForNumberOfCycles(10) machine.runForNumber(ofCycles: 10)
} }
XCTAssert(self.endTime == expectedRunLength, "Took \(self.endTime) cycles to perform") XCTAssert(self.endTime == expectedRunLength, "Took \(self.endTime) cycles to perform")
} }
func testMachine(machine: CSTestMachine!, didJamAtAddress address: UInt16) { func testMachine(_ machine: CSTestMachine!, didJamAtAddress address: UInt16) {
if self.endTime == 0 { if self.endTime == 0 {
self.endTime = machine.timestamp - 9 self.endTime = machine.timestamp - 9
} }

View File

@ -11,7 +11,7 @@ import Foundation
class MOS6522Tests: XCTestCase { class MOS6522Tests: XCTestCase {
private func with6522(action: (MOS6522Bridge) -> ()) { fileprivate func with6522(_ action: (MOS6522Bridge) -> ()) {
let bridge = MOS6522Bridge() let bridge = MOS6522Bridge()
action(bridge) action(bridge)
} }
@ -25,11 +25,11 @@ class MOS6522Tests: XCTestCase {
$0.setValue(0, forRegister: 5) $0.setValue(0, forRegister: 5)
// run for 5 cycles // run for 5 cycles
$0.runForHalfCycles(10) $0.run(forHalfCycles: 10)
// check that the timer has gone down by 5 // check that the timer has gone down by 5
XCTAssert($0.valueForRegister(4) == 5, "Low order byte should be 5; was \($0.valueForRegister(4))") XCTAssert($0.value(forRegister: 4) == 5, "Low order byte should be 5; was \($0.value(forRegister: 4))")
XCTAssert($0.valueForRegister(5) == 0, "High order byte should be 0; was \($0.valueForRegister(5))") XCTAssert($0.value(forRegister: 5) == 0, "High order byte should be 0; was \($0.value(forRegister: 5))")
} }
} }
@ -43,15 +43,15 @@ class MOS6522Tests: XCTestCase {
$0.setValue(0x40, forRegister: 8) $0.setValue(0x40, forRegister: 8)
// chek that the new latched value hasn't been copied // chek that the new latched value hasn't been copied
XCTAssert($0.valueForRegister(8) == 0x10, "Low order byte should be 0x10; was \($0.valueForRegister(8))") XCTAssert($0.value(forRegister: 8) == 0x10, "Low order byte should be 0x10; was \($0.value(forRegister: 8))")
XCTAssert($0.valueForRegister(9) == 0x20, "High order byte should be 0x20; was \($0.valueForRegister(9))") XCTAssert($0.value(forRegister: 9) == 0x20, "High order byte should be 0x20; was \($0.value(forRegister: 9))")
// write the low-byte latch // write the low-byte latch
$0.setValue(0x50, forRegister: 9) $0.setValue(0x50, forRegister: 9)
// chek that the latched value has been copied // chek that the latched value has been copied
XCTAssert($0.valueForRegister(8) == 0x40, "Low order byte should be 0x50; was \($0.valueForRegister(8))") XCTAssert($0.value(forRegister: 8) == 0x40, "Low order byte should be 0x50; was \($0.value(forRegister: 8))")
XCTAssert($0.valueForRegister(9) == 0x50, "High order byte should be 0x40; was \($0.valueForRegister(9))") XCTAssert($0.value(forRegister: 9) == 0x50, "High order byte should be 0x40; was \($0.value(forRegister: 9))")
} }
} }
@ -64,32 +64,32 @@ class MOS6522Tests: XCTestCase {
$0.setValue(0x40 | 0x80, forRegister: 14) $0.setValue(0x40 | 0x80, forRegister: 14)
// run for 16 cycles // run for 16 cycles
$0.runForHalfCycles(32) $0.run(forHalfCycles: 32)
// check that the timer has gone down to 0 but not yet triggered an interrupt // check that the timer has gone down to 0 but not yet triggered an interrupt
XCTAssert($0.valueForRegister(4) == 0, "Low order byte should be 0; was \($0.valueForRegister(4))") XCTAssert($0.value(forRegister: 4) == 0, "Low order byte should be 0; was \($0.value(forRegister: 4))")
XCTAssert($0.valueForRegister(5) == 0, "High order byte should be 0; was \($0.valueForRegister(5))") XCTAssert($0.value(forRegister: 5) == 0, "High order byte should be 0; was \($0.value(forRegister: 5))")
XCTAssert(!$0.irqLine, "IRQ should not yet be active") XCTAssert(!$0.irqLine, "IRQ should not yet be active")
// check that two half-cycles later the timer is $ffff but IRQ still hasn't triggered // check that two half-cycles later the timer is $ffff but IRQ still hasn't triggered
$0.runForHalfCycles(2) $0.run(forHalfCycles: 2)
XCTAssert($0.valueForRegister(4) == 0xff, "Low order byte should be 0xff; was \($0.valueForRegister(4))") XCTAssert($0.value(forRegister: 4) == 0xff, "Low order byte should be 0xff; was \($0.value(forRegister: 4))")
XCTAssert($0.valueForRegister(5) == 0xff, "High order byte should be 0xff; was \($0.valueForRegister(5))") XCTAssert($0.value(forRegister: 5) == 0xff, "High order byte should be 0xff; was \($0.value(forRegister: 5))")
XCTAssert(!$0.irqLine, "IRQ should not yet be active") XCTAssert(!$0.irqLine, "IRQ should not yet be active")
// check that one half-cycle later the timer is still $ffff and IRQ has triggered... // check that one half-cycle later the timer is still $ffff and IRQ has triggered...
$0.runForHalfCycles(1) $0.run(forHalfCycles: 1)
XCTAssert($0.irqLine, "IRQ should be active") XCTAssert($0.irqLine, "IRQ should be active")
XCTAssert($0.valueForRegister(4) == 0xff, "Low order byte should be 0xff; was \($0.valueForRegister(4))") XCTAssert($0.value(forRegister: 4) == 0xff, "Low order byte should be 0xff; was \($0.value(forRegister: 4))")
XCTAssert($0.valueForRegister(5) == 0xff, "High order byte should be 0xff; was \($0.valueForRegister(5))") XCTAssert($0.value(forRegister: 5) == 0xff, "High order byte should be 0xff; was \($0.value(forRegister: 5))")
// ... but that reading the timer cleared the interrupt // ... but that reading the timer cleared the interrupt
XCTAssert(!$0.irqLine, "IRQ should be active") XCTAssert(!$0.irqLine, "IRQ should be active")
// check that one half-cycles later the timer has reloaded // check that one half-cycles later the timer has reloaded
$0.runForHalfCycles(1) $0.run(forHalfCycles: 1)
XCTAssert($0.valueForRegister(4) == 0x10, "Low order byte should be 0x10; was \($0.valueForRegister(4))") XCTAssert($0.value(forRegister: 4) == 0x10, "Low order byte should be 0x10; was \($0.value(forRegister: 4))")
XCTAssert($0.valueForRegister(5) == 0x00, "High order byte should be 0x00; was \($0.valueForRegister(5))") XCTAssert($0.value(forRegister: 5) == 0x00, "High order byte should be 0x00; was \($0.value(forRegister: 5))")
} }
} }
@ -107,7 +107,7 @@ class MOS6522Tests: XCTestCase {
$0.portBInput = 0xda $0.portBInput = 0xda
// test that the result of reading register B is therefore 0x8a // test that the result of reading register B is therefore 0x8a
XCTAssert($0.valueForRegister(0) == 0x8a, "Data direction register should mix input and output; got \($0.valueForRegister(0))") XCTAssert($0.value(forRegister: 0) == 0x8a, "Data direction register should mix input and output; got \($0.value(forRegister: 0))")
} }
} }
} }

View File

@ -11,7 +11,7 @@ import Foundation
class MOS6532Tests: XCTestCase { class MOS6532Tests: XCTestCase {
private func with6532(action: (MOS6532Bridge) -> ()) { fileprivate func with6532(_ action: (MOS6532Bridge) -> ()) {
let bridge = MOS6532Bridge() let bridge = MOS6532Bridge()
action(bridge) action(bridge)
} }
@ -23,12 +23,12 @@ class MOS6532Tests: XCTestCase {
$0.setValue(128, forRegister:0x14) $0.setValue(128, forRegister:0x14)
// run for one clock and the count should now be 127 // run for one clock and the count should now be 127
$0.runForCycles(1) $0.run(forCycles: 1)
XCTAssert($0.valueForRegister(4) == 127, "A single tick should decrease the counter once") XCTAssert($0.value(forRegister: 4) == 127, "A single tick should decrease the counter once")
// run for a further 200 clock counts; timer should reach -73 = 183 // run for a further 200 clock counts; timer should reach -73 = 183
$0.runForCycles(200) $0.run(forCycles: 200)
XCTAssert($0.valueForRegister(4) == 183, "Timer should underflow and keep counting") XCTAssert($0.value(forRegister: 4) == 183, "Timer should underflow and keep counting")
} }
} }
@ -39,24 +39,24 @@ class MOS6532Tests: XCTestCase {
$0.setValue(28, forRegister:0x15) $0.setValue(28, forRegister:0x15)
// run for seven clock and the count should still be 28 // run for seven clock and the count should still be 28
$0.runForCycles(7) $0.run(forCycles: 7)
XCTAssert($0.valueForRegister(4) == 28, "The timer should remain unchanged for seven clocks") XCTAssert($0.value(forRegister: 4) == 28, "The timer should remain unchanged for seven clocks")
// run for a further clock and the count should now be 27 // run for a further clock and the count should now be 27
$0.runForCycles(1) $0.run(forCycles: 1)
XCTAssert($0.valueForRegister(4) == 27, "The timer should have decremented once after 8 cycles") XCTAssert($0.value(forRegister: 4) == 27, "The timer should have decremented once after 8 cycles")
// run for a further 7 + 27*8 + 5 = 228 clock counts; timer should reach -5 = 0xfb // run for a further 7 + 27*8 + 5 = 228 clock counts; timer should reach -5 = 0xfb
$0.runForCycles(228) $0.run(forCycles: 228)
XCTAssert($0.valueForRegister(4) == 0xfb, "Timer should underflow and start counting at single-clock pace") XCTAssert($0.value(forRegister: 4) == 0xfb, "Timer should underflow and start counting at single-clock pace")
// timer should now resume dividing by eight // timer should now resume dividing by eight
$0.runForCycles(7) $0.run(forCycles: 7)
XCTAssert($0.valueForRegister(4) == 0xfb, "Timer should remain unchanged for seven cycles") XCTAssert($0.value(forRegister: 4) == 0xfb, "Timer should remain unchanged for seven cycles")
// timer should now resume dividing by eight // timer should now resume dividing by eight
$0.runForCycles(1) $0.run(forCycles: 1)
XCTAssert($0.valueForRegister(4) == 0xfa, "Timer should decrement after eighth cycle") XCTAssert($0.value(forRegister: 4) == 0xfa, "Timer should decrement after eighth cycle")
} }
} }
@ -66,23 +66,23 @@ class MOS6532Tests: XCTestCase {
$0.setValue(1, forRegister:0x1c) $0.setValue(1, forRegister:0x1c)
// run for one clock and the count should now be zero // run for one clock and the count should now be zero
$0.runForCycles(1) $0.run(forCycles: 1)
// interrupt shouldn't be signalled yet, bit should not be set // interrupt shouldn't be signalled yet, bit should not be set
XCTAssert(!$0.irqLine, "IRQ line should not be set") XCTAssert(!$0.irqLine, "IRQ line should not be set")
XCTAssert($0.valueForRegister(5) == 0x00, "Counter interrupt should not be set") XCTAssert($0.value(forRegister: 5) == 0x00, "Counter interrupt should not be set")
// run for one more clock // run for one more clock
$0.runForCycles(1) $0.run(forCycles: 1)
// the interrupt line and bit should now be set // the interrupt line and bit should now be set
XCTAssert($0.irqLine, "IRQ line should be set") XCTAssert($0.irqLine, "IRQ line should be set")
XCTAssert($0.valueForRegister(5) == 0x80, "Counter interrupt should be set") XCTAssert($0.value(forRegister: 5) == 0x80, "Counter interrupt should be set")
// writing again to the timer should clear both // writing again to the timer should clear both
$0.setValue(1, forRegister:0x1c) $0.setValue(1, forRegister:0x1c)
XCTAssert(!$0.irqLine, "IRQ line should be clear") XCTAssert(!$0.irqLine, "IRQ line should be clear")
XCTAssert($0.valueForRegister(5) == 0x00, "Counter interrupt should not be set") XCTAssert($0.value(forRegister: 5) == 0x00, "Counter interrupt should not be set")
} }
} }
@ -103,10 +103,10 @@ class MOS6532Tests: XCTestCase {
// confirm that the interrupt flag is set but the line is not // confirm that the interrupt flag is set but the line is not
XCTAssert(!$0.irqLine, "IRQ line should not be set") XCTAssert(!$0.irqLine, "IRQ line should not be set")
XCTAssert($0.valueForRegister(5) == 0x40, "Timer interrupt bit should be set") XCTAssert($0.value(forRegister: 5) == 0x40, "Timer interrupt bit should be set")
// reading the status register should have reset the interrupt flag // reading the status register should have reset the interrupt flag
XCTAssert($0.valueForRegister(5) == 0x00, "Timer interrupt bit should be reset") XCTAssert($0.value(forRegister: 5) == 0x00, "Timer interrupt bit should be reset")
} }
} }
@ -114,7 +114,7 @@ class MOS6532Tests: XCTestCase {
with6532 { with6532 {
// seed port a is high; ensure interrupt bit is clear // seed port a is high; ensure interrupt bit is clear
$0.setValue(0x00, forRegister:0) $0.setValue(0x00, forRegister:0)
$0.valueForRegister(5) $0.value(forRegister: 5)
// enable leading edge detection // enable leading edge detection
$0.setValue(0, forRegister:7) $0.setValue(0, forRegister:7)
@ -127,7 +127,7 @@ class MOS6532Tests: XCTestCase {
// confirm that both the interrupt flag are the line are set // confirm that both the interrupt flag are the line are set
XCTAssert($0.irqLine, "IRQ line should be set") XCTAssert($0.irqLine, "IRQ line should be set")
XCTAssert($0.valueForRegister(5) == 0x40, "Timer interrupt bit should be set") XCTAssert($0.value(forRegister: 5) == 0x40, "Timer interrupt bit should be set")
} }
} }
@ -135,7 +135,7 @@ class MOS6532Tests: XCTestCase {
with6532 { with6532 {
// seed port a is high; ensure interrupt bit is clear // seed port a is high; ensure interrupt bit is clear
$0.setValue(0x80, forRegister:0) $0.setValue(0x80, forRegister:0)
$0.valueForRegister(5) $0.value(forRegister: 5)
// enable trailing edge detection // enable trailing edge detection
$0.setValue(0, forRegister:6) $0.setValue(0, forRegister:6)
@ -148,7 +148,7 @@ class MOS6532Tests: XCTestCase {
// confirm that both the interrupt flag are the line are set // confirm that both the interrupt flag are the line are set
XCTAssert($0.irqLine, "IRQ line should be set") XCTAssert($0.irqLine, "IRQ line should be set")
XCTAssert($0.valueForRegister(5) == 0x40, "Timer interrupt bit should be set") XCTAssert($0.value(forRegister: 5) == 0x40, "Timer interrupt bit should be set")
} }
} }
} }

View File

@ -12,22 +12,22 @@ import XCTest
class AllSuiteATests: XCTestCase { class AllSuiteATests: XCTestCase {
func testAllSuiteA() { func testAllSuiteA() {
if let filename = NSBundle(forClass: self.dynamicType).pathForResource("AllSuiteA", ofType: "bin") { if let filename = Bundle(for: type(of: self)).path(forResource: "AllSuiteA", ofType: "bin") {
if let allSuiteA = NSData(contentsOfFile: filename) { if let allSuiteA = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
let machine = CSTestMachine() let machine = CSTestMachine()
machine.setData(allSuiteA, atAddress: 0x4000) machine.setData(allSuiteA, atAddress: 0x4000)
machine.setValue(CSTestMachineJamOpcode, forAddress:0x45c0); // end machine.setValue(CSTestMachineJamOpcode, forAddress:0x45c0); // end
machine.setValue(0x4000, forRegister: CSTestMachineRegister.ProgramCounter) machine.setValue(0x4000, for: CSTestMachineRegister.programCounter)
while !machine.isJammed { while !machine.isJammed {
machine.runForNumberOfCycles(1000) machine.runForNumber(ofCycles: 1000)
} }
if machine.valueForAddress(0x0210) != 0xff { if machine.value(forAddress: 0x0210) != 0xff {
NSException(name: "Failed AllSuiteA", reason: "Failed test \(machine.valueForAddress(0x0210))", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed AllSuiteA"), reason: "Failed test \(machine.value(forAddress: 0x0210))", userInfo: nil).raise()
} }
} }
} }
} }
} }

View File

@ -10,32 +10,32 @@ import XCTest
class C1540Tests: XCTestCase { class C1540Tests: XCTestCase {
private func with1540(action: (C1540Bridge) -> ()) { fileprivate func with1540(_ action: (C1540Bridge) -> ()) {
let bridge = C1540Bridge() let bridge = C1540Bridge()
if let path = NSBundle.mainBundle().pathForResource("1541", ofType: "bin", inDirectory: "ROMImages/Commodore1540") { if let path = Bundle.main.path(forResource: "1541", ofType: "bin", inDirectory: "ROMImages/Commodore1540") {
let data = NSData(contentsOfFile: path) let data = try? Data(contentsOf: URL(fileURLWithPath: path))
bridge.setROM(data) bridge.setROM(data)
} }
action(bridge) action(bridge)
} }
private func transmit(c1540: C1540Bridge, value: Int) { fileprivate func transmit(_ c1540: C1540Bridge, value: Int) {
var shiftedValue = value var shiftedValue = value
c1540.dataLine = true c1540.dataLine = true
c1540.runForCycles(256) c1540.run(forCycles: 256)
XCTAssert(c1540.dataLine == false, "Listener should have taken data line low for start of transmission") XCTAssert(c1540.dataLine == false, "Listener should have taken data line low for start of transmission")
c1540.clockLine = true c1540.clockLine = true
c1540.runForCycles(256) // this isn't time limited on real hardware c1540.run(forCycles: 256) // this isn't time limited on real hardware
XCTAssert(c1540.dataLine == true, "Listener should have let data line go high again") XCTAssert(c1540.dataLine == true, "Listener should have let data line go high again")
// set up for byte transfer // set up for byte transfer
c1540.clockLine = false c1540.clockLine = false
c1540.dataLine = true c1540.dataLine = true
c1540.runForCycles(40) c1540.run(forCycles: 40)
// transmit bits // transmit bits
for _ in 0..<8 { for _ in 0..<8 {
@ -45,14 +45,14 @@ class C1540Tests: XCTestCase {
// toggle clock // toggle clock
c1540.clockLine = true c1540.clockLine = true
c1540.runForCycles(40) c1540.run(forCycles: 40)
c1540.clockLine = false c1540.clockLine = false
c1540.runForCycles(40) c1540.run(forCycles: 40)
} }
// check for acknowledgment // check for acknowledgment
c1540.dataLine = true c1540.dataLine = true
c1540.runForCycles(1000) c1540.run(forCycles: 1000)
XCTAssert(c1540.dataLine == false, "Listener should have acknowledged byte") XCTAssert(c1540.dataLine == false, "Listener should have acknowledged byte")
} }
@ -61,7 +61,7 @@ class C1540Tests: XCTestCase {
func testTransmission() { func testTransmission() {
with1540 { with1540 {
// allow some booting time // allow some booting time
$0.runForCycles(2000000) $0.run(forCycles: 2000000)
// I want to be talker, so hold attention and clock low with data high // I want to be talker, so hold attention and clock low with data high
$0.clockLine = false $0.clockLine = false
@ -69,7 +69,7 @@ class C1540Tests: XCTestCase {
$0.dataLine = true $0.dataLine = true
// proceed 1 ms and check that the 1540 pulled the data line low // proceed 1 ms and check that the 1540 pulled the data line low
$0.runForCycles(1000) $0.run(forCycles: 1000)
XCTAssert($0.dataLine == false, "Listener should have taken data line low") XCTAssert($0.dataLine == false, "Listener should have taken data line low")
// transmit LISTEN #8 // transmit LISTEN #8

View File

@ -10,16 +10,16 @@ import XCTest
class DPLLTests: XCTestCase { class DPLLTests: XCTestCase {
func testRegularNibblesOnPLL(pll: DigitalPhaseLockedLoopBridge, bitLength: UInt) { func testRegularNibblesOnPLL(_ pll: DigitalPhaseLockedLoopBridge, bitLength: UInt) {
// clock in two 1s, a 0, and a 1, 200 times over // clock in two 1s, a 0, and a 1, 200 times over
for _ in 0 ..< 200 { for _ in 0 ..< 200 {
pll.runForCycles(bitLength/2) pll.run(forCycles: bitLength/2)
pll.addPulse() pll.addPulse()
pll.runForCycles(bitLength) pll.run(forCycles: bitLength)
pll.addPulse() pll.addPulse()
pll.runForCycles(bitLength*2) pll.run(forCycles: bitLength*2)
pll.addPulse() pll.addPulse()
pll.runForCycles(bitLength/2) pll.run(forCycles: bitLength/2)
} }
XCTAssert((pll.stream&0xffffffff) == 0xdddddddd, "PLL should have synchronised and clocked repeating 0xd nibbles; got \(String(pll.stream, radix: 16, uppercase: false))") XCTAssert((pll.stream&0xffffffff) == 0xdddddddd, "PLL should have synchronised and clocked repeating 0xd nibbles; got \(String(pll.stream, radix: 16, uppercase: false))")
@ -27,17 +27,17 @@ class DPLLTests: XCTestCase {
func testPerfectInput() { func testPerfectInput() {
let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3) let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3)
testRegularNibblesOnPLL(pll, bitLength: 100) testRegularNibblesOnPLL(pll!, bitLength: 100)
} }
func testFastButRegular() { func testFastButRegular() {
let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3) let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3)
testRegularNibblesOnPLL(pll, bitLength: 90) testRegularNibblesOnPLL(pll!, bitLength: 90)
} }
func testSlowButRegular() { func testSlowButRegular() {
let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3) let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3)
testRegularNibblesOnPLL(pll, bitLength: 110) testRegularNibblesOnPLL(pll!, bitLength: 110)
} }
func testTwentyPercentSinePattern() { func testTwentyPercentSinePattern() {
@ -48,14 +48,14 @@ class DPLLTests: XCTestCase {
for _ in 0 ..< 200 { for _ in 0 ..< 200 {
let bitLength: UInt = UInt(100 + 20 * sin(angle)) let bitLength: UInt = UInt(100 + 20 * sin(angle))
pll.runForCycles(bitLength/2) pll?.run(forCycles: bitLength/2)
pll.addPulse() pll?.addPulse()
pll.runForCycles((bitLength*3)/2) pll?.run(forCycles: (bitLength*3)/2)
angle = angle + 0.1 angle = angle + 0.1
} }
let endOfStream = pll.stream&0xffffffff; let endOfStream = (pll?.stream)!&0xffffffff;
XCTAssert(endOfStream == 0xaaaaaaaa || endOfStream == 0x55555555, "PLL should have synchronised and clocked repeating 0xa or 0x5 nibbles; got \(String(pll.stream, radix: 16, uppercase: false))") XCTAssert(endOfStream == 0xaaaaaaaa || endOfStream == 0x55555555, "PLL should have synchronised and clocked repeating 0xa or 0x5 nibbles; got \(String(pll?.stream, radix: 16, uppercase: false))")
} }
} }

View File

@ -13,7 +13,7 @@ class KlausDormannTests: XCTestCase {
func testKlausDormann() { func testKlausDormann() {
func errorForTrapAddress(address: UInt16) -> String? { func errorForTrapAddress(_ address: UInt16) -> String? {
let hexAddress = String(format:"%04x", address) let hexAddress = String(format:"%04x", address)
switch address { switch address {
case 0x3399: return nil // success! case 0x3399: return nil // success!
@ -32,17 +32,17 @@ class KlausDormannTests: XCTestCase {
} }
} }
if let filename = NSBundle(forClass: self.dynamicType).pathForResource("6502_functional_test", ofType: "bin") { if let filename = Bundle(for: type(of: self)).path(forResource: "6502_functional_test", ofType: "bin") {
if let functionalTest = NSData(contentsOfFile: filename) { if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
let machine = CSTestMachine() let machine = CSTestMachine()
machine.setData(functionalTest, atAddress: 0) machine.setData(functionalTest, atAddress: 0)
machine.setValue(0x400, forRegister: CSTestMachineRegister.ProgramCounter) machine.setValue(0x400, for: CSTestMachineRegister.programCounter)
while true { while true {
let oldPC = machine.valueForRegister(CSTestMachineRegister.LastOperationAddress) let oldPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
machine.runForNumberOfCycles(1000) machine.runForNumber(ofCycles: 1000)
let newPC = machine.valueForRegister(CSTestMachineRegister.LastOperationAddress) let newPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
if newPC == oldPC { if newPC == oldPC {
let error = errorForTrapAddress(oldPC) let error = errorForTrapAddress(oldPC)

View File

@ -186,29 +186,29 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
self.runWolfgangLorenzTest("sbcb(eb)") self.runWolfgangLorenzTest("sbcb(eb)")
} }
private func runWolfgangLorenzTest(name: String, suffixes: [String]) { fileprivate func runWolfgangLorenzTest(_ name: String, suffixes: [String]) {
for suffix in suffixes { for suffix in suffixes {
let testName = name + suffix let testName = name + suffix
self.runWolfgangLorenzTest(testName) self.runWolfgangLorenzTest(testName)
} }
} }
private var output: String = "" fileprivate var output: String = ""
private func runWolfgangLorenzTest(name: String) { fileprivate func runWolfgangLorenzTest(_ name: String) {
var machine: CSTestMachine! var machine: CSTestMachine!
if let filename = NSBundle(forClass: self.dynamicType).pathForResource(name, ofType: nil) { if let filename = Bundle(for: type(of: self)).path(forResource: name, ofType: nil) {
if let testData = NSData(contentsOfFile: filename) { if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
machine = CSTestMachine() machine = CSTestMachine()
machine.jamHandler = self machine.jamHandler = self
// machine.logActivity = true // machine.logActivity = true
output = "" output = ""
let dataPointer = UnsafePointer<UInt8>(testData.bytes) let dataPointer = (testData as NSData).bytes.bindMemory(to: UInt8.self, capacity: testData.count)
let loadAddress = UInt16(dataPointer[0]) | (UInt16(dataPointer[1]) << 8) let loadAddress = UInt16(dataPointer[0]) | (UInt16(dataPointer[1]) << 8)
let contents = testData.subdataWithRange(NSMakeRange(2, testData.length - 2)) let contents = testData.subdata(in: NSMakeRange(2, testData.count - 2))
machine.setData(contents, atAddress: loadAddress) machine.setData(contents, atAddress: loadAddress)
@ -220,10 +220,10 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
machine.setValue(0x48, forAddress: 0xfffe) machine.setValue(0x48, forAddress: 0xfffe)
machine.setValue(0xff, forAddress: 0xffff) machine.setValue(0xff, forAddress: 0xffff)
let irqHandler = NSData(bytes: [ let irqHandler = Data(bytes: UnsafePointer<UInt8>([
0x48, 0x8a, 0x48, 0x98, 0x48, 0xba, 0xbd, 0x04, 0x01, 0x48, 0x8a, 0x48, 0x98, 0x48, 0xba, 0xbd, 0x04, 0x01,
0x29, 0x10, 0xf0, 0x03, 0x6c, 0x16, 0x03, 0x6c, 0x14, 0x03 0x29, 0x10, 0xf0, 0x03, 0x6c, 0x16, 0x03, 0x6c, 0x14, 0x03
] as [UInt8], length: 19) ] as [UInt8]), count: 19)
machine.setData( irqHandler, atAddress: 0xff48) machine.setData( irqHandler, atAddress: 0xff48)
machine.setValue(CSTestMachineJamOpcode, forAddress:0xffd2); // print character machine.setValue(CSTestMachineJamOpcode, forAddress:0xffd2); // print character
@ -232,30 +232,30 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
machine.setValue(CSTestMachineJamOpcode, forAddress:0x8000); // exit machine.setValue(CSTestMachineJamOpcode, forAddress:0x8000); // exit
machine.setValue(CSTestMachineJamOpcode, forAddress:0xa474); // exit machine.setValue(CSTestMachineJamOpcode, forAddress:0xa474); // exit
machine.setValue(0x0801, forRegister: CSTestMachineRegister.ProgramCounter) machine.setValue(0x0801, for: CSTestMachineRegister.programCounter)
machine.setValue(0xfd, forRegister: CSTestMachineRegister.StackPointer) machine.setValue(0xfd, for: CSTestMachineRegister.stackPointer)
machine.setValue(0x04, forRegister: CSTestMachineRegister.Flags) machine.setValue(0x04, for: CSTestMachineRegister.flags)
} }
} }
if machine == nil { if machine == nil {
NSException(name: "Failed Test", reason: "Couldn't load file \(name)", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Couldn't load file \(name)", userInfo: nil).raise()
} }
while !machine.isJammed { while !machine.isJammed {
machine.runForNumberOfCycles(1000) machine.runForNumber(ofCycles: 1000)
} }
let jammedPC = machine.valueForRegister(CSTestMachineRegister.LastOperationAddress) let jammedPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
if jammedPC != 0xe16f { if jammedPC != 0xe16f {
let hexAddress = String(format:"%04x", jammedPC) let hexAddress = String(format:"%04x", jammedPC)
NSException(name: "Failed Test", reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()
} }
} }
// MARK: MachineJamHandler // MARK: MachineJamHandler
func petsciiToString(string: String) -> String { func petsciiToString(_ string: String) -> String {
let petsciiToCharCommon: [String] = [ let petsciiToCharCommon: [String] = [
"?", "?", "?", "[RUN/STOP]", "?", "[WHT]", "?", "?", "[SHIFT DISABLE]", "[SHIFT ENABLE]", "?", "?", "?", "\r", "[TEXT MODE]", "?", "?", "?", "?", "[RUN/STOP]", "?", "[WHT]", "?", "?", "[SHIFT DISABLE]", "[SHIFT ENABLE]", "?", "?", "?", "\r", "[TEXT MODE]", "?",
"?", "\n", "[RVS ON]", "[HOME]", "[DEL]", "?", "?", "?", "?", "?", "?", "?", "[RED]", "[RIGHT]", "[GRN]", "[BLU]", "?", "\n", "[RVS ON]", "[HOME]", "[DEL]", "?", "?", "?", "?", "?", "?", "?", "[RED]", "[RIGHT]", "[GRN]", "[BLU]",
@ -297,33 +297,33 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
return result return result
} }
func testMachine(machine: CSTestMachine!, didJamAtAddress address: UInt16) { func testMachine(_ machine: CSTestMachine!, didJamAtAddress address: UInt16) {
switch address { switch address {
case 0xffd2: case 0xffd2:
machine.setValue(0x00, forAddress: 0x030c) machine.setValue(0x00, forAddress: 0x030c)
let character = machine.valueForRegister(CSTestMachineRegister.A) let character = machine.value(for: CSTestMachineRegister.A)
output.append(Character(UnicodeScalar(character))) output.append(Character(UnicodeScalar(character)!))
machine.returnFromSubroutine() machine.returnFromSubroutine()
case 0xffe4: case 0xffe4:
machine.setValue(0x3, forRegister:CSTestMachineRegister.A) machine.setValue(0x3, for:CSTestMachineRegister.A)
machine.returnFromSubroutine() machine.returnFromSubroutine()
case 0x8000, 0xa474: case 0x8000, 0xa474:
NSException(name: "Failed test", reason: self.petsciiToString(output), userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed test"), reason: self.petsciiToString(output), userInfo: nil).raise()
case 0x0000: case 0x0000:
NSException(name: "Failed test", reason: "Execution hit 0000", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed test"), reason: "Execution hit 0000", userInfo: nil).raise()
case 0xe16f: // load next (which we consider to be success) case 0xe16f: // load next (which we consider to be success)
break; break;
default: default:
let hexAddress = String(format:"%04x", address) let hexAddress = String(format:"%04x", address)
NSException(name: "Failed Test", reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise() NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()
} }
} }