mirror of
https://github.com/Luigi30/FruitMachine-Swift.git
synced 2024-11-16 18:06:49 +00:00
766 lines
30 KiB
Swift
766 lines
30 KiB
Swift
//
|
|
// Opcodes.swift
|
|
// FruitMachine
|
|
//
|
|
// Created by Christopher Rohl on 7/20/17.
|
|
// Copyright © 2017 Christopher Rohl. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
extension CPU {
|
|
|
|
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
|
|
}
|
|
|
|
func pushWord(data: UInt16) -> Void {
|
|
let low = UInt8(data & 0x00FF)
|
|
let high = UInt8((data & 0xFF00) >> 8)
|
|
|
|
pushByte(data: high)
|
|
pushByte(data: low)
|
|
}
|
|
|
|
func stackPointerAsUInt16() -> UInt16 {
|
|
return 0x0100 | UInt16(stack_pointer);
|
|
}
|
|
|
|
func doBranch() {
|
|
let distance = Int8(bitPattern: getOperandByte())
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
if(distance > 0) {
|
|
program_counter = UInt16(Int(program_counter) + Int(distance))
|
|
} else {
|
|
program_counter = UInt16(Int(program_counter) + Int(distance))
|
|
}
|
|
|
|
branch_was_taken = true
|
|
|
|
if(distance == -2) {
|
|
print("Infinite loop at $\(program_counter.asHexString()). Halting execution.")
|
|
cyclesInBatch = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
func getOperandByteForAddressingMode(state: CPU, 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.program_counter + 1))
|
|
//read from (ZP)
|
|
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp &+ state.index_x))
|
|
return state.memoryInterface.readByte(offset: pointer)
|
|
case .indirect_indexed:
|
|
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
|
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: CPU, 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.program_counter + 1))
|
|
//read from (ZP)
|
|
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp &+ state.index_x))
|
|
return pointer
|
|
case .indirect_indexed:
|
|
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
|
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp)) &+ UInt16(state.index_y)
|
|
return pointer
|
|
default:
|
|
print("Called getOperand: UInt16 on an instruction that expects a UInt8. Address: \(state.program_counter.asHexString())")
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func getOperandAddressForAddressingMode(state: CPU, mode: AddressingMode) -> UInt16 {
|
|
//Function that will provide a 16-bit operand to instructions.
|
|
//All instructions have 2 data bytes, little-endian.
|
|
|
|
switch(mode) {
|
|
case .zeropage:
|
|
return UInt16(0x0000 + (state.memoryInterface.readByte(offset: state.program_counter + 1)))
|
|
case .zeropage_indexed_x:
|
|
return UInt16(0x0000 + (state.memoryInterface.readByte(offset: state.program_counter + 1) + state.index_x))
|
|
case .zeropage_indexed_y:
|
|
return UInt16(0x0000 + (state.memoryInterface.readByte(offset: state.program_counter + 1) + state.index_y))
|
|
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 .indexed_indirect:
|
|
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
|
//read from (ZP)
|
|
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp &+ state.index_x))
|
|
return pointer
|
|
case .indirect_indexed:
|
|
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
|
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp)) &+ UInt16(state.index_y)
|
|
return pointer
|
|
default:
|
|
print("Called getOperand: UInt16 on an instruction that expects a UInt8. Address: \(state.program_counter.asHexString())")
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func hex2bcd(hex: UInt8) -> UInt8 {
|
|
var y: UInt8 = (hex / 10) << 4
|
|
y = y | (hex % 10)
|
|
return y
|
|
}
|
|
|
|
/* */
|
|
|
|
class Opcodes: NSObject {
|
|
|
|
static func _Add(state: CPU, operand: UInt8, isSubtract: Bool) {
|
|
if(state.accumulator == 0xFF) {
|
|
_ = 1
|
|
}
|
|
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 & 0x80) != (t8 & 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 = t8
|
|
}
|
|
|
|
static func ADC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
_Add(state: state, operand: UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode)), isSubtract: false)
|
|
}
|
|
|
|
static func SBC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let operand = UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode))
|
|
var t16: UInt16 = UInt16(state.accumulator &- operand) - UInt16((state.status_register.carry ? UInt8(0) : UInt8(1)))
|
|
let t8: UInt8 = UInt8(t16 & 0xFF)
|
|
|
|
state.cyclesInBatch = 0
|
|
state.status_register.overflow = (t8 >= 0x80 && t8 <= 0xFF)
|
|
|
|
if(state.status_register.decimal == true) {
|
|
t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0)))
|
|
} else {
|
|
state.status_register.carry = (t16 >> 8) == 0 ? false : true
|
|
}
|
|
|
|
state.accumulator = t8
|
|
state.updateZeroFlag(value: t8)
|
|
state.updateNegativeFlag(value: t8)
|
|
}
|
|
|
|
static func LDA(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.accumulator)
|
|
state.updateNegativeFlag(value: state.accumulator)
|
|
}
|
|
|
|
static func LDX(state: CPU, 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: CPU, 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: CPU, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
|
|
if(addressingMode == .zeropage) {
|
|
address = AddressConversions.zeroPageAsUInt16(address: state.getOperandByte())
|
|
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
|
|
}
|
|
else if(addressingMode == .zeropage_indexed_x) {
|
|
address = AddressConversions.zeroPageAsUInt16(address: state.getOperandByte() &+ state.index_x)
|
|
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
|
|
}
|
|
else if (addressingMode == .absolute || addressingMode == .absolute_indexed_x || addressingMode == .absolute_indexed_y) {
|
|
address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
|
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
|
|
}
|
|
else if(addressingMode == .indexed_indirect || addressingMode == .indirect_indexed) {
|
|
address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
|
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
|
|
}
|
|
else {
|
|
print("Illegal addressing mode for STA")
|
|
return
|
|
}
|
|
}
|
|
|
|
static func STX(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
|
|
if(addressingMode == .zeropage) {
|
|
address = AddressConversions.zeroPageAsUInt16(address: state.getOperandByte())
|
|
state.memoryInterface.writeByte(offset: address, value: state.index_x)
|
|
}
|
|
else if(addressingMode == .zeropage_indexed_y) {
|
|
address = AddressConversions.zeroPageAsUInt16(address: state.getOperandByte() &+ state.index_y)
|
|
state.memoryInterface.writeByte(offset: address, value: state.index_x)
|
|
}
|
|
else if (addressingMode == .absolute) {
|
|
address = state.getOperandWord()
|
|
state.memoryInterface.writeByte(offset: address, value: state.index_x)
|
|
}
|
|
else {
|
|
print("Illegal addressing mode for STX")
|
|
return
|
|
}
|
|
}
|
|
|
|
static func STY(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
|
|
if(addressingMode == .zeropage) {
|
|
address = AddressConversions.zeroPageAsUInt16(address: state.getOperandByte())
|
|
state.memoryInterface.writeByte(offset: address, value: state.index_y)
|
|
|
|
}
|
|
else if(addressingMode == .zeropage_indexed_x) {
|
|
address = AddressConversions.zeroPageAsUInt16(address: state.getOperandByte() &+ state.index_x)
|
|
state.memoryInterface.writeByte(offset: address, value: state.index_y)
|
|
}
|
|
else if (addressingMode == .absolute) {
|
|
address = state.getOperandWord()
|
|
state.memoryInterface.writeByte(offset: address, value: state.index_y)
|
|
}
|
|
else {
|
|
print("Illegal addressing mode for STY")
|
|
return
|
|
}
|
|
}
|
|
|
|
//Register instructions
|
|
static func TAX(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.index_x = state.accumulator
|
|
|
|
state.updateZeroFlag(value: state.index_x);
|
|
state.updateNegativeFlag(value: state.index_x);
|
|
}
|
|
|
|
static func TXA(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = state.index_x
|
|
|
|
state.updateZeroFlag(value: state.accumulator);
|
|
state.updateNegativeFlag(value: state.accumulator);
|
|
}
|
|
|
|
static func DEX(state: CPU, 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: CPU, 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: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.index_y = state.accumulator
|
|
|
|
state.updateZeroFlag(value: state.index_y);
|
|
state.updateNegativeFlag(value: state.index_y);
|
|
}
|
|
|
|
static func TYA(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = state.index_y
|
|
|
|
state.updateZeroFlag(value: state.accumulator);
|
|
state.updateNegativeFlag(value: state.accumulator);
|
|
}
|
|
|
|
static func DEY(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.index_y = state.index_y &- 1
|
|
|
|
state.updateZeroFlag(value: state.index_y);
|
|
state.updateNegativeFlag(value: state.index_y);
|
|
}
|
|
|
|
static func INY(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.index_y = state.index_y &+ 1
|
|
|
|
state.updateZeroFlag(value: state.index_y);
|
|
state.updateNegativeFlag(value: state.index_y);
|
|
}
|
|
|
|
static func INC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
var val: UInt8
|
|
|
|
if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x) {
|
|
address = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
}
|
|
else if (addressingMode == .absolute || addressingMode == .absolute_indexed_x) {
|
|
address = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
|
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: CPU, addressingMode: AddressingMode) -> Void {
|
|
let address: UInt16
|
|
var val: UInt8
|
|
|
|
if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x) {
|
|
address = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
}
|
|
else if (addressingMode == .absolute || addressingMode == .absolute_indexed_x) {
|
|
address = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
|
val = state.memoryInterface.readByte(offset: address)
|
|
}
|
|
else {
|
|
print("Illegal addressing mode for DEC")
|
|
return
|
|
}
|
|
|
|
val = val &- 1
|
|
state.memoryInterface.writeByte(offset: address, value: val)
|
|
|
|
state.updateZeroFlag(value: val);
|
|
state.updateNegativeFlag(value: val);
|
|
}
|
|
|
|
//CMP
|
|
static func CMP(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let mem = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
let t = state.accumulator &- mem //CMP is a subtract that doesn't affect memory
|
|
|
|
state.status_register.zero = (t == 0) ? true : false
|
|
state.status_register.negative = (t & 0x80) == 0x80 ? true : false
|
|
state.status_register.carry = (state.accumulator >= mem)
|
|
}
|
|
|
|
static func CPX(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let mem = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
let t = state.index_x &- mem //CMP is a subtract that doesn't affect memory
|
|
|
|
state.status_register.zero = (t == 0) ? true : false
|
|
state.status_register.negative = (t & 0x80) == 0x80 ? true : false
|
|
state.status_register.carry = (state.index_x >= mem)
|
|
}
|
|
|
|
static func CPY(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let mem = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
let t = state.index_y &- mem //CMP is a subtract that doesn't affect memory
|
|
|
|
state.status_register.zero = (t == 0) ? true : false
|
|
state.status_register.negative = (t & 0x80) == 0x80 ? true : false
|
|
state.status_register.carry = (state.index_y >= mem)
|
|
}
|
|
|
|
//Boolean operators
|
|
static func EOR(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = state.accumulator ^ getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.accumulator)
|
|
state.updateNegativeFlag(value: state.accumulator)
|
|
}
|
|
|
|
static func AND(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = state.accumulator & getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.accumulator)
|
|
state.updateNegativeFlag(value: state.accumulator)
|
|
}
|
|
|
|
static func ORA(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.accumulator = state.accumulator | getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
|
|
state.updateZeroFlag(value: state.accumulator)
|
|
state.updateNegativeFlag(value: state.accumulator)
|
|
}
|
|
|
|
//Bitwise operators
|
|
static func BIT(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let operand = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
|
let data = state.accumulator & operand
|
|
|
|
state.status_register.zero = data == 0 ? true : false
|
|
state.status_register.negative = (operand & 0x80) == 0x80 ? true : false
|
|
state.status_register.overflow = (operand & UInt8(0x40)) == 0x40
|
|
}
|
|
|
|
static func ASL(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let operand: UInt8
|
|
|
|
if(addressingMode == .accumulator) {
|
|
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 if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x)
|
|
{
|
|
let address = getOperandAddressForAddressingMode(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)
|
|
}
|
|
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: CPU, addressingMode: AddressingMode) -> Void {
|
|
let operand: UInt8
|
|
|
|
if(addressingMode == .accumulator) {
|
|
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 if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x)
|
|
{
|
|
let address = getOperandAddressForAddressingMode(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)
|
|
}
|
|
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: CPU, addressingMode: AddressingMode) -> Void {
|
|
let operand: UInt8
|
|
|
|
if(addressingMode == .accumulator) {
|
|
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.status_register.zero = state.accumulator == 0 ? true : false
|
|
state.status_register.negative = (state.accumulator & 0x80) == 0x80
|
|
} else if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x)
|
|
{
|
|
let address = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
|
var data = state.memoryInterface.readByte(offset: address)
|
|
let t = (data & 0x80) == 0x80 ? true : false
|
|
|
|
data = (data &<< 1) & 0xFE
|
|
data = data | (state.status_register.carry ? 0x01 : 0x00)
|
|
state.memoryInterface.writeByte(offset: address, value: data)
|
|
|
|
state.status_register.carry = t
|
|
state.status_register.zero = data == 0 ? true : false
|
|
state.status_register.negative = (data & 0x80) == 0x80
|
|
}
|
|
else
|
|
{
|
|
let address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
|
var data = state.memoryInterface.readByte(offset: address)
|
|
let t = (data & 0x80) == 0x80 ? true : false
|
|
|
|
data = (data &<< 1) & 0xFE
|
|
data = data | (state.status_register.carry ? 0x01 : 0x00)
|
|
state.memoryInterface.writeByte(offset: address, value: data)
|
|
|
|
state.status_register.carry = t
|
|
state.status_register.zero = data == 0 ? true : false
|
|
state.status_register.negative = (data & 0x80) == 0x80
|
|
}
|
|
}
|
|
|
|
static func ROR(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
let operand: UInt8
|
|
|
|
if(addressingMode == .accumulator) {
|
|
operand = state.accumulator
|
|
|
|
state.accumulator = (state.accumulator &>> 1) & 0x7F
|
|
state.accumulator = state.accumulator | (state.status_register.carry ? 0x80 : 0x00)
|
|
|
|
state.status_register.carry = ((operand & 0x01) == 0x01)
|
|
state.status_register.zero = state.accumulator == 0 ? true : false
|
|
state.status_register.negative = (state.accumulator & 0x80) == 0x80
|
|
}
|
|
else if(addressingMode == .zeropage || addressingMode == .zeropage_indexed_x)
|
|
{
|
|
let address = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
|
var data = state.memoryInterface.readByte(offset: address)
|
|
let t = (data & 0x01) == 0x01 ? true : false
|
|
|
|
data = (data &>> 1) & 0x7F
|
|
data = data | (state.status_register.carry ? 0x80 : 0x00)
|
|
state.memoryInterface.writeByte(offset: address, value: data)
|
|
|
|
state.status_register.carry = t
|
|
state.status_register.zero = data == 0 ? true : false
|
|
state.status_register.negative = (data & 0x80) == 0x80
|
|
}
|
|
else
|
|
{
|
|
let address = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
|
var data = state.memoryInterface.readByte(offset: address)
|
|
let t = (data & 0x01) == 0x01 ? true : false
|
|
|
|
data = (data &>> 1) & 0x7F
|
|
data = data | (state.status_register.carry ? 0x80 : 0x00)
|
|
state.memoryInterface.writeByte(offset: address, value: data)
|
|
|
|
state.status_register.carry = t
|
|
state.status_register.zero = data == 0 ? true : false
|
|
state.status_register.negative = (data & 0x80) == 0x80
|
|
}
|
|
}
|
|
|
|
//Processor flag instructions
|
|
static func CLC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.carry = false
|
|
}
|
|
|
|
static func SEC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.carry = true
|
|
}
|
|
|
|
static func CLI(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.irq_disable = false
|
|
}
|
|
|
|
static func SEI(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.irq_disable = true
|
|
}
|
|
|
|
static func CLV(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.overflow = false
|
|
}
|
|
|
|
static func CLD(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.decimal = false
|
|
}
|
|
|
|
static func SED(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.decimal = true
|
|
}
|
|
|
|
//Stack instructions
|
|
static func TXS(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.stack_pointer = state.index_x
|
|
}
|
|
|
|
static func TSX(state: CPU, 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: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.pushByte(data: state.accumulator)
|
|
}
|
|
|
|
static func PLA(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.stack_pointer = state.stack_pointer &+ 1
|
|
state.accumulator = state.memoryInterface.readByte(offset: state.stackPointerAsUInt16())
|
|
|
|
state.updateZeroFlag(value: state.accumulator);
|
|
state.updateNegativeFlag(value: state.accumulator);
|
|
}
|
|
|
|
static func PHP(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
var sr = state.status_register
|
|
sr.brk = true //PHP pushes B as true
|
|
|
|
state.memoryInterface.writeByte(offset: state.stackPointerAsUInt16(), value: sr.asByte())
|
|
state.stack_pointer = state.stack_pointer &- 1
|
|
}
|
|
|
|
static func PLP(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.stack_pointer = state.stack_pointer &+ 1
|
|
state.status_register.fromByte(state: state.memoryInterface.readByte(offset: state.stackPointerAsUInt16()))
|
|
state.status_register.brk = false //PLP sets B to 0
|
|
}
|
|
|
|
static func BPL(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(!state.status_register.negative) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BMI(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(state.status_register.negative) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BVC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(!state.status_register.overflow) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BVS(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(state.status_register.overflow) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BCC(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(!state.status_register.carry) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BCS(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(state.status_register.carry) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BNE(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(!state.status_register.zero) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
static func BEQ(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
if(state.status_register.zero) {
|
|
state.doBranch()
|
|
}
|
|
}
|
|
|
|
//Misc
|
|
static func JMP(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.program_counter = getOperandWordForAddressingMode(state: state, mode: addressingMode)
|
|
}
|
|
|
|
static func JSR(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.pushWord(data: state.program_counter + 2)
|
|
state.program_counter = state.getOperandWord()
|
|
}
|
|
|
|
static func RTS(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.program_counter = state.popWord()
|
|
}
|
|
|
|
static func RTI(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
state.status_register.fromByte(state: state.popByte())
|
|
state.program_counter = state.popWord()
|
|
state.status_register.brk = false //RTI sets B to 0
|
|
}
|
|
|
|
static func BRK(state: CPU, addressingMode: AddressingMode) -> Void {
|
|
var sr = state.status_register
|
|
sr.brk = true //BRK pushes B as true
|
|
state.pushWord(data: state.program_counter + 2)
|
|
state.pushByte(data: sr.asByte())
|
|
state.status_register.irq_disable = true //BRK disables interrupts before transferring control
|
|
state.program_counter = state.memoryInterface.readWord(offset: 0xFFFE)
|
|
}
|
|
|
|
static func NOP(state: CPU, addressingMode: AddressingMode) -> Void {}
|
|
}
|