mirror of
https://github.com/Luigi30/FruitMachine-Swift.git
synced 2024-11-26 21:52:45 +00:00
how hard can bolting Apple II onto this be?
This commit is contained in:
parent
a2b4003bb8
commit
f6e0467fe1
@ -9,16 +9,23 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
2A2126841F2A9FA300E43DC1 /* DebuggerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2126831F2A9FA300E43DC1 /* DebuggerWindowController.swift */; };
|
||||
2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */; };
|
||||
2A5BC5191F29A28D008C03BE /* AppleScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */; };
|
||||
2A5BC5191F29A28D008C03BE /* AppleIScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC5181F29A28D008C03BE /* AppleIScreenView.swift */; };
|
||||
2A5BC51C1F29A2EB008C03BE /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */; };
|
||||
2A5BC51E1F29A4C3008C03BE /* AppleIBitmapDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC51D1F29A4C3008C03BE /* AppleIBitmapDisplay.swift */; };
|
||||
2A5C5BBC1F304C3A00ED351D /* A2CharacterGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C5BBB1F304C3A00ED351D /* A2CharacterGenerator.swift */; };
|
||||
2A5C5BBE1F304D4B00ED351D /* Glyph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C5BBD1F304D4B00ED351D /* Glyph.swift */; };
|
||||
2A60851E1F2AFAE900E05B64 /* PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A60851D1F2AFAE900E05B64 /* PIA.swift */; };
|
||||
2A6DC7E91F3045280066FE0D /* AppleIIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7E81F3045280066FE0D /* AppleIIViewController.swift */; };
|
||||
2A6DC7EB1F3045C90066FE0D /* EmulatedSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7EA1F3045C90066FE0D /* EmulatedSystem.swift */; };
|
||||
2A6DC7ED1F30492C0066FE0D /* ScreenDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */; };
|
||||
2A6DC7F01F30495D0066FE0D /* ScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7EF1F30495D0066FE0D /* ScreenView.swift */; };
|
||||
2A7665781F2F05F600135518 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A7665761F2F05F600135518 /* PreferencesWindowController.swift */; };
|
||||
2A7665791F2F05F600135518 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A7665771F2F05F600135518 /* PreferencesWindow.xib */; };
|
||||
2A91852A1F2EA84D00A9E5BE /* BitmapPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A9185291F2EA84D00A9E5BE /* BitmapPixels.swift */; };
|
||||
2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5F71F2A8889002B350F /* AppleI.swift */; };
|
||||
2AA8B5FC1F2A8EAD002B350F /* Terminal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */; };
|
||||
2AA8B5FE1F2A942C002B350F /* PIAOverrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */; };
|
||||
2AB6CACD1F3041A200DECAC0 /* AppleII.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AB6CACC1F3041A200DECAC0 /* AppleII.swift */; };
|
||||
2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CD1F205EB700F05121 /* AppDelegate.swift */; };
|
||||
2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */; };
|
||||
2AD458D21F205EB700F05121 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2AD458D11F205EB700F05121 /* Assets.xcassets */; };
|
||||
@ -31,9 +38,9 @@
|
||||
2AE42E081F2850F400C4900E /* ReadOverride.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E071F2850F400C4900E /* ReadOverride.swift */; };
|
||||
2AE42E0A1F28521E00C4900E /* WriteOverride.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E091F28521E00C4900E /* WriteOverride.swift */; };
|
||||
2AE42E0C1F28522D00C4900E /* MemoryOverride.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E0B1F28522D00C4900E /* MemoryOverride.swift */; };
|
||||
2AE42E3A1F28628300C4900E /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E381F28628300C4900E /* MainViewController.swift */; };
|
||||
2AE42E3A1F28628300C4900E /* AppleIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E381F28628300C4900E /* AppleIViewController.swift */; };
|
||||
2AE42E401F28638100C4900E /* FruitMachine.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */; };
|
||||
2AE42E431F28665300C4900E /* CharacterGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E421F28665300C4900E /* CharacterGenerator.swift */; };
|
||||
2AE42E431F28665300C4900E /* A1CharacterGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E421F28665300C4900E /* A1CharacterGenerator.swift */; };
|
||||
2AE5BA041F23DE4400FAA343 /* Disassembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5BA031F23DE4400FAA343 /* Disassembly.swift */; };
|
||||
2AE5BA061F2469EB00FAA343 /* AddressConversions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5BA051F2469EB00FAA343 /* AddressConversions.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -41,16 +48,23 @@
|
||||
/* Begin PBXFileReference section */
|
||||
2A2126831F2A9FA300E43DC1 /* DebuggerWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerWindowController.swift; sourceTree = "<group>"; };
|
||||
2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegerExtensions.swift; sourceTree = "<group>"; };
|
||||
2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScreenView.swift; sourceTree = "<group>"; };
|
||||
2A5BC5181F29A28D008C03BE /* AppleIScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleIScreenView.swift; sourceTree = "<group>"; };
|
||||
2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
2A5BC51D1F29A4C3008C03BE /* AppleIBitmapDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleIBitmapDisplay.swift; sourceTree = "<group>"; };
|
||||
2A5C5BBB1F304C3A00ED351D /* A2CharacterGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A2CharacterGenerator.swift; sourceTree = "<group>"; };
|
||||
2A5C5BBD1F304D4B00ED351D /* Glyph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glyph.swift; sourceTree = "<group>"; };
|
||||
2A60851D1F2AFAE900E05B64 /* PIA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIA.swift; sourceTree = "<group>"; };
|
||||
2A6DC7E81F3045280066FE0D /* AppleIIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleIIViewController.swift; sourceTree = "<group>"; };
|
||||
2A6DC7EA1F3045C90066FE0D /* EmulatedSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmulatedSystem.swift; sourceTree = "<group>"; };
|
||||
2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenDelegate.swift; sourceTree = "<group>"; };
|
||||
2A6DC7EF1F30495D0066FE0D /* ScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenView.swift; sourceTree = "<group>"; };
|
||||
2A7665761F2F05F600135518 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
||||
2A7665771F2F05F600135518 /* PreferencesWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferencesWindow.xib; sourceTree = "<group>"; };
|
||||
2A9185291F2EA84D00A9E5BE /* BitmapPixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitmapPixels.swift; sourceTree = "<group>"; };
|
||||
2AA8B5F71F2A8889002B350F /* AppleI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleI.swift; sourceTree = "<group>"; };
|
||||
2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Terminal.swift; sourceTree = "<group>"; };
|
||||
2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAOverrides.swift; sourceTree = "<group>"; };
|
||||
2AB6CACC1F3041A200DECAC0 /* AppleII.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleII.swift; sourceTree = "<group>"; };
|
||||
2AD458CA1F205EB700F05121 /* FruitMachine.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FruitMachine.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2AD458CD1F205EB700F05121 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerViewController.swift; sourceTree = "<group>"; };
|
||||
@ -66,9 +80,9 @@
|
||||
2AE42E071F2850F400C4900E /* ReadOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadOverride.swift; sourceTree = "<group>"; };
|
||||
2AE42E091F28521E00C4900E /* WriteOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteOverride.swift; sourceTree = "<group>"; };
|
||||
2AE42E0B1F28522D00C4900E /* MemoryOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryOverride.swift; sourceTree = "<group>"; };
|
||||
2AE42E381F28628300C4900E /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
2AE42E381F28628300C4900E /* AppleIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleIViewController.swift; sourceTree = "<group>"; };
|
||||
2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = FruitMachine.storyboard; sourceTree = "<group>"; };
|
||||
2AE42E421F28665300C4900E /* CharacterGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterGenerator.swift; sourceTree = "<group>"; };
|
||||
2AE42E421F28665300C4900E /* A1CharacterGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A1CharacterGenerator.swift; sourceTree = "<group>"; };
|
||||
2AE5BA031F23DE4400FAA343 /* Disassembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disassembly.swift; sourceTree = "<group>"; };
|
||||
2AE5BA051F2469EB00FAA343 /* AddressConversions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressConversions.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@ -93,18 +107,64 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2A6DC7E51F3043DB0066FE0D /* Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A6DC7E71F3044080066FE0D /* Peripherals */,
|
||||
2A6DC7E61F3043E10066FE0D /* Video */,
|
||||
2A6DC7EA1F3045C90066FE0D /* EmulatedSystem.swift */,
|
||||
);
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2A6DC7E61F3043E10066FE0D /* Video */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A9185291F2EA84D00A9E5BE /* BitmapPixels.swift */,
|
||||
2A5C5BBD1F304D4B00ED351D /* Glyph.swift */,
|
||||
);
|
||||
path = Video;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2A6DC7E71F3044080066FE0D /* Peripherals */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A60851D1F2AFAE900E05B64 /* PIA.swift */,
|
||||
);
|
||||
path = Peripherals;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2A6DC7EE1F30492E0066FE0D /* Video */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A5C5BBB1F304C3A00ED351D /* A2CharacterGenerator.swift */,
|
||||
2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */,
|
||||
2A6DC7EF1F30495D0066FE0D /* ScreenView.swift */,
|
||||
);
|
||||
path = Video;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2AA8B5F61F2A8844002B350F /* AppleI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2AE42E411F28663600C4900E /* Video */,
|
||||
2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */,
|
||||
2A5BC5181F29A28D008C03BE /* AppleIScreenView.swift */,
|
||||
2A5BC51D1F29A4C3008C03BE /* AppleIBitmapDisplay.swift */,
|
||||
2AA8B5F71F2A8889002B350F /* AppleI.swift */,
|
||||
2A60851D1F2AFAE900E05B64 /* PIA.swift */,
|
||||
2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */,
|
||||
);
|
||||
path = AppleI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2AB6CAC71F30407200DECAC0 /* AppleII */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A6DC7EE1F30492E0066FE0D /* Video */,
|
||||
2AB6CACC1F3041A200DECAC0 /* AppleII.swift */,
|
||||
);
|
||||
path = AppleII;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2AD458C11F205EB700F05121 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -125,10 +185,13 @@
|
||||
2AD458CC1F205EB700F05121 /* FruitMachine */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A6DC7E51F3043DB0066FE0D /* Common */,
|
||||
2AA8B5F61F2A8844002B350F /* AppleI */,
|
||||
2AB6CAC71F30407200DECAC0 /* AppleII */,
|
||||
2AD458DD1F205F0D00F05121 /* M6502 */,
|
||||
2AD458CD1F205EB700F05121 /* AppDelegate.swift */,
|
||||
2AE42E381F28628300C4900E /* MainViewController.swift */,
|
||||
2AE42E381F28628300C4900E /* AppleIViewController.swift */,
|
||||
2A6DC7E81F3045280066FE0D /* AppleIIViewController.swift */,
|
||||
2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */,
|
||||
2A7665761F2F05F600135518 /* PreferencesWindowController.swift */,
|
||||
2A7665771F2F05F600135518 /* PreferencesWindow.xib */,
|
||||
@ -195,9 +258,7 @@
|
||||
2AE42E411F28663600C4900E /* Video */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2A9185291F2EA84D00A9E5BE /* BitmapPixels.swift */,
|
||||
2AE42E421F28665300C4900E /* CharacterGenerator.swift */,
|
||||
2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */,
|
||||
2AE42E421F28665300C4900E /* A1CharacterGenerator.swift */,
|
||||
2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */,
|
||||
);
|
||||
path = Video;
|
||||
@ -276,29 +337,36 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2A60851E1F2AFAE900E05B64 /* PIA.swift in Sources */,
|
||||
2A5C5BBE1F304D4B00ED351D /* Glyph.swift in Sources */,
|
||||
2A2126841F2A9FA300E43DC1 /* DebuggerWindowController.swift in Sources */,
|
||||
2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */,
|
||||
2A5C5BBC1F304C3A00ED351D /* A2CharacterGenerator.swift in Sources */,
|
||||
2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */,
|
||||
2A7665781F2F05F600135518 /* PreferencesWindowController.swift in Sources */,
|
||||
2AA8B5FC1F2A8EAD002B350F /* Terminal.swift in Sources */,
|
||||
2A5BC51E1F29A4C3008C03BE /* AppleIBitmapDisplay.swift in Sources */,
|
||||
2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */,
|
||||
2A91852A1F2EA84D00A9E5BE /* BitmapPixels.swift in Sources */,
|
||||
2AE42E431F28665300C4900E /* CharacterGenerator.swift in Sources */,
|
||||
2AE42E431F28665300C4900E /* A1CharacterGenerator.swift in Sources */,
|
||||
2A6DC7F01F30495D0066FE0D /* ScreenView.swift in Sources */,
|
||||
2AE42E0C1F28522D00C4900E /* MemoryOverride.swift in Sources */,
|
||||
2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */,
|
||||
2AD6D5841F26E6BF008F3CF5 /* DebuggerCommands.swift in Sources */,
|
||||
2AE5BA041F23DE4400FAA343 /* Disassembly.swift in Sources */,
|
||||
2AE42E3A1F28628300C4900E /* MainViewController.swift in Sources */,
|
||||
2A6DC7EB1F3045C90066FE0D /* EmulatedSystem.swift in Sources */,
|
||||
2AE42E3A1F28628300C4900E /* AppleIViewController.swift in Sources */,
|
||||
2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */,
|
||||
2AE42E081F2850F400C4900E /* ReadOverride.swift in Sources */,
|
||||
2AA8B5FE1F2A942C002B350F /* PIAOverrides.swift in Sources */,
|
||||
2AB6CACD1F3041A200DECAC0 /* AppleII.swift in Sources */,
|
||||
2AE5BA061F2469EB00FAA343 /* AddressConversions.swift in Sources */,
|
||||
2AE42E0A1F28521E00C4900E /* WriteOverride.swift in Sources */,
|
||||
2A5BC5191F29A28D008C03BE /* AppleScreenView.swift in Sources */,
|
||||
2A6DC7ED1F30492C0066FE0D /* ScreenDelegate.swift in Sources */,
|
||||
2A5BC5191F29A28D008C03BE /* AppleIScreenView.swift in Sources */,
|
||||
2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */,
|
||||
2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */,
|
||||
2AD458DF1F205F4500F05121 /* CPU.swift in Sources */,
|
||||
2A6DC7E91F3045280066FE0D /* AppleIIViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -8,10 +8,14 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class AppleI: NSObject {
|
||||
static let sharedInstance = AppleI()
|
||||
class AppleI: NSObject, EmulatedSystem {
|
||||
var CPU_FREQUENCY: Double
|
||||
var FRAMES_PER_SECOND: Double
|
||||
var CYCLES_PER_BATCH: Int
|
||||
|
||||
let cg = CharacterGenerator(romPath: "/Users/luigi/apple1/apple1.vid");
|
||||
static let sharedInstance = AppleI(cpuFrequency: 1000000.0, fps: 60.0)
|
||||
|
||||
let cg = A1CharacterGenerator(romPath: "/Users/luigi/apple1/apple1.vid");
|
||||
let terminal = Terminal()
|
||||
|
||||
let pia: [String:PIA] = [
|
||||
@ -20,14 +24,13 @@ class AppleI: NSObject {
|
||||
]
|
||||
|
||||
let emulatorViewDelegate = AppleIBitmapDisplay()
|
||||
let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 640, 384))
|
||||
let emulatorView = AppleIScreenView(frame: NSMakeRect(0, 0, 640, 384))
|
||||
let emuScreenLayer = CALayer()
|
||||
|
||||
static let CPU_FREQUENCY = 1000000
|
||||
static let FRAMES_PER_SECOND = 60
|
||||
static let CYCLES_PER_BATCH = CPU_FREQUENCY / FRAMES_PER_SECOND
|
||||
|
||||
override init() {
|
||||
required init(cpuFrequency: Double, fps: Double) {
|
||||
CPU_FREQUENCY = cpuFrequency
|
||||
FRAMES_PER_SECOND = fps
|
||||
CYCLES_PER_BATCH = Int(cpuFrequency / fps)
|
||||
super.init()
|
||||
|
||||
emuScreenLayer.shouldRasterize = true
|
||||
@ -35,7 +38,7 @@ class AppleI: NSObject {
|
||||
emuScreenLayer.frame = emulatorView.bounds
|
||||
|
||||
emulatorView.wantsLayer = true
|
||||
|
||||
|
||||
emuScreenLayer.setNeedsDisplay()
|
||||
emulatorView.layer?.addSublayer(emuScreenLayer)
|
||||
|
||||
@ -44,7 +47,6 @@ class AppleI: NSObject {
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/apple1.rom", offset: 0xFF00, length: 0x100)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/basic.bin", offset: 0xE000, length: 0x1000)
|
||||
CPU.sharedInstance.performReset()
|
||||
|
||||
}
|
||||
|
||||
func installOverrides() {
|
||||
@ -59,7 +61,7 @@ class AppleI: NSObject {
|
||||
|
||||
func runFrame() {
|
||||
CPU.sharedInstance.cycles = 0
|
||||
CPU.sharedInstance.cyclesInBatch = AppleI.CYCLES_PER_BATCH
|
||||
CPU.sharedInstance.cyclesInBatch = AppleI.sharedInstance.CYCLES_PER_BATCH
|
||||
CPU.sharedInstance.runCyclesBatch()
|
||||
|
||||
//update the video display
|
||||
|
@ -46,7 +46,7 @@ class AppleIBitmapDisplay: NSObject, CALayerDelegate {
|
||||
//Calculate the offset to reach the desired position.
|
||||
let baseOffset = scanlineOffsets[Int(pixelPosition.y)] + Int(pixelPosition.x)
|
||||
|
||||
for charY in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
for charY in 0..<AppleI.A1CharacterGenerator.CHAR_HEIGHT {
|
||||
let offset = baseOffset + AppleIBitmapDisplay.PIXEL_WIDTH * charY
|
||||
let glyphOffsetY = (charY * 8)
|
||||
|
||||
@ -61,7 +61,7 @@ class AppleIBitmapDisplay: NSObject, CALayerDelegate {
|
||||
}
|
||||
|
||||
func getPixelOffset(charCellIndex: Int) -> CGPoint {
|
||||
return getPixelOffset(charCellX: charCellIndex % Terminal.CELLS_WIDTH, charCellY: charCellIndex / Terminal.CELLS_WIDTH)
|
||||
return getPixelOffset(charCellX: charCellIndex % AppleI.Terminal.CELLS_WIDTH, charCellY: charCellIndex / AppleI.Terminal.CELLS_WIDTH)
|
||||
}
|
||||
|
||||
/* Draw the screen. */
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class AppleScreenView: NSView {
|
||||
class AppleIScreenView: NSView {
|
||||
|
||||
override var acceptsFirstResponder: Bool {
|
||||
return true
|
62
FruitMachine/AppleI/PIAOverrides.swift
Normal file
62
FruitMachine/AppleI/PIAOverrides.swift
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// Overrides.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/27/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension AppleI {
|
||||
|
||||
class PIAOverrides: NSObject {
|
||||
static let writeDSP = WriteOverride(start: 0xD012, end: 0xD012, writeAnyway: false, action: PIAOverrides.actionWriteDSP)
|
||||
static func actionWriteDSP(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
|
||||
let pia = AppleI.sharedInstance.pia["display"]!
|
||||
|
||||
if(pia.getMode() == .Output) {
|
||||
//Writing to DSP sets DSP.7
|
||||
AppleI.sharedInstance.pia["display"]!.data = byte! | 0x80
|
||||
|
||||
//Output our character to the terminal
|
||||
AppleI.sharedInstance.terminal.putCharacter(charIndex: byte!)
|
||||
|
||||
AppleI.sharedInstance.pia["display"]!.data = byte! & ~(0x80)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
static let writeDSPCR = WriteOverride(start: 0xD013, end: 0xD013, writeAnyway: false, action: PIAOverrides.actionWriteDSPCR)
|
||||
static func actionWriteDSPCR(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
AppleI.sharedInstance.pia["display"]?.control = byte!
|
||||
return nil
|
||||
}
|
||||
|
||||
static let readDSP = ReadOverride(start: 0xD012, end: 0xD012, readAnyway: false, action: PIAOverrides.actionReadDSP)
|
||||
static func actionReadDSP(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
|
||||
//DSP.7 is unset when the character is accepted by the terminal
|
||||
return AppleI.sharedInstance.pia["display"]!.data
|
||||
}
|
||||
/* */
|
||||
|
||||
static let readKBDCR = ReadOverride(start: 0xD011, end: 0xD011, readAnyway: false, action: PIAOverrides.actionReadKBDCR)
|
||||
static func actionReadKBDCR(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
return AppleI.sharedInstance.pia["keyboard"]!.control
|
||||
}
|
||||
|
||||
/* */
|
||||
static let readKBD = ReadOverride(start: 0xD010, end: 0xD010, readAnyway: false, action: PIAOverrides.actionReadKBD)
|
||||
static func actionReadKBD(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
//Reading KBD clears KBDCR.7
|
||||
AppleI.sharedInstance.pia["keyboard"]!.control = AppleI.sharedInstance.pia["keyboard"]!.control & ~(0x80)
|
||||
|
||||
//KBD.7 is tied to +5V
|
||||
return AppleI.sharedInstance.pia["keyboard"]!.data | 0x80
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
71
FruitMachine/AppleI/Video/A1CharacterGenerator.swift
Normal file
71
FruitMachine/AppleI/Video/A1CharacterGenerator.swift
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// CharacterGenerator.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/26/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
//The character generator ROM contains 64 8x5 glyphs.
|
||||
|
||||
extension AppleI {
|
||||
|
||||
class A1CharacterGenerator: NSObject {
|
||||
static let CHAR_WIDTH = 5
|
||||
static let CHAR_HEIGHT = 8
|
||||
|
||||
var ROM: [UInt8]
|
||||
var glyphs: [Glyph]
|
||||
|
||||
init(romPath: String) {
|
||||
ROM = [UInt8](repeating: 0xCC, count: 512)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsBE555.PixelData]()), count: 64)
|
||||
|
||||
super.init()
|
||||
loadROM(path: romPath)
|
||||
|
||||
for index in 0..<64 {
|
||||
glyphs[index] = Glyph(inPixels: getCharacterPixels(charIndex: UInt8(index)))
|
||||
}
|
||||
}
|
||||
|
||||
private func loadROM(path: String) {
|
||||
do {
|
||||
let fileContent: NSData = try NSData(contentsOfFile: path)
|
||||
fileContent.getBytes(&ROM, range: NSRange(location: 0, length: 512))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsBE555.PixelData] {
|
||||
var pixelArray = [UInt8](repeating: 0x00, count: A1CharacterGenerator.CHAR_HEIGHT)
|
||||
|
||||
/* Instead of ignoring ASCII bit b6, we ignore bit b5. At the same time ASCII bit b6 must be inverted before it is fed to the character ROM. This way the entire character range from $40 to $7F will end up in the range $00 to $1F (twice of course). Now lower case characters are automatically translated into their corresponding upper case bit maps.
|
||||
*/
|
||||
|
||||
//Don't convert the character indexes if we're populating the glyphs array.
|
||||
for scanlineIndex in 0..<A1CharacterGenerator.CHAR_HEIGHT {
|
||||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * A1CharacterGenerator.CHAR_HEIGHT)]
|
||||
}
|
||||
|
||||
var glyphPixels = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
for charY in 0..<A1CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<8 {
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsBE555.White : BitmapPixelsBE555.Black)
|
||||
}
|
||||
}
|
||||
|
||||
return glyphPixels
|
||||
}
|
||||
|
||||
func asciiToAppleCharIndex(ascii: UInt8) -> UInt8 {
|
||||
return (ascii & 0x1f) | (((ascii ^ 0x40) & 0x40) >> 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
//
|
||||
// CharacterGenerator.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/26/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
//The character generator ROM contains 64 8x5 glyphs.
|
||||
|
||||
struct Glyph {
|
||||
var pixels: [BitmapPixelsBE555.PixelData] = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
init(inPixels: [BitmapPixelsBE555.PixelData]) {
|
||||
pixels = inPixels
|
||||
}
|
||||
}
|
||||
|
||||
class CharacterGenerator: NSObject {
|
||||
static let CHAR_WIDTH = 5
|
||||
static let CHAR_HEIGHT = 8
|
||||
|
||||
var ROM: [UInt8]
|
||||
var glyphs: [Glyph]
|
||||
|
||||
init(romPath: String) {
|
||||
ROM = [UInt8](repeating: 0xCC, count: 512)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsBE555.PixelData]()), count: 64)
|
||||
|
||||
super.init()
|
||||
loadROM(path: romPath)
|
||||
|
||||
for index in 0..<64 {
|
||||
glyphs[index] = Glyph(inPixels: getCharacterPixels(charIndex: UInt8(index)))
|
||||
}
|
||||
}
|
||||
|
||||
private func loadROM(path: String) {
|
||||
do {
|
||||
let fileContent: NSData = try NSData(contentsOfFile: path)
|
||||
fileContent.getBytes(&ROM, range: NSRange(location: 0, length: 512))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsBE555.PixelData] {
|
||||
var pixelArray = [UInt8](repeating: 0x00, count: CharacterGenerator.CHAR_HEIGHT)
|
||||
|
||||
/* Instead of ignoring ASCII bit b6, we ignore bit b5. At the same time ASCII bit b6 must be inverted before it is fed to the character ROM. This way the entire character range from $40 to $7F will end up in the range $00 to $1F (twice of course). Now lower case characters are automatically translated into their corresponding upper case bit maps.
|
||||
*/
|
||||
|
||||
//Don't convert the character indexes if we're populating the glyphs array.
|
||||
for scanlineIndex in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * CharacterGenerator.CHAR_HEIGHT)]
|
||||
}
|
||||
|
||||
var glyphPixels = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
for charY in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<8 {
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsBE555.White : BitmapPixelsBE555.Black)
|
||||
}
|
||||
}
|
||||
|
||||
return glyphPixels
|
||||
}
|
||||
|
||||
func asciiToAppleCharIndex(ascii: UInt8) -> UInt8 {
|
||||
return (ascii & 0x1f) | (((ascii ^ 0x40) & 0x40) >> 1)
|
||||
}
|
||||
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
//
|
||||
// Overrides.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/27/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class PIAOverrides: NSObject {
|
||||
static let writeDSP = WriteOverride(start: 0xD012, end: 0xD012, writeAnyway: false, action: PIAOverrides.actionWriteDSP)
|
||||
static func actionWriteDSP(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
|
||||
let pia = AppleI.sharedInstance.pia["display"]!
|
||||
|
||||
if(pia.getMode() == .Output) {
|
||||
//Writing to DSP sets DSP.7
|
||||
AppleI.sharedInstance.pia["display"]!.data = byte! | 0x80
|
||||
|
||||
//Output our character to the terminal
|
||||
AppleI.sharedInstance.terminal.putCharacter(charIndex: byte!)
|
||||
|
||||
AppleI.sharedInstance.pia["display"]!.data = byte! & ~(0x80)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
static let writeDSPCR = WriteOverride(start: 0xD013, end: 0xD013, writeAnyway: false, action: PIAOverrides.actionWriteDSPCR)
|
||||
static func actionWriteDSPCR(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
AppleI.sharedInstance.pia["display"]?.control = byte!
|
||||
return nil
|
||||
}
|
||||
|
||||
static let readDSP = ReadOverride(start: 0xD012, end: 0xD012, readAnyway: false, action: PIAOverrides.actionReadDSP)
|
||||
static func actionReadDSP(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
|
||||
//DSP.7 is unset when the character is accepted by the terminal
|
||||
return AppleI.sharedInstance.pia["display"]!.data
|
||||
}
|
||||
/* */
|
||||
|
||||
static let readKBDCR = ReadOverride(start: 0xD011, end: 0xD011, readAnyway: false, action: PIAOverrides.actionReadKBDCR)
|
||||
static func actionReadKBDCR(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
return AppleI.sharedInstance.pia["keyboard"]!.control
|
||||
}
|
||||
|
||||
/* */
|
||||
static let readKBD = ReadOverride(start: 0xD010, end: 0xD010, readAnyway: false, action: PIAOverrides.actionReadKBD)
|
||||
static func actionReadKBD(terminal: AnyObject, byte: UInt8?) -> UInt8? {
|
||||
//Reading KBD clears KBDCR.7
|
||||
AppleI.sharedInstance.pia["keyboard"]!.control = AppleI.sharedInstance.pia["keyboard"]!.control & ~(0x80)
|
||||
|
||||
//KBD.7 is tied to +5V
|
||||
return AppleI.sharedInstance.pia["keyboard"]!.data | 0x80
|
||||
}
|
||||
|
||||
}
|
@ -8,42 +8,54 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
struct Cell {
|
||||
var x: Int
|
||||
var y: Int
|
||||
}
|
||||
extension AppleI {
|
||||
|
||||
class Terminal: NSObject {
|
||||
static let CELLS_WIDTH = 40
|
||||
static let CELLS_HEIGHT = 24
|
||||
static let CELLS_COUNT = CELLS_WIDTH * CELLS_HEIGHT
|
||||
|
||||
var cursorPosition: Cell
|
||||
var characters: [UInt8]
|
||||
|
||||
override init() {
|
||||
cursorPosition = Cell(x: 0, y: 0)
|
||||
characters = [UInt8](repeating: 0x00, count: Terminal.CELLS_WIDTH * Terminal.CELLS_HEIGHT)
|
||||
struct Cell {
|
||||
var x: Int
|
||||
var y: Int
|
||||
}
|
||||
|
||||
func cellToIndex(cell: Cell) -> Int {
|
||||
return (cell.y * Terminal.CELLS_WIDTH) + (cell.x % Terminal.CELLS_WIDTH)
|
||||
}
|
||||
|
||||
func putCharacter(charIndex: UInt8) {
|
||||
if(charIndex == 0x8D)
|
||||
{
|
||||
carriageReturn()
|
||||
|
||||
class Terminal: NSObject {
|
||||
static let CELLS_WIDTH = 40
|
||||
static let CELLS_HEIGHT = 24
|
||||
static let CELLS_COUNT = CELLS_WIDTH * CELLS_HEIGHT
|
||||
|
||||
var cursorPosition: Cell
|
||||
var characters: [UInt8]
|
||||
|
||||
override init() {
|
||||
cursorPosition = Cell(x: 0, y: 0)
|
||||
characters = [UInt8](repeating: 0x00, count: Terminal.CELLS_WIDTH * Terminal.CELLS_HEIGHT)
|
||||
}
|
||||
else {
|
||||
characters[cellToIndex(cell: cursorPosition)] = charIndex
|
||||
advanceCursor()
|
||||
|
||||
func cellToIndex(cell: Cell) -> Int {
|
||||
return (cell.y * Terminal.CELLS_WIDTH) + (cell.x % Terminal.CELLS_WIDTH)
|
||||
}
|
||||
}
|
||||
|
||||
func advanceCursor() {
|
||||
cursorPosition.x += 1
|
||||
if(cursorPosition.x == Terminal.CELLS_WIDTH) {
|
||||
|
||||
func putCharacter(charIndex: UInt8) {
|
||||
if(charIndex == 0x8D)
|
||||
{
|
||||
carriageReturn()
|
||||
}
|
||||
else {
|
||||
characters[cellToIndex(cell: cursorPosition)] = charIndex
|
||||
advanceCursor()
|
||||
}
|
||||
}
|
||||
|
||||
func advanceCursor() {
|
||||
cursorPosition.x += 1
|
||||
if(cursorPosition.x == Terminal.CELLS_WIDTH) {
|
||||
cursorPosition.x = 0
|
||||
cursorPosition.y += 1
|
||||
if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
|
||||
cursorPosition.y = Terminal.CELLS_HEIGHT - 1
|
||||
scrollUp(lines: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func carriageReturn() {
|
||||
cursorPosition.x = 0
|
||||
cursorPosition.y += 1
|
||||
if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
|
||||
@ -51,20 +63,12 @@ class Terminal: NSObject {
|
||||
scrollUp(lines: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func carriageReturn() {
|
||||
cursorPosition.x = 0
|
||||
cursorPosition.y += 1
|
||||
if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
|
||||
cursorPosition.y = Terminal.CELLS_HEIGHT - 1
|
||||
scrollUp(lines: 1)
|
||||
|
||||
func scrollUp(lines: Int) {
|
||||
let scrolled = characters[Terminal.CELLS_WIDTH ..< Terminal.CELLS_COUNT]
|
||||
characters = [UInt8](scrolled)
|
||||
characters.append(contentsOf: [UInt8](repeating: 0x00, count: Terminal.CELLS_WIDTH))
|
||||
}
|
||||
}
|
||||
|
||||
func scrollUp(lines: Int) {
|
||||
let scrolled = characters[Terminal.CELLS_WIDTH ..< Terminal.CELLS_COUNT]
|
||||
characters = [UInt8](scrolled)
|
||||
characters.append(contentsOf: [UInt8](repeating: 0x00, count: Terminal.CELLS_WIDTH))
|
||||
}
|
||||
|
||||
}
|
||||
|
67
FruitMachine/AppleII/AppleII.swift
Normal file
67
FruitMachine/AppleII/AppleII.swift
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// AppleII.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class AppleII: NSObject, EmulatedSystem {
|
||||
static let sharedInstance = AppleII(cpuFrequency: (14.31818 / 7 / 2) * 1000000, fps: 60.0)
|
||||
|
||||
var CPU_FREQUENCY: Double
|
||||
var FRAMES_PER_SECOND: Double
|
||||
var CYCLES_PER_BATCH: Int
|
||||
|
||||
let emulatorViewDelegate = AppleII.ScreenDelegate()
|
||||
let emulatorView = AppleII.ScreenView(frame: NSMakeRect(0, 0, 640, 384))
|
||||
let emuScreenLayer = CALayer()
|
||||
|
||||
required init(cpuFrequency: Double, fps: Double) {
|
||||
CPU_FREQUENCY = cpuFrequency
|
||||
FRAMES_PER_SECOND = fps
|
||||
CYCLES_PER_BATCH = Int(cpuFrequency / fps)
|
||||
super.init()
|
||||
|
||||
loadROMs()
|
||||
|
||||
/*
|
||||
emuScreenLayer.shouldRasterize = true
|
||||
emuScreenLayer.delegate = emulatorViewDelegate
|
||||
emuScreenLayer.frame = emulatorView.bounds
|
||||
|
||||
emulatorView.wantsLayer = true
|
||||
|
||||
emuScreenLayer.setNeedsDisplay()
|
||||
emulatorView.layer?.addSublayer(emuScreenLayer)
|
||||
|
||||
installOverrides()
|
||||
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/apple1.rom", offset: 0xFF00, length: 0x100)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/basic.bin", offset: 0xE000, length: 0x1000)
|
||||
CPU.sharedInstance.performReset()
|
||||
*/
|
||||
}
|
||||
|
||||
func loadROMs() {
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0001-00.e0", offset: 0xE000, length: 0x800)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0002-00.e8", offset: 0xE800, length: 0x800)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0003-00.f0", offset: 0xF000, length: 0x800)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0004-00.f8", offset: 0xF800, length: 0x800)
|
||||
}
|
||||
|
||||
func installOverrides() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
func runFrame() {
|
||||
CPU.sharedInstance.cycles = 0
|
||||
CPU.sharedInstance.cyclesInBatch = CYCLES_PER_BATCH
|
||||
CPU.sharedInstance.runCyclesBatch()
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
||||
}
|
70
FruitMachine/AppleII/Video/A2CharacterGenerator.swift
Normal file
70
FruitMachine/AppleII/Video/A2CharacterGenerator.swift
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// CharacterGenerator.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension AppleII {
|
||||
|
||||
//The Apple II character generator is a clone of the Signetics 2513 from the Apple I.
|
||||
|
||||
class A2CharacterGenerator: NSObject {
|
||||
static let CHAR_WIDTH = 5
|
||||
static let CHAR_HEIGHT = 8
|
||||
|
||||
var ROM: [UInt8]
|
||||
var glyphs: [Glyph]
|
||||
|
||||
init(romPath: String) {
|
||||
ROM = [UInt8](repeating: 0xCC, count: 0x800)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsBE555.PixelData]()), count: 64)
|
||||
|
||||
super.init()
|
||||
loadROM(path: romPath)
|
||||
|
||||
for index in 0..<64 {
|
||||
glyphs[index] = Glyph(inPixels: getCharacterPixels(charIndex: UInt8(index)))
|
||||
}
|
||||
}
|
||||
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsBE555.PixelData] {
|
||||
var pixelArray = [UInt8](repeating: 0x00, count: A2CharacterGenerator.CHAR_HEIGHT)
|
||||
|
||||
/* Instead of ignoring ASCII bit b6, we ignore bit b5. At the same time ASCII bit b6 must be inverted before it is fed to the character ROM. This way the entire character range from $40 to $7F will end up in the range $00 to $1F (twice of course). Now lower case characters are automatically translated into their corresponding upper case bit maps.
|
||||
*/
|
||||
|
||||
//Don't convert the character indexes if we're populating the glyphs array.
|
||||
for scanlineIndex in 0..<A2CharacterGenerator.CHAR_HEIGHT {
|
||||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * A2CharacterGenerator.CHAR_HEIGHT)]
|
||||
}
|
||||
|
||||
var glyphPixels = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
for charY in 0..<A2CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<8 {
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsBE555.White : BitmapPixelsBE555.Black)
|
||||
}
|
||||
}
|
||||
|
||||
return glyphPixels
|
||||
}
|
||||
|
||||
func asciiToAppleCharIndex(ascii: UInt8) -> UInt8 {
|
||||
return (ascii & 0x1f) | (((ascii ^ 0x40) & 0x40) >> 1)
|
||||
}
|
||||
|
||||
private func loadROM(path: String) {
|
||||
do {
|
||||
let fileContent: NSData = try NSData(contentsOfFile: path)
|
||||
fileContent.getBytes(&ROM, range: NSRange(location: 0, length: 0x800))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
19
FruitMachine/AppleII/Video/ScreenDelegate.swift
Normal file
19
FruitMachine/AppleII/Video/ScreenDelegate.swift
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// ScreenDelegate.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension AppleII {
|
||||
|
||||
class ScreenDelegate: NSObject, CALayerDelegate {
|
||||
static let PIXEL_WIDTH = 280
|
||||
static let PIXEL_HEIGHT = 192
|
||||
|
||||
}
|
||||
|
||||
}
|
37
FruitMachine/AppleII/Video/ScreenView.swift
Normal file
37
FruitMachine/AppleII/Video/ScreenView.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// ScreenView.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension AppleII {
|
||||
|
||||
class ScreenView: NSView {
|
||||
|
||||
override var acceptsFirstResponder: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func becomeFirstResponder() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func resignFirstResponder() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
// Drawing code here.
|
||||
|
||||
//layer?.sublayers![0].setNeedsDisplay()
|
||||
//layer?.sublayers![0].display()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
52
FruitMachine/AppleIIViewController.swift
Normal file
52
FruitMachine/AppleIIViewController.swift
Normal file
@ -0,0 +1,52 @@
|
||||
//
|
||||
// AppleIIViewController.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class AppleIIViewController: NSViewController {
|
||||
|
||||
let computer = AppleII.sharedInstance
|
||||
var debuggerWindowController: DebuggerWindowController!
|
||||
var preferencesWindowController: PreferencesWindowController!
|
||||
|
||||
var isPaused = false
|
||||
var frameTimer: Timer?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do view setup here.
|
||||
|
||||
preferencesWindowController = PreferencesWindowController()
|
||||
|
||||
self.view.addSubview(computer.emulatorView)
|
||||
|
||||
self.frameTimer = Timer.scheduledTimer(timeInterval: 1/60,
|
||||
target: self,
|
||||
selector: #selector(runEmulation),
|
||||
userInfo: nil,
|
||||
repeats: true)
|
||||
}
|
||||
|
||||
@objc func runEmulation() {
|
||||
computer.runFrame()
|
||||
if(!CPU.sharedInstance.isRunning) {
|
||||
self.frameTimer?.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func showDebugger(_ sender: Any) {
|
||||
let debuggerStoryboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Debugger"), bundle: nil)
|
||||
debuggerWindowController = debuggerStoryboard.instantiateInitialController() as! DebuggerWindowController
|
||||
debuggerWindowController.showWindow(self)
|
||||
}
|
||||
|
||||
@IBAction func showPreferences(_ sender: Any) {
|
||||
preferencesWindowController.loadWindow()
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
import Cocoa
|
||||
import CoreGraphics
|
||||
|
||||
class MainViewController: NSViewController {
|
||||
class AppleIViewController: NSViewController {
|
||||
|
||||
let computer = AppleI.sharedInstance
|
||||
var debuggerWindowController: DebuggerWindowController!
|
18
FruitMachine/Common/EmulatedSystem.swift
Normal file
18
FruitMachine/Common/EmulatedSystem.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// EmulatedSystem.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
protocol EmulatedSystem {
|
||||
var CPU_FREQUENCY: Double { get }
|
||||
var FRAMES_PER_SECOND: Double { get }
|
||||
var CYCLES_PER_BATCH: Int { get }
|
||||
|
||||
init(cpuFrequency: Double, fps: Double)
|
||||
func installOverrides()
|
||||
}
|
17
FruitMachine/Common/Video/Glyph.swift
Normal file
17
FruitMachine/Common/Video/Glyph.swift
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Glyph.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/1/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
struct Glyph {
|
||||
var pixels: [BitmapPixelsBE555.PixelData] = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
init(inPixels: [BitmapPixelsBE555.PixelData]) {
|
||||
pixels = inPixels
|
||||
}
|
||||
}
|
@ -224,10 +224,10 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="97" y="-661"/>
|
||||
</scene>
|
||||
<!--Main View Controller-->
|
||||
<!--AppleI View Controller-->
|
||||
<scene sceneID="AMw-8X-nlH">
|
||||
<objects>
|
||||
<viewController id="gw1-M7-9Je" customClass="MainViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="gw1-M7-9Je" customClass="AppleIViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="DiY-xb-Usb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
|
Loading…
Reference in New Issue
Block a user