mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
commit
788df09f71
@ -1708,11 +1708,12 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0700;
|
||||
LastUpgradeCheck = 0800;
|
||||
ORGANIZATIONNAME = "Thomas Harte";
|
||||
TargetAttributes = {
|
||||
4BB73E9D1B587A5100552FC2 = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
LastSwiftMigration = 0800;
|
||||
SystemCapabilities = {
|
||||
com.apple.Sandbox = {
|
||||
enabled = 1;
|
||||
@ -1721,10 +1722,12 @@
|
||||
};
|
||||
4BB73EB11B587A5100552FC2 = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
LastSwiftMigration = 0800;
|
||||
TestTargetID = 4BB73E9D1B587A5100552FC2;
|
||||
};
|
||||
4BB73EBC1B587A5100552FC2 = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
LastSwiftMigration = 0800;
|
||||
TestTargetID = 4BB73E9D1B587A5100552FC2;
|
||||
};
|
||||
};
|
||||
@ -2207,8 +2210,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
@ -2251,8 +2256,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
@ -2271,6 +2278,7 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -2289,6 +2297,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -2306,6 +2315,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-Signal";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -2321,6 +2331,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
|
||||
};
|
||||
name = Debug;
|
||||
@ -2336,6 +2347,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
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";
|
||||
};
|
||||
name = Release;
|
||||
@ -2348,6 +2360,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_TARGET_NAME = "Clock Signal";
|
||||
USES_XCTRUNNER = YES;
|
||||
};
|
||||
@ -2361,6 +2374,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TEST_TARGET_NAME = "Clock Signal";
|
||||
USES_XCTRUNNER = YES;
|
||||
};
|
||||
|
@ -11,16 +11,16 @@ import Cocoa
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
func applicationDidFinishLaunching(aNotification: NSNotification) {
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
// Insert code here to initialize your application
|
||||
}
|
||||
|
||||
func applicationWillTerminate(aNotification: NSNotification) {
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
// Insert code here to tear down your application
|
||||
}
|
||||
|
||||
// decline to open a new file unless the user explicitly requests it
|
||||
func applicationShouldOpenUntitledFile(sender: NSApplication) -> Bool {
|
||||
func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -9,18 +9,18 @@
|
||||
import Cocoa
|
||||
|
||||
class DocumentController: NSDocumentController {
|
||||
override func makeDocumentWithContentsOfURL(url: NSURL, ofType typeName: String) throws -> NSDocument {
|
||||
if let analyser = CSStaticAnalyser(fileAtURL: url) {
|
||||
override func makeDocument(withContentsOf url: URL, ofType typeName: String) throws -> NSDocument {
|
||||
if let analyser = CSStaticAnalyser(fileAt: url) {
|
||||
if let documentClass = analyser.documentClass as? NSDocument.Type {
|
||||
let document = documentClass.init()
|
||||
if let machineDocument = document as? MachineDocument {
|
||||
machineDocument.setDisplayName(analyser.displayName)
|
||||
machineDocument.displayName = analyser.displayName
|
||||
machineDocument.configureAs(analyser)
|
||||
return machineDocument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return try! super.makeDocumentWithContentsOfURL(url, ofType: typeName)
|
||||
return try! super.makeDocument(withContentsOf: url, ofType: typeName)
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import Cocoa
|
||||
|
||||
class Atari2600Document: MachineDocument {
|
||||
|
||||
private var atari2600 = CSAtari2600()
|
||||
fileprivate var atari2600 = CSAtari2600()
|
||||
override var machine: CSMachine! {
|
||||
get {
|
||||
return atari2600
|
||||
@ -31,7 +31,7 @@ class Atari2600Document: MachineDocument {
|
||||
return "Atari2600Document"
|
||||
}
|
||||
|
||||
override func windowControllerDidLoadNib(aController: NSWindowController) {
|
||||
override func windowControllerDidLoadNib(_ aController: NSWindowController) {
|
||||
super.windowControllerDidLoadNib(aController)
|
||||
|
||||
// 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
|
||||
showOptions(self)
|
||||
self.openGLView.window?.makeKeyWindow()
|
||||
self.openGLView.window?.makeKey()
|
||||
}
|
||||
|
||||
// MARK: CSOpenGLViewResponderDelegate
|
||||
private func inputForKey(event: NSEvent) -> Atari2600DigitalInput? {
|
||||
fileprivate func inputForKey(_ event: NSEvent) -> Atari2600DigitalInput? {
|
||||
switch event.keyCode {
|
||||
case 123: return Atari2600DigitalInputJoy1Left
|
||||
case 126: return Atari2600DigitalInputJoy1Up
|
||||
case 124: return Atari2600DigitalInputJoy1Right
|
||||
case 125: return Atari2600DigitalInputJoy1Down
|
||||
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)
|
||||
|
||||
if let input = inputForKey(event) {
|
||||
atari2600.setState(true, forDigitalInput: input)
|
||||
atari2600.setState(true, for: input)
|
||||
}
|
||||
|
||||
if event.keyCode == 36 {
|
||||
@ -66,11 +68,11 @@ class Atari2600Document: MachineDocument {
|
||||
}
|
||||
}
|
||||
|
||||
override func keyUp(event: NSEvent) {
|
||||
override func keyUp(_ event: NSEvent) {
|
||||
super.keyUp(event)
|
||||
|
||||
if let input = inputForKey(event) {
|
||||
atari2600.setState(false, forDigitalInput: input)
|
||||
atari2600.setState(false, for: input)
|
||||
}
|
||||
|
||||
if event.keyCode == 36 {
|
||||
@ -85,21 +87,21 @@ class Atari2600Document: MachineDocument {
|
||||
@IBOutlet var leftPlayerDifficultyButton: NSButton!
|
||||
@IBOutlet var rightPlayerDifficultyButton: NSButton!
|
||||
|
||||
@IBAction func optionDidChange(sender: AnyObject!) {
|
||||
@IBAction func optionDidChange(_ sender: AnyObject!) {
|
||||
pushSwitchValues()
|
||||
}
|
||||
|
||||
private func pushSwitchValues() {
|
||||
fileprivate func pushSwitchValues() {
|
||||
atari2600.colourButton = colourButton.state == NSOnState
|
||||
atari2600.leftPlayerDifficultyButton = leftPlayerDifficultyButton.state == NSOnState
|
||||
atari2600.rightPlayerDifficultyButton = rightPlayerDifficultyButton.state == NSOnState
|
||||
}
|
||||
|
||||
@IBAction func optionWasPressed(sender: NSButton!) {
|
||||
@IBAction func optionWasPressed(_ sender: NSButton!) {
|
||||
if sender == resetButton {
|
||||
atari2600.pressResetButton()
|
||||
} else {
|
||||
atari2600.pressSelectButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import AudioToolbox
|
||||
|
||||
class ElectronDocument: MachineDocument {
|
||||
|
||||
private lazy var electron = CSElectron()
|
||||
fileprivate lazy var electron = CSElectron()
|
||||
override var machine: CSMachine! {
|
||||
get {
|
||||
return electron
|
||||
@ -27,14 +27,14 @@ class ElectronDocument: MachineDocument {
|
||||
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")
|
||||
}
|
||||
|
||||
override func windowControllerDidLoadNib(aController: NSWindowController) {
|
||||
override func windowControllerDidLoadNib(_ aController: NSWindowController) {
|
||||
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.setBASICROM(basic)
|
||||
}
|
||||
@ -67,21 +67,21 @@ class ElectronDocument: MachineDocument {
|
||||
|
||||
// MARK: IBActions
|
||||
@IBOutlet var displayTypeButton: NSPopUpButton?
|
||||
@IBAction func setDisplayType(sender: NSPopUpButton!) {
|
||||
@IBAction func setDisplayType(_ sender: NSPopUpButton!) {
|
||||
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() {
|
||||
super.establishStoredOptions()
|
||||
let standardUserDefaults = NSUserDefaults.standardUserDefaults()
|
||||
standardUserDefaults.registerDefaults([
|
||||
let standardUserDefaults = UserDefaults.standard
|
||||
standardUserDefaults.register(defaults: [
|
||||
displayTypeUserDefaultsKey: 0,
|
||||
])
|
||||
|
||||
let displayType = standardUserDefaults.integerForKey(self.displayTypeUserDefaultsKey)
|
||||
let displayType = standardUserDefaults.integer(forKey: self.displayTypeUserDefaultsKey)
|
||||
electron.useTelevisionOutput = (displayType == 1)
|
||||
self.displayTypeButton?.selectItemAtIndex(displayType)
|
||||
self.displayTypeButton?.selectItem(at: displayType)
|
||||
}
|
||||
}
|
||||
|
@ -43,24 +43,24 @@ class MachineDocument:
|
||||
}
|
||||
|
||||
@IBOutlet weak var optionsPanel: NSPanel!
|
||||
@IBAction func showOptions(sender: AnyObject!) {
|
||||
@IBAction func showOptions(_ sender: AnyObject!) {
|
||||
optionsPanel?.setIsVisible(true)
|
||||
}
|
||||
|
||||
private var audioQueue: CSAudioQueue! = nil
|
||||
private lazy var bestEffortUpdater: CSBestEffortUpdater = {
|
||||
fileprivate var audioQueue: CSAudioQueue! = nil
|
||||
fileprivate lazy var bestEffortUpdater: CSBestEffortUpdater = {
|
||||
let updater = CSBestEffortUpdater()
|
||||
updater.delegate = self
|
||||
return updater
|
||||
}()
|
||||
|
||||
override func windowControllerDidLoadNib(aController: NSWindowController) {
|
||||
override func windowControllerDidLoadNib(_ aController: NSWindowController) {
|
||||
super.windowControllerDidLoadNib(aController)
|
||||
|
||||
// establish the output aspect ratio and audio
|
||||
let displayAspectRatio = self.aspectRatio()
|
||||
aController.window?.contentAspectRatio = displayAspectRatio
|
||||
openGLView.performWithGLContext({
|
||||
openGLView.perform(glContext: {
|
||||
self.machine.setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height))
|
||||
})
|
||||
|
||||
@ -69,18 +69,18 @@ class MachineDocument:
|
||||
establishStoredOptions()
|
||||
}
|
||||
|
||||
func machineDidChangeClockRate(machine: CSMachine!) {
|
||||
func machineDidChangeClockRate(_ machine: CSMachine!) {
|
||||
setupClockRate()
|
||||
}
|
||||
|
||||
func machineDidChangeClockIsUnlimited(machine: CSMachine!) {
|
||||
func machineDidChangeClockIsUnlimited(_ machine: CSMachine!) {
|
||||
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
|
||||
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 {
|
||||
audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate))
|
||||
audioQueue.delegate = self
|
||||
@ -103,89 +103,89 @@ class MachineDocument:
|
||||
}
|
||||
|
||||
// MARK: configuring
|
||||
func configureAs(analysis: CSStaticAnalyser) {
|
||||
analysis.applyToMachine(self.machine)
|
||||
func configureAs(_ analysis: CSStaticAnalyser) {
|
||||
analysis.apply(to: self.machine)
|
||||
}
|
||||
|
||||
// MARK: the pasteboard
|
||||
func paste(sender: AnyObject!) {
|
||||
let pasteboard = NSPasteboard.generalPasteboard()
|
||||
if let string = pasteboard.stringForType(NSPasteboardTypeString) {
|
||||
func paste(_ sender: AnyObject!) {
|
||||
let pasteboard = NSPasteboard.general()
|
||||
if let string = pasteboard.string(forType: NSPasteboardTypeString) {
|
||||
self.machine.paste(string)
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
func runForNumberOfCycles(numberOfCycles: Int32) {
|
||||
func runForNumberOfCycles(_ numberOfCycles: Int32) {
|
||||
let cyclesToRunFor = min(numberOfCycles, Int32(bestEffortUpdater.clockRate / 10))
|
||||
if actionLock.tryLock() {
|
||||
self.machine.runForNumberOfCycles(cyclesToRunFor)
|
||||
if actionLock.try() {
|
||||
self.machine.runForNumber(ofCycles: cyclesToRunFor)
|
||||
actionLock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Utilities for children
|
||||
func dataForResource(name : String, ofType type: String, inDirectory directory: String) -> NSData? {
|
||||
if let path = NSBundle.mainBundle().pathForResource(name, ofType: type, inDirectory: directory) {
|
||||
return NSData(contentsOfFile: path)
|
||||
func dataForResource(_ name : String, ofType type: String, inDirectory directory: String) -> Data? {
|
||||
if let path = Bundle.main.path(forResource: name, ofType: type, inDirectory: directory) {
|
||||
return (try? Data(contentsOf: URL(fileURLWithPath: path)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: CSAudioQueueDelegate
|
||||
final func audioQueueDidCompleteBuffer(audioQueue: CSAudioQueue) {
|
||||
final func audioQueueDidCompleteBuffer(_ audioQueue: CSAudioQueue) {
|
||||
bestEffortUpdater.update()
|
||||
}
|
||||
|
||||
// MARK: CSOpenGLViewDelegate
|
||||
final func openGLView(view: CSOpenGLView, drawViewOnlyIfDirty onlyIfDirty: Bool) {
|
||||
final func openGLView(_ view: CSOpenGLView, drawViewOnlyIfDirty onlyIfDirty: Bool) {
|
||||
bestEffortUpdater.update()
|
||||
if drawLock.tryLock() {
|
||||
self.machine.drawViewForPixelSize(view.backingSize, onlyIfDirty: onlyIfDirty)
|
||||
if drawLock.try() {
|
||||
self.machine.drawView(forPixelSize: view.backingSize, onlyIfDirty: onlyIfDirty)
|
||||
drawLock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// MARK: Key forwarding
|
||||
private func withKeyboardMachine(action: (CSKeyboardMachine) -> ()) {
|
||||
fileprivate func withKeyboardMachine(_ action: (CSKeyboardMachine) -> ()) {
|
||||
if let keyboardMachine = self.machine as? CSKeyboardMachine {
|
||||
action(keyboardMachine)
|
||||
}
|
||||
}
|
||||
|
||||
func windowDidResignKey(notification: NSNotification) {
|
||||
func windowDidResignKey(_ notification: Notification) {
|
||||
self.withKeyboardMachine { $0.clearAllKeys() }
|
||||
}
|
||||
|
||||
func keyDown(event: NSEvent) {
|
||||
func keyDown(_ event: NSEvent) {
|
||||
self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: true) }
|
||||
}
|
||||
|
||||
func keyUp(event: NSEvent) {
|
||||
func keyUp(_ event: NSEvent) {
|
||||
self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: false) }
|
||||
}
|
||||
|
||||
func flagsChanged(newModifiers: NSEvent) {
|
||||
func flagsChanged(_ newModifiers: NSEvent) {
|
||||
self.withKeyboardMachine {
|
||||
$0.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.ShiftKeyMask))
|
||||
$0.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.ControlKeyMask))
|
||||
$0.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.CommandKeyMask))
|
||||
$0.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.AlternateKeyMask))
|
||||
$0.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.shift))
|
||||
$0.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.control))
|
||||
$0.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.command))
|
||||
$0.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.option))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: IBActions
|
||||
final func prefixedUserDefaultsKey(key: String) -> String {
|
||||
final func prefixedUserDefaultsKey(_ key: String) -> String {
|
||||
return "\(self.name).\(key)"
|
||||
}
|
||||
var fastLoadingUserDefaultsKey: String {
|
||||
@ -195,22 +195,22 @@ class MachineDocument:
|
||||
}
|
||||
|
||||
@IBOutlet var fastLoadingButton: NSButton?
|
||||
@IBAction func setFastLoading(sender: NSButton!) {
|
||||
@IBAction func setFastLoading(_ sender: NSButton!) {
|
||||
if let fastLoadingMachine = machine as? CSFastLoading {
|
||||
let useFastLoadingHack = sender.state == NSOnState
|
||||
fastLoadingMachine.useFastLoadingHack = useFastLoadingHack
|
||||
NSUserDefaults.standardUserDefaults().setBool(useFastLoadingHack, forKey: fastLoadingUserDefaultsKey)
|
||||
UserDefaults.standard.set(useFastLoadingHack, forKey: fastLoadingUserDefaultsKey)
|
||||
}
|
||||
}
|
||||
|
||||
func establishStoredOptions() {
|
||||
let standardUserDefaults = NSUserDefaults.standardUserDefaults()
|
||||
standardUserDefaults.registerDefaults([
|
||||
let standardUserDefaults = UserDefaults.standard
|
||||
standardUserDefaults.register(defaults: [
|
||||
fastLoadingUserDefaultsKey: true
|
||||
])
|
||||
|
||||
if let fastLoadingMachine = machine as? CSFastLoading {
|
||||
let useFastLoadingHack = standardUserDefaults.boolForKey(self.fastLoadingUserDefaultsKey)
|
||||
let useFastLoadingHack = standardUserDefaults.bool(forKey: self.fastLoadingUserDefaultsKey)
|
||||
fastLoadingMachine.useFastLoadingHack = useFastLoadingHack
|
||||
self.fastLoadingButton?.state = useFastLoadingHack ? NSOnState : NSOffState
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import Foundation
|
||||
|
||||
class Vic20Document: MachineDocument {
|
||||
|
||||
private lazy var vic20 = CSVic20()
|
||||
fileprivate lazy var vic20 = CSVic20()
|
||||
override var machine: CSMachine! {
|
||||
get {
|
||||
return vic20
|
||||
@ -41,22 +41,8 @@ class Vic20Document: MachineDocument {
|
||||
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
|
||||
private func rom(name: String) -> NSData? {
|
||||
fileprivate func rom(_ name: String) -> Data? {
|
||||
return dataForResource(name, ofType: "bin", inDirectory: "ROMImages/Vic20")
|
||||
}
|
||||
|
||||
@ -66,10 +52,10 @@ class Vic20Document: MachineDocument {
|
||||
get { return prefixedUserDefaultsKey("autoload") }
|
||||
}
|
||||
|
||||
@IBAction func setShouldLoadAutomatically(sender: NSButton!) {
|
||||
@IBAction func setShouldLoadAutomatically(_ sender: NSButton!) {
|
||||
let loadAutomatically = sender.state == NSOnState
|
||||
vic20.shouldLoadAutomatically = loadAutomatically
|
||||
NSUserDefaults.standardUserDefaults().setBool(loadAutomatically, forKey: self.autoloadingUserDefaultsKey)
|
||||
UserDefaults.standard.set(loadAutomatically, forKey: self.autoloadingUserDefaultsKey)
|
||||
}
|
||||
|
||||
// MARK: country selector
|
||||
@ -78,12 +64,12 @@ class Vic20Document: MachineDocument {
|
||||
get { return prefixedUserDefaultsKey("country") }
|
||||
}
|
||||
|
||||
@IBAction func setCountry(sender: NSPopUpButton!) {
|
||||
NSUserDefaults.standardUserDefaults().setInteger(sender.indexOfSelectedItem, forKey: self.countryUserDefaultsKey)
|
||||
@IBAction func setCountry(_ sender: NSPopUpButton!) {
|
||||
UserDefaults.standard.set(sender.indexOfSelectedItem, forKey: self.countryUserDefaultsKey)
|
||||
setCountry(sender.indexOfSelectedItem)
|
||||
}
|
||||
|
||||
private func setCountry(countryID: Int) {
|
||||
fileprivate func setCountry(_ countryID: Int) {
|
||||
var charactersROM: String?
|
||||
var kernelROM: String?
|
||||
switch countryID {
|
||||
@ -110,8 +96,8 @@ class Vic20Document: MachineDocument {
|
||||
default: break
|
||||
}
|
||||
|
||||
if let charactersROM = charactersROM, kernelROM = kernelROM {
|
||||
if let kernel = rom(kernelROM), basic = rom("basic"), characters = rom(charactersROM) {
|
||||
if let charactersROM = charactersROM, let kernelROM = kernelROM {
|
||||
if let kernel = rom(kernelROM), let basic = rom("basic"), let characters = rom(charactersROM) {
|
||||
vic20.setKernelROM(kernel)
|
||||
vic20.setBASICROM(basic)
|
||||
vic20.setCharactersROM(characters)
|
||||
@ -125,7 +111,7 @@ class Vic20Document: MachineDocument {
|
||||
get { return prefixedUserDefaultsKey("memorySize") }
|
||||
}
|
||||
|
||||
@IBAction func setMemorySize(sender: NSPopUpButton!) {
|
||||
@IBAction func setMemorySize(_ sender: NSPopUpButton!) {
|
||||
var selectedSize: Int?
|
||||
switch sender.indexOfSelectedItem {
|
||||
case 0: selectedSize = 5
|
||||
@ -134,15 +120,15 @@ class Vic20Document: MachineDocument {
|
||||
default: break
|
||||
}
|
||||
if let selectedSize = selectedSize {
|
||||
NSUserDefaults.standardUserDefaults().setInteger(selectedSize, forKey: self.memorySizeUserDefaultsKey)
|
||||
UserDefaults.standard.set(selectedSize, forKey: self.memorySizeUserDefaultsKey)
|
||||
setMemorySize(sender.indexOfSelectedItem)
|
||||
}
|
||||
}
|
||||
private func setMemorySize(sizeIndex: Int) {
|
||||
fileprivate func setMemorySize(_ sizeIndex: Int) {
|
||||
switch sizeIndex {
|
||||
case 2: vic20.memorySize = .Size32Kb
|
||||
case 1: vic20.memorySize = .Size8Kb
|
||||
default: vic20.memorySize = .Size5Kb
|
||||
case 2: vic20.memorySize = .size32Kb
|
||||
case 1: vic20.memorySize = .size8Kb
|
||||
default: vic20.memorySize = .size5Kb
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,19 +136,19 @@ class Vic20Document: MachineDocument {
|
||||
override func establishStoredOptions() {
|
||||
super.establishStoredOptions()
|
||||
|
||||
let standardUserDefaults = NSUserDefaults.standardUserDefaults()
|
||||
standardUserDefaults.registerDefaults([
|
||||
let standardUserDefaults = UserDefaults.standard
|
||||
standardUserDefaults.register(defaults: [
|
||||
self.autoloadingUserDefaultsKey: true,
|
||||
self.memorySizeUserDefaultsKey: 5,
|
||||
self.countryUserDefaultsKey: 1
|
||||
])
|
||||
|
||||
let loadAutomatically = standardUserDefaults.boolForKey(self.autoloadingUserDefaultsKey)
|
||||
let loadAutomatically = standardUserDefaults.bool(forKey: self.autoloadingUserDefaultsKey)
|
||||
vic20.shouldLoadAutomatically = loadAutomatically
|
||||
self.loadAutomaticallyButton?.state = loadAutomatically ? NSOnState : NSOffState
|
||||
|
||||
if !loadAutomatically {
|
||||
let memorySize = standardUserDefaults.integerForKey(self.memorySizeUserDefaultsKey)
|
||||
let memorySize = standardUserDefaults.integer(forKey: self.memorySizeUserDefaultsKey)
|
||||
var indexToSelect: Int?
|
||||
switch memorySize {
|
||||
case 32: indexToSelect = 2
|
||||
@ -170,14 +156,14 @@ class Vic20Document: MachineDocument {
|
||||
default: indexToSelect = 0
|
||||
}
|
||||
if let indexToSelect = indexToSelect {
|
||||
self.memorySizeButton?.selectItemAtIndex(indexToSelect)
|
||||
self.memorySizeButton?.selectItem(at: indexToSelect)
|
||||
setMemorySize(indexToSelect)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be part of the configuration
|
||||
let country = standardUserDefaults.integerForKey(self.countryUserDefaultsKey)
|
||||
let country = standardUserDefaults.integer(forKey: self.countryUserDefaultsKey)
|
||||
setCountry(country)
|
||||
self.countryButton?.selectItemAtIndex(country)
|
||||
self.countryButton?.selectItem(at: country)
|
||||
}
|
||||
}
|
||||
|
@ -28,31 +28,31 @@ class MOS6502InterruptTests: XCTestCase {
|
||||
machine.setValue(0x58, forAddress: 0x4000)
|
||||
|
||||
// pick things off at 0x4000
|
||||
machine.setValue(0x4000, forRegister: CSTestMachineRegister.ProgramCounter)
|
||||
machine.setValue(0x4000, for: CSTestMachineRegister.programCounter)
|
||||
}
|
||||
|
||||
func testIRQLine() {
|
||||
// run for six cycles; check that no interrupt has occurred
|
||||
machine.runForNumberOfCycles(6)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4003, "No interrupt should have occurred with line low")
|
||||
machine.runForNumber(ofCycles: 6)
|
||||
XCTAssert(machine.value(for: .programCounter) == 0x4003, "No interrupt should have occurred with line low")
|
||||
|
||||
// enable the interrupt line, check that it was too late
|
||||
machine.irqLine = true
|
||||
machine.runForNumberOfCycles(2)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4004, "No interrupt should have occurred from interrupt raised between instructions")
|
||||
machine.runForNumber(ofCycles: 2)
|
||||
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
|
||||
machine.runForNumberOfCycles(7)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
machine.runForNumber(ofCycles: 7)
|
||||
XCTAssert(machine.value(for: .programCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
}
|
||||
|
||||
func testIFlagSet() {
|
||||
// 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.runForNumberOfCycles(11)
|
||||
machine.runForNumber(ofCycles: 11)
|
||||
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
XCTAssert(machine.valueForRegister(.Flags) & 0x04 == 0x04, "Interrupt status flag should be set")
|
||||
XCTAssert(machine.value(for: .programCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
XCTAssert(machine.value(for: .flags) & 0x04 == 0x04, "Interrupt status flag should be set")
|
||||
}
|
||||
|
||||
func testCLISEIFlagClear() {
|
||||
@ -61,13 +61,13 @@ class MOS6502InterruptTests: XCTestCase {
|
||||
machine.irqLine = true
|
||||
|
||||
// run for four cycles; the CLI and SEI should have been performed
|
||||
machine.runForNumberOfCycles(4)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4002, "CLI/SEI pair should have been performed in their entirety")
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
XCTAssert(machine.value(for: .programCounter) == 0x4002, "CLI/SEI pair should have been performed in their entirety")
|
||||
|
||||
// run for seven more cycles
|
||||
machine.runForNumberOfCycles(7)
|
||||
machine.runForNumber(ofCycles: 7)
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import XCTest
|
||||
|
||||
class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
|
||||
private var endTime: UInt32 = 0
|
||||
fileprivate var endTime: UInt32 = 0
|
||||
|
||||
func testImplied() {
|
||||
let code: [UInt8] = [
|
||||
@ -195,12 +195,12 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
self.runTest(code, expectedRunLength: 43)
|
||||
}
|
||||
|
||||
func runTest(code: [UInt8], expectedRunLength: UInt32) {
|
||||
func runTest(_ code: [UInt8], expectedRunLength: UInt32) {
|
||||
let machine = CSTestMachine()
|
||||
|
||||
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.setValue(0x00, forAddress: 0x0000)
|
||||
machine.setValue(0x00, forAddress: 0x0001)
|
||||
@ -208,19 +208,19 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
machine.setValue(0x00, forAddress: 0x0003)
|
||||
machine.setValue(0x08, forAddress: 0x0004)
|
||||
machine.setValue(0x02, forAddress: 0x0005)
|
||||
machine.setValue(0x200, forRegister: CSTestMachineRegister.ProgramCounter)
|
||||
machine.setValue(0xff, forRegister: CSTestMachineRegister.X)
|
||||
machine.setValue(0xfe, forRegister: CSTestMachineRegister.Y)
|
||||
machine.setValue(0x200, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0xff, for: CSTestMachineRegister.X)
|
||||
machine.setValue(0xfe, for: CSTestMachineRegister.Y)
|
||||
|
||||
self.endTime = 0
|
||||
while self.endTime == 0 {
|
||||
machine.runForNumberOfCycles(10)
|
||||
machine.runForNumber(ofCycles: 10)
|
||||
}
|
||||
|
||||
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 {
|
||||
self.endTime = machine.timestamp - 9
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import Foundation
|
||||
|
||||
class MOS6522Tests: XCTestCase {
|
||||
|
||||
private func with6522(action: (MOS6522Bridge) -> ()) {
|
||||
fileprivate func with6522(_ action: (MOS6522Bridge) -> ()) {
|
||||
let bridge = MOS6522Bridge()
|
||||
action(bridge)
|
||||
}
|
||||
@ -25,11 +25,11 @@ class MOS6522Tests: XCTestCase {
|
||||
$0.setValue(0, forRegister: 5)
|
||||
|
||||
// run for 5 cycles
|
||||
$0.runForHalfCycles(10)
|
||||
$0.run(forHalfCycles: 10)
|
||||
|
||||
// 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.valueForRegister(5) == 0, "High order byte should be 0; was \($0.valueForRegister(5))")
|
||||
XCTAssert($0.value(forRegister: 4) == 5, "Low order byte should be 5; was \($0.value(forRegister: 4))")
|
||||
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)
|
||||
|
||||
// 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.valueForRegister(9) == 0x20, "High order byte should be 0x20; was \($0.valueForRegister(9))")
|
||||
XCTAssert($0.value(forRegister: 8) == 0x10, "Low order byte should be 0x10; was \($0.value(forRegister: 8))")
|
||||
XCTAssert($0.value(forRegister: 9) == 0x20, "High order byte should be 0x20; was \($0.value(forRegister: 9))")
|
||||
|
||||
// write the low-byte latch
|
||||
$0.setValue(0x50, forRegister: 9)
|
||||
|
||||
// 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.valueForRegister(9) == 0x50, "High order byte should be 0x40; was \($0.valueForRegister(9))")
|
||||
XCTAssert($0.value(forRegister: 8) == 0x40, "Low order byte should be 0x50; was \($0.value(forRegister: 8))")
|
||||
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)
|
||||
|
||||
// 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
|
||||
XCTAssert($0.valueForRegister(4) == 0, "Low order byte should be 0; was \($0.valueForRegister(4))")
|
||||
XCTAssert($0.valueForRegister(5) == 0, "High order byte should be 0; was \($0.valueForRegister(5))")
|
||||
XCTAssert($0.value(forRegister: 4) == 0, "Low order byte should be 0; was \($0.value(forRegister: 4))")
|
||||
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")
|
||||
|
||||
// check that two half-cycles later the timer is $ffff but IRQ still hasn't triggered
|
||||
$0.runForHalfCycles(2)
|
||||
XCTAssert($0.valueForRegister(4) == 0xff, "Low order byte should be 0xff; was \($0.valueForRegister(4))")
|
||||
XCTAssert($0.valueForRegister(5) == 0xff, "High order byte should be 0xff; was \($0.valueForRegister(5))")
|
||||
$0.run(forHalfCycles: 2)
|
||||
XCTAssert($0.value(forRegister: 4) == 0xff, "Low order byte should be 0xff; was \($0.value(forRegister: 4))")
|
||||
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")
|
||||
|
||||
// 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.valueForRegister(4) == 0xff, "Low order byte should be 0xff; was \($0.valueForRegister(4))")
|
||||
XCTAssert($0.valueForRegister(5) == 0xff, "High order byte should be 0xff; was \($0.valueForRegister(5))")
|
||||
XCTAssert($0.value(forRegister: 4) == 0xff, "Low order byte should be 0xff; was \($0.value(forRegister: 4))")
|
||||
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
|
||||
XCTAssert(!$0.irqLine, "IRQ should be active")
|
||||
|
||||
// check that one half-cycles later the timer has reloaded
|
||||
$0.runForHalfCycles(1)
|
||||
XCTAssert($0.valueForRegister(4) == 0x10, "Low order byte should be 0x10; was \($0.valueForRegister(4))")
|
||||
XCTAssert($0.valueForRegister(5) == 0x00, "High order byte should be 0x00; was \($0.valueForRegister(5))")
|
||||
$0.run(forHalfCycles: 1)
|
||||
XCTAssert($0.value(forRegister: 4) == 0x10, "Low order byte should be 0x10; was \($0.value(forRegister: 4))")
|
||||
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
|
||||
|
||||
// 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))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import Foundation
|
||||
|
||||
class MOS6532Tests: XCTestCase {
|
||||
|
||||
private func with6532(action: (MOS6532Bridge) -> ()) {
|
||||
fileprivate func with6532(_ action: (MOS6532Bridge) -> ()) {
|
||||
let bridge = MOS6532Bridge()
|
||||
action(bridge)
|
||||
}
|
||||
@ -23,12 +23,12 @@ class MOS6532Tests: XCTestCase {
|
||||
$0.setValue(128, forRegister:0x14)
|
||||
|
||||
// run for one clock and the count should now be 127
|
||||
$0.runForCycles(1)
|
||||
XCTAssert($0.valueForRegister(4) == 127, "A single tick should decrease the counter once")
|
||||
$0.run(forCycles: 1)
|
||||
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
|
||||
$0.runForCycles(200)
|
||||
XCTAssert($0.valueForRegister(4) == 183, "Timer should underflow and keep counting")
|
||||
$0.run(forCycles: 200)
|
||||
XCTAssert($0.value(forRegister: 4) == 183, "Timer should underflow and keep counting")
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,24 +39,24 @@ class MOS6532Tests: XCTestCase {
|
||||
$0.setValue(28, forRegister:0x15)
|
||||
|
||||
// run for seven clock and the count should still be 28
|
||||
$0.runForCycles(7)
|
||||
XCTAssert($0.valueForRegister(4) == 28, "The timer should remain unchanged for seven clocks")
|
||||
$0.run(forCycles: 7)
|
||||
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
|
||||
$0.runForCycles(1)
|
||||
XCTAssert($0.valueForRegister(4) == 27, "The timer should have decremented once after 8 cycles")
|
||||
$0.run(forCycles: 1)
|
||||
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
|
||||
$0.runForCycles(228)
|
||||
XCTAssert($0.valueForRegister(4) == 0xfb, "Timer should underflow and start counting at single-clock pace")
|
||||
$0.run(forCycles: 228)
|
||||
XCTAssert($0.value(forRegister: 4) == 0xfb, "Timer should underflow and start counting at single-clock pace")
|
||||
|
||||
// timer should now resume dividing by eight
|
||||
$0.runForCycles(7)
|
||||
XCTAssert($0.valueForRegister(4) == 0xfb, "Timer should remain unchanged for seven cycles")
|
||||
$0.run(forCycles: 7)
|
||||
XCTAssert($0.value(forRegister: 4) == 0xfb, "Timer should remain unchanged for seven cycles")
|
||||
|
||||
// timer should now resume dividing by eight
|
||||
$0.runForCycles(1)
|
||||
XCTAssert($0.valueForRegister(4) == 0xfa, "Timer should decrement after eighth cycle")
|
||||
$0.run(forCycles: 1)
|
||||
XCTAssert($0.value(forRegister: 4) == 0xfa, "Timer should decrement after eighth cycle")
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,23 +66,23 @@ class MOS6532Tests: XCTestCase {
|
||||
$0.setValue(1, forRegister:0x1c)
|
||||
|
||||
// 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
|
||||
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
|
||||
$0.runForCycles(1)
|
||||
$0.run(forCycles: 1)
|
||||
|
||||
// the interrupt line and bit should now 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
|
||||
$0.setValue(1, forRegister:0x1c)
|
||||
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
|
||||
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
|
||||
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 {
|
||||
// seed port a is high; ensure interrupt bit is clear
|
||||
$0.setValue(0x00, forRegister:0)
|
||||
$0.valueForRegister(5)
|
||||
$0.value(forRegister: 5)
|
||||
|
||||
// enable leading edge detection
|
||||
$0.setValue(0, forRegister:7)
|
||||
@ -127,7 +127,7 @@ class MOS6532Tests: XCTestCase {
|
||||
|
||||
// confirm that both the interrupt flag are the line are 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 {
|
||||
// seed port a is high; ensure interrupt bit is clear
|
||||
$0.setValue(0x80, forRegister:0)
|
||||
$0.valueForRegister(5)
|
||||
$0.value(forRegister: 5)
|
||||
|
||||
// enable trailing edge detection
|
||||
$0.setValue(0, forRegister:6)
|
||||
@ -148,7 +148,7 @@ class MOS6532Tests: XCTestCase {
|
||||
|
||||
// confirm that both the interrupt flag are the line are 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,22 +12,22 @@ import XCTest
|
||||
class AllSuiteATests: XCTestCase {
|
||||
|
||||
func testAllSuiteA() {
|
||||
if let filename = NSBundle(forClass: self.dynamicType).pathForResource("AllSuiteA", ofType: "bin") {
|
||||
if let allSuiteA = NSData(contentsOfFile: filename) {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "AllSuiteA", ofType: "bin") {
|
||||
if let allSuiteA = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine()
|
||||
|
||||
machine.setData(allSuiteA, atAddress: 0x4000)
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0x45c0); // end
|
||||
|
||||
machine.setValue(0x4000, forRegister: CSTestMachineRegister.ProgramCounter)
|
||||
machine.setValue(0x4000, for: CSTestMachineRegister.programCounter)
|
||||
while !machine.isJammed {
|
||||
machine.runForNumberOfCycles(1000)
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
}
|
||||
|
||||
if machine.valueForAddress(0x0210) != 0xff {
|
||||
NSException(name: "Failed AllSuiteA", reason: "Failed test \(machine.valueForAddress(0x0210))", userInfo: nil).raise()
|
||||
if machine.value(forAddress: 0x0210) != 0xff {
|
||||
NSException(name: NSExceptionName(rawValue: "Failed AllSuiteA"), reason: "Failed test \(machine.value(forAddress: 0x0210))", userInfo: nil).raise()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,32 +10,32 @@ import XCTest
|
||||
|
||||
class C1540Tests: XCTestCase {
|
||||
|
||||
private func with1540(action: (C1540Bridge) -> ()) {
|
||||
fileprivate func with1540(_ action: (C1540Bridge) -> ()) {
|
||||
let bridge = C1540Bridge()
|
||||
|
||||
if let path = NSBundle.mainBundle().pathForResource("1541", ofType: "bin", inDirectory: "ROMImages/Commodore1540") {
|
||||
let data = NSData(contentsOfFile: path)
|
||||
if let path = Bundle.main.path(forResource: "1541", ofType: "bin", inDirectory: "ROMImages/Commodore1540") {
|
||||
let data = try? Data(contentsOf: URL(fileURLWithPath: path))
|
||||
bridge.setROM(data)
|
||||
}
|
||||
|
||||
action(bridge)
|
||||
}
|
||||
|
||||
private func transmit(c1540: C1540Bridge, value: Int) {
|
||||
fileprivate func transmit(_ c1540: C1540Bridge, value: Int) {
|
||||
var shiftedValue = value
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
// set up for byte transfer
|
||||
c1540.clockLine = false
|
||||
c1540.dataLine = true
|
||||
c1540.runForCycles(40)
|
||||
c1540.run(forCycles: 40)
|
||||
|
||||
// transmit bits
|
||||
for _ in 0..<8 {
|
||||
@ -45,14 +45,14 @@ class C1540Tests: XCTestCase {
|
||||
|
||||
// toggle clock
|
||||
c1540.clockLine = true
|
||||
c1540.runForCycles(40)
|
||||
c1540.run(forCycles: 40)
|
||||
c1540.clockLine = false
|
||||
c1540.runForCycles(40)
|
||||
c1540.run(forCycles: 40)
|
||||
}
|
||||
|
||||
// check for acknowledgment
|
||||
c1540.dataLine = true
|
||||
c1540.runForCycles(1000)
|
||||
c1540.run(forCycles: 1000)
|
||||
XCTAssert(c1540.dataLine == false, "Listener should have acknowledged byte")
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ class C1540Tests: XCTestCase {
|
||||
func testTransmission() {
|
||||
with1540 {
|
||||
// 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
|
||||
$0.clockLine = false
|
||||
@ -69,7 +69,7 @@ class C1540Tests: XCTestCase {
|
||||
$0.dataLine = true
|
||||
|
||||
// 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")
|
||||
|
||||
// transmit LISTEN #8
|
||||
|
@ -10,16 +10,16 @@ import XCTest
|
||||
|
||||
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
|
||||
for _ in 0 ..< 200 {
|
||||
pll.runForCycles(bitLength/2)
|
||||
pll.run(forCycles: bitLength/2)
|
||||
pll.addPulse()
|
||||
pll.runForCycles(bitLength)
|
||||
pll.run(forCycles: bitLength)
|
||||
pll.addPulse()
|
||||
pll.runForCycles(bitLength*2)
|
||||
pll.run(forCycles: bitLength*2)
|
||||
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))")
|
||||
@ -27,17 +27,17 @@ class DPLLTests: XCTestCase {
|
||||
|
||||
func testPerfectInput() {
|
||||
let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3)
|
||||
testRegularNibblesOnPLL(pll, bitLength: 100)
|
||||
testRegularNibblesOnPLL(pll!, bitLength: 100)
|
||||
}
|
||||
|
||||
func testFastButRegular() {
|
||||
let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3)
|
||||
testRegularNibblesOnPLL(pll, bitLength: 90)
|
||||
testRegularNibblesOnPLL(pll!, bitLength: 90)
|
||||
}
|
||||
|
||||
func testSlowButRegular() {
|
||||
let pll = DigitalPhaseLockedLoopBridge(clocksPerBit: 100, tolerance: 20, historyLength: 3)
|
||||
testRegularNibblesOnPLL(pll, bitLength: 110)
|
||||
testRegularNibblesOnPLL(pll!, bitLength: 110)
|
||||
}
|
||||
|
||||
func testTwentyPercentSinePattern() {
|
||||
@ -48,14 +48,14 @@ class DPLLTests: XCTestCase {
|
||||
for _ in 0 ..< 200 {
|
||||
let bitLength: UInt = UInt(100 + 20 * sin(angle))
|
||||
|
||||
pll.runForCycles(bitLength/2)
|
||||
pll.addPulse()
|
||||
pll.runForCycles((bitLength*3)/2)
|
||||
pll?.run(forCycles: bitLength/2)
|
||||
pll?.addPulse()
|
||||
pll?.run(forCycles: (bitLength*3)/2)
|
||||
|
||||
angle = angle + 0.1
|
||||
}
|
||||
|
||||
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))")
|
||||
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))")
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class KlausDormannTests: XCTestCase {
|
||||
|
||||
func testKlausDormann() {
|
||||
|
||||
func errorForTrapAddress(address: UInt16) -> String? {
|
||||
func errorForTrapAddress(_ address: UInt16) -> String? {
|
||||
let hexAddress = String(format:"%04x", address)
|
||||
switch address {
|
||||
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 functionalTest = NSData(contentsOfFile: filename) {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "6502_functional_test", ofType: "bin") {
|
||||
if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine()
|
||||
|
||||
machine.setData(functionalTest, atAddress: 0)
|
||||
machine.setValue(0x400, forRegister: CSTestMachineRegister.ProgramCounter)
|
||||
machine.setValue(0x400, for: CSTestMachineRegister.programCounter)
|
||||
|
||||
while true {
|
||||
let oldPC = machine.valueForRegister(CSTestMachineRegister.LastOperationAddress)
|
||||
machine.runForNumberOfCycles(1000)
|
||||
let newPC = machine.valueForRegister(CSTestMachineRegister.LastOperationAddress)
|
||||
let oldPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
let newPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
|
||||
|
||||
if newPC == oldPC {
|
||||
let error = errorForTrapAddress(oldPC)
|
||||
|
@ -186,29 +186,29 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
self.runWolfgangLorenzTest("sbcb(eb)")
|
||||
}
|
||||
|
||||
private func runWolfgangLorenzTest(name: String, suffixes: [String]) {
|
||||
fileprivate func runWolfgangLorenzTest(_ name: String, suffixes: [String]) {
|
||||
for suffix in suffixes {
|
||||
let testName = name + suffix
|
||||
self.runWolfgangLorenzTest(testName)
|
||||
}
|
||||
}
|
||||
|
||||
private var output: String = ""
|
||||
private func runWolfgangLorenzTest(name: String) {
|
||||
fileprivate var output: String = ""
|
||||
fileprivate func runWolfgangLorenzTest(_ name: String) {
|
||||
|
||||
var machine: CSTestMachine!
|
||||
|
||||
if let filename = NSBundle(forClass: self.dynamicType).pathForResource(name, ofType: nil) {
|
||||
if let testData = NSData(contentsOfFile: filename) {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: name, ofType: nil) {
|
||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
|
||||
machine = CSTestMachine()
|
||||
machine.jamHandler = self
|
||||
// machine.logActivity = true
|
||||
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 contents = testData.subdataWithRange(NSMakeRange(2, testData.length - 2))
|
||||
let contents = testData.subdata(in: NSMakeRange(2, testData.count - 2))
|
||||
|
||||
machine.setData(contents, atAddress: loadAddress)
|
||||
|
||||
@ -220,10 +220,10 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
machine.setValue(0x48, forAddress: 0xfffe)
|
||||
machine.setValue(0xff, forAddress: 0xffff)
|
||||
|
||||
let irqHandler = NSData(bytes: [
|
||||
let irqHandler = Data(bytes: UnsafePointer<UInt8>([
|
||||
0x48, 0x8a, 0x48, 0x98, 0x48, 0xba, 0xbd, 0x04, 0x01,
|
||||
0x29, 0x10, 0xf0, 0x03, 0x6c, 0x16, 0x03, 0x6c, 0x14, 0x03
|
||||
] as [UInt8], length: 19)
|
||||
] as [UInt8]), count: 19)
|
||||
machine.setData( irqHandler, atAddress: 0xff48)
|
||||
|
||||
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:0xa474); // exit
|
||||
|
||||
machine.setValue(0x0801, forRegister: CSTestMachineRegister.ProgramCounter)
|
||||
machine.setValue(0xfd, forRegister: CSTestMachineRegister.StackPointer)
|
||||
machine.setValue(0x04, forRegister: CSTestMachineRegister.Flags)
|
||||
machine.setValue(0x0801, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0xfd, for: CSTestMachineRegister.stackPointer)
|
||||
machine.setValue(0x04, for: CSTestMachineRegister.flags)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
machine.runForNumberOfCycles(1000)
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
}
|
||||
|
||||
let jammedPC = machine.valueForRegister(CSTestMachineRegister.LastOperationAddress)
|
||||
let jammedPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
|
||||
if jammedPC != 0xe16f {
|
||||
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
|
||||
|
||||
func petsciiToString(string: String) -> String {
|
||||
func petsciiToString(_ string: String) -> String {
|
||||
let petsciiToCharCommon: [String] = [
|
||||
"?", "?", "?", "[RUN/STOP]", "?", "[WHT]", "?", "?", "[SHIFT DISABLE]", "[SHIFT ENABLE]", "?", "?", "?", "\r", "[TEXT MODE]", "?",
|
||||
"?", "\n", "[RVS ON]", "[HOME]", "[DEL]", "?", "?", "?", "?", "?", "?", "?", "[RED]", "[RIGHT]", "[GRN]", "[BLU]",
|
||||
@ -297,33 +297,33 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
return result
|
||||
}
|
||||
|
||||
func testMachine(machine: CSTestMachine!, didJamAtAddress address: UInt16) {
|
||||
func testMachine(_ machine: CSTestMachine!, didJamAtAddress address: UInt16) {
|
||||
|
||||
switch address {
|
||||
case 0xffd2:
|
||||
machine.setValue(0x00, forAddress: 0x030c)
|
||||
|
||||
let character = machine.valueForRegister(CSTestMachineRegister.A)
|
||||
output.append(Character(UnicodeScalar(character)))
|
||||
let character = machine.value(for: CSTestMachineRegister.A)
|
||||
output.append(Character(UnicodeScalar(character)!))
|
||||
|
||||
machine.returnFromSubroutine()
|
||||
|
||||
case 0xffe4:
|
||||
machine.setValue(0x3, forRegister:CSTestMachineRegister.A)
|
||||
machine.setValue(0x3, for:CSTestMachineRegister.A)
|
||||
machine.returnFromSubroutine()
|
||||
|
||||
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:
|
||||
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)
|
||||
break;
|
||||
|
||||
default:
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user