low res graphics!
This commit is contained in:
parent
5e6ae41c86
commit
d0c22b09eb
|
@ -23,6 +23,7 @@
|
|||
2A7665781F2F05F600135518 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A7665761F2F05F600135518 /* PreferencesWindowController.swift */; };
|
||||
2A7665791F2F05F600135518 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A7665771F2F05F600135518 /* PreferencesWindow.xib */; };
|
||||
2A86FB971F316CB500AD0C68 /* KeyboardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A86FB961F316CB500AD0C68 /* KeyboardController.swift */; };
|
||||
2A86FB991F32694A00AD0C68 /* VideoModes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A86FB981F32694A00AD0C68 /* VideoModes.swift */; };
|
||||
2A91852A1F2EA84D00A9E5BE /* BitmapPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A9185291F2EA84D00A9E5BE /* BitmapPixels.swift */; };
|
||||
2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5F71F2A8889002B350F /* AppleI.swift */; };
|
||||
2AA8B5FC1F2A8EAD002B350F /* Terminal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */; };
|
||||
|
@ -64,6 +65,7 @@
|
|||
2A7665761F2F05F600135518 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
||||
2A7665771F2F05F600135518 /* PreferencesWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferencesWindow.xib; sourceTree = "<group>"; };
|
||||
2A86FB961F316CB500AD0C68 /* KeyboardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardController.swift; sourceTree = "<group>"; };
|
||||
2A86FB981F32694A00AD0C68 /* VideoModes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoModes.swift; sourceTree = "<group>"; };
|
||||
2A9185291F2EA84D00A9E5BE /* BitmapPixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitmapPixels.swift; sourceTree = "<group>"; };
|
||||
2AA8B5F71F2A8889002B350F /* AppleI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleI.swift; sourceTree = "<group>"; };
|
||||
2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Terminal.swift; sourceTree = "<group>"; };
|
||||
|
@ -144,6 +146,7 @@
|
|||
2A5C5BBB1F304C3A00ED351D /* A2CharacterGenerator.swift */,
|
||||
2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */,
|
||||
2A6DC7EF1F30495D0066FE0D /* ScreenView.swift */,
|
||||
2A86FB981F32694A00AD0C68 /* VideoModes.swift */,
|
||||
);
|
||||
path = Video;
|
||||
sourceTree = "<group>";
|
||||
|
@ -374,6 +377,7 @@
|
|||
2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */,
|
||||
2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */,
|
||||
2AD458DF1F205F4500F05121 /* CPU.swift in Sources */,
|
||||
2A86FB991F32694A00AD0C68 /* VideoModes.swift in Sources */,
|
||||
2A6DC7E91F3045280066FE0D /* AppleIIViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -67,7 +67,7 @@ class AppleI: NSObject, EmulatedSystem {
|
|||
//update the video display
|
||||
CVPixelBufferLockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
let pixelBase = CVPixelBufferGetBaseAddress(emulatorViewDelegate.pixels!)
|
||||
let buf = pixelBase?.assumingMemoryBound(to: BitmapPixelsBE555.PixelData.self)
|
||||
let buf = pixelBase?.assumingMemoryBound(to: BitmapPixelsLE555.PixelData.self)
|
||||
|
||||
for (cellNum, character) in terminal.characters.enumerated() {
|
||||
emulatorViewDelegate.putGlyph(buffer: buf,
|
||||
|
|
|
@ -40,7 +40,7 @@ class AppleIBitmapDisplay: NSObject, CALayerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsBE555.PixelData>?, glyph: Glyph, pixelPosition: CGPoint) {
|
||||
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsLE555.PixelData>?, glyph: Glyph, pixelPosition: CGPoint) {
|
||||
//You better have locked the buffer before getting here...
|
||||
|
||||
//Calculate the offset to reach the desired position.
|
||||
|
@ -72,10 +72,10 @@ class AppleIBitmapDisplay: NSObject, CALayerDelegate {
|
|||
|
||||
renderedImage = CGImage(width: AppleIBitmapDisplay.PIXEL_WIDTH,
|
||||
height: AppleIBitmapDisplay.PIXEL_HEIGHT,
|
||||
bitsPerComponent: Int(BitmapPixelsBE555.bitsPerComponent), //5
|
||||
bitsPerPixel: Int(BitmapPixelsBE555.bitsPerPixel), //16
|
||||
bytesPerRow: AppleIBitmapDisplay.PIXEL_WIDTH * Int(MemoryLayout<BitmapPixelsBE555.PixelData>.size),
|
||||
space: BitmapPixelsBE555.colorSpace, //RGB
|
||||
bitsPerComponent: Int(BitmapPixelsLE555.bitsPerComponent), //5
|
||||
bitsPerPixel: Int(BitmapPixelsLE555.bitsPerPixel), //16
|
||||
bytesPerRow: AppleIBitmapDisplay.PIXEL_WIDTH * Int(MemoryLayout<BitmapPixelsLE555.PixelData>.size),
|
||||
space: BitmapPixelsLE555.colorSpace, //RGB
|
||||
bitmapInfo: bitmapInfo, //BE555
|
||||
provider: pixelRef!,
|
||||
decode: nil,
|
||||
|
|
|
@ -21,7 +21,7 @@ extension AppleI {
|
|||
|
||||
init(romPath: String) {
|
||||
ROM = [UInt8](repeating: 0xCC, count: 512)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsBE555.PixelData]()), count: 64)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsLE555.PixelData]()), count: 64)
|
||||
|
||||
super.init()
|
||||
loadROM(path: romPath)
|
||||
|
@ -40,7 +40,7 @@ extension AppleI {
|
|||
}
|
||||
}
|
||||
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsBE555.PixelData] {
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsLE555.PixelData] {
|
||||
var pixelArray = [UInt8](repeating: 0x00, count: A1CharacterGenerator.CHAR_HEIGHT)
|
||||
|
||||
/* Instead of ignoring ASCII bit b6, we ignore bit b5. At the same time ASCII bit b6 must be inverted before it is fed to the character ROM. This way the entire character range from $40 to $7F will end up in the range $00 to $1F (twice of course). Now lower case characters are automatically translated into their corresponding upper case bit maps.
|
||||
|
@ -51,11 +51,11 @@ extension AppleI {
|
|||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * A1CharacterGenerator.CHAR_HEIGHT)]
|
||||
}
|
||||
|
||||
var glyphPixels = [BitmapPixelsBE555.PixelData]()
|
||||
var glyphPixels = [BitmapPixelsLE555.PixelData]()
|
||||
|
||||
for charY in 0..<A1CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<8 {
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsBE555.White : BitmapPixelsBE555.Black)
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsLE555.White : BitmapPixelsLE555.Black)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ class AppleII: NSObject, EmulatedSystem {
|
|||
|
||||
let cg = A2CharacterGenerator(romPath: "/Users/luigi/apple2/a2.chr");
|
||||
let keyboardController = KeyboardController()
|
||||
var videoSoftswitches = VideoSoftswitches()
|
||||
var videoMode: VideoMode
|
||||
|
||||
var CPU_FREQUENCY: Double
|
||||
var FRAMES_PER_SECOND: Double
|
||||
|
@ -28,6 +30,9 @@ class AppleII: NSObject, EmulatedSystem {
|
|||
CPU_FREQUENCY = cpuFrequency
|
||||
FRAMES_PER_SECOND = fps
|
||||
CYCLES_PER_BATCH = Int(cpuFrequency / fps)
|
||||
|
||||
videoMode = .Text
|
||||
|
||||
super.init()
|
||||
|
||||
loadROMs()
|
||||
|
@ -48,23 +53,40 @@ class AppleII: NSObject, EmulatedSystem {
|
|||
}
|
||||
|
||||
func doReset() {
|
||||
videoSoftswitches.reset()
|
||||
videoMode = .Text
|
||||
CPU.sharedInstance.performReset()
|
||||
}
|
||||
|
||||
func loadROMs() {
|
||||
/*
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0001-00.e0", offset: 0xE000, length: 0x800)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0002-00.e8", offset: 0xE800, length: 0x800)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0003-00.f0", offset: 0xF000, length: 0x800)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple2/341-0004-00.f8", offset: 0xF800, length: 0x800)
|
||||
*/
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/6502/test.bin", offset: 0x0000, length: 0x10000)
|
||||
}
|
||||
|
||||
func 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)
|
||||
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC050R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC051R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC052R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC053R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC054R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC055R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC056R)
|
||||
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.switchC057R)
|
||||
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC050W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC051W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC052W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC053W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC054W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC055W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC056W)
|
||||
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.switchC057W)
|
||||
}
|
||||
|
||||
func runFrame() {
|
||||
|
@ -77,25 +99,65 @@ class AppleII: NSObject, EmulatedSystem {
|
|||
CPU.sharedInstance.cyclesInBatch = CYCLES_PER_BATCH
|
||||
CPU.sharedInstance.runCyclesBatch()
|
||||
|
||||
//TODO
|
||||
//update the video display
|
||||
CVPixelBufferLockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
let pixelBase = CVPixelBufferGetBaseAddress(emulatorViewDelegate.pixels!)
|
||||
let buf = pixelBase?.assumingMemoryBound(to: BitmapPixelsBE555.PixelData.self)
|
||||
let buf = pixelBase?.assumingMemoryBound(to: BitmapPixelsLE555.PixelData.self)
|
||||
|
||||
//Text mode: Get character codes from $0400-$07FF
|
||||
for address in 0x0400 ..< 0x07F8 {
|
||||
let charCode = CPU.sharedInstance.memoryInterface.readByte(offset: UInt16(address), bypassOverrides: true)
|
||||
videoMode = getCurrentVideoMode(switches: videoSoftswitches)
|
||||
|
||||
if(videoMode == .Text)
|
||||
{
|
||||
//Text mode: Get character codes from $0400-$07FF
|
||||
putGlyphs(buffer: buf!, start: 0x400, end: 0x7F8)
|
||||
}
|
||||
else if(videoMode == .Lores)
|
||||
{
|
||||
putLoresPixels(buffer: buf!, start: 0x400, end: 0x7F8)
|
||||
}
|
||||
else if(videoMode == .MixedLores) {
|
||||
//Draw the lores pixel rows.
|
||||
putLoresPixels(buffer: buf!, start: 0x400, end: 0x650)
|
||||
putLoresPixels(buffer: buf!, start: 0x680, end: 0x6A8)
|
||||
putLoresPixels(buffer: buf!, start: 0x700, end: 0x728)
|
||||
putLoresPixels(buffer: buf!, start: 0x780, end: 0x7A8)
|
||||
putLoresPixels(buffer: buf!, start: 0x6A8, end: 0x6D0)
|
||||
putLoresPixels(buffer: buf!, start: 0x728, end: 0x750)
|
||||
putLoresPixels(buffer: buf!, start: 0x7A8, end: 0x7D0)
|
||||
|
||||
emulatorViewDelegate.putGlyph(buffer: buf,
|
||||
glyph: cg.glyphs[Int(charCode & 0x3F)],
|
||||
attributes: charCode & 0xC0, //d6 and d7
|
||||
pixelPosition: emulatorViewDelegate.getPixelOffset(memoryOffset: address - 0x400))
|
||||
//Draw the bottom 4 text rows.
|
||||
putGlyphs(buffer: buf!, start: 0x650, end: 0x678)
|
||||
putGlyphs(buffer: buf!, start: 0x6D0, end: 0x6F8)
|
||||
putGlyphs(buffer: buf!, start: 0x750, end: 0x778)
|
||||
putGlyphs(buffer: buf!, start: 0x7D0, end: 0x7F8)
|
||||
} else {
|
||||
print("Unimplemented video mode!")
|
||||
}
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
|
||||
emulatorView.setNeedsDisplay(emulatorView.frame)
|
||||
CVPixelBufferUnlockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
emulatorView.display()
|
||||
}
|
||||
|
||||
func putLoresPixels(buffer: UnsafeMutablePointer<BitmapPixelsLE555.PixelData>, start: UInt16, end: UInt16) {
|
||||
for address in start ..< end {
|
||||
let pixelData = CPU.sharedInstance.memoryInterface.readByte(offset: UInt16(address), bypassOverrides: true)
|
||||
|
||||
emulatorViewDelegate.putLoresPixel(buffer: buffer,
|
||||
pixel: pixelData,
|
||||
address: UInt16(address))
|
||||
}
|
||||
}
|
||||
|
||||
func putGlyphs(buffer: UnsafeMutablePointer<BitmapPixelsLE555.PixelData>, start: UInt16, end: UInt16) {
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
enum MemoryConfiguration {
|
||||
|
|
|
@ -11,6 +11,7 @@ import Cocoa
|
|||
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? {
|
||||
//let b = CPU.sharedInstance.memoryInterface.readByte(offset: 0xC000, bypassOverrides: true)
|
||||
|
@ -34,6 +35,63 @@ extension AppleII {
|
|||
AppleII.sharedInstance.keyboardController.STROBE = b & 0x7F
|
||||
return b
|
||||
}
|
||||
|
||||
/* 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? {
|
||||
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? {
|
||||
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? {
|
||||
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? {
|
||||
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? {
|
||||
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? {
|
||||
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? {
|
||||
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? {
|
||||
AppleII.sharedInstance.videoSoftswitches.HIRES_MODE = true
|
||||
return 0x00
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ extension AppleII {
|
|||
|
||||
init(romPath: String) {
|
||||
ROM = [UInt8](repeating: 0xCC, count: 0x800)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsBE555.PixelData]()), count: 64)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsLE555.PixelData]()), count: 64)
|
||||
|
||||
super.init()
|
||||
loadROM(path: romPath)
|
||||
|
@ -31,7 +31,7 @@ extension AppleII {
|
|||
}
|
||||
}
|
||||
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsBE555.PixelData] {
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsLE555.PixelData] {
|
||||
var pixelArray = [UInt8](repeating: 0x00, count: A2CharacterGenerator.CHAR_HEIGHT)
|
||||
|
||||
/* Instead of ignoring ASCII bit b6, we ignore bit b5. At the same time ASCII bit b6 must be inverted before it is fed to the character ROM. This way the entire character range from $40 to $7F will end up in the range $00 to $1F (twice of course). Now lower case characters are automatically translated into their corresponding upper case bit maps.
|
||||
|
@ -42,11 +42,11 @@ extension AppleII {
|
|||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * A2CharacterGenerator.CHAR_HEIGHT)]
|
||||
}
|
||||
|
||||
var glyphPixels = [BitmapPixelsBE555.PixelData]()
|
||||
var glyphPixels = [BitmapPixelsLE555.PixelData]()
|
||||
|
||||
for charY in 0..<A2CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<8 {
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsBE555.White : BitmapPixelsBE555.Black)
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsLE555.White : BitmapPixelsLE555.Black)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ extension AppleII {
|
|||
var flashIsInverse = false
|
||||
|
||||
/* Pixel data stuff. */
|
||||
let bitmapInfo: CGBitmapInfo = [.byteOrder16Big, CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue)]
|
||||
let bitmapInfo: CGBitmapInfo = [.byteOrder16Little, CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue)]
|
||||
|
||||
var pixels: CVPixelBuffer?
|
||||
|
||||
|
@ -54,7 +54,7 @@ extension AppleII {
|
|||
}
|
||||
}
|
||||
|
||||
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsBE555.PixelData>?, glyph: Glyph, attributes: UInt8, pixelPosition: CGPoint) {
|
||||
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 }
|
||||
|
||||
|
@ -79,12 +79,12 @@ extension AppleII {
|
|||
case .normal:
|
||||
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
|
||||
case .inverse:
|
||||
buffer![offset + 6 - charX] = BitmapPixelsBE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
|
||||
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] = BitmapPixelsBE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
|
||||
buffer![offset + 6 - charX] = BitmapPixelsLE555.PixelData(data: ~glyph.pixels[glyphOffsetY + charX].data)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,39 @@ extension AppleII {
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -137,10 +170,10 @@ extension AppleII {
|
|||
|
||||
renderedImage = CGImage(width: AppleII.ScreenDelegate.PIXEL_WIDTH,
|
||||
height: AppleII.ScreenDelegate.PIXEL_HEIGHT,
|
||||
bitsPerComponent: Int(BitmapPixelsBE555.bitsPerComponent), //5
|
||||
bitsPerPixel: Int(BitmapPixelsBE555.bitsPerPixel), //16
|
||||
bytesPerRow: AppleII.ScreenDelegate.PIXEL_WIDTH * Int(MemoryLayout<BitmapPixelsBE555.PixelData>.size),
|
||||
space: BitmapPixelsBE555.colorSpace, //RGB
|
||||
bitsPerComponent: Int(BitmapPixelsLE555.bitsPerComponent), //5
|
||||
bitsPerPixel: Int(BitmapPixelsLE555.bitsPerPixel), //16
|
||||
bytesPerRow: AppleII.ScreenDelegate.PIXEL_WIDTH * Int(MemoryLayout<BitmapPixelsLE555.PixelData>.size),
|
||||
space: BitmapPixelsLE555.colorSpace, //RGB
|
||||
bitmapInfo: bitmapInfo, //BE555
|
||||
provider: pixelRef!,
|
||||
decode: nil,
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// VideoModes.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 8/2/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension AppleII {
|
||||
|
||||
typealias Softswitch = Bool
|
||||
|
||||
struct VideoSoftswitches {
|
||||
var TEXT_MODE: Softswitch = false // $C050/$C051
|
||||
var MIX_MODE: Softswitch = false // $C052/$C053
|
||||
var PAGE_2: Softswitch = false // $C054/$C055
|
||||
var HIRES_MODE: Softswitch = false // $C056/$C057
|
||||
|
||||
mutating func reset() {
|
||||
TEXT_MODE = true
|
||||
MIX_MODE = false
|
||||
PAGE_2 = false
|
||||
HIRES_MODE = false
|
||||
}
|
||||
}
|
||||
|
||||
enum VideoMode {
|
||||
case Text
|
||||
case Lores
|
||||
case Hires
|
||||
case MixedLores
|
||||
case MixedHires
|
||||
}
|
||||
|
||||
struct LoresColors {
|
||||
static let Black = BitmapPixelsLE555.RGB32toLE555(r: 0, g: 0, b: 0)
|
||||
static let Magenta = BitmapPixelsLE555.RGB32toLE555(r: 227, g: 30, b: 96)
|
||||
static let DarkBlue = BitmapPixelsLE555.RGB32toLE555(r: 96, g: 78, b: 189)
|
||||
static let Purple = BitmapPixelsLE555.RGB32toLE555(r: 255, g: 68, b: 253)
|
||||
static let DarkGreen = BitmapPixelsLE555.RGB32toLE555(r: 0, g: 163, b: 96)
|
||||
static let Gray1 = BitmapPixelsLE555.RGB32toLE555(r: 156, g: 156, b: 156)
|
||||
static let MediumBlue = BitmapPixelsLE555.RGB32toLE555(r: 20, g: 207, b: 253)
|
||||
static let LightBlue = BitmapPixelsLE555.RGB32toLE555(r: 208, g: 195, b: 255)
|
||||
static let Brown = BitmapPixelsLE555.RGB32toLE555(r: 96, g: 114, b: 3)
|
||||
static let Orange = BitmapPixelsLE555.RGB32toLE555(r: 255, g: 106, b: 60)
|
||||
static let Gray2 = BitmapPixelsLE555.RGB32toLE555(r: 156, g: 156, b: 156)
|
||||
static let Pink = BitmapPixelsLE555.RGB32toLE555(r: 255, g: 160, b: 208)
|
||||
static let LightGreen = BitmapPixelsLE555.RGB32toLE555(r: 20, g: 245, b: 60)
|
||||
static let Yellow = BitmapPixelsLE555.RGB32toLE555(r: 208, g: 221, b: 141)
|
||||
static let Aquamarine = BitmapPixelsLE555.RGB32toLE555(r: 114, g: 255, b: 208)
|
||||
static let White = BitmapPixelsLE555.RGB32toLE555(r: 255, g: 255, b: 255)
|
||||
|
||||
static func getColor(index: UInt8) -> BitmapPixelsLE555.PixelData {
|
||||
switch index {
|
||||
case 0: return AppleII.LoresColors.Black
|
||||
case 1: return AppleII.LoresColors.Magenta
|
||||
case 2: return AppleII.LoresColors.DarkBlue
|
||||
case 3: return AppleII.LoresColors.Purple
|
||||
case 4: return AppleII.LoresColors.DarkGreen
|
||||
case 5: return AppleII.LoresColors.Gray1
|
||||
case 6: return AppleII.LoresColors.MediumBlue
|
||||
case 7: return AppleII.LoresColors.LightBlue
|
||||
case 8: return AppleII.LoresColors.Brown
|
||||
case 9: return AppleII.LoresColors.Orange
|
||||
case 10: return AppleII.LoresColors.Gray2
|
||||
case 11: return AppleII.LoresColors.Pink
|
||||
case 12: return AppleII.LoresColors.LightGreen
|
||||
case 13: return AppleII.LoresColors.Yellow
|
||||
case 14: return AppleII.LoresColors.Aquamarine
|
||||
case 15: return AppleII.LoresColors.White
|
||||
default:
|
||||
print("tried to get color > 15")
|
||||
return AppleII.LoresColors.Black
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func getCurrentVideoMode(switches: VideoSoftswitches) -> VideoMode {
|
||||
if(switches.TEXT_MODE == true)
|
||||
{
|
||||
return .Text
|
||||
}
|
||||
else if(switches.MIX_MODE) {
|
||||
if(switches.HIRES_MODE == false) {
|
||||
return .MixedLores
|
||||
} else {
|
||||
return .MixedHires
|
||||
}
|
||||
}
|
||||
else if(switches.HIRES_MODE) {
|
||||
return .Hires
|
||||
} else {
|
||||
return .Lores
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,15 +25,11 @@ class AppleIIViewController: NSViewController {
|
|||
|
||||
self.view.addSubview(computer.emulatorView)
|
||||
|
||||
/*
|
||||
self.frameTimer = Timer.scheduledTimer(timeInterval: 1.0/60.0,
|
||||
target: self,
|
||||
selector: #selector(runEmulation),
|
||||
userInfo: nil,
|
||||
repeats: true)
|
||||
*/
|
||||
|
||||
CPU.sharedInstance.program_counter = 0x400
|
||||
}
|
||||
|
||||
@objc func runEmulation() {
|
||||
|
|
|
@ -38,7 +38,7 @@ class BitmapPixelsARGB32 : NSObject {
|
|||
static let Black = PixelData(a: 255, r: 0, g: 0, b: 0)
|
||||
}
|
||||
|
||||
class BitmapPixelsBE555 : NSObject {
|
||||
class BitmapPixelsLE555 : NSObject {
|
||||
struct PixelData {
|
||||
var data: UInt16 = 0
|
||||
}
|
||||
|
@ -47,6 +47,19 @@ class BitmapPixelsBE555 : NSObject {
|
|||
static let bitsPerPixel: UInt = 16
|
||||
static let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
|
||||
static let White = PixelData(data: 0b1111111101111111)
|
||||
static let White = PixelData(data: 0b0111111111111111)
|
||||
static let Black = PixelData(data: 0b0000000000000000)
|
||||
|
||||
static func RGB32toLE555(r: UInt8, g: UInt8, b: UInt8) -> PixelData {
|
||||
let r5: UInt16 = UInt16(r >> 3)
|
||||
let g5: UInt16 = UInt16(g >> 3)
|
||||
let b5: UInt16 = UInt16(b >> 3)
|
||||
|
||||
var pixel = PixelData()
|
||||
pixel.data |= b5
|
||||
pixel.data |= g5 << 5
|
||||
pixel.data |= r5 << 10
|
||||
|
||||
return pixel
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
import Cocoa
|
||||
|
||||
struct Glyph {
|
||||
var pixels: [BitmapPixelsBE555.PixelData] = [BitmapPixelsBE555.PixelData]()
|
||||
var pixels: [BitmapPixelsLE555.PixelData] = [BitmapPixelsLE555.PixelData]()
|
||||
|
||||
init(inPixels: [BitmapPixelsBE555.PixelData]) {
|
||||
init(inPixels: [BitmapPixelsLE555.PixelData]) {
|
||||
pixels = inPixels
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,10 +157,10 @@
|
|||
<windowController id="0Wh-dg-gsU" sceneMemberID="viewController">
|
||||
<window key="window" title="Fruit Machine" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" frameAutosaveName="" animationBehavior="default" id="O0r-h6-7La">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
||||
<rect key="contentRect" x="293" y="264" width="640" height="360"/>
|
||||
<rect key="contentRect" x="293" y="264" width="560" height="360"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1916" height="936"/>
|
||||
<value key="minSize" type="size" width="640" height="360"/>
|
||||
<value key="maxSize" type="size" width="640" height="360"/>
|
||||
<value key="minSize" type="size" width="560" height="360"/>
|
||||
<value key="maxSize" type="size" width="560" height="360"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="0Wh-dg-gsU" id="tmJ-Ae-YJP"/>
|
||||
</connections>
|
||||
|
@ -178,7 +178,7 @@
|
|||
<objects>
|
||||
<viewController id="gw1-M7-9Je" customClass="AppleIIViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="DiY-xb-Usb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="384"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="560" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</viewController>
|
||||
|
|
|
@ -74,7 +74,7 @@ class DebuggerViewController: NSViewController {
|
|||
isRunning = true
|
||||
|
||||
cpuInstance.cycles = 0
|
||||
cpuInstance.cyclesInBatch = 10000
|
||||
cpuInstance.cyclesInBatch = 1000000
|
||||
|
||||
while(!cpuInstance.outOfCycles() && isRunning) {
|
||||
cpuInstance.cpuStep()
|
||||
|
|
|
@ -142,20 +142,21 @@ fileprivate func hex2bcd(hex: UInt8) -> UInt8 {
|
|||
final class Opcodes: NSObject {
|
||||
|
||||
static func _Add(state: CPU, operand: UInt8, isSubtract: Bool) {
|
||||
if(state.accumulator == 0xFF) {
|
||||
if((state.accumulator == 0xFF) && operand == 0x01 && state.status_register.carry == false) {
|
||||
_ = 1
|
||||
}
|
||||
var t16: UInt16 = UInt16(state.accumulator &+ operand) + UInt16((state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
var t16: UInt16 = UInt16(state.accumulator) &+ UInt16(operand) + UInt16((state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
let t8: UInt8 = UInt8(t16 & 0xFF)
|
||||
|
||||
state.status_register.overflow = (state.accumulator & 0x80) != (t8 & 0x80)
|
||||
//state.status_register.overflow = (state.accumulator & 0x80) != (t8 & 0x80)
|
||||
state.status_register.overflow = ((t16 ^ UInt16(state.accumulator)) & (t16 ^ UInt16(operand)) & 0x0080) > UInt16(0)
|
||||
state.status_register.zero = (t8 == 0)
|
||||
state.status_register.negative = (t8 & 0x80) == 0x80
|
||||
|
||||
if(state.status_register.decimal) {
|
||||
t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
} else {
|
||||
state.status_register.carry = (t16 > 255)
|
||||
state.status_register.carry = (t16 & 0xFF00) > 0
|
||||
}
|
||||
|
||||
state.accumulator = t8
|
||||
|
@ -166,25 +167,16 @@ final class Opcodes: NSObject {
|
|||
}
|
||||
|
||||
static func SBC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand = UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode))
|
||||
//I don't think this 16-bit calculation is working right
|
||||
var t16: UInt16 = UInt16(state.accumulator &- operand) &- UInt16((state.status_register.carry ? UInt8(0) : UInt8(1)))
|
||||
let t8: UInt8 = UInt8(t16 & 0xFF)
|
||||
let operand = UInt16(getOperandByteForAddressingMode(state: state, mode: addressingMode))
|
||||
|
||||
state.status_register.overflow = (t8 >= 0x80 && t8 <= 0xFF)
|
||||
let carryValue = UInt16(state.status_register.carry ? 0 : 1)
|
||||
let t16 = UInt16(state.accumulator) &- operand &- carryValue
|
||||
|
||||
if(state.status_register.decimal == true) {
|
||||
t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
} else {
|
||||
state.status_register.carry = (t16 >> 8) == 0
|
||||
//carry flag isn't being set properly
|
||||
//let signed = Int8(bitPattern: t8)
|
||||
//state.status_register.carry = ((-128 > signed) || (127 < signed)) ? true : false
|
||||
}
|
||||
|
||||
state.accumulator = t8
|
||||
state.updateZeroFlag(value: t8)
|
||||
state.updateNegativeFlag(value: t8)
|
||||
state.status_register.overflow = ((UInt16(state.accumulator) ^ operand) & (UInt16(state.accumulator) ^ t16) & 0x80) > 0
|
||||
state.status_register.carry = (t16 >> 8) == 0
|
||||
state.accumulator = UInt8(t16 & 0xFF)
|
||||
state.updateZeroFlag(value: UInt8(t16 & 0xFF))
|
||||
state.updateNegativeFlag(value: UInt8(t16 & 0xFF))
|
||||
}
|
||||
|
||||
static func LDA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
|
|
Loading…
Reference in New Issue