apple II boots to monitor and BASIC starts but doesn't run programs

This commit is contained in:
Luigi Thirty 2017-08-01 17:40:01 -04:00
parent caad9c6ff6
commit 16ad485931
7 changed files with 138 additions and 11 deletions

View File

@ -15,6 +15,7 @@
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 */; };
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 */; };
2A6DC7ED1F30492C0066FE0D /* ScreenDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */; };
@ -54,6 +55,7 @@
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>"; };
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>"; };
2A6DC7EC1F30492C0066FE0D /* ScreenDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenDelegate.swift; sourceTree = "<group>"; };
@ -161,6 +163,7 @@
children = (
2A6DC7EE1F30492E0066FE0D /* Video */,
2AB6CACC1F3041A200DECAC0 /* AppleII.swift */,
2A6C2D161F31216700B8DC60 /* SoftswitchOverrides.swift */,
);
path = AppleII;
sourceTree = "<group>";
@ -337,6 +340,7 @@
buildActionMask = 2147483647;
files = (
2A60851E1F2AFAE900E05B64 /* PIA.swift in Sources */,
2A6C2D171F31216700B8DC60 /* SoftswitchOverrides.swift in Sources */,
2A5C5BBE1F304D4B00ED351D /* Glyph.swift in Sources */,
2A2126841F2A9FA300E43DC1 /* DebuggerWindowController.swift in Sources */,
2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */,

View File

@ -11,6 +11,8 @@ import Cocoa
class AppleII: NSObject, EmulatedSystem {
static let sharedInstance = AppleII(cpuFrequency: (14.31818 / 7 / 2) * 1000000, fps: 60.0)
var frameCounter: Int = 0
let cg = A2CharacterGenerator(romPath: "/Users/luigi/apple2/a2.chr");
var CPU_FREQUENCY: Double
@ -51,10 +53,17 @@ class AppleII: NSObject, EmulatedSystem {
}
func installOverrides() {
//TODO
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.readKeyboard)
CPU.sharedInstance.memoryInterface.read_overrides.append(SoftswitchOverrides.clearKeypressStrobeR)
CPU.sharedInstance.memoryInterface.write_overrides.append(SoftswitchOverrides.clearKeypressStrobeW)
}
func runFrame() {
frameCounter = (frameCounter + 1) % 60
if(frameCounter % 15) == 0 {
emulatorViewDelegate.flashIsInverse = !emulatorViewDelegate.flashIsInverse
}
CPU.sharedInstance.cycles = 0
CPU.sharedInstance.cyclesInBatch = CYCLES_PER_BATCH
CPU.sharedInstance.runCyclesBatch()
@ -66,12 +75,13 @@ class AppleII: NSObject, EmulatedSystem {
let buf = pixelBase?.assumingMemoryBound(to: BitmapPixelsBE555.PixelData.self)
//Text mode: Get character codes from $0400-$07FF
for address in 0x0400 ..< 0x07C0 {
for address in 0x0400 ..< 0x07F8 {
let charCode = CPU.sharedInstance.memoryInterface.readByte(offset: UInt16(address), bypassOverrides: true)
emulatorViewDelegate.putGlyph(buffer: buf,
glyph: cg.glyphs[Int(charCode & ~(0x80))],
pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: address - 0x400))
glyph: cg.glyphs[Int(charCode & 0x3F)],
attributes: charCode & 0xC0, //d6 and d7
pixelPosition: emulatorViewDelegate.getPixelOffset(memoryOffset: address - 0x400))
}
CVPixelBufferUnlockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))

View File

@ -0,0 +1,36 @@
//
// SoftswitchOverrides.swift
// FruitMachine
//
// Created by Christopher Rohl on 8/1/17.
// Copyright © 2017 Christopher Rohl. All rights reserved.
//
import Cocoa
extension AppleII {
class SoftswitchOverrides: NSObject {
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)
CPU.sharedInstance.memoryInterface.writeByte(offset: 0xC000, value: b)
return b
}
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? {
//Clears b7 of $C000 on write.
let b = CPU.sharedInstance.memoryInterface.readByte(offset: 0xC000, bypassOverrides: true)
CPU.sharedInstance.memoryInterface.writeByte(offset: 0xC000, value: b & 0x7F, bypassOverrides: true)
//CPU.sharedInstance.memoryInterface.writeByte(offset: 0xC010, value: b & 0x7F, bypassOverrides: true)
return b
}
}
}

View File

@ -10,6 +10,12 @@ import Cocoa
extension AppleII {
enum CharacterAttributes {
case normal
case flashing
case inverse
}
class ScreenDelegate: NSObject, CALayerDelegate {
static let PIXEL_WIDTH = 280
static let PIXEL_HEIGHT = 192
@ -18,6 +24,8 @@ extension AppleII {
static let CELLS_HEIGHT = 24
static let CELLS_COUNT = CELLS_WIDTH * CELLS_HEIGHT
var flashIsInverse = false
/* Pixel data stuff. */
let bitmapInfo: CGBitmapInfo = [.byteOrder16Big, CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue)]
@ -46,8 +54,18 @@ extension AppleII {
}
}
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsBE555.PixelData>?, glyph: Glyph, pixelPosition: CGPoint) {
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsBE555.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)
@ -57,7 +75,19 @@ extension AppleII {
let glyphOffsetY = (charY * 8)
for charX in 0..<7 {
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
switch(ca) {
case .normal:
buffer![offset + 6 - charX] = glyph.pixels[glyphOffsetY + charX]
case .inverse:
buffer![offset + 6 - charX] = BitmapPixelsBE555.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)
}
}
}
}
}
@ -66,8 +96,37 @@ extension AppleII {
return CGPoint(x: charCellX * 7, y: charCellY * 8)
}
func getPixelOffset(charCellIndex: Int) -> CGPoint {
return getPixelOffset(charCellX: charCellIndex % AppleII.ScreenDelegate.CELLS_WIDTH, charCellY: charCellIndex / AppleII.ScreenDelegate.CELLS_WIDTH)
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. */

View File

@ -25,7 +25,7 @@ class AppleIIViewController: NSViewController {
self.view.addSubview(computer.emulatorView)
self.frameTimer = Timer.scheduledTimer(timeInterval: 1/60,
self.frameTimer = Timer.scheduledTimer(timeInterval: 1.0/60.0,
target: self,
selector: #selector(runEmulation),
userInfo: nil,
@ -49,4 +49,23 @@ class AppleIIViewController: NSViewController {
preferencesWindowController.loadWindow()
}
override func keyDown(with event: NSEvent) {
let c = returnChar(theEvent: event)
guard let ascii32 = c?.asciiValue else {
return
}
//Poke the ASCII byte into $C000.
CPU.sharedInstance.memoryInterface.writeByte(offset: 0xC000, value: UInt8((ascii32 | 0x80) & 0x000000FF))
}
private func returnChar(theEvent: NSEvent) -> Character?{
let s: String = theEvent.characters!
for char in s{
return char
}
return nil
}
}

View File

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

View File

@ -170,7 +170,6 @@ final class Opcodes: NSObject {
var t16: UInt16 = UInt16(state.accumulator &- operand) &- UInt16((state.status_register.carry ? UInt8(0) : UInt8(1)))
let t8: UInt8 = UInt8(t16 & 0xFF)
state.cyclesInBatch = 0
state.status_register.overflow = (t8 >= 0x80 && t8 <= 0xFF)
if(state.status_register.decimal == true) {