nesemu/cpu/op.c

1384 lines
36 KiB
C
Raw Normal View History

2023-11-26 12:11:49 -05:00
#include <stdbool.h>
#include <assert.h>
#include "op.h"
#include "cpu.h"
2024-01-09 15:56:54 -05:00
#include "decoding.h"
2023-10-05 17:05:06 -04:00
// Reference: https://www.nesdev.org/wiki/CPU_unofficial_opcodes
2023-11-26 12:11:49 -05:00
// https://www.middle-engine.com/blog/posts/2020/06/23/programming-the-nes-the-6502-in-detail
2023-10-05 17:05:06 -04:00
#define IS_OP_CODE_MODE(op, op_code, addr_mode) \
2023-12-03 00:27:07 -05:00
case op_code: \
2024-05-06 20:23:44 -04:00
op_ ## op(ADDR_MODE_ ## addr_mode); \
2023-10-05 17:05:06 -04:00
break;
#define IS_OP_CODE(op, op_code) \
IS_OP_CODE_MODE(op, op_code, IMPLICIT)
#define IS_ALU_OP_CODE_(op, offset, addr_mode) \
IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## op + offset, addr_mode)
#define IS_ALU_OP_CODE(op) \
2023-11-26 12:11:49 -05:00
IS_ALU_OP_CODE_(op, 0x01, INDIRECT_X) \
2023-10-05 17:05:06 -04:00
IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \
IS_ALU_OP_CODE_(op, 0x09, IMMEDIATE) \
IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \
2023-11-26 12:11:49 -05:00
IS_ALU_OP_CODE_(op, 0x11, INDIRECT_Y) \
2023-10-05 17:05:06 -04:00
IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \
IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \
IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X)
#define IS_ALU_OP_CODE_NO_IMMEDIATE(op) \
2023-11-26 12:11:49 -05:00
IS_ALU_OP_CODE_(op, 0x01, INDIRECT_X) \
2023-10-05 17:05:06 -04:00
IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \
IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \
2023-11-26 12:11:49 -05:00
IS_ALU_OP_CODE_(op, 0x11, INDIRECT_Y) \
2023-10-05 17:05:06 -04:00
IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \
IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \
IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X)
#define IS_RMW_OP_CODE_(op, line, offset, addr_mode) \
IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## line + offset, addr_mode)
#define IS_RMW_OP_CODE(op, line) \
IS_RMW_OP_CODE_(op, line, 0x06, ZERO_PAGE) \
2024-01-06 14:27:09 -05:00
IS_RMW_OP_CODE_(op, line, 0x0a, ACCUMULATOR) \
2023-10-05 17:05:06 -04:00
IS_RMW_OP_CODE_(op, line, 0x0e, ABSOLUTE) \
IS_RMW_OP_CODE_(op, line, 0x16, ZERO_PAGE_INDEXED_X) \
IS_RMW_OP_CODE_(op, line, 0x1e, ABSOLUTE_INDEXED_X)
#define IS_UNOFFICIAL_OP_CODE_(op, line, offset, addr_mode) \
IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## line + offset, addr_mode)
#define IS_UNOFFICIAL_OP_CODE(op, line) \
2023-11-26 12:11:49 -05:00
IS_UNOFFICIAL_OP_CODE_(op, line, 0x03, INDIRECT_X) \
2023-10-05 17:05:06 -04:00
IS_UNOFFICIAL_OP_CODE_(op, line, 0x07, ZERO_PAGE) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x0f, ABSOLUTE) \
2023-11-26 12:11:49 -05:00
IS_UNOFFICIAL_OP_CODE_(op, line, 0x13, INDIRECT_Y) \
2023-10-05 17:05:06 -04:00
IS_UNOFFICIAL_OP_CODE_(op, line, 0x17, ZERO_PAGE_INDEXED_X) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x1b, ABSOLUTE_INDEXED_Y) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x1f, ABSOLUTE_INDEXED_X)
2024-05-06 20:23:44 -04:00
void write_operand(Operand operand, byte value) {
2023-11-26 12:11:49 -05:00
switch (operand.type) {
case OPERAND_TYPE_ACCUMULATOR:
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = value;
2023-11-26 12:11:49 -05:00
break;
case OPERAND_TYPE_ADDRESS:
2024-05-06 20:23:44 -04:00
mem_set_byte(operand.value, value);
2023-11-26 12:11:49 -05:00
break;
default:
assert(false);
}
}
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
bool is_sign_overflow(byte val1, byte val2, byte result) {
return ((val1 & 0x80) == (val2 & 0x80)) &&
((val1 & 0x80) != (result & 0x80));
}
byte get_cycle_count(Operand operand, AddressingMode addr_mode) {
switch (addr_mode) {
case ADDR_MODE_ACCUMULATOR:
2024-01-06 14:27:09 -05:00
case ADDR_MODE_IMMEDIATE:
2023-11-26 12:11:49 -05:00
return 2;
case ADDR_MODE_ZERO_PAGE:
return 3;
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
case ADDR_MODE_ZERO_PAGE_INDEXED_Y:
case ADDR_MODE_ABSOLUTE:
return 4;
case ADDR_MODE_ABSOLUTE_INDEXED_X:
case ADDR_MODE_ABSOLUTE_INDEXED_Y:
return operand.is_page_crossing ? 5 : 4;
case ADDR_MODE_INDIRECT_X:
return 6;
case ADDR_MODE_INDIRECT_Y:
return operand.is_page_crossing ? 6 : 5;
default:
assert(false);
}
2023-10-05 17:05:06 -04:00
}
2023-11-26 12:11:49 -05:00
byte get_shift_cycle_count(AddressingMode addr_mode) {
switch (addr_mode) {
case ADDR_MODE_ACCUMULATOR:
return 2;
case ADDR_MODE_ZERO_PAGE:
return 5;
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
case ADDR_MODE_ABSOLUTE:
return 6;
case ADDR_MODE_ABSOLUTE_INDEXED_X:
2024-01-06 14:27:09 -05:00
case ADDR_MODE_ABSOLUTE_INDEXED_Y:
2023-11-26 12:11:49 -05:00
return 7;
2024-01-06 14:27:09 -05:00
case ADDR_MODE_INDIRECT_X:
case ADDR_MODE_INDIRECT_Y:
return 8;
2023-11-26 12:11:49 -05:00
default:
assert(false);
}
}
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
void set_acl_flags(byte result) {
cpu_set_flag(CPU_STATUS_ZERO_MASK, result == 0);
cpu_set_flag(CPU_STATUS_NEGATIVE_MASK, result & 0x80);
2023-10-05 17:05:06 -04:00
}
2024-05-06 20:23:44 -04:00
byte get_branch_cycle_count(bool branching, char offset) {
address target = cpu_get_state()->program_counter;
2023-11-26 12:11:49 -05:00
byte cycle_count = 2;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
if (branching) {
cycle_count += 1;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
if ((target & 0xff00) != ((target - offset) & 0xff00)) {
cycle_count += 2;
}
}
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
return cycle_count;
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_branch(bool branching) {
char offset = (char) cpu_get_next_byte();
2023-11-26 12:11:49 -05:00
if (branching) {
2024-05-06 20:23:44 -04:00
address counter = cpu_get_state()->program_counter;
2023-11-26 12:11:49 -05:00
address target = counter + offset;
2024-05-06 20:23:44 -04:00
cpu_get_state()->program_counter = target;
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_branch_cycle_count(branching, offset));
2023-10-05 17:05:06 -04:00
}
2024-05-06 20:23:44 -04:00
void add_with_carry(byte value) {
byte acc = cpu_get_state()->accumulator;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte addition = acc + value;
bool overflow = false;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
// Check for overflow
if (addition < acc) {
overflow = true;
}
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
// Add carry flag and check for overflow again
2024-05-06 20:23:44 -04:00
byte result = addition + cpu_get_flag(CPU_STATUS_CARRY_MASK);
2023-11-26 12:11:49 -05:00
if (result < addition) {
overflow = true;
}
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = result;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, overflow);
cpu_set_flag(CPU_STATUS_OVERFLOW_MASK, is_sign_overflow(acc, value, result));
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(result);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ADC(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
byte value = read_operand(operand);
add_with_carry(value);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_AHX(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ALR(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ANC(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_AND(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte result = acc & value;
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = result;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(result);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ARR(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ASL(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-11-26 12:11:49 -05:00
byte result = value << 1;
2024-05-06 20:23:44 -04:00
write_operand(operand, result);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x80);
set_acl_flags(result);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_AXS(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BCC(AddressingMode addr_mode) {
op_branch(!cpu_get_flag(CPU_STATUS_CARRY_MASK));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BCS(AddressingMode addr_mode) {
op_branch(cpu_get_flag(CPU_STATUS_CARRY_MASK));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BEQ(AddressingMode addr_mode) {
op_branch(cpu_get_flag(CPU_STATUS_ZERO_MASK));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BIT(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte result = value & acc;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_ZERO_MASK, result == 0);
cpu_set_flag(CPU_STATUS_OVERFLOW_MASK, value & 0x40);
cpu_set_flag(CPU_STATUS_NEGATIVE_MASK, value & 0x80);
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BMI(AddressingMode addr_mode) {
op_branch(cpu_get_flag(CPU_STATUS_NEGATIVE_MASK));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BNE(AddressingMode addr_mode) {
op_branch(!cpu_get_flag(CPU_STATUS_ZERO_MASK));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BPL(AddressingMode addr_mode) {
op_branch(!cpu_get_flag(CPU_STATUS_NEGATIVE_MASK));
2023-10-05 17:05:06 -04:00
}
2023-11-26 12:11:49 -05:00
// Stops program execution, useful for debugging
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BRK(AddressingMode addr_mode) {
cpu_stack_push_context();
2023-11-26 12:11:49 -05:00
// TODO Load IRQ interrupt vector in PC at $FFFE/F
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
assert(false);
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_B_MASK, true);
cpu_add_cycles(7);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BVC(AddressingMode addr_mode) {
op_branch(!cpu_get_flag(CPU_STATUS_OVERFLOW_MASK));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_BVS(AddressingMode addr_mode) {
op_branch(cpu_get_flag(CPU_STATUS_OVERFLOW_MASK));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CLC(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_CARRY_MASK, false);
cpu_add_cycles(2);
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CLD(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_DECIMAL_MASK, false);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CLI(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_INTERRUPT_DISABLE_MASK, false);
cpu_add_cycles(2);
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CLV(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_OVERFLOW_MASK, false);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CMP(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte result = acc - value;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, acc >= value);
cpu_set_flag(CPU_STATUS_ZERO_MASK, result == 0);
cpu_set_flag(CPU_STATUS_NEGATIVE_MASK, result & 0x80);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CPX(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte x = cpu_get_state()->x;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte result = x - value;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, x >= value);
cpu_set_flag(CPU_STATUS_ZERO_MASK, result == 0);
cpu_set_flag(CPU_STATUS_NEGATIVE_MASK, result & 0x80);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_CPY(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte y = cpu_get_state()->y;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte result = y - value;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, y >= value);
cpu_set_flag(CPU_STATUS_ZERO_MASK, result == 0);
cpu_set_flag(CPU_STATUS_NEGATIVE_MASK, result & 0x80);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_DCP(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2024-01-06 14:27:09 -05:00
byte result = value - 1;
byte cmp_result = acc - result;
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, acc >= value);
cpu_set_flag(CPU_STATUS_ZERO_MASK, cmp_result == 0);
cpu_set_flag(CPU_STATUS_NEGATIVE_MASK, cmp_result & 0x80);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
write_operand(operand, result);
2024-01-06 14:27:09 -05:00
byte cycle_count;
switch (addr_mode) {
case ADDR_MODE_ZERO_PAGE:
cycle_count = 5;
break;
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
case ADDR_MODE_ABSOLUTE:
cycle_count = 6;
break;
case ADDR_MODE_ABSOLUTE_INDEXED_X:
case ADDR_MODE_ABSOLUTE_INDEXED_Y:
cycle_count = 7;
break;
case ADDR_MODE_INDIRECT_X:
case ADDR_MODE_INDIRECT_Y:
cycle_count = 8;
break;
default:
assert(false);
}
2024-05-06 20:23:44 -04:00
cpu_add_cycles(cycle_count);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_DEC(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-11-26 12:11:49 -05:00
byte result = value - 1;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(result);
write_operand(operand, result);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_DEX(AddressingMode addr_mode) {
byte x = cpu_get_state()->x;
2023-11-26 12:11:49 -05:00
byte result = x - 1;
2024-05-06 20:23:44 -04:00
cpu_get_state()->x = result;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(result);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_DEY(AddressingMode addr_mode) {
byte y = cpu_get_state()->y;
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
byte result = y - 1;
2024-05-06 20:23:44 -04:00
cpu_get_state()->y = result;
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(result);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_EOR(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2023-11-26 12:11:49 -05:00
acc ^= value;
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = acc;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(acc);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_INC(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
value += 1;
2024-05-06 20:23:44 -04:00
write_operand(operand, value);
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_INX(AddressingMode addr_mode) {
byte x = cpu_get_state()->x;
2023-11-26 12:11:49 -05:00
x += 1;
2024-05-06 20:23:44 -04:00
cpu_get_state()->x = x;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(x);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_INY(AddressingMode addr_mode) {
byte y = cpu_get_state()->y;
2023-11-26 12:11:49 -05:00
y += 1;
2024-05-06 20:23:44 -04:00
cpu_get_state()->y = y;
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(y);
cpu_add_cycles(2);
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ISC(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2024-01-06 14:27:09 -05:00
value += 1;
2024-05-06 20:23:44 -04:00
write_operand(operand, value);
add_with_carry(~value);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_JMP(AddressingMode addr_mode) {
word addr = decode_operand_addr(addr_mode, NULL);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->program_counter = addr;
2023-11-26 12:11:49 -05:00
// TODO WN: Handle CPU bug?
// > An original 6502 has does not correctly fetch the target address if the indirect vector falls on a page boundary (e.g. $xxFF where xx is any value from $00 to $FF).
// > In this case fetches the LSB from $xxFF as expected but takes the MSB from $xx00.
// > This is fixed in some later chips like the 65SC02 so for compatibility always ensure the indirect vector is not at the end of the page.
2024-01-06 14:27:09 -05:00
int cycle_count = 3;
if (addr_mode == ADDR_MODE_INDIRECT_JUMP) {
cycle_count = 5;
}
2024-05-06 20:23:44 -04:00
cpu_add_cycles(cycle_count);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_JSR(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
// Push the program counter on the stack
2024-05-06 20:23:44 -04:00
address program_counter = cpu_get_state()->program_counter + 1;
cpu_stack_push(program_counter >> 8);
cpu_stack_push(program_counter & 0xff);
2023-11-26 12:11:49 -05:00
// Updates the program counter to the address in the operand
2024-05-06 20:23:44 -04:00
address addr = decode_operand_addr(addr_mode, NULL);
cpu_get_state()->program_counter = addr;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(6);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_LAS(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_LAX(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = value;
cpu_get_state()->x = value;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_LDA(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = value;
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_LDX(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->x = value;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_LDY(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->y = value;
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2024-01-06 14:27:09 -05:00
}
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_LSR(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
// Put bit 0 in the carry flag
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x01);
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
value >>= 1;
2024-05-06 20:23:44 -04:00
write_operand(operand, value);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_NOP(AddressingMode addr_mode) {
2024-01-06 14:27:09 -05:00
if (addr_mode != ADDR_MODE_IMPLICIT) {
2024-05-06 20:23:44 -04:00
Operand operand = decode_operand(addr_mode);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2024-01-06 14:27:09 -05:00
} else {
2024-05-06 20:23:44 -04:00
cpu_add_cycles(2);
2024-01-06 14:27:09 -05:00
}
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ORA(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2023-11-26 12:11:49 -05:00
acc |= value;
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = acc;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(acc);
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_PHA(AddressingMode addr_mode) {
byte acc = cpu_get_state()->accumulator;
cpu_stack_push(acc);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(3);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_PHP(AddressingMode addr_mode) {
byte status = cpu_get_state()->status;
cpu_stack_push(status);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
// cpu_set_flag(CPU_STATUS_B_MASK, true);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(3);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_PLA(AddressingMode addr_mode) {
byte value = cpu_stack_pop();
cpu_get_state()->accumulator = value;
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(4);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_PLP(AddressingMode addr_mode) {
byte value = cpu_stack_pop();
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
value &= 0xef; // The B mask cannot be set as it is a CPU signal
value |= 0x20; // This value is always set
2024-05-06 20:23:44 -04:00
cpu_get_state()->status = value;
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(4);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_RLA(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte carry = cpu_get_flag(CPU_STATUS_CARRY_MASK);
byte acc = cpu_get_state()->accumulator;
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x80);
2024-01-06 14:27:09 -05:00
value = (value << 1) | carry;
byte and_result = acc & value;
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = and_result;
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
write_operand(operand, value);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ROL(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte carry = cpu_get_flag(CPU_STATUS_CARRY_MASK);
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x80);
2023-11-26 12:11:49 -05:00
value = (value << 1) | carry;
2024-05-06 20:23:44 -04:00
write_operand(operand, value);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_ROR(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte carry = cpu_get_flag(CPU_STATUS_CARRY_MASK);
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x01);
2023-11-26 12:11:49 -05:00
value = (value >> 1) | (carry << 7);
2024-05-06 20:23:44 -04:00
write_operand(operand, value);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_RRA(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte carry = cpu_get_flag(CPU_STATUS_CARRY_MASK);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x01);
2024-01-06 14:27:09 -05:00
value = (value >> 1) | (carry << 7);
2024-05-06 20:23:44 -04:00
add_with_carry(value);
write_operand(operand, value);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
// set_acl_flags(value);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_RTI(AddressingMode addr_mode) {
cpu_stack_pop_context();
cpu_add_cycles(6);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_RTS(AddressingMode addr_mode) {
byte lo = cpu_stack_pop();
address pc = cpu_stack_pop() << 8;
2023-11-26 12:11:49 -05:00
pc += lo;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_get_state()->program_counter = pc + 1;
cpu_add_cycles(6);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SAX(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
byte x = cpu_get_state()->x;
byte acc = cpu_get_state()->accumulator;
2024-01-06 14:27:09 -05:00
byte result = acc & x;
2024-05-06 20:23:44 -04:00
write_operand(operand, result);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SBC(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
add_with_carry(~value);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SEC(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_CARRY_MASK, true);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SED(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_DECIMAL_MASK, true);
cpu_add_cycles(2);
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SEI(AddressingMode addr_mode) {
cpu_set_flag(CPU_STATUS_INTERRUPT_DISABLE_MASK, true);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SHX(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SHY(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SLO(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2024-01-06 14:27:09 -05:00
byte result = value << 1;
acc |= result;
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = acc;
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
write_operand(operand, result);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x80);
set_acl_flags(acc);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_SRE(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte value = read_operand(operand);
byte acc = cpu_get_state()->accumulator;
2024-01-06 14:27:09 -05:00
// Put bit 0 in the carry flag
2024-05-06 20:23:44 -04:00
cpu_set_flag(CPU_STATUS_CARRY_MASK, value & 0x01);
2024-01-06 14:27:09 -05:00
value >>= 1;
acc ^= value;
2024-05-06 20:23:44 -04:00
cpu_get_state()->accumulator = acc;
write_operand(operand, value);
2024-01-06 14:27:09 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(acc);
cpu_add_cycles(get_shift_cycle_count(addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_STA(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte acc = cpu_get_state()->accumulator;
2023-11-26 12:11:49 -05:00
assert(operand.type == OPERAND_TYPE_ADDRESS);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
mem_set_byte(operand.value, acc);
2023-10-05 17:05:06 -04:00
2023-11-26 12:11:49 -05:00
operand.is_page_crossing = true;
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_STP(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_STX(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte x = cpu_get_state()->x;
2023-11-26 12:11:49 -05:00
assert(operand.type == OPERAND_TYPE_ADDRESS);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
mem_set_byte(operand.value, x);
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_STY(AddressingMode addr_mode) {
Operand operand = decode_operand(addr_mode);
byte y = cpu_get_state()->y;
2023-11-26 12:11:49 -05:00
assert(operand.type == OPERAND_TYPE_ADDRESS);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
mem_set_byte(operand.value, y);
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(get_cycle_count(operand, addr_mode));
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TAS(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TAX(AddressingMode addr_mode) {
byte acc = cpu_get_state()->accumulator;
cpu_get_state()->x = acc;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(acc);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TAY(AddressingMode addr_mode) {
byte acc = cpu_get_state()->accumulator;
cpu_get_state()->y = acc;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(acc);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TSX(AddressingMode addr_mode) {
byte value = cpu_get_state()->stack_pointer;
cpu_get_state()->x = value;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(value);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TXA(AddressingMode addr_mode) {
byte x = cpu_get_state()->x;
cpu_get_state()->accumulator = x;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
set_acl_flags(x);
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TXS(AddressingMode addr_mode) {
byte x = cpu_get_state()->x;
cpu_get_state()->stack_pointer = x;
2023-10-05 17:05:06 -04:00
2024-05-06 20:23:44 -04:00
cpu_add_cycles(2);
2023-10-05 17:05:06 -04:00
}
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_TYA(AddressingMode addr_mode) {
byte y = cpu_get_state()->y;
cpu_get_state()->accumulator = y;
2023-11-26 12:11:49 -05:00
2024-05-06 20:23:44 -04:00
set_acl_flags(y);
cpu_add_cycles(2);
2023-11-26 12:11:49 -05:00
}
2023-10-05 17:05:06 -04:00
2024-01-06 14:27:09 -05:00
__attribute__((unused))
2024-05-06 20:23:44 -04:00
void op_XAA(AddressingMode addr_mode) {
2023-11-26 12:11:49 -05:00
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-05-06 20:23:44 -04:00
void process_op_code(byte op) {
2023-10-05 17:05:06 -04:00
switch (op) {
2024-01-06 14:27:09 -05:00
// CTRL
2023-10-05 17:05:06 -04:00
IS_OP_CODE(BRK, 0x00)
IS_OP_CODE(PHP, 0x08)
IS_OP_CODE(CLC, 0x18)
IS_OP_CODE(PLP, 0x28)
IS_OP_CODE(SEC, 0x38)
IS_OP_CODE(RTI, 0x40)
IS_OP_CODE(PHA, 0x48)
IS_OP_CODE(CLI, 0x58)
IS_OP_CODE(RTS, 0x60)
IS_OP_CODE(PLA, 0x68)
IS_OP_CODE(SEI, 0x78)
IS_OP_CODE(DEY, 0x88)
IS_OP_CODE(TYA, 0x98)
IS_OP_CODE(TAY, 0xa8)
IS_OP_CODE(CLV, 0xb8)
IS_OP_CODE(INY, 0xc8)
IS_OP_CODE(CLD, 0xd8)
IS_OP_CODE(INX, 0xe8)
IS_OP_CODE(SED, 0xf8)
IS_OP_CODE_MODE(JSR, 0x20, ABSOLUTE)
IS_OP_CODE_MODE(BIT, 0x24, ZERO_PAGE)
IS_OP_CODE_MODE(BIT, 0x2c, ABSOLUTE)
2024-01-11 16:02:53 -05:00
IS_OP_CODE_MODE(JMP, 0x4c, ABSOLUTE)
2024-01-06 14:27:09 -05:00
IS_OP_CODE_MODE(JMP, 0x6c, INDIRECT_JUMP)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(STY, 0x84, ZERO_PAGE)
IS_OP_CODE_MODE(STY, 0x8c, ABSOLUTE)
IS_OP_CODE_MODE(STY, 0x94, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(SHY, 0x9c, ABSOLUTE_INDEXED_X)
IS_OP_CODE_MODE(LDY, 0xa0, IMMEDIATE)
IS_OP_CODE_MODE(LDY, 0xa4, ZERO_PAGE)
IS_OP_CODE_MODE(LDY, 0xac, ABSOLUTE)
IS_OP_CODE_MODE(LDY, 0xb4, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(LDY, 0xbc, ABSOLUTE_INDEXED_X)
IS_OP_CODE_MODE(CPY, 0xc0, IMMEDIATE)
IS_OP_CODE_MODE(CPY, 0xc4, ZERO_PAGE)
IS_OP_CODE_MODE(CPY, 0xcc, ABSOLUTE)
IS_OP_CODE_MODE(CPX, 0xe0, IMMEDIATE)
IS_OP_CODE_MODE(CPX, 0xe4, ZERO_PAGE)
IS_OP_CODE_MODE(CPX, 0xec, ABSOLUTE)
2023-11-26 12:11:49 -05:00
IS_OP_CODE_MODE(BPL, 0x10, RELATIVE)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(BMI, 0x30, RELATIVE)
IS_OP_CODE_MODE(BVC, 0x50, RELATIVE)
IS_OP_CODE_MODE(BVS, 0x70, RELATIVE)
IS_OP_CODE_MODE(BCC, 0x90, RELATIVE)
IS_OP_CODE_MODE(BCS, 0xb0, RELATIVE)
IS_OP_CODE_MODE(BNE, 0xd0, RELATIVE)
IS_OP_CODE_MODE(BEQ, 0xf0, RELATIVE)
IS_OP_CODE_MODE(NOP, 0x04, ZERO_PAGE)
IS_OP_CODE_MODE(NOP, 0x0c, ABSOLUTE)
IS_OP_CODE_MODE(NOP, 0x14, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0x1c, ABSOLUTE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0x34, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0x3c, ABSOLUTE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0x44, ZERO_PAGE)
IS_OP_CODE_MODE(NOP, 0x54, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0x5c, ABSOLUTE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0x64, ZERO_PAGE)
IS_OP_CODE_MODE(NOP, 0x74, ZERO_PAGE_INDEXED_X)
2024-01-06 14:27:09 -05:00
IS_OP_CODE_MODE(NOP, 0x7c, ABSOLUTE_INDEXED_X)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(NOP, 0x80, IMMEDIATE)
IS_OP_CODE_MODE(NOP, 0xd4, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0xdc, ABSOLUTE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0xf4, ZERO_PAGE_INDEXED_X)
IS_OP_CODE_MODE(NOP, 0xfc, ABSOLUTE_INDEXED_X)
2024-01-06 14:27:09 -05:00
// ALU
2023-10-05 17:05:06 -04:00
IS_ALU_OP_CODE(ORA)
IS_ALU_OP_CODE(AND)
IS_ALU_OP_CODE(EOR)
IS_ALU_OP_CODE(ADC)
IS_ALU_OP_CODE_NO_IMMEDIATE(STA)
IS_ALU_OP_CODE(LDA)
IS_ALU_OP_CODE(CMP)
IS_ALU_OP_CODE(SBC)
2024-01-06 14:27:09 -05:00
// RMW
2023-10-05 17:05:06 -04:00
IS_RMW_OP_CODE(ASL, ORA)
IS_RMW_OP_CODE(ROL, AND)
IS_RMW_OP_CODE(LSR, EOR)
IS_RMW_OP_CODE(ROR, ADC)
IS_OP_CODE(STP, 0x02)
IS_OP_CODE(STP, 0x12)
IS_OP_CODE(NOP, 0x1a)
IS_OP_CODE(STP, 0x22)
IS_OP_CODE(STP, 0x32)
IS_OP_CODE(NOP, 0x3a)
IS_OP_CODE(STP, 0x42)
IS_OP_CODE(STP, 0x52)
IS_OP_CODE(NOP, 0x5a)
IS_OP_CODE(STP, 0x62)
IS_OP_CODE(STP, 0x72)
IS_OP_CODE(NOP, 0x7a)
IS_OP_CODE_MODE(NOP, 0x82, IMMEDIATE)
IS_OP_CODE_MODE(STX, 0x86, ZERO_PAGE)
IS_OP_CODE(TXA, 0x8a)
IS_OP_CODE_MODE(STX, 0x8e, ABSOLUTE)
IS_OP_CODE(STP, 0x92)
IS_OP_CODE_MODE(STX, 0x96, ZERO_PAGE_INDEXED_Y)
2024-01-06 14:27:09 -05:00
IS_OP_CODE(TXS, 0x9a)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(SHX, 0x9e, ABSOLUTE_INDEXED_Y)
IS_OP_CODE_MODE(LDX, 0xa2, IMMEDIATE)
IS_OP_CODE_MODE(LDX, 0xa6, ZERO_PAGE)
IS_OP_CODE(TAX, 0xaa)
IS_OP_CODE_MODE(LDX, 0xae, ABSOLUTE)
IS_OP_CODE(STP, 0xb2)
IS_OP_CODE_MODE(LDX, 0xb6, ZERO_PAGE_INDEXED_Y)
IS_OP_CODE(TSX, 0xba)
IS_OP_CODE_MODE(LDX, 0xbe, ABSOLUTE_INDEXED_Y)
IS_OP_CODE_MODE(NOP, 0xc2, IMMEDIATE)
IS_OP_CODE_MODE(DEC, 0xc6, ZERO_PAGE)
IS_OP_CODE(DEX, 0xca)
IS_OP_CODE_MODE(DEC, 0xce, ABSOLUTE)
IS_OP_CODE(STP, 0xd2)
2024-01-06 14:27:09 -05:00
IS_OP_CODE_MODE(DEC, 0xd6, ZERO_PAGE_INDEXED_X)
2023-10-05 17:05:06 -04:00
IS_OP_CODE(NOP, 0xda)
2024-01-06 14:27:09 -05:00
IS_OP_CODE_MODE(DEC, 0xde, ABSOLUTE_INDEXED_X)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(NOP, 0xe2, IMMEDIATE)
IS_OP_CODE_MODE(INC, 0xe6, ZERO_PAGE)
IS_OP_CODE(NOP, 0xea) // The official NOP
IS_OP_CODE_MODE(INC, 0xee, ABSOLUTE)
IS_OP_CODE(STP, 0xf2)
2024-01-06 14:27:09 -05:00
IS_OP_CODE_MODE(INC, 0xf6, ZERO_PAGE_INDEXED_X)
2023-10-05 17:05:06 -04:00
IS_OP_CODE(NOP, 0xfa)
IS_OP_CODE_MODE(INC, 0xfe, ABSOLUTE_INDEXED_X)
2024-01-06 14:27:09 -05:00
// Unofficial
2023-10-05 17:05:06 -04:00
IS_UNOFFICIAL_OP_CODE(SLO, ORA)
IS_UNOFFICIAL_OP_CODE(RLA, AND)
IS_UNOFFICIAL_OP_CODE(SRE, EOR)
IS_UNOFFICIAL_OP_CODE(RRA, ADC)
IS_UNOFFICIAL_OP_CODE(DCP, CMP)
IS_UNOFFICIAL_OP_CODE(ISC, SBC)
IS_OP_CODE_MODE(ANC, 0x0b, IMMEDIATE)
IS_OP_CODE_MODE(ANC, 0x2b, IMMEDIATE)
IS_OP_CODE_MODE(ALR, 0x4b, IMMEDIATE)
IS_OP_CODE_MODE(ARR, 0x6b, IMMEDIATE)
IS_OP_CODE_MODE(AXS, 0xcb, IMMEDIATE)
IS_OP_CODE_MODE(SBC, 0xeb, IMMEDIATE)
2023-11-26 12:11:49 -05:00
IS_OP_CODE_MODE(SAX, 0x83, INDIRECT_X)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(SAX, 0x87, ZERO_PAGE)
IS_OP_CODE_MODE(XAA, 0x8b, IMMEDIATE)
IS_OP_CODE_MODE(SAX, 0x8f, ABSOLUTE)
2023-11-26 12:11:49 -05:00
IS_OP_CODE_MODE(AHX, 0x93, INDIRECT_Y)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(SAX, 0x97, ZERO_PAGE_INDEXED_Y)
IS_OP_CODE_MODE(TAS, 0x9b, ABSOLUTE_INDEXED_Y)
IS_OP_CODE_MODE(AHX, 0x9f, ABSOLUTE_INDEXED_Y)
2023-11-26 12:11:49 -05:00
IS_OP_CODE_MODE(LAX, 0xa3, INDIRECT_X)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(LAX, 0xa7, ZERO_PAGE)
IS_OP_CODE_MODE(LAX, 0xab, IMMEDIATE)
IS_OP_CODE_MODE(LAX, 0xaf, ABSOLUTE)
2023-11-26 12:11:49 -05:00
IS_OP_CODE_MODE(LAX, 0xb3, INDIRECT_Y)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(LAX, 0xb7, ZERO_PAGE_INDEXED_Y)
2024-01-06 14:27:09 -05:00
IS_OP_CODE_MODE(LAS, 0xbb, ABSOLUTE_INDEXED_Y)
2023-10-05 17:05:06 -04:00
IS_OP_CODE_MODE(LAX, 0xbf, ABSOLUTE_INDEXED_Y)
2024-01-06 14:27:09 -05:00
default:
assert(false);
2023-10-05 17:05:06 -04:00
}
2024-01-11 16:02:53 -05:00
}
AddressingMode get_op_addr_mode(byte op_code) {
switch (op_code) {
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
case 0x20:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
case 0x4c:
case 0x4d:
case 0x4e:
case 0x4f:
case 0x6d:
case 0x6e:
case 0x6f:
case 0x8c:
case 0x8d:
case 0x8e:
case 0x8f:
case 0xac:
case 0xad:
case 0xae:
case 0xaf:
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
case 0xec:
case 0xed:
case 0xee:
case 0xef:
return ADDR_MODE_ABSOLUTE;
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
case 0x5c:
case 0x5d:
case 0x5e:
case 0x5f:
case 0x7c:
case 0x7d:
case 0x7e:
case 0x7f:
case 0x9c:
case 0x9d:
case 0xbc:
case 0xbd:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
case 0xfc:
case 0xfd:
case 0xfe:
case 0xff:
return ADDR_MODE_ABSOLUTE_INDEXED_X;
case 0x19:
case 0x1b:
case 0x39:
case 0x3b:
case 0x59:
case 0x5b:
case 0x79:
case 0x7b:
case 0x99:
case 0x9b:
case 0x9e:
case 0x9f:
case 0xb9:
case 0xbb:
case 0xbe:
case 0xbf:
case 0xd9:
case 0xdb:
case 0xf9:
case 0xfb:
return ADDR_MODE_ABSOLUTE_INDEXED_Y;
case 0x0a:
case 0x2a:
case 0x4a:
case 0x6a:
return ADDR_MODE_ACCUMULATOR;
case 0x09:
case 0x0b:
case 0x29:
case 0x2b:
case 0x49:
case 0x4b:
case 0x69:
case 0x6b:
case 0x80:
case 0x82:
case 0x89:
case 0x8b:
case 0xa0:
case 0xa2:
case 0xa9:
case 0xab:
case 0xc0:
case 0xc2:
case 0xc9:
case 0xcb:
case 0xe0:
case 0xe2:
case 0xe9:
case 0xeb:
return ADDR_MODE_IMMEDIATE;
case 0x00:
case 0x02:
case 0x08:
case 0x12:
case 0x18:
case 0x1a:
case 0x22:
case 0x28:
case 0x32:
2024-01-16 15:46:22 -05:00
case 0x38:
2024-01-11 16:02:53 -05:00
case 0x3a:
case 0x40:
case 0x42:
case 0x48:
case 0x52:
case 0x58:
case 0x5a:
case 0x60:
case 0x62:
case 0x68:
case 0x72:
case 0x78:
case 0x7a:
case 0x88:
case 0x8a:
case 0x92:
case 0x98:
case 0x9a:
case 0xa8:
case 0xaa:
case 0xb2:
case 0xb8:
case 0xba:
case 0xc8:
case 0xca:
case 0xd2:
case 0xd8:
case 0xda:
case 0xe8:
case 0xea:
case 0xf2:
case 0xf8:
case 0xfa:
return ADDR_MODE_IMPLICIT;
case 0x01:
case 0x03:
case 0x21:
case 0x23:
case 0x41:
case 0x43:
case 0x61:
case 0x63:
case 0x81:
case 0x83:
case 0xa1:
case 0xa3:
case 0xc1:
case 0xc3:
case 0xe1:
case 0xe3:
return ADDR_MODE_INDIRECT_X;
case 0x6c:
return ADDR_MODE_INDIRECT_JUMP;
case 0x11:
case 0x13:
case 0x31:
case 0x33:
case 0x51:
case 0x53:
case 0x71:
case 0x73:
case 0x91:
case 0x93:
case 0xb1:
case 0xb3:
case 0xd1:
case 0xd3:
case 0xf1:
case 0xf3:
return ADDR_MODE_INDIRECT_Y;
case 0x10:
case 0x30:
case 0x50:
case 0x70:
case 0x90:
case 0xb0:
case 0xd0:
case 0xf0:
return ADDR_MODE_RELATIVE;
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x44:
case 0x45:
case 0x46:
case 0x47:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
case 0xa4:
case 0xa5:
case 0xa6:
case 0xa7:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
case 0xe4:
case 0xe5:
case 0xe6:
case 0xe7:
return ADDR_MODE_ZERO_PAGE;
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x94:
case 0x95:
case 0xb4:
case 0xb5:
case 0xd4:
case 0xd5:
case 0xd6:
case 0xd7:
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
return ADDR_MODE_ZERO_PAGE_INDEXED_X;
case 0x96:
case 0x97:
case 0xb6:
case 0xb7:
return ADDR_MODE_ZERO_PAGE_INDEXED_Y;
default:
assert(false);
}
2023-11-26 12:11:49 -05:00
}