mirror of
https://github.com/Luigi30/FruitMachine-Swift.git
synced 2024-11-26 21:52:45 +00:00
cool
This commit is contained in:
parent
0c73b4751b
commit
0d6988541d
@ -11,6 +11,10 @@
|
||||
2AD458D01F205EB700F05121 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD458CF1F205EB700F05121 /* ViewController.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 */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -21,6 +25,10 @@
|
||||
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>"; };
|
||||
2AD458D71F205EB700F05121 /* FruitMachine.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FruitMachine.entitlements; sourceTree = "<group>"; };
|
||||
2AD458DE1F205F4500F05121 /* CPUState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPUState.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -53,6 +61,7 @@
|
||||
2AD458CC1F205EB700F05121 /* FruitMachine */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2AD458DD1F205F0D00F05121 /* M6502 */,
|
||||
2AD458CD1F205EB700F05121 /* AppDelegate.swift */,
|
||||
2AD458CF1F205EB700F05121 /* ViewController.swift */,
|
||||
2AD458D11F205EB700F05121 /* Assets.xcassets */,
|
||||
@ -63,6 +72,17 @@
|
||||
path = FruitMachine;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2AD458DD1F205F0D00F05121 /* M6502 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2AD458DE1F205F4500F05121 /* CPUState.swift */,
|
||||
2AD458E21F20661300F05121 /* CPUInstructions.swift */,
|
||||
2AD458E41F2070DF00F05121 /* Opcodes.swift */,
|
||||
2AD458E01F2064CB00F05121 /* MemoryInterface.swift */,
|
||||
);
|
||||
path = M6502;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -133,8 +153,12 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2AD458E31F20661300F05121 /* CPUInstructions.swift in Sources */,
|
||||
2AD458D01F205EB700F05121 /* ViewController.swift in Sources */,
|
||||
2AD458CE1F205EB700F05121 /* AppDelegate.swift in Sources */,
|
||||
2AD458E51F2070DF00F05121 /* Opcodes.swift in Sources */,
|
||||
2AD458E11F2064CB00F05121 /* MemoryInterface.swift in Sources */,
|
||||
2AD458DF1F205F4500F05121 /* CPUState.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -10,5 +10,13 @@
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>2AD458C91F205EB700F05121</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
51
FruitMachine/M6502/CPUInstructions.swift
Normal file
51
FruitMachine/M6502/CPUInstructions.swift
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// CPUInstructions.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/20/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
enum AddressingMode {
|
||||
case accumulator
|
||||
case immediate
|
||||
case implied
|
||||
case relative
|
||||
case absolute
|
||||
case zeropage
|
||||
case indirect
|
||||
case absolute_indexed_x
|
||||
case absolute_indexed_y
|
||||
case zeropage_indexed_x
|
||||
case zeropage_indexed_y
|
||||
case indexed_indirect
|
||||
case indirect_indexed
|
||||
}
|
||||
|
||||
class CPUInstruction: NSObject {
|
||||
let mnemonic: String //The mnemonic for this instruction.
|
||||
let cycles: Int //How many cycles does this instruction take?
|
||||
let bytes: Int //How many bytes long is this instruction?
|
||||
let addressingMode: AddressingMode //The addressing mode of this instruction.
|
||||
|
||||
let action: (CPUState, AddressingMode) -> Void //A closure that describes this function's action.
|
||||
|
||||
init(mnemonic: String, cycles: Int, bytes: Int, addressingMode: AddressingMode, action: @escaping (CPUState, AddressingMode) -> Void) {
|
||||
self.mnemonic = mnemonic
|
||||
self.cycles = cycles
|
||||
self.bytes = bytes
|
||||
self.addressingMode = addressingMode
|
||||
self.action = action
|
||||
}
|
||||
}
|
||||
|
||||
let InstructionTable: [UInt8:CPUInstruction] = [
|
||||
0xA5: CPUInstruction.init(mnemonic: "LDA", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDA),
|
||||
0xA9: CPUInstruction.init(mnemonic: "LDA", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDA),
|
||||
0xAD: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDA),
|
||||
0xB5: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.LDA),
|
||||
0xB9: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.LDA),
|
||||
0xBD: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.LDA),
|
||||
]
|
93
FruitMachine/M6502/CPUState.swift
Normal file
93
FruitMachine/M6502/CPUState.swift
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// CPUState.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/19/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
enum CPUExceptions : Error {
|
||||
case invalidInstruction
|
||||
}
|
||||
|
||||
struct StatusRegister {
|
||||
var negative: Bool //N - 0x80
|
||||
var overflow: Bool //V - 0x40
|
||||
// - 0x20
|
||||
var brk: Bool //B - 0x10
|
||||
var decimal: Bool //D - 0x08
|
||||
var irq_disable: Bool //I - 0x04
|
||||
var zero: Bool //Z - 0x02
|
||||
var carry: Bool //C - 0x01
|
||||
|
||||
mutating func setState(state: UInt8) {
|
||||
negative = (state & 0x80 == 0x80)
|
||||
overflow = (state & 0x40 == 0x40)
|
||||
brk = (state & 0x10 == 0x10)
|
||||
decimal = (state & 0x08 == 0x08)
|
||||
irq_disable = (state & 0x04 == 0x04)
|
||||
zero = (state & 0x02 == 0x02)
|
||||
carry = (state & 0x01 == 0x01)
|
||||
}
|
||||
}
|
||||
|
||||
class CPUState: NSObject {
|
||||
static var sharedInstance = CPUState()
|
||||
|
||||
var cycles: Int
|
||||
|
||||
var instruction_register: UInt8
|
||||
|
||||
var accumulator: UInt8
|
||||
var index_x: UInt8
|
||||
var index_y: UInt8
|
||||
var stack_pointer: UInt8
|
||||
var program_counter: UInt16
|
||||
var status_register: StatusRegister
|
||||
|
||||
var page_boundary_crossed: Bool
|
||||
|
||||
var memoryInterface: MemoryInterface
|
||||
|
||||
override init() {
|
||||
cycles = 0
|
||||
|
||||
instruction_register = 0
|
||||
|
||||
accumulator = 0
|
||||
index_x = 0
|
||||
index_y = 0
|
||||
stack_pointer = 0
|
||||
program_counter = 0
|
||||
status_register = StatusRegister(negative: false, overflow: false, brk: false, decimal: false, irq_disable: false, zero: false, carry: false)
|
||||
memoryInterface = MemoryInterface()
|
||||
|
||||
page_boundary_crossed = false
|
||||
}
|
||||
|
||||
func executeNextInstruction() throws {
|
||||
instruction_register = memoryInterface.memory[Int(program_counter)]
|
||||
let operation = InstructionTable[instruction_register]
|
||||
if(operation == nil) {
|
||||
throw CPUExceptions.invalidInstruction
|
||||
}
|
||||
|
||||
operation!.action(CPUState.sharedInstance, operation!.addressingMode)
|
||||
|
||||
self.cycles += operation!.cycles
|
||||
if(self.page_boundary_crossed) {
|
||||
self.cycles += 1
|
||||
self.page_boundary_crossed = false
|
||||
}
|
||||
}
|
||||
|
||||
func setNegativeFlag() {
|
||||
status_register.negative = (accumulator & 0x80 == 0x80)
|
||||
}
|
||||
|
||||
func setZeroFlag() {
|
||||
status_register.zero = (accumulator == 0)
|
||||
}
|
||||
}
|
17
FruitMachine/M6502/MemoryInterface.swift
Normal file
17
FruitMachine/M6502/MemoryInterface.swift
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// MemoryInterface.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/20/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class MemoryInterface: NSObject {
|
||||
var memory: [UInt8]
|
||||
|
||||
override init() {
|
||||
memory = [UInt8](repeating: 0x00, count: 65536)
|
||||
}
|
||||
}
|
79
FruitMachine/M6502/Opcodes.swift
Normal file
79
FruitMachine/M6502/Opcodes.swift
Normal file
@ -0,0 +1,79 @@
|
||||
//
|
||||
// Opcodes.swift
|
||||
// FruitMachine
|
||||
//
|
||||
// Created by Christopher Rohl on 7/20/17.
|
||||
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
/* Addressing mode helper functions */
|
||||
func PC_PLUS_1(state: CPUState) -> UInt16 {
|
||||
return state.program_counter + 1
|
||||
}
|
||||
|
||||
func OPERAND_IMMEDIATE(state: CPUState) -> UInt8 {
|
||||
//Operand = PC+1
|
||||
return MEMORY_READ_UINT8(state: state, address: state.program_counter + 1)
|
||||
}
|
||||
|
||||
func OPERAND_ZEROPAGE_INDEXED_X(state: CPUState) -> UInt8 {
|
||||
//Operand = (PC+1) + X
|
||||
return MEMORY_READ_UINT8(state: state, address: (state.program_counter + 1) + UInt16(state.index_x))
|
||||
}
|
||||
|
||||
func OPERAND_ZEROPAGE_INDEXED_Y(state: CPUState) -> UInt8 {
|
||||
//Operand = (PC+1) + Y
|
||||
return MEMORY_READ_UINT8(state: state, address: (state.program_counter + 1) + UInt16(state.index_y))
|
||||
}
|
||||
|
||||
func OPERAND_ABSOLUTE(state: CPUState) -> UInt16 {
|
||||
//Operand = L:(PC+1) H:(PC+2)
|
||||
let low: UInt8 = MEMORY_READ_UINT8(state: state, address: state.program_counter + 1)
|
||||
let high: UInt8 = MEMORY_READ_UINT8(state: state, address: state.program_counter + 2)
|
||||
return UInt16(high << 8 | low)
|
||||
}
|
||||
|
||||
func OPERAND_ABSOLUTE_INDEXED_X(state: CPUState) -> UInt16 {
|
||||
//Operand = L:(PC+1)+X H:(PC+2)+X
|
||||
let low: UInt8 = MEMORY_READ_UINT8(state: state, address: state.program_counter + 1 + UInt16(state.index_x))
|
||||
let high: UInt8 = MEMORY_READ_UINT8(state: state, address: state.program_counter + 2 + UInt16(state.index_x))
|
||||
return UInt16(high << 8 | low)
|
||||
}
|
||||
|
||||
func OPERAND_ABSOLUTE_INDEXED_Y(state: CPUState) -> UInt16 {
|
||||
//Operand = L:(PC+1)+Y H:(PC+2)+Y
|
||||
let low: UInt8 = MEMORY_READ_UINT8(state: state, address: state.program_counter + 1 + UInt16(state.index_y))
|
||||
let high: UInt8 = MEMORY_READ_UINT8(state: state, address: state.program_counter + 2 + UInt16(state.index_y))
|
||||
return UInt16(high << 8 | low)
|
||||
}
|
||||
|
||||
func MEMORY_READ_UINT8(state: CPUState, address: UInt16) -> UInt8 {
|
||||
return state.memoryInterface.memory[Int(address)]
|
||||
}
|
||||
|
||||
class Opcodes: NSObject {
|
||||
static func LDA(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
|
||||
switch addressingMode {
|
||||
case .immediate:
|
||||
state.accumulator = OPERAND_IMMEDIATE(state: state)
|
||||
case .zeropage:
|
||||
state.accumulator = OPERAND_ZEROPAGE_INDEXED_X(state: state)
|
||||
case .zeropage_indexed_x:
|
||||
state.accumulator = MEMORY_READ_UINT8(state: state, address: UInt16(0x0000 + OPERAND_ZEROPAGE_INDEXED_X(state: state)))
|
||||
case .absolute:
|
||||
state.accumulator = MEMORY_READ_UINT8(state: state, address: OPERAND_ABSOLUTE(state: state))
|
||||
case .absolute_indexed_x:
|
||||
state.accumulator = MEMORY_READ_UINT8(state: state, address: OPERAND_ABSOLUTE_INDEXED_X(state: state))
|
||||
case .absolute_indexed_y:
|
||||
state.accumulator = MEMORY_READ_UINT8(state: state, address: OPERAND_ABSOLUTE_INDEXED_Y(state: state))
|
||||
default:
|
||||
print("Unhandled addressing mode \(addressingMode) for LDA")
|
||||
}
|
||||
|
||||
state.setZeroFlag();
|
||||
state.setNegativeFlag();
|
||||
}
|
||||
}
|
@ -9,10 +9,22 @@
|
||||
import Cocoa
|
||||
|
||||
class ViewController: NSViewController {
|
||||
|
||||
let CPU = CPUState.sharedInstance
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
CPU.memoryInterface.memory[0] = 0xAD
|
||||
CPU.memoryInterface.memory[1] = 0x00
|
||||
CPU.memoryInterface.memory[2] = 0x00
|
||||
|
||||
do {
|
||||
try CPU.executeNextInstruction()
|
||||
} catch CPUExceptions.invalidInstruction {
|
||||
print("*** 6502 Exception: Invalid instruction 0xXX at 0xXXXX")
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user