attached the Disk II ROM

peripherals
This commit is contained in:
Luigi Thirty 2017-08-03 00:31:12 -04:00
parent d0c22b09eb
commit ab3c32af3d
21 changed files with 364 additions and 170 deletions

View File

@ -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 = "<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>"; };
2A63C2321F32C39300D4F4F8 /* TextMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMode.swift; sourceTree = "<group>"; };
2A63C2341F32C4F700D4F4F8 /* LoresMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoresMode.swift; sourceTree = "<group>"; };
2A63C2361F32C55100D4F4F8 /* VideoHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoHelpers.swift; sourceTree = "<group>"; };
2A63C2391F32CCE900D4F4F8 /* DiskII.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskII.swift; sourceTree = "<group>"; };
2A63C23B1F32CD4800D4F4F8 /* Peripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Peripheral.swift; sourceTree = "<group>"; };
2A6C2D161F31216700B8DC60 /* SoftswitchOverrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftswitchOverrides.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>"; };
@ -83,6 +94,7 @@
2AD458E21F20661300F05121 /* CPUInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPUInstructions.swift; sourceTree = "<group>"; };
2AD458E41F2070DF00F05121 /* Opcodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Opcodes.swift; sourceTree = "<group>"; };
2AD6D5831F26E6BF008F3CF5 /* DebuggerCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerCommands.swift; sourceTree = "<group>"; };
2AE3BB961F32CEB100C11060 /* ROMManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ROMManager.swift; sourceTree = "<group>"; };
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>"; };
@ -113,9 +125,29 @@
name = Frameworks;
sourceTree = "<group>";
};
2A63C2311F32C38400D4F4F8 /* Modes */ = {
isa = PBXGroup;
children = (
2A86FB981F32694A00AD0C68 /* VideoModes.swift */,
2A63C2321F32C39300D4F4F8 /* TextMode.swift */,
2A63C2341F32C4F700D4F4F8 /* LoresMode.swift */,
);
path = Modes;
sourceTree = "<group>";
};
2A63C2381F32CCDB00D4F4F8 /* Peripherals */ = {
isa = PBXGroup;
children = (
2A63C2391F32CCE900D4F4F8 /* DiskII.swift */,
2A63C23B1F32CD4800D4F4F8 /* Peripheral.swift */,
);
path = Peripherals;
sourceTree = "<group>";
};
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 = "<group>";
@ -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 = "<group>";
};
2AE3BB981F32D24D00C11060 /* Memory */ = {
isa = PBXGroup;
children = (
2AE3BB961F32CEB100C11060 /* ROMManager.swift */,
);
path = Memory;
sourceTree = "<group>";
};
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;

View File

@ -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)

View File

@ -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..<A1CharacterGenerator.CHAR_HEIGHT {
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * A1CharacterGenerator.CHAR_HEIGHT)]
pixelArray[scanlineIndex] = romManager.ROM[scanlineIndex + (Int(charIndex) * A1CharacterGenerator.CHAR_HEIGHT)]
}
var glyphPixels = [BitmapPixelsLE555.PixelData]()

View File

@ -8,7 +8,7 @@
import Cocoa
class AppleII: NSObject, EmulatedSystem {
final class AppleII: NSObject, EmulatedSystem {
static let sharedInstance = AppleII(cpuFrequency: (14.31818 / 7 / 2) * 1000000, fps: 60.0)
var frameCounter: Int = 0
@ -18,6 +18,9 @@ class AppleII: NSObject, EmulatedSystem {
var videoSoftswitches = VideoSoftswitches()
var videoMode: VideoMode
//Peripherals
var backplane = [Int: Peripheral?]()
var CPU_FREQUENCY: Double
var FRAMES_PER_SECOND: Double
var CYCLES_PER_BATCH: Int
@ -33,10 +36,15 @@ class AppleII: NSObject, EmulatedSystem {
videoMode = .Text
for i in 1...7 {
backplane[i] = nil
}
super.init()
loadROMs()
setupMemory(ramConfig: .sixteenK)
backplane[6] = DiskII(slot: 6, romPath: "/Users/luigi/apple2/341-0027-a.p5")
emuScreenLayer.shouldRasterize = true
emuScreenLayer.delegate = emulatorViewDelegate
@ -66,6 +74,12 @@ class AppleII: NSObject, EmulatedSystem {
}
func installOverrides() {
for (slotNum, peripheral) in backplane {
if(peripheral != nil) {
peripheral!.installOverrides()
}
}
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.readKeyboard)
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.clearKeypressStrobeR)
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.clearKeypressStrobeW)
@ -143,7 +157,7 @@ class AppleII: NSObject, EmulatedSystem {
for address in start ..< end {
let pixelData = CPU.sharedInstance.memoryInterface.readByte(offset: UInt16(address), bypassOverrides: true)
emulatorViewDelegate.putLoresPixel(buffer: buffer,
LoresMode.putLoresPixel(buffer: buffer,
pixel: pixelData,
address: UInt16(address))
}
@ -153,10 +167,10 @@ class AppleII: NSObject, EmulatedSystem {
for address in start ... end {
let charCode = CPU.sharedInstance.memoryInterface.readByte(offset: UInt16(address), bypassOverrides: true)
emulatorViewDelegate.putGlyph(buffer: buffer,
glyph: cg.glyphs[Int(charCode & 0x3F)],
attributes: charCode & 0xC0, //d6 and d7
pixelPosition: emulatorViewDelegate.getPixelOffset(memoryOffset: Int(address - 0x400)))
TextMode.putGlyph(buffer: buffer,
glyph: cg.glyphs[Int(charCode & 0x3F)],
attributes: charCode & 0xC0, //d6 and d7
pixelPosition: VideoHelpers.getPixelOffset(memoryOffset: Int(address - 0x400)))
}
}

View File

@ -0,0 +1,45 @@
//
// DiskII.swift
// FruitMachine
//
// Created by Christopher Rohl on 8/2/17.
// Copyright © 2017 Christopher Rohl. All rights reserved.
//
import Cocoa
class DiskII: NSObject, Peripheral {
let slotNumber: Int
let romManager: ROMManager
var readMemoryOverride: ReadOverride? = nil
var writeMemoryOverride: WriteOverride? = nil
init(slot: Int, romPath: String) {
slotNumber = slot
romManager = ROMManager(path: romPath, atAddress: 0x0, size: 256)
super.init()
readMemoryOverride = ReadOverride(start: UInt16(0xC000 + (0x100 * slotNumber)),
end: UInt16(0xC0FF + (0x100 * slotNumber)),
readAnyway: false,
action: actionReadMemory)
}
func actionReadMemory(something: AnyObject, address: UInt16, byte: UInt8?) -> 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!)
}
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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..<A2CharacterGenerator.CHAR_HEIGHT {
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * A2CharacterGenerator.CHAR_HEIGHT)]
pixelArray[scanlineIndex] = romManager.ROM[scanlineIndex + (Int(charIndex) * A2CharacterGenerator.CHAR_HEIGHT)]
}
var glyphPixels = [BitmapPixelsLE555.PixelData]()
@ -56,15 +55,6 @@ extension AppleII {
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)
}
}
}
}

View File

@ -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<BitmapPixelsLE555.PixelData>?, 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
}
}
}
}
}

View File

@ -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<BitmapPixelsLE555.PixelData>?, 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..<AppleII.A2CharacterGenerator.CHAR_HEIGHT {
let offset = baseOffset + (AppleII.ScreenDelegate.PIXEL_WIDTH * charY)
let glyphOffsetY = (charY * 8)
for charX in 0..<7 {
switch(ca) {
case .normal:
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
case .inverse:
buffer![offset + 6 - charX] = BitmapPixelsLE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
case .flashing:
if(!AppleII.sharedInstance.emulatorViewDelegate.flashIsInverse) {
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
} else {
buffer![offset + 6 - charX] = BitmapPixelsLE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
}
}
}
}
}
}
}

View File

@ -29,6 +29,7 @@ extension AppleII {
/* Pixel data stuff. */
let bitmapInfo: CGBitmapInfo = [.byteOrder16Little, CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue)]
var scanlineOffsets: [Int]
var pixels: CVPixelBuffer?
let sourceRowBytes: Int
@ -36,8 +37,6 @@ extension AppleII {
let bufferHeight: Int
var renderedImage: CGImage?
var scanlineOffsets: [Int]
override init() {
_ = CVPixelBufferCreate(kCFAllocatorDefault, AppleII.ScreenDelegate.PIXEL_WIDTH, AppleII.ScreenDelegate.PIXEL_HEIGHT, OSType(k16BE555PixelFormat), nil, &pixels)
@ -54,114 +53,6 @@ extension AppleII {
}
}
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsLE555.PixelData>?, 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..<AppleII.A2CharacterGenerator.CHAR_HEIGHT {
let offset = baseOffset + (AppleII.ScreenDelegate.PIXEL_WIDTH * charY)
let glyphOffsetY = (charY * 8)
for charX in 0..<7 {
switch(ca) {
case .normal:
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
case .inverse:
buffer![offset + 6 - charX] = BitmapPixelsLE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
case .flashing:
if(!flashIsInverse) {
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
} else {
buffer![offset + 6 - charX] = BitmapPixelsLE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
}
}
}
}
}
func putLoresPixel(buffer: UnsafeMutablePointer<BitmapPixelsLE555.PixelData>?, 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)

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)

View File

@ -32,12 +32,12 @@
<tabViewItems>
<tabViewItem label="General" identifier="1" id="nQU-pA-pvF">
<view key="view" id="iK8-x4-ay0">
<rect key="frame" x="10" y="33" width="137" height="0.0"/>
<rect key="frame" x="10" y="33" width="554" height="208"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</tabViewItem>
<tabViewItem label="Paths" identifier="2" id="zXY-01-Th8">
<view key="view" ambiguous="YES" id="tiQ-eh-pdD">
<view key="view" id="tiQ-eh-pdD">
<rect key="frame" x="10" y="33" width="554" height="208"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -131,6 +131,18 @@
</subviews>
</view>
</tabViewItem>
<tabViewItem label="Apple I" identifier="" id="0ak-CP-2BL">
<view key="view" id="BGQ-27-4EP">
<rect key="frame" x="10" y="33" width="554" height="208"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</tabViewItem>
<tabViewItem label="Apple II" identifier="" id="aVa-m9-VEl">
<view key="view" ambiguous="YES" id="mjS-Jn-KXO">
<rect key="frame" x="10" y="33" width="554" height="208"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</tabViewItem>
</tabViewItems>
</tabView>
</subviews>