diff --git a/FruitMachine.xcodeproj/project.pbxproj b/FruitMachine.xcodeproj/project.pbxproj index 1e59d3e..41fdf48 100644 --- a/FruitMachine.xcodeproj/project.pbxproj +++ b/FruitMachine.xcodeproj/project.pbxproj @@ -7,10 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 2A2126841F2A9FA300E43DC1 /* DebuggerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2126831F2A9FA300E43DC1 /* DebuggerWindowController.swift */; }; 2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */; }; 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 */; }; + 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 */; }; 2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CD1F205EB700F05121 /* AppDelegate.swift */; }; 2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */; }; 2AD458D21F205EB700F05121 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2AD458D11F205EB700F05121 /* Assets.xcassets */; }; @@ -31,10 +35,14 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 2A2126831F2A9FA300E43DC1 /* DebuggerWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerWindowController.swift; sourceTree = ""; }; 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegerExtensions.swift; sourceTree = ""; }; 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 = ""; }; + 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 = ""; }; 2AD458CA1F205EB700F05121 /* FruitMachine.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FruitMachine.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2AD458CD1F205EB700F05121 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerViewController.swift; sourceTree = ""; }; @@ -77,6 +85,17 @@ name = Frameworks; sourceTree = ""; }; + 2AA8B5F61F2A8844002B350F /* AppleI */ = { + isa = PBXGroup; + children = ( + 2AE42E411F28663600C4900E /* Video */, + 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */, + 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */, + 2AA8B5F71F2A8889002B350F /* AppleI.swift */, + ); + path = AppleI; + sourceTree = ""; + }; 2AD458C11F205EB700F05121 = { isa = PBXGroup; children = ( @@ -97,11 +116,9 @@ 2AD458CC1F205EB700F05121 /* FruitMachine */ = { isa = PBXGroup; children = ( + 2AA8B5F61F2A8844002B350F /* AppleI */, 2AD458DD1F205F0D00F05121 /* M6502 */, - 2AE42E411F28663600C4900E /* Video */, 2AD458CD1F205EB700F05121 /* AppDelegate.swift */, - 2A5BC5181F29A28D008C03BE /* AppleScreenView.swift */, - 2A5BC51D1F29A4C3008C03BE /* AppleScreenViewDelegate.swift */, 2AE42E381F28628300C4900E /* MainViewController.swift */, 2AE42E3F1F28638100C4900E /* FruitMachine.storyboard */, 2AD458D11F205EB700F05121 /* Assets.xcassets */, @@ -139,6 +156,7 @@ children = ( 2AD458D31F205EB700F05121 /* Debugger.storyboard */, 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */, + 2A2126831F2A9FA300E43DC1 /* DebuggerWindowController.swift */, 2AD6D5831F26E6BF008F3CF5 /* DebuggerCommands.swift */, 2AE5BA031F23DE4400FAA343 /* Disassembly.swift */, ); @@ -167,6 +185,8 @@ isa = PBXGroup; children = ( 2AE42E421F28665300C4900E /* CharacterGenerator.swift */, + 2AA8B5FB1F2A8EAD002B350F /* Terminal.swift */, + 2AA8B5FD1F2A942C002B350F /* PIAOverrides.swift */, ); path = Video; sourceTree = ""; @@ -242,8 +262,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2A2126841F2A9FA300E43DC1 /* DebuggerWindowController.swift in Sources */, 2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */, 2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */, + 2AA8B5FC1F2A8EAD002B350F /* Terminal.swift in Sources */, 2A5BC51E1F29A4C3008C03BE /* AppleScreenViewDelegate.swift in Sources */, 2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */, 2AE42E431F28665300C4900E /* CharacterGenerator.swift in Sources */, @@ -254,10 +276,12 @@ 2AE42E3A1F28628300C4900E /* MainViewController.swift in Sources */, 2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */, 2AE42E081F2850F400C4900E /* ReadOverride.swift in Sources */, + 2AA8B5FE1F2A942C002B350F /* PIAOverrides.swift in Sources */, 2AE5BA061F2469EB00FAA343 /* AddressConversions.swift in Sources */, 2AE42E0A1F28521E00C4900E /* WriteOverride.swift in Sources */, 2A5BC5191F29A28D008C03BE /* AppleScreenView.swift in Sources */, 2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */, + 2AA8B5F81F2A8889002B350F /* AppleI.swift in Sources */, 2AD458DF1F205F4500F05121 /* CPU.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/FruitMachine/AppDelegate.swift b/FruitMachine/AppDelegate.swift index 9e473c7..1f9b1ca 100644 --- a/FruitMachine/AppDelegate.swift +++ b/FruitMachine/AppDelegate.swift @@ -10,6 +10,7 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { + let AppleScreenNotifications = Notification.Name("com.luigithirty.appleScreenNotifications") func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application @@ -19,5 +20,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { // Insert code here to tear down your application } + @IBAction func view_scale_1x(_ sender: Any) { + NotificationCenter.default.post(Notification(name: AppleScreenNotifications, object: "scaleFactor", userInfo: ["scaleFactor": 1])) + } + + @IBAction func view_scale_2x(_ sender: Any) { + NotificationCenter.default.post(Notification(name: AppleScreenNotifications, object: "scaleFactor", userInfo: ["scaleFactor": 2])) + } } diff --git a/FruitMachine/AppleI/AppleI.swift b/FruitMachine/AppleI/AppleI.swift new file mode 100644 index 0000000..d4094eb --- /dev/null +++ b/FruitMachine/AppleI/AppleI.swift @@ -0,0 +1,67 @@ +// +// AppleI.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/27/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +class AppleI: NSObject { + static let sharedInstance = AppleI() + + let cg = CharacterGenerator(romPath: "/Users/luigi/apple1/apple1.vid"); + let terminal = Terminal() + + let emulatorViewDelegate = AppleScreenViewDelegate() + let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 400, 384)) + let emuScreenLayer = CALayer() + + static let CPU_FREQUENCY = 1000000 + static let FRAMES_PER_SECOND = 60 + static let CYCLES_PER_BATCH = CPU_FREQUENCY / FRAMES_PER_SECOND + + override init() { + super.init() + + emulatorView.wantsLayer = true + emuScreenLayer.delegate = emulatorViewDelegate + emuScreenLayer.frame = emulatorView.bounds + emuScreenLayer.setNeedsDisplay() + emulatorView.layer?.addSublayer(emuScreenLayer) + + installOverrides() + + for (cellNum, character) in terminal.characters.enumerated() { + emulatorViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: character), pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: cellNum)) + } + + CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/apple1.rom", offset: 0xFF00) + CPU.sharedInstance.performReset() + + } + + func installOverrides() { + CPU.sharedInstance.memoryInterface.write_overrides.append(PIAOverrides.writeDSP) + CPU.sharedInstance.memoryInterface.read_overrides.append(PIAOverrides.readDSP) + } + + func runFrame() { + CPU.sharedInstance.cycles = 0 + CPU.sharedInstance.cyclesInBatch = AppleI.CYCLES_PER_BATCH + CPU.sharedInstance.runCyclesBatch() + + //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)) + } + + emulatorView.display() + } +} diff --git a/FruitMachine/AppleScreenView.swift b/FruitMachine/AppleI/AppleScreenView.swift similarity index 77% rename from FruitMachine/AppleScreenView.swift rename to FruitMachine/AppleI/AppleScreenView.swift index cd09153..002aab1 100644 --- a/FruitMachine/AppleScreenView.swift +++ b/FruitMachine/AppleI/AppleScreenView.swift @@ -10,10 +10,6 @@ import Cocoa class AppleScreenView: NSView { - //In characters - static let TERMINAL_WIDTH = 40 - static let TERMINAL_HEIGHT = 24 - override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Drawing code here. diff --git a/FruitMachine/AppleScreenViewDelegate.swift b/FruitMachine/AppleI/AppleScreenViewDelegate.swift similarity index 90% rename from FruitMachine/AppleScreenViewDelegate.swift rename to FruitMachine/AppleI/AppleScreenViewDelegate.swift index eed5135..1fe57d5 100644 --- a/FruitMachine/AppleScreenViewDelegate.swift +++ b/FruitMachine/AppleI/AppleScreenViewDelegate.swift @@ -52,7 +52,7 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate { for charY in 0.. 0 ? 1 : 0 + indexedPixels[baseOffset + (PIXEL_WIDTH * charY) + CharacterGenerator.CHAR_WIDTH - charX - 1] = (charPixels[charY] & UInt8(1 << charX)) > 0 ? 1 : 0 } } } @@ -60,6 +60,10 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate { func getPixelOffset(charCellX: Int, charCellY: Int) -> CGPoint { return CGPoint(x: charCellX * 5, y: charCellY * 8) } + + func getPixelOffset(charCellIndex: Int) -> CGPoint { + return getPixelOffset(charCellX: charCellIndex % Terminal.CELLS_WIDTH, charCellY: charCellIndex / Terminal.CELLS_WIDTH) + } /* Draw the screen. */ func draw(_ layer: CALayer, in ctx: CGContext) { @@ -70,8 +74,8 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate { let pixelProvider = CGDataProvider(data: NSData(bytes: &pixels, length: pixels.count * MemoryLayout.size)) let renderedImage = CGImage(width: PIXEL_WIDTH, height: PIXEL_HEIGHT, bitsPerComponent: Int(bitsPerComponent), bitsPerPixel: Int(bitsPerPixel), bytesPerRow: PIXEL_WIDTH * Int(MemoryLayout.size), space: colorSpace, bitmapInfo: bitmapInfo, provider: pixelProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) + ctx.draw(renderedImage!, in: bounds) - //draw stuff here } } diff --git a/FruitMachine/Video/CharacterGenerator.swift b/FruitMachine/AppleI/Video/CharacterGenerator.swift similarity index 56% rename from FruitMachine/Video/CharacterGenerator.swift rename to FruitMachine/AppleI/Video/CharacterGenerator.swift index d44941f..3ce2ed3 100644 --- a/FruitMachine/Video/CharacterGenerator.swift +++ b/FruitMachine/AppleI/Video/CharacterGenerator.swift @@ -35,8 +35,26 @@ class CharacterGenerator: NSObject { func getCharacterPixels(charIndex: UInt8) -> [UInt8] { var pixelArray = [UInt8](repeating: 0x00, count: CharacterGenerator.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. + */ + + var convertedCharIndex = charIndex & 0x7F + convertedCharIndex = convertedCharIndex & ~(0x20) + convertedCharIndex = convertedCharIndex & ~(0x40) + + /* + if((convertedCharIndex & 0x40) == 0x40) + { + convertedCharIndex = convertedCharIndex & ~(0x40) + } + else + { + convertedCharIndex = convertedCharIndex | 0x40 + } + */ + for scanlineIndex in 0.. Void { + //(terminal as! Terminal).putCharacter(charIndex: byte!) + AppleI.sharedInstance.terminal.putCharacter(charIndex: byte!) + } + + 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 + } + +} diff --git a/FruitMachine/AppleI/Video/Terminal.swift b/FruitMachine/AppleI/Video/Terminal.swift new file mode 100644 index 0000000..681eeb6 --- /dev/null +++ b/FruitMachine/AppleI/Video/Terminal.swift @@ -0,0 +1,47 @@ +// +// Terminal.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/27/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +struct Cell { + var x: Int + var y: Int +} + +class Terminal: NSObject { + static let CELLS_WIDTH = 40 + static let CELLS_HEIGHT = 24 + + var cursorPosition: Cell + var characters: [UInt8] + + override init() { + cursorPosition = Cell(x: 0, y: 0) + characters = [UInt8](repeating: 0x40, count: Terminal.CELLS_WIDTH * Terminal.CELLS_HEIGHT) + } + + func cellToIndex(cell: Cell) -> Int { + return (cell.y * Terminal.CELLS_WIDTH) + (cell.x % Terminal.CELLS_WIDTH) + } + + func putCharacter(charIndex: UInt8) { + characters[cellToIndex(cell: cursorPosition)] = charIndex + advanceCursor() + } + + func advanceCursor() { + cursorPosition.x += 1 + if(cursorPosition.x == Terminal.CELLS_WIDTH) { + cursorPosition.x = 0 + cursorPosition.y += 1 + if(cursorPosition.y == Terminal.CELLS_HEIGHT) { + cursorPosition.y = 0 //TODO: scrolling + } + } + } +} diff --git a/FruitMachine/FruitMachine.storyboard b/FruitMachine/FruitMachine.storyboard index 70ff467..4668927 100644 --- a/FruitMachine/FruitMachine.storyboard +++ b/FruitMachine/FruitMachine.storyboard @@ -629,6 +629,17 @@ + + + + + + + + + + + diff --git a/FruitMachine/M6502/CPU.swift b/FruitMachine/M6502/CPU.swift index b3f8068..60d70ac 100644 --- a/FruitMachine/M6502/CPU.swift +++ b/FruitMachine/M6502/CPU.swift @@ -116,7 +116,9 @@ class CPU: NSObject { let RESET_VECTOR: UInt16 = 0xFFFC let IRQ_VECTOR: UInt16 = 0xFFFE - static var sharedInstance = CPU() + static let sharedInstance = CPU() + + var isRunning: Bool var cycles: Int var cyclesInBatch: Int @@ -138,6 +140,8 @@ class CPU: NSObject { var breakpoints: [UInt16] override init() { + isRunning = false + cycles = 0 cyclesInBatch = 0 @@ -216,7 +220,7 @@ class CPU: NSObject { } } - func checkOutOfCycles() -> Bool { + func outOfCycles() -> Bool { if(cycles > cyclesInBatch) { return true } else { @@ -238,4 +242,28 @@ class CPU: NSObject { status_register.zero = (value == 0) } + /* Running */ + func cpuStep() { + do { + try executeNextInstruction() + } catch CPUExceptions.invalidInstruction { + isRunning = false + } catch { + print(error) + } + } + + func runCyclesBatch() { + isRunning = true + + while(!outOfCycles() && isRunning) { + cpuStep() + + if (breakpoints.contains(program_counter)) { + isRunning = false + } + + } + } + } diff --git a/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard b/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard index 0da2fdd..f72e367 100644 --- a/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard +++ b/FruitMachine/M6502/Debugger/Base.lproj/Debugger.storyboard @@ -9,7 +9,7 @@ - + diff --git a/FruitMachine/M6502/Debugger/DebuggerViewController.swift b/FruitMachine/M6502/Debugger/DebuggerViewController.swift index c455fa8..191f2c4 100644 --- a/FruitMachine/M6502/Debugger/DebuggerViewController.swift +++ b/FruitMachine/M6502/Debugger/DebuggerViewController.swift @@ -46,7 +46,7 @@ class DebuggerViewController: NSViewController { text_CPU_SR.stringValue = String(format:"%02X", cpuInstance.stack_pointer) text_CPU_Flags.stringValue = String(cpuInstance.status_register.asString()) - disassembly = cpuInstance.disassemble(fromAddress: 0, length: 65535) + disassembly = cpuInstance.disassemble(fromAddress: CPU.sharedInstance.program_counter, length: 256) highlightCurrentInstruction() } @@ -56,15 +56,10 @@ class DebuggerViewController: NSViewController { debuggerTableView.delegate = self debuggerTableView.dataSource = self - cpuInstance.memoryInterface.loadBinary(path: "/Users/luigi/6502/test.bin") - cpuInstance.performReset() - cpuInstance.program_counter = 0x400 //entry point for the test program updateCPUStatusFields() - disassembly = cpuInstance.disassemble(fromAddress: 0, length: 65535) + disassembly = cpuInstance.disassemble(fromAddress: CPU.sharedInstance.program_counter, length: 256) debuggerTableView.reloadData() - cpuInstance.breakpoints.append(0x34E8) //failing at $34FD SBC test - // Do any additional setup after loading the view. } @@ -73,26 +68,15 @@ class DebuggerViewController: NSViewController { // Update the view, if already loaded. } } - - func cpuStep() { - do { - try cpuInstance.executeNextInstruction() - } catch CPUExceptions.invalidInstruction { - isRunning = false - - } catch { - print(error) - } - } - func cpuRun() { + func debugRun() { isRunning = true cpuInstance.cycles = 0 cpuInstance.cyclesInBatch = 1000000 - while(!cpuInstance.checkOutOfCycles() && isRunning) { - cpuStep() + while(!cpuInstance.outOfCycles() && isRunning) { + cpuInstance.cpuStep() if (cpuInstance.breakpoints.contains(cpuInstance.program_counter)) { isRunning = false @@ -105,12 +89,12 @@ class DebuggerViewController: NSViewController { func queueCPUStep(queue: DispatchQueue) { queue.async { - self.cpuStep() + self.cpuInstance.cpuStep() } } @IBAction func btn_CPUStep(_ sender: Any) { - cpuStep() + cpuInstance.cpuStep() updateCPUStatusFields() } @@ -120,7 +104,7 @@ class DebuggerViewController: NSViewController { } @IBAction func btn_CPURun(_ sender: Any) { - cpuRun() + debugRun() } @IBAction func btn_CPU_Restart(_ sender: Any) { @@ -155,6 +139,11 @@ extension DebuggerViewController: NSTableViewDelegate { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { var cellText: String = "" var cellIdentifier: String = "" + + if(row >= disassembly.count) { + return nil //no cell + } + let operation = disassembly[row] if(tableColumn == tableView.tableColumns[0]) { diff --git a/FruitMachine/M6502/Debugger/DebuggerWindowController.swift b/FruitMachine/M6502/Debugger/DebuggerWindowController.swift new file mode 100644 index 0000000..aaab189 --- /dev/null +++ b/FruitMachine/M6502/Debugger/DebuggerWindowController.swift @@ -0,0 +1,19 @@ +// +// DebuggerWindowController.swift +// FruitMachine +// +// Created by Christopher Rohl on 7/27/17. +// Copyright © 2017 Christopher Rohl. All rights reserved. +// + +import Cocoa + +class DebuggerWindowController: NSWindowController { + + override func windowDidLoad() { + super.windowDidLoad() + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + } + +} diff --git a/FruitMachine/M6502/Debugger/Disassembly.swift b/FruitMachine/M6502/Debugger/Disassembly.swift index d92369e..44a2dfd 100644 --- a/FruitMachine/M6502/Debugger/Disassembly.swift +++ b/FruitMachine/M6502/Debugger/Disassembly.swift @@ -74,7 +74,7 @@ extension CPU { var disassembly: [Disassembly] = [Disassembly]() var currentAddress: UInt16 = fromAddress - let endAddress: UInt16 = fromAddress + length + let endAddress: UInt16 = max(fromAddress &+ length, 0xFFFF) while(currentAddress < endAddress) { let instruction = memoryInterface.readByte(offset: currentAddress) diff --git a/FruitMachine/M6502/Memory/MemoryInterface.swift b/FruitMachine/M6502/Memory/MemoryInterface.swift index 7425f73..8823ab8 100644 --- a/FruitMachine/M6502/Memory/MemoryInterface.swift +++ b/FruitMachine/M6502/Memory/MemoryInterface.swift @@ -21,10 +21,13 @@ class MemoryInterface: NSObject { write_overrides = [WriteOverride]() } - func readByte(offset: UInt16) -> UInt8 { - for override in read_overrides { - if case override.rangeStart ... override.rangeEnd = offset { - override.action(CPU.sharedInstance, nil) + func readByte(offset: UInt16, bypassOverrides: Bool = false) -> UInt8 { + + if(!bypassOverrides) { + for override in read_overrides { + if case override.rangeStart ... override.rangeEnd = offset { + override.action(CPU.sharedInstance, nil) + } } } @@ -32,10 +35,16 @@ class MemoryInterface: NSObject { return memory[Int(offset)] } - func writeByte(offset: UInt16, value: UInt8) { - for override in read_overrides { - if case override.rangeStart ... override.rangeEnd = offset { - override.action(CPU.sharedInstance, value) + func writeByte(offset: UInt16, value: UInt8, bypassOverrides: Bool = false) { + + if(!bypassOverrides) { + for override in write_overrides { + if case override.rangeStart ... override.rangeEnd = offset { + override.action(CPU.sharedInstance, value) + if(!override.writeValue) { + return + } + } } } @@ -48,10 +57,10 @@ class MemoryInterface: NSObject { return (UInt16(high) << 8) | UInt16(low) } - func loadBinary(path: String) { + func loadBinary(path: String, offset: UInt16) { do { let fileContent: NSData = try NSData(contentsOfFile: path) - fileContent.getBytes(&memory, range: NSRange(location: 0, length: 65536)) + fileContent.getBytes(&memory[Int(offset)], range: NSRange(location: 0, length: 256)) } catch { print(error) } diff --git a/FruitMachine/M6502/Memory/MemoryOverride.swift b/FruitMachine/M6502/Memory/MemoryOverride.swift index 03a716d..980c948 100644 --- a/FruitMachine/M6502/Memory/MemoryOverride.swift +++ b/FruitMachine/M6502/Memory/MemoryOverride.swift @@ -11,12 +11,14 @@ import Cocoa class MemoryOverride: NSObject { let rangeStart: UInt16 let rangeEnd: UInt16 + let writeValue: Bool let action: (CPU, UInt8?) -> Void - init(start: UInt16, end: UInt16, action: @escaping (CPU, UInt8?) -> Void) { + init(start: UInt16, end: UInt16, writeValue: Bool, action: @escaping (AnyObject, UInt8?) -> Void) { rangeStart = start rangeEnd = end + self.writeValue = writeValue self.action = action } diff --git a/FruitMachine/MainViewController.swift b/FruitMachine/MainViewController.swift index 4a5d9c7..cc94118 100644 --- a/FruitMachine/MainViewController.swift +++ b/FruitMachine/MainViewController.swift @@ -10,36 +10,23 @@ import Cocoa import CoreGraphics class MainViewController: NSViewController { - var windowController: NSWindowController? - var debuggerViewController = DebuggerViewController() - let emuScreenLayer = CALayer() - - let cg = CharacterGenerator(romPath: "/Users/luigi/apple1/apple1.vid"); - var appleScreenView: AppleScreenView = AppleScreenView(frame: NSMakeRect(0, 0, 400, 384)) - let appleScreenViewDelegate = AppleScreenViewDelegate() - override func viewDidLoad() { + let computer = AppleI.sharedInstance + + var debuggerWindowController: DebuggerWindowController! + + override func viewDidLoad() { super.viewDidLoad() + + let debuggerStoryboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Debugger"), bundle: nil) + debuggerWindowController = debuggerStoryboard.instantiateInitialController() as! DebuggerWindowController + debuggerWindowController.showWindow(self) + // Do view setup here. - self.view.addSubview(appleScreenView) + self.view.addSubview(computer.emulatorView) + computer.emulatorView.display() - appleScreenView.wantsLayer = true - - emuScreenLayer.delegate = appleScreenViewDelegate - emuScreenLayer.frame = appleScreenView.bounds - emuScreenLayer.setNeedsDisplay() - appleScreenView.layer?.addSublayer(emuScreenLayer) - - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x00), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 0, charCellY: 0)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x01), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 1, charCellY: 1)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x02), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 2, charCellY: 2)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x03), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 3, charCellY: 3)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x04), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 4, charCellY: 4)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x05), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 5, charCellY: 5)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x06), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 6, charCellY: 6)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x07), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 7, charCellY: 7)) - appleScreenViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: 0x08), pixelPosition: appleScreenViewDelegate.getPixelOffset(charCellX: 8, charCellY: 8)) - - appleScreenView.display() + computer.runFrame() } + } diff --git a/FruitMachine/MainViewStoryboard.storyboard b/FruitMachine/MainViewStoryboard.storyboard new file mode 100644 index 0000000..c0a2821 --- /dev/null +++ b/FruitMachine/MainViewStoryboard.storyboard @@ -0,0 +1,8 @@ + + + + + + + +