started on the disassembler

This commit is contained in:
Luigi Thirty 2017-07-22 15:46:02 -04:00
parent 87d5584eee
commit f3bbb0413e
8 changed files with 356 additions and 75 deletions

View File

@ -9,20 +9,21 @@
/* Begin PBXBuildFile section */
2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */; };
2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CD1F205EB700F05121 /* AppDelegate.swift */; };
2AD458D01F205EB700F05121 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CF1F205EB700F05121 /* ViewController.swift */; };
2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */; };
2AD458D21F205EB700F05121 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2AD458D11F205EB700F05121 /* Assets.xcassets */; };
2AD458D51F205EB700F05121 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2AD458D31F205EB700F05121 /* Main.storyboard */; };
2AD458DF1F205F4500F05121 /* CPUState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458DE1F205F4500F05121 /* CPUState.swift */; };
2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E01F2064CB00F05121 /* MemoryInterface.swift */; };
2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E21F20661300F05121 /* CPUInstructions.swift */; };
2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458E41F2070DF00F05121 /* Opcodes.swift */; };
2AE5BA041F23DE4400FAA343 /* Disassembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5BA031F23DE4400FAA343 /* Disassembly.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegerExtensions.swift; sourceTree = "<group>"; };
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 = "<group>"; };
2AD458CF1F205EB700F05121 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerViewController.swift; sourceTree = "<group>"; };
2AD458D11F205EB700F05121 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2AD458D41F205EB700F05121 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
2AD458D61F205EB700F05121 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -31,6 +32,7 @@
2AD458E01F2064CB00F05121 /* MemoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryInterface.swift; sourceTree = "<group>"; };
2AD458E21F20661300F05121 /* CPUInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPUInstructions.swift; sourceTree = "<group>"; };
2AD458E41F2070DF00F05121 /* Opcodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Opcodes.swift; sourceTree = "<group>"; };
2AE5BA031F23DE4400FAA343 /* Disassembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disassembly.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -65,7 +67,7 @@
children = (
2AD458DD1F205F0D00F05121 /* M6502 */,
2AD458CD1F205EB700F05121 /* AppDelegate.swift */,
2AD458CF1F205EB700F05121 /* ViewController.swift */,
2AD458CF1F205EB700F05121 /* DebuggerViewController.swift */,
2AD458D11F205EB700F05121 /* Assets.xcassets */,
2AD458D31F205EB700F05121 /* Main.storyboard */,
2AD458D61F205EB700F05121 /* Info.plist */,
@ -79,6 +81,7 @@
children = (
2AD458DE1F205F4500F05121 /* CPUState.swift */,
2AD458E21F20661300F05121 /* CPUInstructions.swift */,
2AE5BA031F23DE4400FAA343 /* Disassembly.swift */,
2AD458E41F2070DF00F05121 /* Opcodes.swift */,
2AD458E01F2064CB00F05121 /* MemoryInterface.swift */,
2A22EBFA1F21A7A700A36A61 /* IntegerExtensions.swift */,
@ -157,9 +160,10 @@
buildActionMask = 2147483647;
files = (
2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */,
2AD458D01F205EB700F05121 /* ViewController.swift in Sources */,
2AD458D01F205EB700F05121 /* DebuggerViewController.swift in Sources */,
2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */,
2A22EBFB1F21A7A700A36A61 /* IntegerExtensions.swift in Sources */,
2AE5BA041F23DE4400FAA343 /* Disassembly.swift in Sources */,
2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */,
2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */,
2AD458DF1F205F4500F05121 /* CPUState.swift in Sources */,

View File

@ -685,7 +685,7 @@
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
<window key="window" title="Debugger" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
@ -702,10 +702,10 @@
</objects>
<point key="canvasLocation" x="75" y="250"/>
</scene>
<!--View Controller-->
<!--Debugger View Controller-->
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="XfG-lQ-9wD" customClass="DebuggerViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
@ -767,7 +767,7 @@
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="X2P-rm-4XW">
<rect key="frame" x="18" y="145" width="18" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="IP" id="okQ-uV-ovH">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="PC" id="okQ-uV-ovH">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@ -782,6 +782,15 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iZJ-VB-xRU">
<rect key="frame" x="18" y="115" width="18" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="SR" id="2XF-Q8-qZg">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5TT-BA-Iw1">
<rect key="frame" x="42" y="110" width="96" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -802,18 +811,107 @@
<action selector="btn_CPUStep:" target="XfG-lQ-9wD" id="sht-OT-bFK"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iZJ-VB-xRU">
<rect key="frame" x="18" y="115" width="18" height="17"/>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D58-pD-kHB">
<rect key="frame" x="146" y="20" width="314" height="232"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="SR" id="2XF-Q8-qZg">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<clipView key="contentView" ambiguous="YES" id="bpK-Jl-YbG">
<rect key="frame" x="1" y="0.0" width="312" height="231"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="Ep4-FK-mkU" viewBased="YES" id="MuT-J3-VZ6">
<rect key="frame" x="0.0" y="0.0" width="312" height="208"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="AddressCellID" width="116" minWidth="40" maxWidth="1000" id="hX8-rd-9WQ">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Address">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="Paw-o4-m30">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="CfD-bj-I9h">
<rect key="frame" x="1" y="1" width="116" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gF6-Xd-zbg">
<rect key="frame" x="0.0" y="0.0" width="116" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="rhk-Nf-Hah">
<font key="font" size="11" name="Menlo-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="gF6-Xd-zbg" id="lep-1z-ZAt"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="DataCellID" width="190" minWidth="40" maxWidth="1000" id="Ma5-Fz-J7v">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Disassembly">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="pvJ-AI-di6">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="ZF1-Mn-oL5">
<rect key="frame" x="120" y="1" width="190" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gen-Zj-0O4">
<rect key="frame" x="0.0" y="0.0" width="190" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="lxl-6b-xYm">
<font key="font" metaFont="fixedUser" size="11"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="gen-Zj-0O4" id="t04-GH-nId"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="jEY-yd-b3r">
<rect key="frame" x="1" y="119" width="223" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="xl3-SC-c8c">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="Ep4-FK-mkU">
<rect key="frame" x="0.0" y="0.0" width="312" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
</subviews>
</view>
<connections>
<outlet property="debuggerTableView" destination="MuT-J3-VZ6" id="TMx-Do-29u"/>
<outlet property="text_CPU_A" destination="WjO-ue-iRg" id="kaI-Bh-Efs"/>
<outlet property="text_CPU_IP" destination="XbV-5m-dd0" id="IoJ-th-0Ve"/>
<outlet property="text_CPU_SR" destination="5TT-BA-Iw1" id="Bnh-oz-AnZ"/>

View File

@ -0,0 +1,139 @@
//
// ViewController.swift
// FruitMachine
//
// Created by Christopher Rohl on 7/19/17.
// Copyright © 2017 Christopher Rohl. All rights reserved.
//
import Cocoa
class DebuggerViewController: NSViewController {
@IBOutlet weak var text_CPU_A: NSTextField!
@IBOutlet weak var text_CPU_X: NSTextField!
@IBOutlet weak var text_CPU_Y: NSTextField!
@IBOutlet weak var text_CPU_IP: NSTextField!
@IBOutlet weak var text_CPU_SR: NSTextField!
@IBOutlet weak var debuggerTableView: NSTableView!
let CPU = CPUState.sharedInstance
var disassembly: [Disassembly] = [Disassembly]()
func updateCPUStatusFields() {
text_CPU_A.stringValue = String(format:"%02X", CPU.accumulator)
text_CPU_X.stringValue = String(format:"%02X", CPU.index_x)
text_CPU_Y.stringValue = String(format:"%02X", CPU.index_y)
text_CPU_IP.stringValue = String(format:"%04X", CPU.program_counter)
text_CPU_SR.stringValue = String(format:"%02X", CPU.stack_pointer)
}
override func viewDidLoad() {
super.viewDidLoad()
debuggerTableView.delegate = self
debuggerTableView.dataSource = self
CPU.memoryInterface.loadBinary(path: "/Users/luigi/6502/test.bin")
updateCPUStatusFields()
disassembly = CPU.disassemble(fromAddress: 0x0000, length: 16)
debuggerTableView.reloadData()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func cpuStep() {
do {
try CPU.executeNextInstruction()
updateCPUStatusFields()
} catch CPUExceptions.invalidInstruction {
print("*** 6502 Exception: Invalid instruction 0xXX at 0xXXXX")
} catch {
print(error)
}
}
@IBAction func btn_CPUStep(_ sender: Any) {
cpuStep()
}
}
extension DebuggerViewController: NSTableViewDelegate {
fileprivate enum CellIdentifiers {
static let AddressCell = "AddressCellID"
static let DataCell = "DataCellID"
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
var cellText: String = ""
var cellIdentifier: String = ""
let operation = disassembly[row]
if(tableColumn == tableView.tableColumns[0]) {
cellText = String(format: "%04X", operation.address)
cellIdentifier = CellIdentifiers.AddressCell
}
if(tableColumn == tableView.tableColumns[1]) {
if(operation.instruction == nil) {
cellText = "ILLEGAL"
} else {
switch(operation.instruction!.addressingMode) {
case .accumulator:
cellText = String(format: "%@ A", operation.instruction!.mnemonic)
case .immediate:
cellText = String(format: "%@ #%02X", operation.instruction!.mnemonic, operation.data[0])
case .implied:
cellText = String(format: "%@", operation.instruction!.mnemonic)
case .relative:
cellText = String(format: "%@ #%04X", operation.instruction!.mnemonic, UInt16(operation.data[0]) + operation.address)
case .absolute:
cellText = String(format: "%@ #%02X%02X", operation.instruction!.mnemonic, operation.data[1], operation.data[0])
case .zeropage:
cellText = String(format: "%@ $%02X", operation.instruction!.mnemonic, operation.data[0])
case .indirect:
cellText = String(format: "%@ ($%02X%02X)", operation.instruction!.mnemonic, operation.data[1], operation.data[0])
case .absolute_indexed_x:
cellText = String(format: "%@ #%02X%02X,X", operation.instruction!.mnemonic, operation.data[1], operation.data[0])
case .absolute_indexed_y:
cellText = String(format: "%@ #%02X%02X,Y", operation.instruction!.mnemonic, operation.data[1], operation.data[0])
case .zeropage_indexed_x:
cellText = String(format: "%@ $%02X,X", operation.instruction!.mnemonic, operation.data[0])
case .zeropage_indexed_y:
cellText = String(format: "%@ $%02X,Y", operation.instruction!.mnemonic, operation.data[0])
case .indexed_indirect:
cellText = String(format: "%@ ($%02X,X)", operation.instruction!.mnemonic, operation.data[0])
case .indirect_indexed:
cellText = String(format: "%@ ($%02X),Y", operation.instruction!.mnemonic, operation.data[0])
}
}
cellIdentifier = CellIdentifiers.DataCell
}
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: nil) as? NSTableCellView {
cell.textField?.stringValue = cellText
return cell
}
return nil
}
}
extension DebuggerViewController: NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
return disassembly.count
}
func getItem(atIndex: Int) -> Disassembly {
return disassembly[atIndex]
}
}

View File

@ -83,6 +83,15 @@ let InstructionTable: [UInt8:CPUInstruction] = [
0xAC: CPUInstruction(mnemonic: "LDY", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDY),
0xBC: CPUInstruction(mnemonic: "LDY", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.LDY),
//ST functions
0x85: CPUInstruction(mnemonic: "STA", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.STA),
0x95: CPUInstruction(mnemonic: "STA", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.STA),
0x8D: CPUInstruction(mnemonic: "STA", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.STA),
0x9D: CPUInstruction(mnemonic: "STA", cycles: 5, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.STA),
0x99: CPUInstruction(mnemonic: "STA", cycles: 5, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.STA),
0x81: CPUInstruction(mnemonic: "STA", cycles: 6, bytes: 2, addressingMode: .indexed_indirect, action: Opcodes.STA),
0x91: CPUInstruction(mnemonic: "STA", cycles: 6, bytes: 2, addressingMode: .indirect_indexed, action: Opcodes.STA),
//Register functions
0x88: CPUInstruction(mnemonic: "DEY", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.DEY),
0x8A: CPUInstruction(mnemonic: "TXA", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TXA),

View File

@ -95,6 +95,32 @@ class CPUState: NSObject {
page_boundary_crossed = false
}
func disassemble(fromAddress: UInt16, length: UInt16) -> [Disassembly] {
var disassembly: [Disassembly] = [Disassembly]()
var currentAddress: UInt16 = fromAddress
let endAddress: UInt16 = fromAddress + length
while(currentAddress < endAddress) {
let instruction = memoryInterface.readByte(offset: currentAddress)
let operation = InstructionTable[instruction]
var data = [UInt8]()
if(operation != nil) {
for index in 1...operation!.bytes {
data.append(memoryInterface.readByte(offset:currentAddress + UInt16(index)))
}
disassembly.append(Disassembly(instruction: operation, address: currentAddress, data: data))
currentAddress = currentAddress + UInt16(operation!.bytes)
} else {
currentAddress = currentAddress + 1
}
}
return disassembly
}
func getOperandByte() -> UInt8 {
//Returns the operand byte after the current instruction byte.
return memoryInterface.readByte(offset: program_counter + 1)
@ -111,6 +137,22 @@ class CPUState: NSObject {
return word
}
func getInstructionBytes(atAddress: UInt16) -> [UInt8] {
var bytes = [UInt8]()
let instruction = memoryInterface.readByte(offset: atAddress)
let operation = InstructionTable[instruction]
if(operation != nil){
for offset in 0...operation!.bytes {
bytes.append(memoryInterface.readByte(offset: atAddress + UInt16(offset)))
}
}
return bytes
}
func executeNextInstruction() throws {
instruction_register = memoryInterface.readByte(offset: program_counter)

View File

@ -0,0 +1,21 @@
//
// Disassembly.swift
// FruitMachine
//
// Created by Christopher Rohl on 7/22/17.
// Copyright © 2017 Christopher Rohl. All rights reserved.
//
import Cocoa
class Disassembly: NSObject {
let instruction: CPUInstruction?
let address: UInt16
let data: [UInt8]
init(instruction: CPUInstruction?, address: UInt16, data: [UInt8]) {
self.instruction = instruction
self.address = address
self.data = data
}
}

View File

@ -65,6 +65,15 @@ func getOperandWordForAddressingMode(state: CPUState, mode: AddressingMode) -> U
return state.getOperandWord() + state.index_y
case .indirect:
return state.memoryInterface.readWord(offset: state.getOperandWord())
case .indexed_indirect:
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.getOperandByte() + state.index_x))
//read from (ZP)
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp))
return state.memoryInterface.readWord(offset: pointer)
case .indirect_indexed:
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.getOperandByte()))
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp)) + UInt16(state.index_y)
return state.memoryInterface.readWord(offset: pointer)
default:
print("Called getOperand: UInt16 on an instruction that expects a UInt8")
return 0
@ -97,6 +106,24 @@ class Opcodes: NSObject {
state.updateNegativeFlag(value: state.index_y)
}
static func STA(state: CPUState, addressingMode: AddressingMode) -> Void {
let address: UInt16
if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x) {
address = zpAsUInt16(address: state.getOperandByte())
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
}
else if (addressingMode == .absolute || addressingMode == .absolute_indexed_x || addressingMode == .absolute_indexed_y || addressingMode == .indexed_indirect || addressingMode == .indirect_indexed) {
address = state.getOperandWord()
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
}
else {
print("Illegal addressing mode for STA")
return
}
}
//Register instructions
static func TAX(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_x = state.accumulator

View File

@ -1,59 +0,0 @@
//
// ViewController.swift
// FruitMachine
//
// Created by Christopher Rohl on 7/19/17.
// Copyright © 2017 Christopher Rohl. All rights reserved.
//
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var text_CPU_A: NSTextField!
@IBOutlet weak var text_CPU_X: NSTextField!
@IBOutlet weak var text_CPU_Y: NSTextField!
@IBOutlet weak var text_CPU_IP: NSTextField!
@IBOutlet weak var text_CPU_SR: NSTextField!
let CPU = CPUState.sharedInstance
func updateCPUStatusFields() {
text_CPU_A.stringValue = String(format:"%02X", CPU.accumulator)
text_CPU_X.stringValue = String(format:"%02X", CPU.index_x)
text_CPU_Y.stringValue = String(format:"%02X", CPU.index_y)
text_CPU_IP.stringValue = String(format:"%04X", CPU.instruction_register)
text_CPU_SR.stringValue = String(format:"%02X", CPU.instruction_register)
}
override func viewDidLoad() {
super.viewDidLoad()
CPU.memoryInterface.loadBinary(path: "/Users/luigi/6502/test.bin")
updateCPUStatusFields()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func cpuStep() {
do {
try CPU.executeNextInstruction()
updateCPUStatusFields()
} catch CPUExceptions.invalidInstruction {
print("*** 6502 Exception: Invalid instruction 0xXX at 0xXXXX")
} catch {
print(error)
}
}
@IBAction func btn_CPUStep(_ sender: Any) {
cpuStep()
}
}