306 lines
12 KiB
Swift
306 lines
12 KiB
Swift
//
|
|
// Opcodes.swift
|
|
// FruitMachine
|
|
//
|
|
// Created by Christopher Rohl on 7/20/17.
|
|
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
func stackPointerAsUInt16(state: CPUState) -> UInt16 {
|
|
return 0x0100 | UInt16(state.stack_pointer);
|
|
}
|
|
|
|
func zpAsUInt16(address: UInt8) -> UInt16 {
|
|
return 0x0000 | UInt16(address)
|
|
}
|
|
|
|
func getOperandByteForAddressingMode(state: CPUState, mode: AddressingMode) -> UInt8 {
|
|
switch (mode) {
|
|
|
|
case .immediate:
|
|
return state.getOperandByte()
|
|
|
|
case .zeropage:
|
|
return state.memoryInterface.readByte(offset: UInt16(0x0000 + state.getOperandByte()))
|
|
case .zeropage_indexed_x:
|
|
return state.memoryInterface.readByte(offset: UInt16(state.getOperandByte() + state.index_x) & 0x00FF)
|
|
case .zeropage_indexed_y:
|
|
return state.memoryInterface.readByte(offset: UInt16(state.getOperandByte() + state.index_y) & 0x00FF)
|
|
|
|
case .absolute:
|
|
let word: UInt16 = state.getOperandWord()
|
|
return state.memoryInterface.readByte(offset: word)
|
|
case .absolute_indexed_x:
|
|
return state.memoryInterface.readByte(offset: state.getOperandWord() + UInt16(state.index_x))
|
|
case .absolute_indexed_y:
|
|
return state.memoryInterface.readByte(offset: state.getOperandWord() + UInt16(state.index_y))
|
|
|
|
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.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)
|
|
return state.memoryInterface.readByte(offset: pointer)
|
|
default:
|
|
print("Called getOperand: UInt8 on an instruction that expects a UInt16.")
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func getOperandWordForAddressingMode(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())
|
|
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
|
|
}
|
|
|
|
}
|
|
|
|
/* */
|
|
|
|
class Opcodes: NSObject {
|
|
|
|
static func LDA(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.accumulator)
|
|
state.updateNegativeFlag(value: state.accumulator)
|
|
}
|
|
|
|
static func LDX(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.index_x = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.index_x)
|
|
state.updateNegativeFlag(value: state.index_x)
|
|
}
|
|
|
|
static func LDY(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.index_y = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.index_y)
|
|
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
|
|
|
|
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(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(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(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(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(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(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(value: state.index_y);
|
|
state.updateNegativeFlag(value: state.index_y);
|
|
}
|
|
|
|
static func INC(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
var val: UInt8
|
|
|
|
if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x) {
|
|
address = zpAsUInt16(address: state.getOperandByte())
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
|
|
}
|
|
else if (addressingMode == .absolute || addressingMode == .absolute_indexed_x) {
|
|
address = state.getOperandWord()
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
}
|
|
else {
|
|
print("Illegal addressing mode for INC")
|
|
return
|
|
}
|
|
|
|
val = val &+ 1
|
|
state.memoryInterface.writeByte(offset: address, value: val)
|
|
|
|
state.updateZeroFlag(value: val);
|
|
state.updateNegativeFlag(value: val);
|
|
}
|
|
|
|
static func DEC(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
var val: UInt8
|
|
|
|
if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x) {
|
|
address = zpAsUInt16(address: state.getOperandByte())
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
|
|
}
|
|
else if (addressingMode == .absolute || addressingMode == .absolute_indexed_x) {
|
|
address = state.getOperandWord()
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
}
|
|
else {
|
|
print("Illegal addressing mode for INC")
|
|
return
|
|
}
|
|
|
|
val = val &- 1
|
|
state.memoryInterface.writeByte(offset: address, value: val)
|
|
|
|
state.updateZeroFlag(value: val);
|
|
state.updateNegativeFlag(value: val);
|
|
}
|
|
|
|
//Processor flag instructions
|
|
static func CLC(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.carry = false
|
|
}
|
|
|
|
static func SEC(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.carry = true
|
|
}
|
|
|
|
static func CLI(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.irq_disable = false
|
|
}
|
|
|
|
static func SEI(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.irq_disable = true
|
|
}
|
|
|
|
static func CLV(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.overflow = false
|
|
}
|
|
|
|
static func CLD(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.decimal = false
|
|
}
|
|
|
|
static func SED(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.carry = true
|
|
}
|
|
|
|
//Stack instructions
|
|
static func TXS(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.stack_pointer = state.index_x
|
|
}
|
|
|
|
static func TSX(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.index_x = state.stack_pointer
|
|
|
|
state.updateZeroFlag(value: state.index_x);
|
|
state.updateNegativeFlag(value: state.index_x);
|
|
}
|
|
|
|
static func PHA(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
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: stackPointerAsUInt16(state: state))
|
|
|
|
state.updateZeroFlag(value: state.accumulator);
|
|
state.updateNegativeFlag(value: state.accumulator);
|
|
}
|
|
|
|
static func PHP(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
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.fromByte(state: state.memoryInterface.readByte(offset: stackPointerAsUInt16(state: state)))
|
|
}
|
|
|
|
//Misc
|
|
static func JMP(state: CPUState, addressingMode: AddressingMode) -> Void {
|
|
state.program_counter = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
|
}
|
|
|
|
|
|
static func NOP(state: CPUState, addressingMode: AddressingMode) -> Void {}
|
|
}
|