more instructions work
This commit is contained in:
parent
eb9f02758b
commit
dc0d454a12
|
@ -21,6 +21,16 @@ class DebuggerViewController: NSViewController {
|
|||
let CPU = CPUState.sharedInstance
|
||||
var disassembly: [Disassembly] = [Disassembly]()
|
||||
|
||||
func highlightCurrentInstruction() -> Bool {
|
||||
for (index, instruction) in disassembly.enumerated() {
|
||||
if(instruction.address == CPU.program_counter) {
|
||||
debuggerTableView.selectRowIndexes(NSIndexSet(index: index) as IndexSet, byExtendingSelection: false)
|
||||
return true //instruction found
|
||||
}
|
||||
}
|
||||
return false //instruction not found
|
||||
}
|
||||
|
||||
func updateCPUStatusFields() {
|
||||
text_CPU_A.stringValue = String(format:"%02X", CPU.accumulator)
|
||||
text_CPU_X.stringValue = String(format:"%02X", CPU.index_x)
|
||||
|
@ -28,6 +38,11 @@ class DebuggerViewController: NSViewController {
|
|||
text_CPU_IP.stringValue = String(format:"%04X", CPU.program_counter)
|
||||
text_CPU_SR.stringValue = String(format:"%02X", CPU.stack_pointer)
|
||||
text_CPU_Flags.stringValue = String(CPU.status_register.asString())
|
||||
|
||||
if(!highlightCurrentInstruction()) {
|
||||
disassembly = CPU.disassemble(fromAddress: CPU.program_counter, length: 256)
|
||||
highlightCurrentInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
@ -37,8 +52,10 @@ class DebuggerViewController: NSViewController {
|
|||
debuggerTableView.dataSource = self
|
||||
|
||||
CPU.memoryInterface.loadBinary(path: "/Users/luigi/6502/test.bin")
|
||||
CPU.performReset()
|
||||
CPU.program_counter = 0x400 //entry point for the test program
|
||||
updateCPUStatusFields()
|
||||
disassembly = CPU.disassemble(fromAddress: 0x0000, length: 16)
|
||||
disassembly = CPU.disassemble(fromAddress: CPU.program_counter, length: 10000)
|
||||
debuggerTableView.reloadData()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
|
|
|
@ -46,6 +46,16 @@ class CPUInstruction: NSObject {
|
|||
|
||||
let InstructionTable: [UInt8:CPUInstruction] = [
|
||||
|
||||
//ADC/SBC
|
||||
0x69: CPUInstruction(mnemonic: "ADC", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.ADC),
|
||||
0x65: CPUInstruction(mnemonic: "ADC", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.ADC),
|
||||
0x75: CPUInstruction(mnemonic: "ADC", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.ADC),
|
||||
0x6D: CPUInstruction(mnemonic: "ADC", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.ADC),
|
||||
0x7D: CPUInstruction(mnemonic: "ADC", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.ADC),
|
||||
0x79: CPUInstruction(mnemonic: "ADC", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.ADC),
|
||||
0x61: CPUInstruction(mnemonic: "ADC", cycles: 6, bytes: 2, addressingMode: .indexed_indirect, action: Opcodes.ADC),
|
||||
0x71: CPUInstruction(mnemonic: "ADC", cycles: 5, bytes: 2, addressingMode: .indirect_indexed, action: Opcodes.ADC),
|
||||
|
||||
//Boolean operators
|
||||
0x09: CPUInstruction(mnemonic: "ORA", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.ORA),
|
||||
0x05: CPUInstruction(mnemonic: "ORA", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.ORA),
|
||||
|
@ -74,6 +84,34 @@ let InstructionTable: [UInt8:CPUInstruction] = [
|
|||
0x21: CPUInstruction(mnemonic: "AND", cycles: 6, bytes: 2, addressingMode: .indexed_indirect, action: Opcodes.AND),
|
||||
0x31: CPUInstruction(mnemonic: "AND", cycles: 5, bytes: 2, addressingMode: .indirect_indexed, action: Opcodes.AND),
|
||||
|
||||
//Bitwise operations
|
||||
0x24: CPUInstruction(mnemonic: "BIT", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.BIT),
|
||||
0x2C: CPUInstruction(mnemonic: "BIT", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.BIT),
|
||||
|
||||
0x0A: CPUInstruction(mnemonic: "ASL", cycles: 2, bytes: 1, addressingMode: .accumulator, action: Opcodes.ASL),
|
||||
0x06: CPUInstruction(mnemonic: "ASL", cycles: 5, bytes: 2, addressingMode: .zeropage, action: Opcodes.ASL),
|
||||
0x16: CPUInstruction(mnemonic: "ASL", cycles: 6, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.ASL),
|
||||
0x0E: CPUInstruction(mnemonic: "ASL", cycles: 6, bytes: 3, addressingMode: .absolute, action: Opcodes.ASL),
|
||||
0x1E: CPUInstruction(mnemonic: "ASL", cycles: 7, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.ASL),
|
||||
|
||||
0x4A: CPUInstruction(mnemonic: "LSR", cycles: 2, bytes: 1, addressingMode: .accumulator, action: Opcodes.LSR),
|
||||
0x46: CPUInstruction(mnemonic: "LSR", cycles: 5, bytes: 2, addressingMode: .zeropage, action: Opcodes.LSR),
|
||||
0x56: CPUInstruction(mnemonic: "LSR", cycles: 6, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.LSR),
|
||||
0x4E: CPUInstruction(mnemonic: "LSR", cycles: 6, bytes: 3, addressingMode: .absolute, action: Opcodes.LSR),
|
||||
0x5E: CPUInstruction(mnemonic: "LSR", cycles: 7, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.LSR),
|
||||
|
||||
0x2A: CPUInstruction(mnemonic: "ROL", cycles: 2, bytes: 1, addressingMode: .accumulator, action: Opcodes.ROL),
|
||||
0x26: CPUInstruction(mnemonic: "ROL", cycles: 5, bytes: 2, addressingMode: .zeropage, action: Opcodes.ROL),
|
||||
0x36: CPUInstruction(mnemonic: "ROL", cycles: 6, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.ROL),
|
||||
0x2E: CPUInstruction(mnemonic: "ROL", cycles: 6, bytes: 3, addressingMode: .absolute, action: Opcodes.ROL),
|
||||
0x3E: CPUInstruction(mnemonic: "ROL", cycles: 7, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.ROL),
|
||||
|
||||
0x6A: CPUInstruction(mnemonic: "ROL", cycles: 2, bytes: 1, addressingMode: .accumulator, action: Opcodes.ROR),
|
||||
0x66: CPUInstruction(mnemonic: "ROL", cycles: 5, bytes: 2, addressingMode: .zeropage, action: Opcodes.ROR),
|
||||
0x76: CPUInstruction(mnemonic: "ROL", cycles: 6, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.ROR),
|
||||
0x6E: CPUInstruction(mnemonic: "ROL", cycles: 6, bytes: 3, addressingMode: .absolute, action: Opcodes.ROR),
|
||||
0x7E: CPUInstruction(mnemonic: "ROL", cycles: 7, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.ROR),
|
||||
|
||||
//INC/DEC
|
||||
0xC6: CPUInstruction(mnemonic: "DEC", cycles: 5, bytes: 2, addressingMode: .zeropage, action: Opcodes.DEC),
|
||||
0xD6: CPUInstruction(mnemonic: "DEC", cycles: 6, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.DEC),
|
||||
|
@ -128,6 +166,24 @@ let InstructionTable: [UInt8:CPUInstruction] = [
|
|||
0x94: CPUInstruction(mnemonic: "STY", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.STY),
|
||||
0x8C: CPUInstruction(mnemonic: "STY", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.STY),
|
||||
|
||||
//Compare functions
|
||||
0xC9: CPUInstruction(mnemonic: "CMP", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.CMP),
|
||||
0xC5: CPUInstruction(mnemonic: "CMP", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.CMP),
|
||||
0xD5: CPUInstruction(mnemonic: "CMP", cycles: 4, bytes: 2, addressingMode: .zeropage_indexed_x, action: Opcodes.CMP),
|
||||
0xCD: CPUInstruction(mnemonic: "CMP", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.CMP),
|
||||
0xDD: CPUInstruction(mnemonic: "CMP", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_x, action: Opcodes.CMP),
|
||||
0xD9: CPUInstruction(mnemonic: "CMP", cycles: 4, bytes: 3, addressingMode: .absolute_indexed_y, action: Opcodes.CMP),
|
||||
0xC1: CPUInstruction(mnemonic: "CMP", cycles: 6, bytes: 2, addressingMode: .indexed_indirect, action: Opcodes.CMP),
|
||||
0xD1: CPUInstruction(mnemonic: "CMP", cycles: 5, bytes: 2, addressingMode: .indirect_indexed, action: Opcodes.CMP),
|
||||
|
||||
0xE0: CPUInstruction(mnemonic: "CPX", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.CPX),
|
||||
0xE4: CPUInstruction(mnemonic: "CPX", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.CPX),
|
||||
0xEC: CPUInstruction(mnemonic: "CPX", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.CPX),
|
||||
|
||||
0xC0: CPUInstruction(mnemonic: "CPY", cycles: 2, bytes: 2, addressingMode: .immediate, action: Opcodes.CPY),
|
||||
0xC4: CPUInstruction(mnemonic: "CPY", cycles: 3, bytes: 2, addressingMode: .zeropage, action: Opcodes.CPY),
|
||||
0xCC: CPUInstruction(mnemonic: "CPY", cycles: 4, bytes: 3, addressingMode: .absolute, action: Opcodes.CPY),
|
||||
|
||||
//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),
|
||||
|
|
|
@ -77,7 +77,7 @@ struct StatusRegister {
|
|||
}
|
||||
|
||||
func asByte() -> UInt8 {
|
||||
var val: UInt8 = 0x00
|
||||
var val: UInt8 = 0x20 //unused bit is hardwired to 1
|
||||
|
||||
if(negative) {
|
||||
val |= 0x80
|
||||
|
@ -106,6 +106,10 @@ struct StatusRegister {
|
|||
}
|
||||
|
||||
class CPUState: NSObject {
|
||||
let NMI_VECTOR: UInt16 = 0xFFFA
|
||||
let RESET_VECTOR: UInt16 = 0xFFFC
|
||||
let IRQ_VECTOR: UInt16 = 0xFFFE
|
||||
|
||||
static var sharedInstance = CPUState()
|
||||
|
||||
var cycles: Int
|
||||
|
@ -228,6 +232,12 @@ class CPUState: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
func performReset() {
|
||||
program_counter = memoryInterface.readWord(offset: RESET_VECTOR)
|
||||
stack_pointer = 0xFF
|
||||
status_register.irq_disable = true
|
||||
}
|
||||
|
||||
func updateNegativeFlag(value: UInt8) {
|
||||
status_register.negative = (value & 0x80 == 0x80)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ import Cocoa
|
|||
|
||||
extension UInt16 {
|
||||
static func + (left: UInt16, right: UInt8) -> UInt16 {
|
||||
return left + right
|
||||
return left + UInt16(right)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,19 @@ extension CPUState {
|
|||
}
|
||||
|
||||
func doBranch() {
|
||||
let distance = getOperandByte()
|
||||
let distance = Int8(bitPattern: getOperandByte())
|
||||
|
||||
if(((program_counter & 0x00FF) + distance) > 0x0100) {
|
||||
page_boundary_crossed = true
|
||||
if(distance < 0) {
|
||||
if((program_counter & 0x00FF) - UInt16(abs(Int16(distance))) > 0x8000) {
|
||||
page_boundary_crossed = true
|
||||
}
|
||||
} else {
|
||||
if((program_counter & 0x00FF) + UInt16(abs(Int16(distance)))ß > 0x0100) {
|
||||
page_boundary_crossed = true
|
||||
}
|
||||
}
|
||||
program_counter = program_counter + distance
|
||||
|
||||
program_counter = UInt16(Int(program_counter) + Int(distance))
|
||||
branch_was_taken = true
|
||||
}
|
||||
}
|
||||
|
@ -115,10 +122,35 @@ func getOperandWordForAddressingMode(state: CPUState, mode: AddressingMode) -> U
|
|||
|
||||
}
|
||||
|
||||
func hex2bcd(hex: UInt8) -> UInt8 {
|
||||
var y: UInt8 = (hex / 10) << 4
|
||||
y = y | (hex % 10)
|
||||
return y
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
class Opcodes: NSObject {
|
||||
|
||||
static func ADC(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
let operand = UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode))
|
||||
|
||||
var t16: UInt16 = UInt16(state.accumulator &+ operand) + UInt16((state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
let t8: UInt8 = UInt8(t16 & 0xFF)
|
||||
|
||||
state.status_register.overflow = (~(state.accumulator ^ operand) & (state.accumulator ^ t8) & 0x80) == 0x80
|
||||
state.status_register.zero = (t8 == 0)
|
||||
state.status_register.negative = (t8 & 0x80) == 0x80
|
||||
|
||||
if(state.status_register.decimal) {
|
||||
t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
} else {
|
||||
state.status_register.carry = (t16 > 255)
|
||||
}
|
||||
|
||||
state.accumulator = (UInt8(t16 & 0xFF))
|
||||
}
|
||||
|
||||
static func LDA(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
state.accumulator = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
|
@ -323,7 +355,7 @@ class Opcodes: NSObject {
|
|||
|
||||
state.updateZeroFlag(value: data)
|
||||
state.updateNegativeFlag(value: data)
|
||||
state.status_register.carry = (data >= 0)
|
||||
state.status_register.carry = (data >= 0)
|
||||
}
|
||||
|
||||
//Boolean operators
|
||||
|
@ -348,6 +380,106 @@ class Opcodes: NSObject {
|
|||
state.updateNegativeFlag(value: state.accumulator)
|
||||
}
|
||||
|
||||
//Bitwise operators
|
||||
static func BIT(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
let operand = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
let data = state.accumulator & operand
|
||||
|
||||
state.updateZeroFlag(value: data)
|
||||
state.updateNegativeFlag(value: operand)
|
||||
state.status_register.overflow = (state.accumulator & UInt8(0x40)) == 0x40
|
||||
}
|
||||
|
||||
static func ASL(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .implied) {
|
||||
operand = state.accumulator
|
||||
state.status_register.carry = ((operand & 0x80) == 0x80)
|
||||
state.accumulator = (state.accumulator &<< 1) & 0xFE
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.updateNegativeFlag(value: state.accumulator)
|
||||
} else {
|
||||
let address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
||||
var data = state.memoryInterface.readByte(offset: address)
|
||||
state.status_register.carry = (data & 0x80) == 0x80
|
||||
data = (data &<< 1) & 0xFE
|
||||
state.memoryInterface.writeByte(offset: address, value: data)
|
||||
state.updateZeroFlag(value: data)
|
||||
state.updateNegativeFlag(value: data)
|
||||
}
|
||||
}
|
||||
|
||||
static func LSR(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .implied) {
|
||||
operand = state.accumulator
|
||||
state.status_register.carry = ((operand & 0x01) == 0x01)
|
||||
state.accumulator = (state.accumulator &>> 1) & 0x7F
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.status_register.negative = false
|
||||
} else {
|
||||
let address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
||||
var data = state.memoryInterface.readByte(offset: address)
|
||||
state.status_register.carry = (data & 0x01) == 0x01
|
||||
data = (data &>> 1) & 0x7F
|
||||
state.memoryInterface.writeByte(offset: address, value: data)
|
||||
state.updateZeroFlag(value: data)
|
||||
state.updateNegativeFlag(value: data)
|
||||
}
|
||||
}
|
||||
|
||||
static func ROL(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .implied) {
|
||||
operand = state.accumulator
|
||||
|
||||
state.accumulator = (state.accumulator &<< 1) & 0xFE
|
||||
state.accumulator = state.accumulator | (state.status_register.carry ? 0x01 : 0x00)
|
||||
|
||||
state.status_register.carry = ((operand & 0x80) == 0x80)
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.status_register.negative = (state.accumulator & 0x80) == 0x80
|
||||
} else {
|
||||
let address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
||||
var data = state.memoryInterface.readByte(offset: address)
|
||||
|
||||
data = (data &<< 1) & 0xFE
|
||||
data = data | (state.status_register.carry ? 0x01 : 0x00)
|
||||
state.memoryInterface.writeByte(offset: address, value: data)
|
||||
|
||||
state.status_register.carry = (data & 0x80) == 0x80
|
||||
state.updateZeroFlag(value: data)
|
||||
state.status_register.negative = (data & 0x80) == 0x80
|
||||
}
|
||||
}
|
||||
|
||||
static func ROR(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .implied) {
|
||||
operand = state.accumulator
|
||||
|
||||
state.status_register.carry = ((operand & 0x01) == 0x01)
|
||||
state.accumulator = (state.accumulator &>> 1) & 0x7F
|
||||
state.accumulator = state.accumulator | (state.status_register.carry ? 0x80 : 0x00)
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.status_register.negative = (state.accumulator & 0x80) == 0x80
|
||||
} else {
|
||||
let address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
||||
var data = state.memoryInterface.readByte(offset: address)
|
||||
|
||||
state.status_register.carry = (data & 0x01) == 0x01
|
||||
data = (data &>> 1) & 0x7F
|
||||
data = data | (state.status_register.carry ? 0x80 : 0x00)
|
||||
state.memoryInterface.writeByte(offset: address, value: data)
|
||||
state.updateZeroFlag(value: data)
|
||||
state.status_register.negative = (data & 0x80) == 0x80
|
||||
}
|
||||
}
|
||||
|
||||
//Processor flag instructions
|
||||
static func CLC(state: CPUState, addressingMode: AddressingMode) -> Void {
|
||||
state.status_register.carry = false
|
||||
|
|
Loading…
Reference in New Issue