From 906fe2076159993b9a6c52d166cf4c09647e75db Mon Sep 17 00:00:00 2001 From: Luigi Thirty Date: Sat, 29 Jul 2017 02:56:06 -0400 Subject: [PATCH] why aren't view refreshing! --- FruitMachine.xcodeproj/project.pbxproj | 4 ++ FruitMachine/AppleI/AppleI.swift | 16 +++++--- FruitMachine/AppleI/PIA.swift | 20 ++++++++++ .../AppleI/Video/CharacterGenerator.swift | 15 +------- FruitMachine/AppleI/Video/PIAOverrides.swift | 38 ++++++++++++++++--- FruitMachine/AppleI/Video/Terminal.swift | 20 ++++++++-- .../Debugger/Base.lproj/Debugger.storyboard | 2 +- .../M6502/Debugger/DebuggerCommands.swift | 9 ++++- .../M6502/Memory/MemoryInterface.swift | 7 +++- .../M6502/Memory/MemoryOverride.swift | 6 +-- FruitMachine/M6502/Memory/ReadOverride.swift | 5 +++ FruitMachine/M6502/Memory/WriteOverride.swift | 5 +++ FruitMachine/MainViewController.swift | 21 +++++++++- 13 files changed, 129 insertions(+), 39 deletions(-) create mode 100644 FruitMachine/AppleI/PIA.swift diff --git a/FruitMachine.xcodeproj/project.pbxproj b/FruitMachine.xcodeproj/project.pbxproj index 41fdf48..2d6f43e 100644 --- a/FruitMachine.xcodeproj/project.pbxproj +++ b/FruitMachine.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 2A5BC5191F29A28D008C03BE /* AppleScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */; }; 2A5BC51C1F29A2EB008C03BE /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */; }; 2A5BC51E1F29A4C3008C03BE /* AppleScreenViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */; }; + 2A60851E1F2AFAE900E05B64 /* PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A60851D1F2AFAE900E05B64 /* PIA.swift */; }; 2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5F71F2A8889002B350F /* AppleI.swift */; }; 2AA8B5FC1F2A8EAD002B350F /* Terminal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */; }; 2AA8B5FE1F2A942C002B350F /* PIAOverrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */; }; @@ -40,6 +41,7 @@ 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScreenView.swift; sourceTree = ""; }; 2A5BC51B1F29A2EB008C03BE /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScreenViewDelegate.swift; sourceTree = ""; }; + 2A60851D1F2AFAE900E05B64 /* PIA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIA.swift; sourceTree = ""; }; 2AA8B5F71F2A8889002B350F /* AppleI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleI.swift; sourceTree = ""; }; 2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Terminal.swift; sourceTree = ""; }; 2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAOverrides.swift; sourceTree = ""; }; @@ -92,6 +94,7 @@ 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */, 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */, 2AA8B5F71F2A8889002B350F /* AppleI.swift */, + 2A60851D1F2AFAE900E05B64 /* PIA.swift */, ); path = AppleI; sourceTree = ""; @@ -262,6 +265,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2A60851E1F2AFAE900E05B64 /* PIA.swift in Sources */, 2A2126841F2A9FA300E43DC1 /* DebuggerWindowController.swift in Sources */, 2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */, 2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */, diff --git a/FruitMachine/AppleI/AppleI.swift b/FruitMachine/AppleI/AppleI.swift index d4094eb..d062221 100644 --- a/FruitMachine/AppleI/AppleI.swift +++ b/FruitMachine/AppleI/AppleI.swift @@ -14,6 +14,14 @@ class AppleI: NSObject { let cg = CharacterGenerator(romPath: "/Users/luigi/apple1/apple1.vid"); let terminal = Terminal() + //PIA 0 = KBD + //PIA 1 = DSP + //let pia = [PIA(), PIA()] + let pia: [String:PIA] = [ + "keyboard": PIA(), + "display": PIA() + ] + let emulatorViewDelegate = AppleScreenViewDelegate() let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 400, 384)) let emuScreenLayer = CALayer() @@ -45,6 +53,9 @@ class AppleI: NSObject { func installOverrides() { CPU.sharedInstance.memoryInterface.write_overrides.append(PIAOverrides.writeDSP) CPU.sharedInstance.memoryInterface.read_overrides.append(PIAOverrides.readDSP) + + CPU.sharedInstance.memoryInterface.read_overrides.append(PIAOverrides.readKBD) + CPU.sharedInstance.memoryInterface.read_overrides.append(PIAOverrides.readKBDCR) } func runFrame() { @@ -54,11 +65,6 @@ class AppleI: NSObject { //update the video display for (cellNum, character) in terminal.characters.enumerated() { - if(character == 0x8D) //CR - { - continue //ignore for now - } - emulatorViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: character), pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: cellNum)) } diff --git a/FruitMachine/AppleI/PIA.swift b/FruitMachine/AppleI/PIA.swift new file mode 100644 index 0000000..5139edc --- /dev/null +++ b/FruitMachine/AppleI/PIA.swift @@ -0,0 +1,20 @@ +// +// PIA.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/28/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +class PIA: NSObject { + var data: UInt8 + var control: UInt8 + + override init() { + data = 0x00 + control = 0x00 + } + +} diff --git a/FruitMachine/AppleI/Video/CharacterGenerator.swift b/FruitMachine/AppleI/Video/CharacterGenerator.swift index 3ce2ed3..754383c 100644 --- a/FruitMachine/AppleI/Video/CharacterGenerator.swift +++ b/FruitMachine/AppleI/Video/CharacterGenerator.swift @@ -38,20 +38,7 @@ class CharacterGenerator: NSObject { /* 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. */ - var convertedCharIndex = charIndex & 0x7F - convertedCharIndex = convertedCharIndex & ~(0x20) - convertedCharIndex = convertedCharIndex & ~(0x40) - - /* - if((convertedCharIndex & 0x40) == 0x40) - { - convertedCharIndex = convertedCharIndex & ~(0x40) - } - else - { - convertedCharIndex = convertedCharIndex | 0x40 - } - */ + var convertedCharIndex = (charIndex & 0x1f) | (((charIndex ^ 0x40) & 0x40) >> 1) for scanlineIndex in 0.. Void { - //(terminal as! Terminal).putCharacter(charIndex: byte!) + static let writeDSP = WriteOverride(start: 0xD012, end: 0xD012, writeAnyway: false, action: PIAOverrides.actionWriteDSP) + static func actionWriteDSP(terminal: AnyObject, byte: UInt8?) -> UInt8? { + //TODO: implement actual 6520 PIA behavior + + //Writing to DSP sets DSP.7 + AppleI.sharedInstance.pia["display"]!.data = byte! | 0x80 + + //Output our character to the terminal AppleI.sharedInstance.terminal.putCharacter(charIndex: byte!) + + AppleI.sharedInstance.pia["display"]!.data = byte! & ~(0x80) + return nil; } - static let readDSP = ReadOverride(start: 0xD012, end: 0xD012, writeValue: false, action: PIAOverrides.actionReadDSP) - static func actionReadDSP(terminal: AnyObject, byte: UInt8?) -> Void { - CPU.sharedInstance.memoryInterface.writeByte(offset: 0xD012, value: CPU.sharedInstance.memoryInterface.readByte(offset: 0xD012, bypassOverrides: true) & 0x7F, bypassOverrides: true) //the display is always ready + static let readDSP = ReadOverride(start: 0xD012, end: 0xD012, readAnyway: false, action: PIAOverrides.actionReadDSP) + static func actionReadDSP(terminal: AnyObject, byte: UInt8?) -> UInt8? { + + //DSP.7 is unset when the character is accepted by the terminal + return AppleI.sharedInstance.pia["display"]!.data + } + /* */ + + static let readKBDCR = ReadOverride(start: 0xD011, end: 0xD011, readAnyway: false, action: PIAOverrides.actionReadKBDCR) + static func actionReadKBDCR(terminal: AnyObject, 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? { + //Reading KBD clears KBDCR.7 + AppleI.sharedInstance.pia["keyboard"]!.control = AppleI.sharedInstance.pia["keyboard"]!.control & ~(0x80) + + //KBD.7 is tied to +5V + return AppleI.sharedInstance.pia["keyboard"]!.data | 0x80 } } diff --git a/FruitMachine/AppleI/Video/Terminal.swift b/FruitMachine/AppleI/Video/Terminal.swift index 681eeb6..65ed308 100644 --- a/FruitMachine/AppleI/Video/Terminal.swift +++ b/FruitMachine/AppleI/Video/Terminal.swift @@ -22,7 +22,7 @@ class Terminal: NSObject { override init() { cursorPosition = Cell(x: 0, y: 0) - characters = [UInt8](repeating: 0x40, count: Terminal.CELLS_WIDTH * Terminal.CELLS_HEIGHT) + characters = [UInt8](repeating: 0x00, count: Terminal.CELLS_WIDTH * Terminal.CELLS_HEIGHT) } func cellToIndex(cell: Cell) -> Int { @@ -30,8 +30,14 @@ class Terminal: NSObject { } func putCharacter(charIndex: UInt8) { - characters[cellToIndex(cell: cursorPosition)] = charIndex - advanceCursor() + if(charIndex == 0x8D) + { + carriageReturn() + } + else { + characters[cellToIndex(cell: cursorPosition)] = charIndex + advanceCursor() + } } func advanceCursor() { @@ -44,4 +50,12 @@ class Terminal: NSObject { } } } + + func carriageReturn() { + cursorPosition.x = 0 + cursorPosition.y += 1 + if(cursorPosition.y == Terminal.CELLS_HEIGHT) { + cursorPosition.y = 0 + } + } } diff --git a/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard b/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard index f72e367..759613a 100644 --- a/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard +++ b/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard @@ -309,7 +309,7 @@ - + diff --git a/FruitMachine/M6502/Debugger/DebuggerCommands.swift b/FruitMachine/M6502/Debugger/DebuggerCommands.swift index 92c4cb2..6400632 100644 --- a/FruitMachine/M6502/Debugger/DebuggerCommands.swift +++ b/FruitMachine/M6502/Debugger/DebuggerCommands.swift @@ -48,10 +48,15 @@ extension DebuggerViewController { class DebuggerCommands: NSObject { static func bplist(state: CPU, parameters: [String]) -> String { var output = "" - for (index, bp) in state.breakpoints.enumerated() { - output += "Breakpoint \(index): $\(bp.asHexString())\r\n" + + if(state.breakpoints.count > 0){ + for (index, bp) in state.breakpoints.enumerated() { + output += "Breakpoint \(index): $\(bp.asHexString())\r\n" + } } + output = "No breakpoints are set." + return output } diff --git a/FruitMachine/M6502/Memory/MemoryInterface.swift b/FruitMachine/M6502/Memory/MemoryInterface.swift index 8823ab8..0ca2f5f 100644 --- a/FruitMachine/M6502/Memory/MemoryInterface.swift +++ b/FruitMachine/M6502/Memory/MemoryInterface.swift @@ -26,7 +26,10 @@ class MemoryInterface: NSObject { if(!bypassOverrides) { for override in read_overrides { if case override.rangeStart ... override.rangeEnd = offset { - override.action(CPU.sharedInstance, nil) + let readValue = override.action(CPU.sharedInstance, nil) + if(!override.doRead) { + return readValue! + } } } } @@ -41,7 +44,7 @@ class MemoryInterface: NSObject { for override in write_overrides { if case override.rangeStart ... override.rangeEnd = offset { override.action(CPU.sharedInstance, value) - if(!override.writeValue) { + if(!override.doWrite) { return } } diff --git a/FruitMachine/M6502/Memory/MemoryOverride.swift b/FruitMachine/M6502/Memory/MemoryOverride.swift index 980c948..69416a7 100644 --- a/FruitMachine/M6502/Memory/MemoryOverride.swift +++ b/FruitMachine/M6502/Memory/MemoryOverride.swift @@ -11,14 +11,12 @@ import Cocoa class MemoryOverride: NSObject { let rangeStart: UInt16 let rangeEnd: UInt16 - let writeValue: Bool - let action: (CPU, UInt8?) -> Void + let action: (CPU, UInt8?) -> UInt8? - init(start: UInt16, end: UInt16, writeValue: Bool, action: @escaping (AnyObject, UInt8?) -> Void) { + init(start: UInt16, end: UInt16, action: @escaping (AnyObject, UInt8?) -> UInt8?) { rangeStart = start rangeEnd = end - self.writeValue = writeValue self.action = action } diff --git a/FruitMachine/M6502/Memory/ReadOverride.swift b/FruitMachine/M6502/Memory/ReadOverride.swift index 852b20e..175da3d 100644 --- a/FruitMachine/M6502/Memory/ReadOverride.swift +++ b/FruitMachine/M6502/Memory/ReadOverride.swift @@ -12,5 +12,10 @@ import Cocoa Memory-mapped registers, peripherals, etc. */ class ReadOverride: MemoryOverride { + let doRead: Bool //do we write anyway? + init(start: UInt16, end: UInt16, readAnyway: Bool, action: @escaping (AnyObject, UInt8?) -> UInt8?) { + doRead = readAnyway + super.init(start: start, end: end, action: action) + } } diff --git a/FruitMachine/M6502/Memory/WriteOverride.swift b/FruitMachine/M6502/Memory/WriteOverride.swift index ec65521..f1b62a0 100644 --- a/FruitMachine/M6502/Memory/WriteOverride.swift +++ b/FruitMachine/M6502/Memory/WriteOverride.swift @@ -12,5 +12,10 @@ import Cocoa Memory-mapped registers, peripherals, etc. */ class WriteOverride: MemoryOverride { + let doWrite: Bool //do we write anyway? + init(start: UInt16, end: UInt16, writeAnyway: Bool, action: @escaping (AnyObject, UInt8?) -> UInt8?) { + doWrite = writeAnyway + super.init(start: start, end: end, action: action) + } } diff --git a/FruitMachine/MainViewController.swift b/FruitMachine/MainViewController.swift index cc94118..ed8a382 100644 --- a/FruitMachine/MainViewController.swift +++ b/FruitMachine/MainViewController.swift @@ -12,9 +12,11 @@ import CoreGraphics class MainViewController: NSViewController { let computer = AppleI.sharedInstance - var debuggerWindowController: DebuggerWindowController! + var isPaused = false + var frameTimer: Timer? + override func viewDidLoad() { super.viewDidLoad() @@ -26,7 +28,22 @@ class MainViewController: NSViewController { self.view.addSubview(computer.emulatorView) computer.emulatorView.display() - computer.runFrame() + self.frameTimer = Timer.scheduledTimer(timeInterval: 1/60, target: self, selector: #selector(runEmulation), userInfo: nil, repeats: true) + //runEmulation() + } + + @objc func runEmulation() { + AppleI.sharedInstance.runFrame() + computer.emulatorView.setNeedsDisplay(computer.emulatorView.frame) + computer.emulatorView.layer!.setNeedsDisplay(computer.emulatorView.layer!.frame) + computer.emulatorView.display() + } + + override func keyDown(with event: NSEvent) { + let character = event.characters?.first + + computer.pia["keyboard"]?.data = 0x41 + computer.pia["keyboard"]?.control |= 0x80 } }