JMP works now yay

This commit is contained in:
Luigi Thirty 2017-07-21 22:13:53 -04:00
parent 944f51a186
commit e1a6a0c1b3
6 changed files with 129 additions and 97 deletions

View File

@ -2,9 +2,9 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>

View File

@ -46,54 +46,58 @@ class CPUInstruction: NSObject {
let InstructionTable: [UInt8:CPUInstruction] = [
//JMP
0x4C: CPUInstruction(mnemonic: "JMP", cycles: 3, bytes: 3, addressingMode: .absolute, action: Opcodes.JMP),
0x6C: CPUInstruction(mnemonic: "JMP", cycles: 5, bytes: 3, addressingMode: .indirect, action: Opcodes.JMP),
//LD instructions
0xA9: CPUInstruction.init(mnemonic: "LDA", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDA),
0xA5: CPUInstruction.init(mnemonic: "LDA", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDA),
0xB5: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.LDA),
0xAD: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDA),
0xBD: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.LDA),
0xB9: CPUInstruction.init(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.LDA),
0xA1: CPUInstruction.init(mnemonic: "LDA", cycles: 6, bytes: 2, addressingMode: .indexed_indirect, action: Opcodes.LDA),
0xB1: CPUInstruction.init(mnemonic: "LDA", cycles: 5, bytes: 2, addressingMode: .indirect_indexed, action: Opcodes.LDA),
0xA9: CPUInstruction(mnemonic: "LDA", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDA),
0xA5: CPUInstruction(mnemonic: "LDA", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDA),
0xB5: CPUInstruction(mnemonic: "LDA", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.LDA),
0xAD: CPUInstruction(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDA),
0xBD: CPUInstruction(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.LDA),
0xB9: CPUInstruction(mnemonic: "LDA", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.LDA),
0xA1: CPUInstruction(mnemonic: "LDA", cycles: 6, bytes: 2, addressingMode: .indexed_indirect, action: Opcodes.LDA),
0xB1: CPUInstruction(mnemonic: "LDA", cycles: 5, bytes: 2, addressingMode: .indirect_indexed, action: Opcodes.LDA),
0xA2: CPUInstruction.init(mnemonic: "LDX", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDX),
0xA6: CPUInstruction.init(mnemonic: "LDX", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDX),
0xB6: CPUInstruction.init(mnemonic: "LDX", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_y, action: Opcodes.LDX),
0xAE: CPUInstruction.init(mnemonic: "LDX", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDX),
0xBE: CPUInstruction.init(mnemonic: "LDX", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.LDX),
0xA2: CPUInstruction(mnemonic: "LDX", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDX),
0xA6: CPUInstruction(mnemonic: "LDX", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDX),
0xB6: CPUInstruction(mnemonic: "LDX", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_y, action: Opcodes.LDX),
0xAE: CPUInstruction(mnemonic: "LDX", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDX),
0xBE: CPUInstruction(mnemonic: "LDX", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.LDX),
0xA0: CPUInstruction.init(mnemonic: "LDY", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDY),
0xA4: CPUInstruction.init(mnemonic: "LDY", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDY),
0xB4: CPUInstruction.init(mnemonic: "LDY", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.LDY),
0xAC: CPUInstruction.init(mnemonic: "LDY", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.LDY),
0xBC: CPUInstruction.init(mnemonic: "LDY", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.LDY),
0xA0: CPUInstruction(mnemonic: "LDY", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.LDY),
0xA4: CPUInstruction(mnemonic: "LDY", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.LDY),
0xB4: CPUInstruction(mnemonic: "LDY", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.LDY),
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),
//Register functions
0x88: CPUInstruction.init(mnemonic: "DEY", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.DEY),
0x8A: CPUInstruction.init(mnemonic: "TXA", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TXA),
0x98: CPUInstruction.init(mnemonic: "TYA", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TYA),
0xA8: CPUInstruction.init(mnemonic: "TAY", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TAY),
0xAA: CPUInstruction.init(mnemonic: "TAX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TAX),
0xC8: CPUInstruction.init(mnemonic: "INY", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.INY),
0xCA: CPUInstruction.init(mnemonic: "DEX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.DEX),
0xE8: CPUInstruction.init(mnemonic: "INX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.INX),
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),
0x98: CPUInstruction(mnemonic: "TYA", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TYA),
0xA8: CPUInstruction(mnemonic: "TAY", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TAY),
0xAA: CPUInstruction(mnemonic: "TAX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TAX),
0xC8: CPUInstruction(mnemonic: "INY", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.INY),
0xCA: CPUInstruction(mnemonic: "DEX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.DEX),
0xE8: CPUInstruction(mnemonic: "INX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.INX),
//Processor flag instructions
0x18: CPUInstruction.init(mnemonic: "CLC", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLC),
0x38: CPUInstruction.init(mnemonic: "SEC", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.SEC),
0x58: CPUInstruction.init(mnemonic: "CLI", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLI),
0x78: CPUInstruction.init(mnemonic: "SEI", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.SEI),
0xB8: CPUInstruction.init(mnemonic: "CLV", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLV),
0xD8: CPUInstruction.init(mnemonic: "CLD", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLD),
0xF8: CPUInstruction.init(mnemonic: "SED", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.SED),
0x18: CPUInstruction(mnemonic: "CLC", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLC),
0x38: CPUInstruction(mnemonic: "SEC", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.SEC),
0x58: CPUInstruction(mnemonic: "CLI", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLI),
0x78: CPUInstruction(mnemonic: "SEI", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.SEI),
0xB8: CPUInstruction(mnemonic: "CLV", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLV),
0xD8: CPUInstruction(mnemonic: "CLD", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.CLD),
0xF8: CPUInstruction(mnemonic: "SED", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.SED),
//Stack instructions
0x9A: CPUInstruction.init(mnemonic: "TXS", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TXS),
0xBA: CPUInstruction.init(mnemonic: "TSX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TSX),
0x48: CPUInstruction.init(mnemonic: "PHA", cycles: 3, bytes: 1, addressingMode: .implied, action: Opcodes.PHA),
0x68: CPUInstruction.init(mnemonic: "PLA", cycles: 4, bytes: 1, addressingMode: .implied, action: Opcodes.PLA),
0x08: CPUInstruction.init(mnemonic: "PHP", cycles: 3, bytes: 1, addressingMode: .implied, action: Opcodes.PHP),
0x28: CPUInstruction.init(mnemonic: "PLP", cycles: 4, bytes: 1, addressingMode: .implied, action: Opcodes.PLP),
0x9A: CPUInstruction(mnemonic: "TXS", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TXS),
0xBA: CPUInstruction(mnemonic: "TSX", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.TSX),
0x48: CPUInstruction(mnemonic: "PHA", cycles: 3, bytes: 1, addressingMode: .implied, action: Opcodes.PHA),
0x68: CPUInstruction(mnemonic: "PLA", cycles: 4, bytes: 1, addressingMode: .implied, action: Opcodes.PLA),
0x08: CPUInstruction(mnemonic: "PHP", cycles: 3, bytes: 1, addressingMode: .implied, action: Opcodes.PHP),
0x28: CPUInstruction(mnemonic: "PLP", cycles: 4, bytes: 1, addressingMode: .implied, action: Opcodes.PLP),
0xEA: CPUInstruction.init(mnemonic: "NOP", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.NOP),
0xEA: CPUInstruction(mnemonic: "NOP", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.NOP),
]

View File

@ -22,7 +22,7 @@ struct StatusRegister {
var zero: Bool //Z - 0x02
var carry: Bool //C - 0x01
mutating func setState(state: UInt8) {
mutating func fromByte(state: UInt8) {
negative = (state & 0x80 == 0x80)
overflow = (state & 0x40 == 0x40)
brk = (state & 0x10 == 0x10)
@ -113,7 +113,7 @@ class CPUState: NSObject {
}
func executeNextInstruction() throws {
instruction_register = memoryInterface.memory[Int(program_counter)]
instruction_register = memoryInterface.readByte(offset: program_counter)
let operation = InstructionTable[instruction_register]
if(operation == nil) {
throw CPUExceptions.invalidInstruction
@ -127,15 +127,17 @@ class CPUState: NSObject {
self.page_boundary_crossed = false
}
self.program_counter = UInt16(Int(self.program_counter) + operation!.bytes)
if(operation!.mnemonic != "JMP") {
self.program_counter = UInt16(Int(self.program_counter) + operation!.bytes)
}
}
func updateNegativeFlag() {
status_register.negative = (accumulator & 0x80 == 0x80)
func updateNegativeFlag(value: UInt8) {
status_register.negative = (value & 0x80 == 0x80)
}
func updateZeroFlag() {
status_register.zero = (accumulator == 0)
func updateZeroFlag(value: UInt8) {
status_register.zero = (value == 0)
}
}

View File

@ -9,7 +9,8 @@
import Cocoa
class MemoryInterface: NSObject {
var memory: [UInt8]
fileprivate var memory: [UInt8]
override init() {
memory = [UInt8](repeating: 0x00, count: 65536)
@ -26,4 +27,13 @@ class MemoryInterface: NSObject {
func readWord(offset: UInt16) -> UInt16 {
return UInt16(memory[Int(offset)] | (memory[Int(offset+1)] << 8))
}
func loadBinary(path: String) {
do {
let fileContent: NSData = try NSData(contentsOfFile: path)
fileContent.getBytes(&memory, range: NSRange(location: 0, length: 65536))
} catch {
print(error)
}
}
}

View File

@ -8,6 +8,10 @@
import Cocoa
func stackPointerAsUInt16(state: CPUState) -> UInt16 {
return 0x0100 | UInt16(state.stack_pointer);
}
func getOperand(state: CPUState, mode: AddressingMode) -> UInt8 {
switch (mode) {
@ -33,22 +37,35 @@ func getOperand(state: CPUState, mode: AddressingMode) -> UInt8 {
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))
state.accumulator = state.memoryInterface.readByte(offset: pointer)
return state.memoryInterface.readByte(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)
state.accumulator = state.memoryInterface.readByte(offset: pointer)
case .indirect:
//JMP is the only instruction that does this - handle it specially since it's a UInt16
break
return state.memoryInterface.readByte(offset: pointer)
default:
print("Called getOperand on an instruction in addressing mode \(mode)")
print("Called getOperand: UInt8 on an instruction that expects a UInt16.")
return 0
}
}
func getOperand(state: CPUState, mode: AddressingMode) -> UInt16 {
//Function that will provide a 16-bit operand to instructions.
//All instructions have 2 data bytes, little-endian.
switch(mode) {
case .absolute:
return state.getOperandWord()
case .absolute_indexed_x:
return state.getOperandWord() + state.index_x
case .absolute_indexed_y:
return state.getOperandWord() + state.index_y
case .indirect:
return state.memoryInterface.readWord(offset: state.getOperandWord())
default:
print("Called getOperand: UInt16 on an instruction that expects a UInt8")
return 0
}
return 0 //never gets here
}
/* */
@ -58,79 +75,79 @@ class Opcodes: NSObject {
static func LDA(state: CPUState, addressingMode: AddressingMode) -> Void {
state.accumulator = getOperand(state: state, mode: addressingMode)
state.updateZeroFlag()
state.updateNegativeFlag()
state.updateZeroFlag(value: state.accumulator)
state.updateNegativeFlag(value: state.accumulator)
}
static func LDX(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_x = getOperand(state: state, mode: addressingMode)
state.updateZeroFlag()
state.updateNegativeFlag()
state.updateZeroFlag(value: state.index_x)
state.updateNegativeFlag(value: state.index_x)
}
static func LDY(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_y = getOperand(state: state, mode: addressingMode)
state.updateZeroFlag()
state.updateNegativeFlag()
state.updateZeroFlag(value: state.index_y)
state.updateNegativeFlag(value: state.index_y)
}
//Register instructions
static func TAX(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_x = state.accumulator
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_x);
state.updateNegativeFlag(value: state.index_x);
}
static func TXA(state: CPUState, addressingMode: AddressingMode) -> Void {
state.accumulator = state.index_x
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.accumulator);
state.updateNegativeFlag(value: state.accumulator);
}
static func DEX(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_x = state.index_x &- 1
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_x);
state.updateNegativeFlag(value: state.index_x);
}
static func INX(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_x = state.index_x &+ 1
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_x);
state.updateNegativeFlag(value: state.index_x);
}
static func TAY(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_y = state.accumulator
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_y);
state.updateNegativeFlag(value: state.index_y);
}
static func TYA(state: CPUState, addressingMode: AddressingMode) -> Void {
state.accumulator = state.index_y
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.accumulator);
state.updateNegativeFlag(value: state.accumulator);
}
static func DEY(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_y = state.index_x &- 1
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_y);
state.updateNegativeFlag(value: state.index_y);
}
static func INY(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_y = state.index_x &+ 1
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_y);
state.updateNegativeFlag(value: state.index_y);
}
//Processor flag instructions
@ -170,31 +187,35 @@ class Opcodes: NSObject {
static func TSX(state: CPUState, addressingMode: AddressingMode) -> Void {
state.index_x = state.stack_pointer
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.index_x);
state.updateNegativeFlag(value: state.index_x);
}
static func PHA(state: CPUState, addressingMode: AddressingMode) -> Void {
state.memoryInterface.writeByte(offset: 0x0100 | UInt16(state.stack_pointer), value: state.accumulator)
state.memoryInterface.writeByte(offset: stackPointerAsUInt16(state: state), value: state.accumulator)
state.stack_pointer = state.stack_pointer &- 1
}
static func PLA(state: CPUState, addressingMode: AddressingMode) -> Void {
state.stack_pointer = state.stack_pointer &+ 1
state.accumulator = state.memoryInterface.readByte(offset: 0x0100 | UInt16(state.stack_pointer))
state.accumulator = state.memoryInterface.readByte(offset: stackPointerAsUInt16(state: state))
state.updateZeroFlag();
state.updateNegativeFlag();
state.updateZeroFlag(value: state.accumulator);
state.updateNegativeFlag(value: state.accumulator);
}
static func PHP(state: CPUState, addressingMode: AddressingMode) -> Void {
state.memoryInterface.writeByte(offset: 0x0100 | UInt16(state.stack_pointer), value: state.status_register.asByte())
state.memoryInterface.writeByte(offset: stackPointerAsUInt16(state: state), value: state.status_register.asByte())
state.stack_pointer = state.stack_pointer &- 1
}
static func PLP(state: CPUState, addressingMode: AddressingMode) -> Void {
state.stack_pointer = state.stack_pointer &+ 1
state.status_register.setState(state: state.memoryInterface.readByte(offset: 0x0100 | UInt16(state.stack_pointer)))
state.status_register.fromByte(state: state.memoryInterface.readByte(offset: stackPointerAsUInt16(state: state)))
}
static func JMP(state: CPUState, addressingMode: AddressingMode) -> Void {
state.program_counter = getOperand(state: state, mode: addressingMode)
}
static func NOP(state: CPUState, addressingMode: AddressingMode) -> Void {}

View File

@ -14,12 +14,7 @@ class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
CPU.memoryInterface.memory[0] = 0xAD
CPU.memoryInterface.memory[1] = 0x34
CPU.memoryInterface.memory[2] = 0x12
CPU.memoryInterface.memory[0x1234] = 0xAA
CPU.memoryInterface.loadBinary(path: "/Users/luigi/6502/test.bin")
do {
try CPU.executeNextInstruction()