From ab3c32af3d7815689eb5b3ab36f436c917158a0c Mon Sep 17 00:00:00 2001 From: Luigi Thirty Date: Thu, 3 Aug 2017 00:31:12 -0400 Subject: [PATCH] attached the Disk II ROM peripherals --- FruitMachine.xcodeproj/project.pbxproj | 50 +++++++- FruitMachine/AppleI/PIAOverrides.swift | 10 +- .../AppleI/Video/A1CharacterGenerator.swift | 16 +-- FruitMachine/AppleII/AppleII.swift | 26 +++- FruitMachine/AppleII/Peripherals/DiskII.swift | 45 +++++++ .../AppleII/Peripherals/Peripheral.swift | 14 +++ .../AppleII/SoftswitchOverrides.swift | 20 ++-- .../AppleII/Video/A2CharacterGenerator.swift | 18 +-- .../AppleII/Video/Modes/LoresMode.swift | 48 ++++++++ .../AppleII/Video/Modes/TextMode.swift | 53 +++++++++ .../Video/{ => Modes}/VideoModes.swift | 0 .../AppleII/Video/ScreenDelegate.swift | 111 +----------------- FruitMachine/AppleII/Video/VideoHelpers.swift | 50 ++++++++ FruitMachine/AppleIIViewController.swift | 9 ++ FruitMachine/Common/Memory/ROMManager.swift | 33 ++++++ .../M6502/Memory/MemoryInterface.swift | 4 +- .../M6502/Memory/MemoryOverride.swift | 4 +- FruitMachine/M6502/Memory/ReadOverride.swift | 2 +- FruitMachine/M6502/Memory/WriteOverride.swift | 2 +- FruitMachine/M6502/Opcodes/Opcodes.swift | 3 - FruitMachine/PreferencesWindow.xib | 16 ++- 21 files changed, 364 insertions(+), 170 deletions(-) create mode 100644 FruitMachine/AppleII/Peripherals/DiskII.swift create mode 100644 FruitMachine/AppleII/Peripherals/Peripheral.swift create mode 100644 FruitMachine/AppleII/Video/Modes/LoresMode.swift create mode 100644 FruitMachine/AppleII/Video/Modes/TextMode.swift rename FruitMachine/AppleII/Video/{ => Modes}/VideoModes.swift (100%) create mode 100644 FruitMachine/AppleII/Video/VideoHelpers.swift create mode 100644 FruitMachine/Common/Memory/ROMManager.swift diff --git a/FruitMachine.xcodeproj/project.pbxproj b/FruitMachine.xcodeproj/project.pbxproj index 57237f2..dd0f13d 100644 --- a/FruitMachine.xcodeproj/project.pbxproj +++ b/FruitMachine.xcodeproj/project.pbxproj @@ -15,6 +15,11 @@ 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 */; }; + 2A63C2331F32C39300D4F4F8 /* TextMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A63C2321F32C39300D4F4F8 /* TextMode.swift */; }; + 2A63C2351F32C4F700D4F4F8 /* LoresMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A63C2341F32C4F700D4F4F8 /* LoresMode.swift */; }; + 2A63C2371F32C55100D4F4F8 /* VideoHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A63C2361F32C55100D4F4F8 /* VideoHelpers.swift */; }; + 2A63C23A1F32CCE900D4F4F8 /* DiskII.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A63C2391F32CCE900D4F4F8 /* DiskII.swift */; }; + 2A63C23C1F32CD4800D4F4F8 /* Peripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A63C23B1F32CD4800D4F4F8 /* Peripheral.swift */; }; 2A6C2D171F31216700B8DC60 /* SoftswitchOverrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6C2D161F31216700B8DC60 /* SoftswitchOverrides.swift */; }; 2A6DC7E91F3045280066FE0D /* AppleIIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7E81F3045280066FE0D /* AppleIIViewController.swift */; }; 2A6DC7EB1F3045C90066FE0D /* EmulatedSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7EA1F3045C90066FE0D /* EmulatedSystem.swift */; }; @@ -38,6 +43,7 @@ 2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E21F20661300F05121 /* CPUInstructions.swift */; }; 2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E41F2070DF00F05121 /* Opcodes.swift */; }; 2AD6D5841F26E6BF008F3CF5 /* DebuggerCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD6D5831F26E6BF008F3CF5 /* DebuggerCommands.swift */; }; + 2AE3BB971F32CEB100C11060 /* ROMManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE3BB961F32CEB100C11060 /* ROMManager.swift */; }; 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 */; }; @@ -57,6 +63,11 @@ 2A5C5BBB1F304C3A00ED351D /* A2CharacterGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A2CharacterGenerator.swift; sourceTree = ""; }; 2A5C5BBD1F304D4B00ED351D /* Glyph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glyph.swift; sourceTree = ""; }; 2A60851D1F2AFAE900E05B64 /* PIA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIA.swift; sourceTree = ""; }; + 2A63C2321F32C39300D4F4F8 /* TextMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMode.swift; sourceTree = ""; }; + 2A63C2341F32C4F700D4F4F8 /* LoresMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoresMode.swift; sourceTree = ""; }; + 2A63C2361F32C55100D4F4F8 /* VideoHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoHelpers.swift; sourceTree = ""; }; + 2A63C2391F32CCE900D4F4F8 /* DiskII.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskII.swift; sourceTree = ""; }; + 2A63C23B1F32CD4800D4F4F8 /* Peripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Peripheral.swift; sourceTree = ""; }; 2A6C2D161F31216700B8DC60 /* SoftswitchOverrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftswitchOverrides.swift; sourceTree = ""; }; 2A6DC7E81F3045280066FE0D /* AppleIIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleIIViewController.swift; sourceTree = ""; }; 2A6DC7EA1F3045C90066FE0D /* EmulatedSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmulatedSystem.swift; sourceTree = ""; }; @@ -83,6 +94,7 @@ 2AD458E21F20661300F05121 /* CPUInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPUInstructions.swift; sourceTree = ""; }; 2AD458E41F2070DF00F05121 /* Opcodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Opcodes.swift; sourceTree = ""; }; 2AD6D5831F26E6BF008F3CF5 /* DebuggerCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerCommands.swift; sourceTree = ""; }; + 2AE3BB961F32CEB100C11060 /* ROMManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ROMManager.swift; sourceTree = ""; }; 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 = ""; }; @@ -113,9 +125,29 @@ name = Frameworks; sourceTree = ""; }; + 2A63C2311F32C38400D4F4F8 /* Modes */ = { + isa = PBXGroup; + children = ( + 2A86FB981F32694A00AD0C68 /* VideoModes.swift */, + 2A63C2321F32C39300D4F4F8 /* TextMode.swift */, + 2A63C2341F32C4F700D4F4F8 /* LoresMode.swift */, + ); + path = Modes; + sourceTree = ""; + }; + 2A63C2381F32CCDB00D4F4F8 /* Peripherals */ = { + isa = PBXGroup; + children = ( + 2A63C2391F32CCE900D4F4F8 /* DiskII.swift */, + 2A63C23B1F32CD4800D4F4F8 /* Peripheral.swift */, + ); + path = Peripherals; + sourceTree = ""; + }; 2A6DC7E51F3043DB0066FE0D /* Common */ = { isa = PBXGroup; children = ( + 2AE3BB981F32D24D00C11060 /* Memory */, 2A6DC7E71F3044080066FE0D /* Peripherals */, 2A6DC7E61F3043E10066FE0D /* Video */, 2A6DC7EA1F3045C90066FE0D /* EmulatedSystem.swift */, @@ -143,10 +175,11 @@ 2A6DC7EE1F30492E0066FE0D /* Video */ = { isa = PBXGroup; children = ( + 2A63C2311F32C38400D4F4F8 /* Modes */, 2A5C5BBB1F304C3A00ED351D /* A2CharacterGenerator.swift */, + 2A63C2361F32C55100D4F4F8 /* VideoHelpers.swift */, 2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */, 2A6DC7EF1F30495D0066FE0D /* ScreenView.swift */, - 2A86FB981F32694A00AD0C68 /* VideoModes.swift */, ); path = Video; sourceTree = ""; @@ -166,6 +199,7 @@ 2AB6CAC71F30407200DECAC0 /* AppleII */ = { isa = PBXGroup; children = ( + 2A63C2381F32CCDB00D4F4F8 /* Peripherals */, 2A6DC7EE1F30492E0066FE0D /* Video */, 2AB6CACC1F3041A200DECAC0 /* AppleII.swift */, 2A86FB961F316CB500AD0C68 /* KeyboardController.swift */, @@ -223,6 +257,14 @@ path = M6502; sourceTree = ""; }; + 2AE3BB981F32D24D00C11060 /* Memory */ = { + isa = PBXGroup; + children = ( + 2AE3BB961F32CEB100C11060 /* ROMManager.swift */, + ); + path = Memory; + sourceTree = ""; + }; 2AE42E061F2850E100C4900E /* Memory */ = { isa = PBXGroup; children = ( @@ -362,22 +404,28 @@ 2AE42E0C1F28522D00C4900E /* MemoryOverride.swift in Sources */, 2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */, 2AD6D5841F26E6BF008F3CF5 /* DebuggerCommands.swift in Sources */, + 2AE3BB971F32CEB100C11060 /* ROMManager.swift in Sources */, 2AE5BA041F23DE4400FAA343 /* Disassembly.swift in Sources */, 2A6DC7EB1F3045C90066FE0D /* EmulatedSystem.swift in Sources */, 2A86FB971F316CB500AD0C68 /* KeyboardController.swift in Sources */, + 2A63C2351F32C4F700D4F4F8 /* LoresMode.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 */, + 2A63C2331F32C39300D4F4F8 /* TextMode.swift in Sources */, 2AE5BA061F2469EB00FAA343 /* AddressConversions.swift in Sources */, 2AE42E0A1F28521E00C4900E /* WriteOverride.swift in Sources */, 2A6DC7ED1F30492C0066FE0D /* ScreenDelegate.swift in Sources */, 2A5BC5191F29A28D008C03BE /* AppleIScreenView.swift in Sources */, + 2A63C2371F32C55100D4F4F8 /* VideoHelpers.swift in Sources */, + 2A63C23A1F32CCE900D4F4F8 /* DiskII.swift in Sources */, 2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */, 2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */, 2AD458DF1F205F4500F05121 /* CPU.swift in Sources */, 2A86FB991F32694A00AD0C68 /* VideoModes.swift in Sources */, + 2A63C23C1F32CD4800D4F4F8 /* Peripheral.swift in Sources */, 2A6DC7E91F3045280066FE0D /* AppleIIViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/FruitMachine/AppleI/PIAOverrides.swift b/FruitMachine/AppleI/PIAOverrides.swift index 9217a53..bcfa44c 100644 --- a/FruitMachine/AppleI/PIAOverrides.swift +++ b/FruitMachine/AppleI/PIAOverrides.swift @@ -12,7 +12,7 @@ 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? { + static func actionWriteDSP(terminal: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { let pia = AppleI.sharedInstance.pia["display"]! @@ -29,13 +29,13 @@ extension AppleI { } static let writeDSPCR = WriteOverride(start: 0xD013, end: 0xD013, writeAnyway: false, action: PIAOverrides.actionWriteDSPCR) - static func actionWriteDSPCR(terminal: AnyObject, byte: UInt8?) -> UInt8? { + static func actionWriteDSPCR(terminal: AnyObject, address: UInt16, 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? { + static func actionReadDSP(terminal: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { //DSP.7 is unset when the character is accepted by the terminal return AppleI.sharedInstance.pia["display"]!.data @@ -43,13 +43,13 @@ extension AppleI { /* */ static let readKBDCR = ReadOverride(start: 0xD011, end: 0xD011, readAnyway: false, action: PIAOverrides.actionReadKBDCR) - static func actionReadKBDCR(terminal: AnyObject, byte: UInt8?) -> UInt8? { + static func actionReadKBDCR(terminal: AnyObject, address: UInt16, 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? { + static func actionReadKBD(terminal: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { //Reading KBD clears KBDCR.7 AppleI.sharedInstance.pia["keyboard"]!.control = AppleI.sharedInstance.pia["keyboard"]!.control & ~(0x80) diff --git a/FruitMachine/AppleI/Video/A1CharacterGenerator.swift b/FruitMachine/AppleI/Video/A1CharacterGenerator.swift index 7daecd6..a80b895 100644 --- a/FruitMachine/AppleI/Video/A1CharacterGenerator.swift +++ b/FruitMachine/AppleI/Video/A1CharacterGenerator.swift @@ -16,29 +16,19 @@ extension AppleI { static let CHAR_WIDTH = 5 static let CHAR_HEIGHT = 8 - var ROM: [UInt8] var glyphs: [Glyph] + var romManager: ROMDelegate init(romPath: String) { - ROM = [UInt8](repeating: 0xCC, count: 512) glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsLE555.PixelData]()), count: 64) + romManager = ROMManager(path: romPath, atAddress: 0x00, size: 512) 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) -> [BitmapPixelsLE555.PixelData] { var pixelArray = [UInt8](repeating: 0x00, count: A1CharacterGenerator.CHAR_HEIGHT) @@ -48,7 +38,7 @@ extension AppleI { //Don't convert the character indexes if we're populating the glyphs array. for scanlineIndex in 0.. UInt8? { + let offset: UInt16 = 0xC000 + UInt16(slotNumber*0x100) + let local = address - offset + + return getMemoryMappedByte(address: local) + } + + private func getMemoryMappedByte(address: UInt16) -> UInt8 { + //Disk II just maps its ROM to the memory addressed by the slot. + + return romManager.ROM[Int(address)] + } + + func installOverrides() { + CPU.sharedInstance.memoryInterface.read_overrides.append(readMemoryOverride!) + } +} diff --git a/FruitMachine/AppleII/Peripherals/Peripheral.swift b/FruitMachine/AppleII/Peripherals/Peripheral.swift new file mode 100644 index 0000000..6c91185 --- /dev/null +++ b/FruitMachine/AppleII/Peripherals/Peripheral.swift @@ -0,0 +1,14 @@ +// +// Peripheral.swift +// FruitMachine +// +// Created by Christopher Rohl on 8/2/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +protocol Peripheral { + var slotNumber: Int { get } + func installOverrides() +} diff --git a/FruitMachine/AppleII/SoftswitchOverrides.swift b/FruitMachine/AppleII/SoftswitchOverrides.swift index 53e5b87..6449ee9 100644 --- a/FruitMachine/AppleII/SoftswitchOverrides.swift +++ b/FruitMachine/AppleII/SoftswitchOverrides.swift @@ -13,7 +13,7 @@ extension AppleII { class SoftswitchOverrides: NSObject { /* Keyboard port */ static let readKeyboard = ReadOverride(start: 0xC000, end: 0xC000, readAnyway: false, action: SoftswitchOverrides.actionReadKeyboard) - static func actionReadKeyboard(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionReadKeyboard(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { //let b = CPU.sharedInstance.memoryInterface.readByte(offset: 0xC000, bypassOverrides: true) //CPU.sharedInstance.memoryInterface.writeByte(offset: 0xC000, value: b) //return b @@ -22,7 +22,7 @@ extension AppleII { static let clearKeypressStrobeR = ReadOverride(start: 0xC010, end: 0xC010, readAnyway: false, action: SoftswitchOverrides.actionClearKeypressStrobe) static let clearKeypressStrobeW = WriteOverride(start: 0xC010, end: 0xC010, writeAnyway: false, action: SoftswitchOverrides.actionClearKeypressStrobe) - static func actionClearKeypressStrobe(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionClearKeypressStrobe(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { //Clears b7 of $C000 on write. //let b = CPU.sharedInstance.memoryInterface.readByte(offset: 0xC000, bypassOverrides: true) @@ -39,56 +39,56 @@ extension AppleII { /* Video settings */ static let switchC050R = ReadOverride(start: 0xC050, end: 0xC050, readAnyway: false, action: SoftswitchOverrides.actionSwitchC050) static let switchC050W = WriteOverride(start: 0xC050, end: 0xC050, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC050) - static func actionSwitchC050(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC050(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.TEXT_MODE = false return 0x00 } static let switchC051R = ReadOverride(start: 0xC051, end: 0xC051, readAnyway: false, action: SoftswitchOverrides.actionSwitchC051) static let switchC051W = WriteOverride(start: 0xC051, end: 0xC051, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC051) - static func actionSwitchC051(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC051(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.TEXT_MODE = true return 0x00 } static let switchC052R = ReadOverride(start: 0xC052, end: 0xC052, readAnyway: false, action: SoftswitchOverrides.actionSwitchC052) static let switchC052W = WriteOverride(start: 0xC052, end: 0xC052, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC052) - static func actionSwitchC052(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC052(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.MIX_MODE = false return 0x00 } static let switchC053R = ReadOverride(start: 0xC053, end: 0xC053, readAnyway: false, action: SoftswitchOverrides.actionSwitchC053) static let switchC053W = WriteOverride(start: 0xC053, end: 0xC053, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC053) - static func actionSwitchC053(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC053(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.MIX_MODE = true return 0x00 } static let switchC054R = ReadOverride(start: 0xC054, end: 0xC054, readAnyway: false, action: SoftswitchOverrides.actionSwitchC054) static let switchC054W = WriteOverride(start: 0xC054, end: 0xC054, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC054) - static func actionSwitchC054(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC054(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.PAGE_2 = false return 0x00 } static let switchC055R = ReadOverride(start: 0xC055, end: 0xC055, readAnyway: false, action: SoftswitchOverrides.actionSwitchC055) static let switchC055W = WriteOverride(start: 0xC055, end: 0xC055, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC055) - static func actionSwitchC055(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC055(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.MIX_MODE = true return 0x00 } static let switchC056R = ReadOverride(start: 0xC056, end: 0xC056, readAnyway: false, action: SoftswitchOverrides.actionSwitchC056) static let switchC056W = WriteOverride(start: 0xC056, end: 0xC056, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC056) - static func actionSwitchC056(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC056(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.HIRES_MODE = false return 0x00 } static let switchC057R = ReadOverride(start: 0xC057, end: 0xC057, readAnyway: false, action: SoftswitchOverrides.actionSwitchC057) static let switchC057W = WriteOverride(start: 0xC057, end: 0xC057, writeAnyway: false, action: SoftswitchOverrides.actionSwitchC057) - static func actionSwitchC057(dummy: AnyObject, byte: UInt8?) -> UInt8? { + static func actionSwitchC057(dummy: AnyObject, address: UInt16, byte: UInt8?) -> UInt8? { AppleII.sharedInstance.videoSoftswitches.HIRES_MODE = true return 0x00 } diff --git a/FruitMachine/AppleII/Video/A2CharacterGenerator.swift b/FruitMachine/AppleII/Video/A2CharacterGenerator.swift index d17422c..864c561 100644 --- a/FruitMachine/AppleII/Video/A2CharacterGenerator.swift +++ b/FruitMachine/AppleII/Video/A2CharacterGenerator.swift @@ -12,19 +12,18 @@ extension AppleII { //The Apple II character generator is a clone of the Signetics 2513 from the Apple I. - class A2CharacterGenerator: NSObject { + class A2CharacterGenerator: NSObject, HasROM { static let CHAR_WIDTH = 5 static let CHAR_HEIGHT = 8 - var ROM: [UInt8] var glyphs: [Glyph] + var romManager: ROMManager init(romPath: String) { - ROM = [UInt8](repeating: 0xCC, count: 0x800) + romManager = ROMManager(path: romPath, atAddress: 0x00, size: 0x800) glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsLE555.PixelData]()), count: 64) super.init() - loadROM(path: romPath) for index in 0..<64 { glyphs[index] = Glyph(inPixels: getCharacterPixels(charIndex: UInt8(index))) @@ -39,7 +38,7 @@ extension AppleII { //Don't convert the character indexes if we're populating the glyphs array. for scanlineIndex in 0.. 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) - } - } } } diff --git a/FruitMachine/AppleII/Video/Modes/LoresMode.swift b/FruitMachine/AppleII/Video/Modes/LoresMode.swift new file mode 100644 index 0000000..1dd6dfc --- /dev/null +++ b/FruitMachine/AppleII/Video/Modes/LoresMode.swift @@ -0,0 +1,48 @@ +// +// LoresMode.swift +// FruitMachine +// +// Created by Christopher Rohl on 8/2/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +extension AppleII { + + class LoresMode: NSObject { + static func putLoresPixel(buffer: UnsafeMutablePointer?, pixel: UInt8, address: UInt16) { + let pageOffset = address - 0x400 + let pixelPosition = VideoHelpers.getPixelOffset(memoryOffset: Int(pageOffset)) + if(pixelPosition.x == -1 && pixelPosition.y == -1) { + return + } + + let pixelNybbleHi = pixel & 0x0F + let pixelNybbleLo = (pixel & 0xF0) >> 4 + + let colorHi = AppleII.LoresColors.getColor(index: pixelNybbleHi) + let colorLo = LoresColors.getColor(index: pixelNybbleLo) + + //One lores pixel is 7px wide and 4px tall for a resolution of 40x48. + let baseOffset = AppleII.sharedInstance.emulatorViewDelegate.scanlineOffsets[Int(pixelPosition.y)] + Int(pixelPosition.x) + + for charY in 0..<5 { + let offsetHi = baseOffset + (AppleII.ScreenDelegate.PIXEL_WIDTH * charY) + + for charX in 0..<7 { + buffer![offsetHi + 6 - charX] = colorHi + } + } + for charY in 4..<8 { + let offsetLo = baseOffset + (AppleII.ScreenDelegate.PIXEL_WIDTH * charY) + + for charX in 0..<7 { + buffer![offsetLo + 6 - charX] = colorLo + } + } + + } + } + +} diff --git a/FruitMachine/AppleII/Video/Modes/TextMode.swift b/FruitMachine/AppleII/Video/Modes/TextMode.swift new file mode 100644 index 0000000..b41ac24 --- /dev/null +++ b/FruitMachine/AppleII/Video/Modes/TextMode.swift @@ -0,0 +1,53 @@ +// +// TextMode.swift +// FruitMachine +// +// Created by Christopher Rohl on 8/2/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +extension AppleII { + + class TextMode: NSObject { + static func putGlyph(buffer: UnsafeMutablePointer?, glyph: Glyph, attributes: UInt8, pixelPosition: CGPoint) { + //You better have locked the buffer before getting here... + if(pixelPosition.x == -1 && pixelPosition.y == -1) { return } + + let ca: CharacterAttributes + if(attributes == 0x00) { + ca = .inverse + } else if(attributes == 0x40) { + ca = .flashing + } else { + ca = .normal + } + + //Calculate the offset to reach the desired position. + let baseOffset = AppleII.sharedInstance.emulatorViewDelegate.scanlineOffsets[Int(pixelPosition.y)] + Int(pixelPosition.x) + + for charY in 0..?, glyph: Glyph, attributes: UInt8, pixelPosition: CGPoint) { - //You better have locked the buffer before getting here... - if(pixelPosition.x == -1 && pixelPosition.y == -1) { return } - - let ca: CharacterAttributes - if(attributes == 0x00) { - ca = .inverse - } else if(attributes == 0x40) { - ca = .flashing - } else { - ca = .normal - } - - //Calculate the offset to reach the desired position. - let baseOffset = scanlineOffsets[Int(pixelPosition.y)] + Int(pixelPosition.x) - - for charY in 0..?, pixel: UInt8, address: UInt16) { - let pageOffset = address - 0x400 - let pixelPosition = getPixelOffset(memoryOffset: Int(pageOffset)) - if(pixelPosition.x == -1 && pixelPosition.y == -1) { - return - } - - let pixelNybbleHi = pixel & 0x0F - let pixelNybbleLo = (pixel & 0xF0) >> 4 - - let colorHi = LoresColors.getColor(index: pixelNybbleHi) - let colorLo = LoresColors.getColor(index: pixelNybbleLo) - - //One lores pixel is 7px wide and 4px tall for a resolution of 40x48. - let baseOffset = scanlineOffsets[Int(pixelPosition.y)] + Int(pixelPosition.x) - - for charY in 0..<5 { - let offsetHi = baseOffset + (AppleII.ScreenDelegate.PIXEL_WIDTH * charY) - - for charX in 0..<7 { - buffer![offsetHi + 6 - charX] = colorHi - } - } - for charY in 4..<8 { - let offsetLo = baseOffset + (AppleII.ScreenDelegate.PIXEL_WIDTH * charY) - - for charX in 0..<7 { - buffer![offsetLo + 6 - charX] = colorLo - } - } - - } - - func getPixelOffset(charCellX: Int, charCellY: Int) -> CGPoint { - return CGPoint(x: charCellX * 7, y: charCellY * 8) - } - - func getPixelOffset(memoryOffset: Int) -> CGPoint { - //Offset is between 0x000 and 0x3FF. - //If offset & 0x28, second batch. - //If offset & 0x50, third batch. - //Else, first batch. - - var rowNumber = memoryOffset / 0x80 - let lowByte = memoryOffset & 0x0FF - let cellX: Int - - if(0x28 ... 0x4F ~= lowByte || 0xA8 ... 0xCF ~= lowByte) { - //Middle third. - rowNumber += 8 - cellX = (lowByte & ~(0x80)) - 0x28 - } - else if(0x50 ... 0x77 ~= lowByte || 0xD0 ... 0xF7 ~= lowByte) { - //Bottom third. - rowNumber += 16 - cellX = (lowByte & ~(0x80)) - 0x50 - } - else if(0x78 ... 0x7F ~= lowByte || 0xF8 ... 0xFF ~= lowByte) { - //Discard. - return CGPoint(x: -1, y: -1) - } - else { - //Top third. - rowNumber += 0 - cellX = (lowByte & ~(0x80)) - } - - return getPixelOffset(charCellX: cellX, charCellY: rowNumber) - } - /* Draw the screen. */ func draw(_ layer: CALayer, in ctx: CGContext) { CVPixelBufferLockBaseAddress(pixels!, CVPixelBufferLockFlags.readOnly) diff --git a/FruitMachine/AppleII/Video/VideoHelpers.swift b/FruitMachine/AppleII/Video/VideoHelpers.swift new file mode 100644 index 0000000..a3990cd --- /dev/null +++ b/FruitMachine/AppleII/Video/VideoHelpers.swift @@ -0,0 +1,50 @@ +// +// VideoHelpers.swift +// FruitMachine +// +// Created by Christopher Rohl on 8/2/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +extension AppleII { + class VideoHelpers: NSObject { + static func getPixelOffset(charCellX: Int, charCellY: Int) -> CGPoint { + return CGPoint(x: charCellX * 7, y: charCellY * 8) + } + + static func getPixelOffset(memoryOffset: Int) -> CGPoint { + //Offset is between 0x000 and 0x3FF. + //If offset & 0x28, second batch. + //If offset & 0x50, third batch. + //Else, first batch. + + var rowNumber = memoryOffset / 0x80 + let lowByte = memoryOffset & 0x0FF + let cellX: Int + + if(0x28 ... 0x4F ~= lowByte || 0xA8 ... 0xCF ~= lowByte) { + //Middle third. + rowNumber += 8 + cellX = (lowByte & ~(0x80)) - 0x28 + } + else if(0x50 ... 0x77 ~= lowByte || 0xD0 ... 0xF7 ~= lowByte) { + //Bottom third. + rowNumber += 16 + cellX = (lowByte & ~(0x80)) - 0x50 + } + else if(0x78 ... 0x7F ~= lowByte || 0xF8 ... 0xFF ~= lowByte) { + //Discard. + return CGPoint(x: -1, y: -1) + } + else { + //Top third. + rowNumber += 0 + cellX = (lowByte & ~(0x80)) + } + + return getPixelOffset(charCellX: cellX, charCellY: rowNumber) + } + } +} diff --git a/FruitMachine/AppleIIViewController.swift b/FruitMachine/AppleIIViewController.swift index f661845..3f4cb5c 100644 --- a/FruitMachine/AppleIIViewController.swift +++ b/FruitMachine/AppleIIViewController.swift @@ -54,8 +54,17 @@ class AppleIIViewController: NSViewController { } override func keyDown(with event: NSEvent) { + let leftArrowKeyCode = 123 + let rightArrowKeyCode = 124 + let c = returnChar(theEvent: event) + if(event.keyCode == leftArrowKeyCode) { + computer.keyboardController.KEYBOARD = UInt8((0x08 | 0x80) & 0x000000FF) + } else if(event.keyCode == rightArrowKeyCode) { + computer.keyboardController.KEYBOARD = UInt8((0x15 | 0x80) & 0x000000FF) + } + guard let ascii32 = c?.asciiValue else { return } diff --git a/FruitMachine/Common/Memory/ROMManager.swift b/FruitMachine/Common/Memory/ROMManager.swift new file mode 100644 index 0000000..cd13037 --- /dev/null +++ b/FruitMachine/Common/Memory/ROMManager.swift @@ -0,0 +1,33 @@ +// +// HasROM.swift +// FruitMachine +// +// Created by Christopher Rohl on 8/2/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Foundation + +protocol HasROM { + var romManager: ROMManager { get } +} + +protocol ROMDelegate { + var ROM: [UInt8] { get } + init(path: String, atAddress: UInt16, size: Int) +} + +class ROMManager: ROMDelegate { + var ROM: [UInt8] + + required init(path: String, atAddress: UInt16, size: Int) { + ROM = [UInt8](repeating: 0xCC, count: size) + + do { + let fileContent: NSData = try NSData(contentsOfFile: path) + fileContent.getBytes(&ROM, range: NSRange(location: Int(atAddress), length: size)) + } catch { + print(error) + } + } +} diff --git a/FruitMachine/M6502/Memory/MemoryInterface.swift b/FruitMachine/M6502/Memory/MemoryInterface.swift index ec3ffc8..ab2eb6b 100644 --- a/FruitMachine/M6502/Memory/MemoryInterface.swift +++ b/FruitMachine/M6502/Memory/MemoryInterface.swift @@ -37,7 +37,7 @@ final class MemoryInterface: NSObject { if(!bypassOverrides) { for override in read_overrides { if case override.rangeStart ... override.rangeEnd = offset { - let readValue = override.action(CPU.sharedInstance, nil) + let readValue = override.action(CPU.sharedInstance, offset, nil) if(!override.doRead) { return readValue! } @@ -59,7 +59,7 @@ final class MemoryInterface: NSObject { if(!bypassOverrides) { for override in write_overrides { if case override.rangeStart ... override.rangeEnd = offset { - _ = override.action(CPU.sharedInstance, value) + _ = override.action(CPU.sharedInstance, offset, value) if(!override.doWrite) { return } diff --git a/FruitMachine/M6502/Memory/MemoryOverride.swift b/FruitMachine/M6502/Memory/MemoryOverride.swift index 69416a7..b133de2 100644 --- a/FruitMachine/M6502/Memory/MemoryOverride.swift +++ b/FruitMachine/M6502/Memory/MemoryOverride.swift @@ -12,9 +12,9 @@ class MemoryOverride: NSObject { let rangeStart: UInt16 let rangeEnd: UInt16 - let action: (CPU, UInt8?) -> UInt8? + let action: (CPU, UInt16, UInt8?) -> UInt8? - init(start: UInt16, end: UInt16, action: @escaping (AnyObject, UInt8?) -> UInt8?) { + init(start: UInt16, end: UInt16, action: @escaping (AnyObject, UInt16, UInt8?) -> UInt8?) { rangeStart = start rangeEnd = end diff --git a/FruitMachine/M6502/Memory/ReadOverride.swift b/FruitMachine/M6502/Memory/ReadOverride.swift index 845d19e..0c6de59 100644 --- a/FruitMachine/M6502/Memory/ReadOverride.swift +++ b/FruitMachine/M6502/Memory/ReadOverride.swift @@ -14,7 +14,7 @@ import Cocoa final class ReadOverride: MemoryOverride { let doRead: Bool //do we write anyway? - init(start: UInt16, end: UInt16, readAnyway: Bool, action: @escaping (AnyObject, UInt8?) -> UInt8?) { + init(start: UInt16, end: UInt16, readAnyway: Bool, action: @escaping (AnyObject, UInt16, UInt8?) -> UInt8?) { doRead = readAnyway super.init(start: start, end: end, action: action) } diff --git a/FruitMachine/M6502/Memory/WriteOverride.swift b/FruitMachine/M6502/Memory/WriteOverride.swift index d021fb9..c62652f 100644 --- a/FruitMachine/M6502/Memory/WriteOverride.swift +++ b/FruitMachine/M6502/Memory/WriteOverride.swift @@ -14,7 +14,7 @@ import Cocoa final class WriteOverride: MemoryOverride { let doWrite: Bool //do we write anyway? - init(start: UInt16, end: UInt16, writeAnyway: Bool, action: @escaping (AnyObject, UInt8?) -> UInt8?) { + init(start: UInt16, end: UInt16, writeAnyway: Bool, action: @escaping (AnyObject, UInt16, UInt8?) -> UInt8?) { doWrite = writeAnyway super.init(start: start, end: end, action: action) } diff --git a/FruitMachine/M6502/Opcodes/Opcodes.swift b/FruitMachine/M6502/Opcodes/Opcodes.swift index a8bd065..6237706 100644 --- a/FruitMachine/M6502/Opcodes/Opcodes.swift +++ b/FruitMachine/M6502/Opcodes/Opcodes.swift @@ -142,9 +142,6 @@ fileprivate func hex2bcd(hex: UInt8) -> UInt8 { final class Opcodes: NSObject { static func _Add(state: CPU, operand: UInt8, isSubtract: Bool) { - if((state.accumulator == 0xFF) && operand == 0x01 && state.status_register.carry == false) { - _ = 1 - } var t16: UInt16 = UInt16(state.accumulator) &+ UInt16(operand) + UInt16((state.status_register.carry ? UInt8(1) : UInt8(0))) let t8: UInt8 = UInt8(t16 & 0xFF) diff --git a/FruitMachine/PreferencesWindow.xib b/FruitMachine/PreferencesWindow.xib index 97b6d32..4821d7a 100644 --- a/FruitMachine/PreferencesWindow.xib +++ b/FruitMachine/PreferencesWindow.xib @@ -32,12 +32,12 @@ - + - + @@ -131,6 +131,18 @@ + + + + + + + + + + + +