low res graphics!

This commit is contained in:
Luigi Thirty 2017-08-02 18:54:50 -04:00
parent 5e6ae41c86
commit d0c22b09eb
15 changed files with 327 additions and 70 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,7 +74,7 @@ class DebuggerViewController: NSViewController {
isRunning = true
cpuInstance.cycles = 0
cpuInstance.cyclesInBatch = 10000
cpuInstance.cyclesInBatch = 1000000
while(!cpuInstance.outOfCycles() && isRunning) {
cpuInstance.cpuStep()

View File

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