mirror of
https://github.com/Luigi30/FruitMachine-Swift.git
synced 2025-01-18 01:29:50 +00:00
apple II boots to monitor and BASIC starts but doesn't run programs
This commit is contained in:
parent
caad9c6ff6
commit
16ad485931
@ -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 */,
|
||||
|
@ -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))
|
||||
|
36
FruitMachine/AppleII/SoftswitchOverrides.swift
Normal file
36
FruitMachine/AppleII/SoftswitchOverrides.swift
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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. */
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class DebuggerViewController: NSViewController {
|
||||
isRunning = true
|
||||
|
||||
cpuInstance.cycles = 0
|
||||
cpuInstance.cyclesInBatch = 1000000
|
||||
cpuInstance.cyclesInBatch = 10000
|
||||
|
||||
while(!cpuInstance.outOfCycles() && isRunning) {
|
||||
cpuInstance.cpuStep()
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user