From dd8301ccabdeabc5216e745334e9468726a886ec Mon Sep 17 00:00:00 2001 From: Luigi Thirty Date: Thu, 27 Jul 2017 02:28:52 -0400 Subject: [PATCH] started implementing the 40x24 video terminal. can draw characters from the character generator ROM anywhere on the screen, plus support routines for finding offsets of character cells. --- FruitMachine.xcodeproj/project.pbxproj | 90 ++++- FruitMachine/AppDelegate.swift | 3 - FruitMachine/AppleScreenView.swift | 22 + FruitMachine/AppleScreenViewDelegate.swift | 77 ++++ ...ain.storyboard => FruitMachine.storyboard} | 375 +---------------- FruitMachine/Info.plist | 2 +- .../Debugger/Base.lproj/Debugger.storyboard | 380 ++++++++++++++++++ .../Debugger}/DebuggerCommands.swift | 0 .../Debugger}/DebuggerViewController.swift | 0 .../M6502/{ => Debugger}/Disassembly.swift | 0 .../M6502/{ => Opcodes}/CPUInstructions.swift | 0 .../M6502/{ => Opcodes}/Opcodes.swift | 0 .../{ => Types}/AddressConversions.swift | 0 .../M6502/{ => Types}/IntegerExtensions.swift | 0 FruitMachine/MainViewController.swift | 45 +++ FruitMachine/Video/CharacterGenerator.swift | 45 +++ 16 files changed, 666 insertions(+), 373 deletions(-) create mode 100644 FruitMachine/AppleScreenView.swift create mode 100644 FruitMachine/AppleScreenViewDelegate.swift rename FruitMachine/{Base.lproj/Main.storyboard => FruitMachine.storyboard} (61%) create mode 100644 FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard rename FruitMachine/{ => M6502/Debugger}/DebuggerCommands.swift (100%) rename FruitMachine/{ => M6502/Debugger}/DebuggerViewController.swift (100%) rename FruitMachine/M6502/{ => Debugger}/Disassembly.swift (100%) rename FruitMachine/M6502/{ => Opcodes}/CPUInstructions.swift (100%) rename FruitMachine/M6502/{ => Opcodes}/Opcodes.swift (100%) rename FruitMachine/M6502/{ => Types}/AddressConversions.swift (100%) rename FruitMachine/M6502/{ => Types}/IntegerExtensions.swift (100%) create mode 100644 FruitMachine/MainViewController.swift create mode 100644 FruitMachine/Video/CharacterGenerator.swift diff --git a/FruitMachine.xcodeproj/project.pbxproj b/FruitMachine.xcodeproj/project.pbxproj index 0831fb8..1e59d3e 100644 --- a/FruitMachine.xcodeproj/project.pbxproj +++ b/FruitMachine.xcodeproj/project.pbxproj @@ -8,10 +8,13 @@ /* Begin PBXBuildFile section */ 2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */; }; + 2A5BC5191F29A28D008C03BE /* AppleScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */; }; + 2A5BC51C1F29A2EB008C03BE /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */; }; + 2A5BC51E1F29A4C3008C03BE /* AppleScreenViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.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 */; }; - 2AD458D51F205EB700F05121 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2AD458D31F205EB700F05121 /* Main.storyboard */; }; + 2AD458D51F205EB700F05121 /* Debugger.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2AD458D31F205EB700F05121 /* Debugger.storyboard */; }; 2AD458DF1F205F4500F05121 /* CPU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458DE1F205F4500F05121 /* CPU.swift */; }; 2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E01F2064CB00F05121 /* MemoryInterface.swift */; }; 2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E21F20661300F05121 /* CPUInstructions.swift */; }; @@ -20,17 +23,23 @@ 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 */; }; + 2AE42E401F28638100C4900E /* FruitMachine.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */; }; + 2AE42E431F28665300C4900E /* CharacterGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE42E421F28665300C4900E /* CharacterGenerator.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 */ /* Begin PBXFileReference section */ 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegerExtensions.swift; sourceTree = ""; }; + 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScreenView.swift; sourceTree = ""; }; + 2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScreenViewDelegate.swift; sourceTree = ""; }; 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 = ""; }; 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerViewController.swift; sourceTree = ""; }; 2AD458D11F205EB700F05121 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 2AD458D41F205EB700F05121 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 2AD458D41F205EB700F05121 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Debugger.storyboard; sourceTree = ""; }; 2AD458D61F205EB700F05121 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2AD458D71F205EB700F05121 /* FruitMachine.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FruitMachine.entitlements; sourceTree = ""; }; 2AD458DE1F205F4500F05121 /* CPU.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPU.swift; sourceTree = ""; }; @@ -41,6 +50,9 @@ 2AE42E071F2850F400C4900E /* ReadOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadOverride.swift; sourceTree = ""; }; 2AE42E091F28521E00C4900E /* WriteOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteOverride.swift; sourceTree = ""; }; 2AE42E0B1F28522D00C4900E /* MemoryOverride.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryOverride.swift; sourceTree = ""; }; + 2AE42E381F28628300C4900E /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; + 2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = FruitMachine.storyboard; sourceTree = ""; }; + 2AE42E421F28665300C4900E /* CharacterGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterGenerator.swift; sourceTree = ""; }; 2AE5BA031F23DE4400FAA343 /* Disassembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disassembly.swift; sourceTree = ""; }; 2AE5BA051F2469EB00FAA343 /* AddressConversions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressConversions.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -50,17 +62,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2A5BC51C1F29A2EB008C03BE /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2A5BC51A1F29A2EB008C03BE /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 2AD458C11F205EB700F05121 = { isa = PBXGroup; children = ( 2AD458CC1F205EB700F05121 /* FruitMachine */, 2AD458CB1F205EB700F05121 /* Products */, + 2A5BC51A1F29A2EB008C03BE /* Frameworks */, ); sourceTree = ""; }; @@ -76,11 +98,13 @@ isa = PBXGroup; children = ( 2AD458DD1F205F0D00F05121 /* M6502 */, + 2AE42E411F28663600C4900E /* Video */, 2AD458CD1F205EB700F05121 /* AppDelegate.swift */, - 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */, - 2AD6D5831F26E6BF008F3CF5 /* DebuggerCommands.swift */, + 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */, + 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */, + 2AE42E381F28628300C4900E /* MainViewController.swift */, + 2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */, 2AD458D11F205EB700F05121 /* Assets.xcassets */, - 2AD458D31F205EB700F05121 /* Main.storyboard */, 2AD458D61F205EB700F05121 /* Info.plist */, 2AD458D71F205EB700F05121 /* FruitMachine.entitlements */, ); @@ -90,13 +114,11 @@ 2AD458DD1F205F0D00F05121 /* M6502 */ = { isa = PBXGroup; children = ( + 2AE42E0F1F28563800C4900E /* Types */, + 2AE42E0E1F28562D00C4900E /* Opcodes */, + 2AE42E0D1F28561A00C4900E /* Debugger */, 2AE42E061F2850E100C4900E /* Memory */, 2AD458DE1F205F4500F05121 /* CPU.swift */, - 2AD458E21F20661300F05121 /* CPUInstructions.swift */, - 2AE5BA031F23DE4400FAA343 /* Disassembly.swift */, - 2AD458E41F2070DF00F05121 /* Opcodes.swift */, - 2AE5BA051F2469EB00FAA343 /* AddressConversions.swift */, - 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */, ); path = M6502; sourceTree = ""; @@ -112,6 +134,43 @@ path = Memory; sourceTree = ""; }; + 2AE42E0D1F28561A00C4900E /* Debugger */ = { + isa = PBXGroup; + children = ( + 2AD458D31F205EB700F05121 /* Debugger.storyboard */, + 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */, + 2AD6D5831F26E6BF008F3CF5 /* DebuggerCommands.swift */, + 2AE5BA031F23DE4400FAA343 /* Disassembly.swift */, + ); + path = Debugger; + sourceTree = ""; + }; + 2AE42E0E1F28562D00C4900E /* Opcodes */ = { + isa = PBXGroup; + children = ( + 2AD458E41F2070DF00F05121 /* Opcodes.swift */, + 2AD458E21F20661300F05121 /* CPUInstructions.swift */, + ); + path = Opcodes; + sourceTree = ""; + }; + 2AE42E0F1F28563800C4900E /* Types */ = { + isa = PBXGroup; + children = ( + 2AE5BA051F2469EB00FAA343 /* AddressConversions.swift */, + 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */, + ); + path = Types; + sourceTree = ""; + }; + 2AE42E411F28663600C4900E /* Video */ = { + isa = PBXGroup; + children = ( + 2AE42E421F28665300C4900E /* CharacterGenerator.swift */, + ); + path = Video; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -171,7 +230,8 @@ buildActionMask = 2147483647; files = ( 2AD458D21F205EB700F05121 /* Assets.xcassets in Resources */, - 2AD458D51F205EB700F05121 /* Main.storyboard in Resources */, + 2AE42E401F28638100C4900E /* FruitMachine.storyboard in Resources */, + 2AD458D51F205EB700F05121 /* Debugger.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -184,15 +244,19 @@ files = ( 2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */, 2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */, + 2A5BC51E1F29A4C3008C03BE /* AppleScreenViewDelegate.swift in Sources */, 2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */, + 2AE42E431F28665300C4900E /* CharacterGenerator.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 */, 2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */, 2AE42E081F2850F400C4900E /* ReadOverride.swift in Sources */, 2AE5BA061F2469EB00FAA343 /* AddressConversions.swift in Sources */, 2AE42E0A1F28521E00C4900E /* WriteOverride.swift in Sources */, + 2A5BC5191F29A28D008C03BE /* AppleScreenView.swift in Sources */, 2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */, 2AD458DF1F205F4500F05121 /* CPU.swift in Sources */, ); @@ -201,12 +265,12 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 2AD458D31F205EB700F05121 /* Main.storyboard */ = { + 2AD458D31F205EB700F05121 /* Debugger.storyboard */ = { isa = PBXVariantGroup; children = ( 2AD458D41F205EB700F05121 /* Base */, ); - name = Main.storyboard; + name = Debugger.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ diff --git a/FruitMachine/AppDelegate.swift b/FruitMachine/AppDelegate.swift index f49ce9b..9e473c7 100644 --- a/FruitMachine/AppDelegate.swift +++ b/FruitMachine/AppDelegate.swift @@ -11,8 +11,6 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - - func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application } @@ -21,6 +19,5 @@ class AppDelegate: NSObject, NSApplicationDelegate { // Insert code here to tear down your application } - } diff --git a/FruitMachine/AppleScreenView.swift b/FruitMachine/AppleScreenView.swift new file mode 100644 index 0000000..cd09153 --- /dev/null +++ b/FruitMachine/AppleScreenView.swift @@ -0,0 +1,22 @@ +// +// AppleScreenView.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/27/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +class AppleScreenView: NSView { + + //In characters + static let TERMINAL_WIDTH = 40 + static let TERMINAL_HEIGHT = 24 + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + // Drawing code here. + } + +} diff --git a/FruitMachine/AppleScreenViewDelegate.swift b/FruitMachine/AppleScreenViewDelegate.swift new file mode 100644 index 0000000..eed5135 --- /dev/null +++ b/FruitMachine/AppleScreenViewDelegate.swift @@ -0,0 +1,77 @@ +// +// AppleScreenViewDelegate.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/27/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +class AppleScreenViewDelegate: NSObject, CALayerDelegate { + let PIXEL_WIDTH = 200 + let PIXEL_HEIGHT = 192 + + /* Pixel data stuff. */ + struct PixelData { + var a: UInt8 = 255 + var r: UInt8 + var g: UInt8 + var b: UInt8 + } + let bitsPerComponent: UInt = 8 + let bitsPerPixel: UInt = 32 + let colorSpace = CGColorSpaceCreateDeviceRGB() + let bitmapInfo: CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue) + /* */ + + var indexedPixels: [UInt8] + var colorValues: [PixelData] + + override init() + { + indexedPixels = [UInt8](repeating: 0x00, count: 200*192) + colorValues = [PixelData](repeating: PixelData(a: 255, r: 0, g: 0, b: 0), count: 256) + colorValues[1] = PixelData(a: 0, r: 200, g: 200, b: 200 + ) + } + + func convertIndexedPixelsToRGB(pixels: [UInt8]) -> [PixelData] { + var rgbPixels = [PixelData](repeating: PixelData(a: 255, r: 0, g: 0, b: 0), count: 200*192) + + for (num, colorIndex) in pixels.enumerated() { + rgbPixels[num] = colorValues[Int(colorIndex)] + } + + return rgbPixels + } + + func putCharacterPixels(charPixels: [UInt8], pixelPosition: CGPoint) { + //Calculate the offset to reach the desired position. + let baseOffset = (Int(pixelPosition.y) * PIXEL_WIDTH) + Int(pixelPosition.x) + + for charY in 0.. 0 ? 1 : 0 + } + } + } + + func getPixelOffset(charCellX: Int, charCellY: Int) -> CGPoint { + return CGPoint(x: charCellX * 5, y: charCellY * 8) + } + + /* Draw the screen. */ + func draw(_ layer: CALayer, in ctx: CGContext) { + let bounds = layer.bounds + ctx.interpolationQuality = CGInterpolationQuality.none + + var pixels = convertIndexedPixelsToRGB(pixels: indexedPixels) + let pixelProvider = CGDataProvider(data: NSData(bytes: &pixels, length: pixels.count * MemoryLayout.size)) + + let renderedImage = CGImage(width: PIXEL_WIDTH, height: PIXEL_HEIGHT, bitsPerComponent: Int(bitsPerComponent), bitsPerPixel: Int(bitsPerPixel), bytesPerRow: PIXEL_WIDTH * Int(MemoryLayout.size), space: colorSpace, bitmapInfo: bitmapInfo, provider: pixelProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) + ctx.draw(renderedImage!, in: bounds) + //draw stuff here + } + +} diff --git a/FruitMachine/Base.lproj/Main.storyboard b/FruitMachine/FruitMachine.storyboard similarity index 61% rename from FruitMachine/Base.lproj/Main.storyboard rename to FruitMachine/FruitMachine.storyboard index 3dfc83f..70ff467 100644 --- a/FruitMachine/Base.lproj/Main.storyboard +++ b/FruitMachine/FruitMachine.storyboard @@ -1,8 +1,8 @@ - + - + @@ -679,377 +679,40 @@ - + - + - - + + - - - + + - + - + - + - + - - + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + diff --git a/FruitMachine/Info.plist b/FruitMachine/Info.plist index a87c821..2cba8e9 100644 --- a/FruitMachine/Info.plist +++ b/FruitMachine/Info.plist @@ -25,7 +25,7 @@ NSHumanReadableCopyright Copyright © 2017 Christopher Rohl. All rights reserved. NSMainStoryboardFile - Main + FruitMachine NSPrincipalClass NSApplication diff --git a/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard b/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard new file mode 100644 index 0000000..0da2fdd --- /dev/null +++ b/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FruitMachine/DebuggerCommands.swift b/FruitMachine/M6502/Debugger/DebuggerCommands.swift similarity index 100% rename from FruitMachine/DebuggerCommands.swift rename to FruitMachine/M6502/Debugger/DebuggerCommands.swift diff --git a/FruitMachine/DebuggerViewController.swift b/FruitMachine/M6502/Debugger/DebuggerViewController.swift similarity index 100% rename from FruitMachine/DebuggerViewController.swift rename to FruitMachine/M6502/Debugger/DebuggerViewController.swift diff --git a/FruitMachine/M6502/Disassembly.swift b/FruitMachine/M6502/Debugger/Disassembly.swift similarity index 100% rename from FruitMachine/M6502/Disassembly.swift rename to FruitMachine/M6502/Debugger/Disassembly.swift diff --git a/FruitMachine/M6502/CPUInstructions.swift b/FruitMachine/M6502/Opcodes/CPUInstructions.swift similarity index 100% rename from FruitMachine/M6502/CPUInstructions.swift rename to FruitMachine/M6502/Opcodes/CPUInstructions.swift diff --git a/FruitMachine/M6502/Opcodes.swift b/FruitMachine/M6502/Opcodes/Opcodes.swift similarity index 100% rename from FruitMachine/M6502/Opcodes.swift rename to FruitMachine/M6502/Opcodes/Opcodes.swift diff --git a/FruitMachine/M6502/AddressConversions.swift b/FruitMachine/M6502/Types/AddressConversions.swift similarity index 100% rename from FruitMachine/M6502/AddressConversions.swift rename to FruitMachine/M6502/Types/AddressConversions.swift diff --git a/FruitMachine/M6502/IntegerExtensions.swift b/FruitMachine/M6502/Types/IntegerExtensions.swift similarity index 100% rename from FruitMachine/M6502/IntegerExtensions.swift rename to FruitMachine/M6502/Types/IntegerExtensions.swift diff --git a/FruitMachine/MainViewController.swift b/FruitMachine/MainViewController.swift new file mode 100644 index 0000000..4a5d9c7 --- /dev/null +++ b/FruitMachine/MainViewController.swift @@ -0,0 +1,45 @@ +// +// MainViewController.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/26/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa +import CoreGraphics + +class MainViewController: NSViewController { + var windowController: NSWindowController? + var debuggerViewController = DebuggerViewController() + let emuScreenLayer = CALayer() + + let cg = CharacterGenerator(romPath: "/Users/luigi/apple1/apple1.vid"); + var appleScreenView: AppleScreenView = AppleScreenView(frame: NSMakeRect(0, 0, 400, 384)) + let appleScreenViewDelegate = AppleScreenViewDelegate() + + override func viewDidLoad() { + super.viewDidLoad() + // Do view setup here. + self.view.addSubview(appleScreenView) + + appleScreenView.wantsLayer = true + + emuScreenLayer.delegate = appleScreenViewDelegate + emuScreenLayer.frame = appleScreenView.bounds + emuScreenLayer.setNeedsDisplay() + appleScreenView.layer?.addSublayer(emuScreenLayer) + + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x00), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 0, charCellY: 0)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x01), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 1, charCellY: 1)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x02), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 2, charCellY: 2)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x03), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 3, charCellY: 3)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x04), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 4, charCellY: 4)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x05), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 5, charCellY: 5)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x06), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 6, charCellY: 6)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x07), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 7, charCellY: 7)) + appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x08), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 8, charCellY: 8)) + + appleScreenView.display() + } +} diff --git a/FruitMachine/Video/CharacterGenerator.swift b/FruitMachine/Video/CharacterGenerator.swift new file mode 100644 index 0000000..d44941f --- /dev/null +++ b/FruitMachine/Video/CharacterGenerator.swift @@ -0,0 +1,45 @@ +// +// 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. + +class CharacterGenerator: NSObject { + static let CHAR_WIDTH = 5 + static let CHAR_HEIGHT = 8 + + var ROM: [UInt8] + + init(romPath: String) { + ROM = [UInt8](repeating: 0xCC, count: 512) + + super.init() + loadROM(path: romPath) + } + + func loadROM(path: String) { + do { + let fileContent: NSData = try NSData(contentsOfFile: path) + fileContent.getBytes(&ROM, range: NSRange(location: 0, length: 512)) + } catch { + print(error) + } + } + + func getCharacterPixels(charIndex: UInt8) -> [UInt8] { + var pixelArray = [UInt8](repeating: 0x00, count: CharacterGenerator.CHAR_HEIGHT) + + for scanlineIndex in 0..