From eb9f02758b6dc1413072f93829081ad638e6b5cb Mon Sep 17 00:00:00 2001 From: Luigi Thirty Date: Sun, 23 Jul 2017 14:50:46 -0400 Subject: [PATCH] more instructions, just need ADC/SBC and the shift instructions now --- FruitMachine/M6502/CPUInstructions.swift | 13 ++++ FruitMachine/M6502/CPUState.swift | 10 +++ FruitMachine/M6502/Opcodes.swift | 83 +++++++++++++++++++++++- 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/FruitMachine/M6502/CPUInstructions.swift b/FruitMachine/M6502/CPUInstructions.swift index 069c231..f4c01a0 100644 --- a/FruitMachine/M6502/CPUInstructions.swift +++ b/FruitMachine/M6502/CPUInstructions.swift @@ -155,7 +155,20 @@ let InstructionTable: [UInt8:CPUInstruction] = [ 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), + //Branch instructions + 0x10: CPUInstruction(mnemonic: "BPL", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BPL), + 0x30: CPUInstruction(mnemonic: "BMI", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BMI), + 0x50: CPUInstruction(mnemonic: "BVC", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BVC), + 0x70: CPUInstruction(mnemonic: "BVS", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BVS), + 0x90: CPUInstruction(mnemonic: "BCC", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BCC), + 0xB0: CPUInstruction(mnemonic: "BCS", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BCS), + 0xD0: CPUInstruction(mnemonic: "BNE", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BNE), + 0xF0: CPUInstruction(mnemonic: "BEQ", cycles: 2, bytes: 2, addressingMode: .relative, action: Opcodes.BEQ), + 0x20: CPUInstruction(mnemonic: "JSR", cycles: 6, bytes: 3, addressingMode: .absolute, action: Opcodes.JSR), + 0x60: CPUInstruction(mnemonic: "RTS", cycles: 6, bytes: 1, addressingMode: .implied, action: Opcodes.RTS), + + 0x00: CPUInstruction(mnemonic: "BRK", cycles: 7, bytes: 1, addressingMode: .implied, action: Opcodes.BRK), 0xEA: CPUInstruction(mnemonic: "NOP", cycles: 2, bytes: 1, addressingMode: .implied, action: Opcodes.NOP), ] diff --git a/FruitMachine/M6502/CPUState.swift b/FruitMachine/M6502/CPUState.swift index 1d0c1e8..14151e1 100644 --- a/FruitMachine/M6502/CPUState.swift +++ b/FruitMachine/M6502/CPUState.swift @@ -123,6 +123,8 @@ class CPUState: NSObject { var memoryInterface: MemoryInterface + var branch_was_taken: Bool + override init() { cycles = 0 @@ -136,7 +138,11 @@ class CPUState: NSObject { status_register = StatusRegister(negative: false, overflow: false, brk: false, decimal: false, irq_disable: false, zero: false, carry: false) memoryInterface = MemoryInterface() + //Some instructions incur a 1-cycle penalty if crossing a page boundary. page_boundary_crossed = false + //Branches incur a 1-cycle penalty if taken plus the page boundary penalty if necessary. + branch_was_taken = false + } func disassemble(fromAddress: UInt16, length: UInt16) -> [Disassembly] { @@ -212,6 +218,10 @@ class CPUState: NSObject { self.cycles += 1 self.page_boundary_crossed = false } + if(self.branch_was_taken) { + self.cycles += 1 + self.branch_was_taken = false + } if(operation!.mnemonic != "JMP") { self.program_counter = UInt16(Int(self.program_counter) + operation!.bytes) diff --git a/FruitMachine/M6502/Opcodes.swift b/FruitMachine/M6502/Opcodes.swift index bf27792..77d9a4b 100644 --- a/FruitMachine/M6502/Opcodes.swift +++ b/FruitMachine/M6502/Opcodes.swift @@ -10,6 +10,18 @@ import Cocoa extension CPUState { + func popByte() -> UInt8 { + stack_pointer = stack_pointer &+ 1 + return memoryInterface.readByte(offset: stackPointerAsUInt16()) + } + + func popWord() -> UInt16 { + let low = popByte() + let high = popByte() + + return (UInt16(high) << 8) | UInt16(low) + } + func pushByte(data: UInt8) -> Void { memoryInterface.writeByte(offset: stackPointerAsUInt16(), value: data) stack_pointer = stack_pointer &- 1 @@ -27,6 +39,15 @@ extension CPUState { return 0x0100 | UInt16(stack_pointer); } + func doBranch() { + let distance = getOperandByte() + + if(((program_counter & 0x00FF) + distance) > 0x0100) { + page_boundary_crossed = true + } + program_counter = program_counter + distance + branch_was_taken = true + } } func getOperandByteForAddressingMode(state: CPUState, mode: AddressingMode) -> UInt8 { @@ -391,16 +412,74 @@ class Opcodes: NSObject { state.status_register.fromByte(state: state.memoryInterface.readByte(offset: state.stackPointerAsUInt16())) } + static func BPL(state: CPUState, addressingMode: AddressingMode) -> Void { + if(!state.status_register.negative) { + state.doBranch() + } + } + + static func BMI(state: CPUState, addressingMode: AddressingMode) -> Void { + if(state.status_register.negative) { + state.doBranch() + } + } + + static func BVC(state: CPUState, addressingMode: AddressingMode) -> Void { + if(!state.status_register.overflow) { + state.doBranch() + } + } + + static func BVS(state: CPUState, addressingMode: AddressingMode) -> Void { + if(state.status_register.overflow) { + state.doBranch() + } + } + + static func BCC(state: CPUState, addressingMode: AddressingMode) -> Void { + if(!state.status_register.carry) { + state.doBranch() + } + } + + static func BCS(state: CPUState, addressingMode: AddressingMode) -> Void { + if(state.status_register.carry) { + state.doBranch() + } + } + + static func BNE(state: CPUState, addressingMode: AddressingMode) -> Void { + if(!state.status_register.zero) { + state.doBranch() + } + } + + static func BEQ(state: CPUState, addressingMode: AddressingMode) -> Void { + if(state.status_register.zero) { + state.doBranch() + } + } + //Misc static func JMP(state: CPUState, addressingMode: AddressingMode) -> Void { state.program_counter = getOperandWordForAddressingMode(state: state, mode: addressingMode) } static func JSR(state: CPUState, addressingMode: AddressingMode) -> Void { - //JSR pushes the address-1 of the next operation on to the stack before transferring program control to the following address - state.pushWord(data: state.program_counter + 3) + state.pushWord(data: state.program_counter - 1) state.program_counter = state.getOperandWord() } + static func RTS(state: CPUState, addressingMode: AddressingMode) -> Void { + state.program_counter = state.popWord() + 1 + } + + static func BRK(state: CPUState, addressingMode: AddressingMode) -> Void { + state.status_register.brk = true + state.pushWord(data: state.program_counter) + state.pushByte(data: state.status_register.asByte()) + state.program_counter = state.memoryInterface.readWord(offset: 0xFFFE) + } + static func NOP(state: CPUState, addressingMode: AddressingMode) -> Void {} }