From 2bc37b1b610e4acbc0b69e88da11ec021f9824dd Mon Sep 17 00:00:00 2001 From: Tony Di Nucci Date: Sat, 20 Apr 2019 23:58:03 +0100 Subject: [PATCH] Most bitwise operations --- .../bitwise-opcode-handler-container.cpp | 314 +++++++ .../bitwise-opcode-handler-container.h | 133 +++ .../maths-opcode-handler-container.cpp | 15 +- .../handler/maths-opcode-handler-container.h | 2 - src/opcode/handler/opcode-handler-container.h | 2 - src/opcode/opcode-handler-directory.cpp | 2 + src/utils.cpp | 5 + src/utils.h | 3 + test/bitwise-opcode-handler-test.cpp | 785 ++++++++++++++++++ 9 files changed, 1247 insertions(+), 14 deletions(-) create mode 100644 src/opcode/handler/bitwise-opcode-handler-container.cpp create mode 100644 src/opcode/handler/bitwise-opcode-handler-container.h create mode 100644 test/bitwise-opcode-handler-test.cpp diff --git a/src/opcode/handler/bitwise-opcode-handler-container.cpp b/src/opcode/handler/bitwise-opcode-handler-container.cpp new file mode 100644 index 0000000..75bc44a --- /dev/null +++ b/src/opcode/handler/bitwise-opcode-handler-container.cpp @@ -0,0 +1,314 @@ +#include "bitwise-opcode-handler-container.h" +#include "../../utils.h" + +namespace emu_6502 { + BitwiseOpcodeHandlerContainer::BitwiseOpcodeHandlerContainer() { + handlers.insert({Op::AND_IMM, [this](Machine& machine) { and_imm(machine); }}); + handlers.insert({Op::AND_ZPG, [this](Machine& machine) { and_zpg(machine); }}); + handlers.insert({Op::AND_ZPG_X, [this](Machine& machine) { and_zpg_x(machine); }}); + handlers.insert({Op::AND_ABS, [this](Machine& machine) { and_abs(machine); }}); + handlers.insert({Op::AND_ABS_X, [this](Machine& machine) { and_abs_x(machine); }}); + handlers.insert({Op::AND_ABS_Y, [this](Machine& machine) { and_abs_y(machine); }}); + handlers.insert({Op::AND_IND_X, [this](Machine& machine) { and_ind_x(machine); }}); + handlers.insert({Op::AND_IND_Y, [this](Machine& machine) { and_ind_y(machine); }}); + + handlers.insert({Op::ORA_IMM, [this](Machine& machine) { or_imm(machine); }}); + handlers.insert({Op::ORA_ZPG, [this](Machine& machine) { or_zpg(machine); }}); + handlers.insert({Op::ORA_ZPG_X, [this](Machine& machine) { or_zpg_x(machine); }}); + handlers.insert({Op::ORA_ABS, [this](Machine& machine) { or_abs(machine); }}); + handlers.insert({Op::ORA_ABS_X, [this](Machine& machine) { or_abs_x(machine); }}); + handlers.insert({Op::ORA_ABS_Y, [this](Machine& machine) { or_abs_y(machine); }}); + handlers.insert({Op::ORA_IND_X, [this](Machine& machine) { or_ind_x(machine); }}); + handlers.insert({Op::ORA_IND_Y, [this](Machine& machine) { or_ind_y(machine); }}); + + handlers.insert({Op::EOR_IMM, [this](Machine& machine) { xor_imm(machine); }}); + handlers.insert({Op::EOR_ZPG, [this](Machine& machine) { xor_zpg(machine); }}); + handlers.insert({Op::EOR_ZPG_X, [this](Machine& machine) { xor_zpg_x(machine); }}); + handlers.insert({Op::EOR_ABS, [this](Machine& machine) { xor_abs(machine); }}); + handlers.insert({Op::EOR_ABS_X, [this](Machine& machine) { xor_abs_x(machine); }}); + handlers.insert({Op::EOR_ABS_Y, [this](Machine& machine) { xor_abs_y(machine); }}); + handlers.insert({Op::EOR_IND_X, [this](Machine& machine) { xor_ind_x(machine); }}); + handlers.insert({Op::EOR_IND_Y, [this](Machine& machine) { xor_ind_y(machine); }}); + + handlers.insert({Op::BIT_ZPG, [this](Machine& machine) { bit_zpg(machine); }}); + handlers.insert({Op::BIT_ABS, [this](Machine& machine) { bit_abs(machine); }}); + + handlers.insert({Op::ASL_ACC, [this](Machine& machine) { asl_acc(machine); }}); + handlers.insert({Op::ASL_ZPG, [this](Machine& machine) { asl_zpg(machine); }}); + handlers.insert({Op::ASL_ZPG_X, [this](Machine& machine) { asl_zpg_x(machine); }}); + handlers.insert({Op::ASL_ABS, [this](Machine& machine) { asl_abs(machine); }}); + handlers.insert({Op::ASL_ABS_X, [this](Machine& machine) { asl_abs_x(machine); }}); + + handlers.insert({Op::LSR_ACC, [this](Machine& machine) { lsr_acc(machine); }}); + handlers.insert({Op::LSR_ZPG, [this](Machine& machine) { lsr_zpg(machine); }}); + handlers.insert({Op::LSR_ZPG_X, [this](Machine& machine) { lsr_zpg_x(machine); }}); + handlers.insert({Op::LSR_ABS, [this](Machine& machine) { lsr_abs(machine); }}); + handlers.insert({Op::LSR_ABS_X, [this](Machine& machine) { lsr_abs_x(machine); }}); + + handlers.insert({Op::ROL_ACC, [this](Machine& machine) { rol_acc(machine); }}); + handlers.insert({Op::ROL_ZPG, [this](Machine& machine) { rol_zpg(machine); }}); + handlers.insert({Op::ROL_ZPG_X, [this](Machine& machine) { rol_zpg_x(machine); }}); + handlers.insert({Op::ROL_ABS, [this](Machine& machine) { rol_abs(machine); }}); + handlers.insert({Op::ROL_ABS_X, [this](Machine& machine) { rol_abs_x(machine); }}); + } + + void BitwiseOpcodeHandlerContainer::do_and(Machine& machine, uint8_t value) { + auto& cpu = machine.get_cpu(); + auto result = cpu.get_a().get_value() & value; + cpu.get_a().set_value(result); + + set_zero_and_neg_flags(machine.get_cpu().get_ps(), result); + } + + void BitwiseOpcodeHandlerContainer::do_and_with(Machine& machine, uint16_t address) { + do_and(machine, machine.get_memory().get_at(address)); + } + + void BitwiseOpcodeHandlerContainer::and_imm(Machine& machine) { + do_and(machine, machine.read_program_byte()); + } + + void BitwiseOpcodeHandlerContainer::and_zpg(Machine& machine) { + do_and_with(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::and_zpg_x(Machine& machine) { + do_and_with(machine, get_zpg_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::and_abs(Machine& machine) { + do_and_with(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::and_abs_x(Machine& machine) { + do_and_with(machine, get_abs_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::and_abs_y(Machine& machine) { + do_and_with(machine, get_abs_y_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::and_ind_x(Machine& machine) { + do_and_with(machine, get_ind_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::and_ind_y(Machine& machine) { + do_and_with(machine, get_ind_y_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::do_or(Machine& machine, uint8_t value) { + auto& cpu = machine.get_cpu(); + auto result = cpu.get_a().get_value() | value; + cpu.get_a().set_value(result); + + set_zero_and_neg_flags(machine.get_cpu().get_ps(), result); + } + + void BitwiseOpcodeHandlerContainer::do_or_with(Machine& machine, uint16_t address) { + do_or(machine, machine.get_memory().get_at(address)); + } + + void BitwiseOpcodeHandlerContainer::or_imm(Machine& machine) { + do_or(machine, machine.read_program_byte()); + } + + void BitwiseOpcodeHandlerContainer::or_zpg(Machine& machine) { + do_or_with(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::or_zpg_x(Machine& machine) { + do_or_with(machine, get_zpg_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::or_abs(Machine& machine) { + do_or_with(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::or_abs_x(Machine& machine) { + do_or_with(machine, get_abs_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::or_abs_y(Machine& machine) { + do_or_with(machine, get_abs_y_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::or_ind_x(Machine& machine) { + do_or_with(machine, get_ind_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::or_ind_y(Machine& machine) { + do_or_with(machine, get_ind_y_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::do_xor(Machine& machine, uint8_t value) { + auto& cpu = machine.get_cpu(); + auto result = cpu.get_a().get_value() ^value; + cpu.get_a().set_value(result); + + set_zero_and_neg_flags(machine.get_cpu().get_ps(), result); + } + + void BitwiseOpcodeHandlerContainer::do_xor_with(Machine& machine, uint16_t address) { + do_xor(machine, machine.get_memory().get_at(address)); + } + + void BitwiseOpcodeHandlerContainer::xor_imm(Machine& machine) { + do_xor(machine, machine.read_program_byte()); + } + + void BitwiseOpcodeHandlerContainer::xor_zpg(Machine& machine) { + do_xor_with(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::xor_zpg_x(Machine& machine) { + do_xor_with(machine, get_zpg_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::xor_abs(Machine& machine) { + do_xor_with(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::xor_abs_x(Machine& machine) { + do_xor_with(machine, get_abs_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::xor_abs_y(Machine& machine) { + do_xor_with(machine, get_abs_y_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::xor_ind_x(Machine& machine) { + do_xor_with(machine, get_ind_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::xor_ind_y(Machine& machine) { + do_xor_with(machine, get_ind_y_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::bit(Machine& machine, uint16_t address) { + auto a = machine.get_cpu().get_a().get_value(); + auto mem = machine.get_memory().get_at(address); + auto& ps = machine.get_cpu().get_ps(); + + ps.set_zero((a & mem) == 0); + ps.set_negative((mem & 0x80) == 0x80); + ps.set_overflow((mem & 0x40) == 0x40); + } + + void BitwiseOpcodeHandlerContainer::bit_zpg(Machine& machine) { + bit(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::bit_abs(Machine& machine) { + bit(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::asl_at(Machine& machine, uint16_t address) { + uint16_t result = machine.get_memory().get_at(address) << 1; + machine.get_memory().set_at(address, result); + + auto& ps = machine.get_cpu().get_ps(); + ps.set_carry((result & 0x100) == 0x100); + set_zero_and_neg_flags(ps, result); + } + + void BitwiseOpcodeHandlerContainer::asl_acc(Machine& machine) { + uint16_t result = machine.get_cpu().get_a().get_value() << 1; + machine.get_cpu().get_a().set_value(result); + + auto& ps = machine.get_cpu().get_ps(); + ps.set_carry((result & 0x100) == 0x100); + set_zero_and_neg_flags(ps, result); + } + + void BitwiseOpcodeHandlerContainer::asl_zpg(Machine& machine) { + asl_at(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::asl_zpg_x(Machine& machine) { + asl_at(machine, get_zpg_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::asl_abs(Machine& machine) { + asl_at(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::asl_abs_x(Machine& machine) { + asl_at(machine, get_abs_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::lsr_at(Machine& machine, uint16_t address) { + auto orig = machine.get_memory().get_at(address); + auto result = orig >> 1; + machine.get_memory().set_at(address, result); + + auto& ps = machine.get_cpu().get_ps(); + ps.set_carry((orig & 1) == 1); + ps.set_zero(result == 0); + } + + void BitwiseOpcodeHandlerContainer::lsr_acc(Machine& machine) { + auto orig = machine.get_cpu().get_a().get_value(); + auto result = orig >> 1; + machine.get_cpu().get_a().set_value(result); + + auto& ps = machine.get_cpu().get_ps(); + ps.set_carry((orig & 1) == 1); + ps.set_zero(result == 0); + } + + void BitwiseOpcodeHandlerContainer::lsr_zpg(Machine& machine) { + lsr_at(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::lsr_zpg_x(Machine& machine) { + lsr_at(machine, get_zpg_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::lsr_abs(Machine& machine) { + lsr_at(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::lsr_abs_x(Machine& machine) { + lsr_at(machine, get_abs_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::rol_at(Machine& machine, uint16_t address) { + uint16_t result = machine.get_memory().get_at(address) << 1; + + auto& ps = machine.get_cpu().get_ps(); + if (ps.is_carry_set()) + result += 1; + + machine.get_memory().set_at(address, result); + ps.set_carry((result & 0x100) == 0x100); + set_zero_and_neg_flags(ps, result); + } + + void BitwiseOpcodeHandlerContainer::rol_acc(Machine& machine) { + uint16_t result = machine.get_cpu().get_a().get_value() << 1; + + auto& ps = machine.get_cpu().get_ps(); + if (ps.is_carry_set()) + result += 1; + + machine.get_cpu().get_a().set_value(result); + ps.set_carry((result & 0x100) == 0x100); + set_zero_and_neg_flags(ps, result); + } + + void BitwiseOpcodeHandlerContainer::rol_zpg(Machine& machine) { + rol_at(machine, get_zpg_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::rol_zpg_x(Machine& machine) { + rol_at(machine, get_zpg_x_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::rol_abs(Machine& machine) { + rol_at(machine, get_abs_address(machine)); + } + + void BitwiseOpcodeHandlerContainer::rol_abs_x(Machine& machine) { + rol_at(machine, get_abs_x_address(machine)); + } +} \ No newline at end of file diff --git a/src/opcode/handler/bitwise-opcode-handler-container.h b/src/opcode/handler/bitwise-opcode-handler-container.h new file mode 100644 index 0000000..a35a002 --- /dev/null +++ b/src/opcode/handler/bitwise-opcode-handler-container.h @@ -0,0 +1,133 @@ +#ifndef INC_6502_EMULATOR_BITWISE_OPCODE_HANDLER_CONTAINER_H +#define INC_6502_EMULATOR_BITWISE_OPCODE_HANDLER_CONTAINER_H + +#include "opcode-handler-container.h" + +namespace emu_6502 { + class BitwiseOpcodeHandlerContainer : public OpcodeHandlerContainer { + private: + enum Op { + AND_IMM = 0x29, + AND_ZPG = 0x25, + AND_ZPG_X = 0x35, + AND_ABS = 0x2D, + AND_ABS_X = 0x3D, + AND_ABS_Y = 0x39, + AND_IND_X = 0x21, + AND_IND_Y = 0x31, + + ORA_IMM = 0x09, + ORA_ZPG = 0x05, + ORA_ZPG_X = 0x15, + ORA_ABS = 0x0D, + ORA_ABS_X = 0x1D, + ORA_ABS_Y = 0x19, + ORA_IND_X = 0x01, + ORA_IND_Y = 0x11, + + EOR_IMM = 0x49, + EOR_ZPG = 0x45, + EOR_ZPG_X = 0x55, + EOR_ABS = 0x4D, + EOR_ABS_X = 0x5D, + EOR_ABS_Y = 0x59, + EOR_IND_X = 0x41, + EOR_IND_Y = 0x51, + + BIT_ZPG = 0x24, + BIT_ABS = 0x2C, + + ASL_ACC = 0x0A, + ASL_ZPG = 0x06, + ASL_ZPG_X = 0x16, + ASL_ABS = 0x0E, + ASL_ABS_X = 0x1E, + + LSR_ACC = 0x4A, + LSR_ZPG = 0x46, + LSR_ZPG_X = 0x56, + LSR_ABS = 0x4E, + LSR_ABS_X = 0x5E, + + ROL_ACC = 0x2A, + ROL_ZPG = 0x26, + ROL_ZPG_X = 0x36, + ROL_ABS = 0x2E, + ROL_ABS_X = 0x3E, + + ROR_ACC = 0x6A, + ROR_ZPG = 0x66, + ROR_ZPG_X = 0x76, + ROR_ABS = 0x6E, + ROR_ABS_X = 0x7E, + }; + + void do_and(Machine& machine, uint8_t value); + void do_and_with(Machine& machine, uint16_t address); + void and_imm(Machine& machine); + void and_zpg(Machine& machine); + void and_zpg_x(Machine& machine); + void and_abs(Machine& machine); + void and_abs_x(Machine& machine); + void and_abs_y(Machine& machine); + void and_ind_x(Machine& machine); + void and_ind_y(Machine& machine); + + void do_or(Machine& machine, uint8_t value); + void do_or_with(Machine& machine, uint16_t address); + void or_imm(Machine& machine); + void or_zpg(Machine& machine); + void or_zpg_x(Machine& machine); + void or_abs(Machine& machine); + void or_abs_x(Machine& machine); + void or_abs_y(Machine& machine); + void or_ind_x(Machine& machine); + void or_ind_y(Machine& machine); + + void do_xor(Machine& machine, uint8_t value); + void do_xor_with(Machine& machine, uint16_t address); + void xor_imm(Machine& machine); + void xor_zpg(Machine& machine); + void xor_zpg_x(Machine& machine); + void xor_abs(Machine& machine); + void xor_abs_x(Machine& machine); + void xor_abs_y(Machine& machine); + void xor_ind_x(Machine& machine); + void xor_ind_y(Machine& machine); + + void bit(Machine& machine, uint16_t address); + void bit_zpg(Machine& machine); + void bit_abs(Machine& machine); + + void asl_at(Machine& machine, uint16_t address); + void asl_acc(Machine& machine); + void asl_zpg(Machine& machine); + void asl_zpg_x(Machine& machine); + void asl_abs(Machine& machine); + void asl_abs_x(Machine& machine); + + void lsr_at(Machine& machine, uint16_t address); + void lsr_acc(Machine& machine); + void lsr_zpg(Machine& machine); + void lsr_zpg_x(Machine& machine); + void lsr_abs(Machine& machine); + void lsr_abs_x(Machine& machine); + + void rol_at(Machine& machine, uint16_t address); + void rol_acc(Machine& machine); + void rol_zpg(Machine& machine); + void rol_zpg_x(Machine& machine); + void rol_abs(Machine& machine); + void rol_abs_x(Machine& machine); + + + + public: + BitwiseOpcodeHandlerContainer(); + BitwiseOpcodeHandlerContainer(const BitwiseOpcodeHandlerContainer& other) = delete; + BitwiseOpcodeHandlerContainer operator=(const BitwiseOpcodeHandlerContainer& other) = delete; + }; +} + + +#endif //INC_6502_EMULATOR_BITWISE_OPCODE_HANDLER_CONTAINER_H diff --git a/src/opcode/handler/maths-opcode-handler-container.cpp b/src/opcode/handler/maths-opcode-handler-container.cpp index 3defe77..a63f76a 100644 --- a/src/opcode/handler/maths-opcode-handler-container.cpp +++ b/src/opcode/handler/maths-opcode-handler-container.cpp @@ -37,11 +37,6 @@ namespace emu_6502 { handlers.insert({Op::DEY, [this](Machine& machine) { dey(machine); }}); } - void MathsOpcodeHandlerContainer::set_zero_neg(StatusRegister& ps, uint8_t value) { - ps.set_zero(value == 0); - ps.set_negative((value & 0x80) == 0x80); - } - void MathsOpcodeHandlerContainer::adc(Machine& machine, uint8_t value) { auto& cpu = machine.get_cpu(); auto init_a = cpu.get_a().get_value(); @@ -55,7 +50,7 @@ namespace emu_6502 { auto a = cpu.get_a().get_value(); // 'a' may be 0 if the result wasn't 0, i.e. the cary bit is set - set_zero_neg(cpu.get_ps(), a); + set_zero_and_neg_flags(cpu.get_ps(), a); cpu.get_ps().set_carry(result > 0xFF); cpu.get_ps().set_overflow( (value < 0x7F && init_a < 0x7F && a > 0x7F) || @@ -137,7 +132,7 @@ namespace emu_6502 { uint8_t value = machine.get_memory().get_at(address) - 1; machine.get_memory().set_at(address, value); - set_zero_neg(machine.get_cpu().get_ps(), value); + set_zero_and_neg_flags(machine.get_cpu().get_ps(), value); } void MathsOpcodeHandlerContainer::dec_zpg(Machine& machine) { @@ -160,7 +155,7 @@ namespace emu_6502 { uint8_t value = machine.get_memory().get_at(address) + 1; machine.get_memory().set_at(address, value); - set_zero_neg(machine.get_cpu().get_ps(), value); + set_zero_and_neg_flags(machine.get_cpu().get_ps(), value); } void MathsOpcodeHandlerContainer::inc_zpg(Machine& machine) { @@ -183,7 +178,7 @@ namespace emu_6502 { uint8_t value = reg.get_value() - 1; reg.set_value(value); - set_zero_neg(machine.get_cpu().get_ps(), value); + set_zero_and_neg_flags(machine.get_cpu().get_ps(), value); } void MathsOpcodeHandlerContainer::dex(Machine& machine) { @@ -198,7 +193,7 @@ namespace emu_6502 { uint8_t value = reg.get_value() + 1; reg.set_value(value); - set_zero_neg(machine.get_cpu().get_ps(), value); + set_zero_and_neg_flags(machine.get_cpu().get_ps(), value); } void MathsOpcodeHandlerContainer::inx(Machine& machine) { diff --git a/src/opcode/handler/maths-opcode-handler-container.h b/src/opcode/handler/maths-opcode-handler-container.h index 2ecd64a..8f68b44 100644 --- a/src/opcode/handler/maths-opcode-handler-container.h +++ b/src/opcode/handler/maths-opcode-handler-container.h @@ -41,8 +41,6 @@ namespace emu_6502 { INY = 0xC8 }; - void set_zero_neg(StatusRegister& ps, uint8_t value); - void adc(Machine& machine, uint8_t value); void adc_imm(Machine& machine); void adc_zpg(Machine& machine); diff --git a/src/opcode/handler/opcode-handler-container.h b/src/opcode/handler/opcode-handler-container.h index 18907b1..0e87218 100644 --- a/src/opcode/handler/opcode-handler-container.h +++ b/src/opcode/handler/opcode-handler-container.h @@ -17,8 +17,6 @@ namespace emu_6502 { OpcodeHandlerContainer(const OpcodeHandlerContainer& other) = delete; OpcodeHandlerContainer operator=(const OpcodeHandlerContainer& other) = delete; - virtual ~OpcodeHandlerContainer() {}; - const unordered_map>& get_handlers(); }; } diff --git a/src/opcode/opcode-handler-directory.cpp b/src/opcode/opcode-handler-directory.cpp index 6d0487f..715f86c 100644 --- a/src/opcode/opcode-handler-directory.cpp +++ b/src/opcode/opcode-handler-directory.cpp @@ -3,6 +3,7 @@ #include "handler/store-opcode-handler-container.h" #include "handler/transfer-opcode-handler-container.h" #include "handler/maths-opcode-handler-container.h" +#include "handler/bitwise-opcode-handler-container.h" #include "../utils.h" namespace emu_6502 { @@ -12,6 +13,7 @@ namespace emu_6502 { handler_containers.push_back(make_unique()); handler_containers.push_back(make_unique()); handler_containers.push_back(make_unique()); + handler_containers.push_back(make_unique()); init_handlers(); } diff --git a/src/utils.cpp b/src/utils.cpp index 32b91fb..4b2964b 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -8,6 +8,11 @@ namespace emu_6502 { return ss.str(); } + void set_zero_and_neg_flags(StatusRegister& ps, uint8_t value) { + ps.set_zero(value == 0); + ps.set_negative((value & 0x80) == 0x80); + } + uint8_t get_zpg_address(Machine& machine) { return machine.read_program_byte(); } diff --git a/src/utils.h b/src/utils.h index 43659f0..e6e977e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,6 +9,9 @@ using namespace std; namespace emu_6502 { string uint_to_hex(uint64_t value); + + void set_zero_and_neg_flags(StatusRegister& ps, uint8_t value); + uint8_t get_zpg_address(Machine& machine); uint8_t get_zpg_x_address(Machine& machine); uint8_t get_zpg_y_address(Machine& machine); diff --git a/test/bitwise-opcode-handler-test.cpp b/test/bitwise-opcode-handler-test.cpp new file mode 100644 index 0000000..dbf5eb5 --- /dev/null +++ b/test/bitwise-opcode-handler-test.cpp @@ -0,0 +1,785 @@ +#include "gtest/gtest.h" +#include "test-utils.h" + +using namespace std; +using namespace emu_6502; + +const uint8_t AND_IMM = 0x29; +const uint8_t AND_ZPG = 0x25; +const uint8_t AND_ZPG_X = 0x35; +const uint8_t AND_ABS = 0x2D; +const uint8_t AND_ABS_X = 0x3D; +const uint8_t AND_ABS_Y = 0x39; +const uint8_t AND_IND_X = 0x21; +const uint8_t AND_IND_Y = 0x31; + +const uint8_t ORA_IMM = 0x09; +const uint8_t ORA_ZPG = 0x05; +const uint8_t ORA_ZPG_X = 0x15; +const uint8_t ORA_ABS = 0x0D; +const uint8_t ORA_ABS_X = 0x1D; +const uint8_t ORA_ABS_Y = 0x19; +const uint8_t ORA_IND_X = 0x01; +const uint8_t ORA_IND_Y = 0x11; + +const uint8_t EOR_IMM = 0x49; +const uint8_t EOR_ZPG = 0x45; +const uint8_t EOR_ZPG_X = 0x55; +const uint8_t EOR_ABS = 0x4D; +const uint8_t EOR_ABS_X = 0x5D; +const uint8_t EOR_ABS_Y = 0x59; +const uint8_t EOR_IND_X = 0x41; +const uint8_t EOR_IND_Y = 0x51; + +const uint8_t BIT_ZPG = 0x24; +const uint8_t BIT_ABS = 0x2C; + +const uint8_t ASL_ACC = 0x0A; +const uint8_t ASL_ZPG = 0x06; +const uint8_t ASL_ZPG_X = 0x16; +const uint8_t ASL_ABS = 0x0E; +const uint8_t ASL_ABS_X = 0x1E; + +const uint8_t LSR_ACC = 0x4A; +const uint8_t LSR_ZPG = 0x46; +const uint8_t LSR_ZPG_X = 0x56; +const uint8_t LSR_ABS = 0x4E; +const uint8_t LSR_ABS_X = 0x5E; + +const uint8_t ROL_ACC = 0x2A; +const uint8_t ROL_ZPG = 0x26; +const uint8_t ROL_ZPG_X = 0x36; +const uint8_t ROL_ABS = 0x2E; +const uint8_t ROL_ABS_X = 0x3E; + +TEST(LoadOpcodeHandlerContainer, AND_IMM) { + auto machine = create_machine({AND_IMM, 0x23}); + machine->get_cpu().get_a().set_value(0x13); + machine->execute(); + + ASSERT_EQ(0x03, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_IMM_ZeroFlag) { + auto machine = create_machine({AND_IMM, 0x11}); + machine->get_cpu().get_a().set_value(0x22); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, AND_IMM_NegativeFlag) { + auto machine = create_machine({AND_IMM, 0xF0}); + machine->get_cpu().get_a().set_value(0xA1); + machine->execute(); + + ASSERT_EQ(0xA0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, AND_ZPG) { + auto machine = create_machine({AND_ZPG, 0xF5}); + machine->get_memory().set_at(0xF5, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x41, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_ZPG_X) { + auto machine = create_machine({AND_ZPG_X, 0x30}); + machine->get_cpu().get_x().set_value(0x50); + machine->get_memory().set_at(0x80, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x41, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_ABS) { + auto machine = create_machine({AND_ABS, 0x30, 0x05}); + machine->get_memory().set_at(0x0530, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x41, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_ABS_X) { + auto machine = create_machine({AND_ABS_X, 0x30, 0x05}); + machine->get_cpu().get_x().set_value(0xA); + machine->get_memory().set_at(0x053A, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x41, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_ABS_Y) { + auto machine = create_machine({AND_ABS_Y, 0x30, 0x05}); + machine->get_cpu().get_y().set_value(0xA); + machine->get_memory().set_at(0x053A, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x41, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_IND_X) { + auto machine = create_machine({AND_IND_X, 0x55}); + machine->get_cpu().get_x().set_value(0x22); + machine->get_cpu().get_a().set_value(0x41); + machine->get_memory().set_at(0x77, 0x34); + machine->get_memory().set_at(0x78, 0x12); + machine->get_memory().set_at(0x1234, 0x43); + machine->execute(); + + ASSERT_EQ(0x41, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, AND_IND_Y) { + auto machine = create_machine({AND_IND_Y, 0x41}); + machine->get_cpu().get_y().set_value(0x22); + machine->get_cpu().get_a().set_value(0xFF); + machine->get_memory().set_at(0x41, 0x34); + machine->get_memory().set_at(0x42, 0x12); + machine->get_memory().set_at(0x1256, 0x29); + machine->execute(); + + ASSERT_EQ(0x29, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_IMM) { + auto machine = create_machine({ORA_IMM, 0x30}); + machine->get_cpu().get_a().set_value(0x13); + machine->execute(); + + ASSERT_EQ(0x33, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_IMM_ZeroFlag) { + auto machine = create_machine({ORA_IMM, 0x00}); + machine->get_cpu().get_a().set_value(0x00); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ORA_IMM_NegativeFlag) { + auto machine = create_machine({ORA_IMM, 0xF0}); + machine->get_cpu().get_a().set_value(0xA1); + machine->execute(); + + ASSERT_EQ(0xF1, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ORA_ZPG) { + auto machine = create_machine({ORA_ZPG, 0xF5}); + machine->get_memory().set_at(0xF5, 0x10); + machine->get_cpu().get_a().set_value(0x25); + machine->execute(); + + ASSERT_EQ(0x35, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_ZPG_X) { + auto machine = create_machine({ORA_ZPG_X, 0x30}); + machine->get_cpu().get_x().set_value(0x50); + machine->get_memory().set_at(0x80, 0x81); + machine->get_cpu().get_a().set_value(0x42); + machine->execute(); + + ASSERT_EQ(0xC3, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ORA_ABS) { + auto machine = create_machine({ORA_ABS, 0x30, 0x05}); + machine->get_memory().set_at(0x0530, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x55, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_ABS_X) { + auto machine = create_machine({ORA_ABS_X, 0x30, 0x05}); + machine->get_cpu().get_x().set_value(0xA); + machine->get_memory().set_at(0x053A, 0x40); + machine->get_cpu().get_a().set_value(0x53); + machine->execute(); + + ASSERT_EQ(0x53, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_ABS_Y) { + auto machine = create_machine({ORA_ABS_Y, 0x30, 0x05}); + machine->get_cpu().get_y().set_value(0xA); + machine->get_memory().set_at(0x053A, 0x20); + machine->get_cpu().get_a().set_value(0x02); + machine->execute(); + + ASSERT_EQ(0x22, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_IND_X) { + auto machine = create_machine({ORA_IND_X, 0x55}); + machine->get_cpu().get_x().set_value(0x22); + machine->get_cpu().get_a().set_value(0x18); + machine->get_memory().set_at(0x77, 0x34); + machine->get_memory().set_at(0x78, 0x12); + machine->get_memory().set_at(0x1234, 0x18); + machine->execute(); + + ASSERT_EQ(0x18, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ORA_IND_Y) { + auto machine = create_machine({ORA_IND_Y, 0x41}); + machine->get_cpu().get_y().set_value(0x22); + machine->get_cpu().get_a().set_value(0xFF); + machine->get_memory().set_at(0x41, 0x34); + machine->get_memory().set_at(0x42, 0x12); + machine->get_memory().set_at(0x1256, 0x23); + machine->execute(); + + ASSERT_EQ(0xFF, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, EOR_IMM) { + auto machine = create_machine({EOR_IMM, 0x30}); + machine->get_cpu().get_a().set_value(0x13); + machine->execute(); + + ASSERT_EQ(0x23, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_IMM_ZeroFlag) { + auto machine = create_machine({EOR_IMM, 0x11}); + machine->get_cpu().get_a().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, EOR_IMM_NegativeFlag) { + auto machine = create_machine({EOR_IMM, 0xF0}); + machine->get_cpu().get_a().set_value(0x05); + machine->execute(); + + ASSERT_EQ(0xF5, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, EOR_ZPG) { + auto machine = create_machine({EOR_ZPG, 0xF5}); + machine->get_memory().set_at(0xF5, 0x31); + machine->get_cpu().get_a().set_value(0x25); + machine->execute(); + + ASSERT_EQ(0x14, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_ZPG_X) { + auto machine = create_machine({EOR_ZPG_X, 0x30}); + machine->get_cpu().get_x().set_value(0x50); + machine->get_memory().set_at(0x80, 0x31); + machine->get_cpu().get_a().set_value(0x23); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_ABS) { + auto machine = create_machine({EOR_ABS, 0x30, 0x05}); + machine->get_memory().set_at(0x0530, 0x55); + machine->get_cpu().get_a().set_value(0x41); + machine->execute(); + + ASSERT_EQ(0x14, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_ABS_X) { + auto machine = create_machine({EOR_ABS_X, 0x30, 0x05}); + machine->get_cpu().get_x().set_value(0xA); + machine->get_memory().set_at(0x053A, 0x40); + machine->get_cpu().get_a().set_value(0x53); + machine->execute(); + + ASSERT_EQ(0x13, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_ABS_Y) { + auto machine = create_machine({EOR_ABS_Y, 0x30, 0x05}); + machine->get_cpu().get_y().set_value(0xA); + machine->get_memory().set_at(0x053A, 0x20); + machine->get_cpu().get_a().set_value(0x02); + machine->execute(); + + ASSERT_EQ(0x22, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_IND_X) { + auto machine = create_machine({EOR_IND_X, 0x55}); + machine->get_cpu().get_x().set_value(0x22); + machine->get_cpu().get_a().set_value(0x19); + machine->get_memory().set_at(0x77, 0x34); + machine->get_memory().set_at(0x78, 0x12); + machine->get_memory().set_at(0x1234, 0x28); + machine->execute(); + + ASSERT_EQ(0x31, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, EOR_IND_Y) { + auto machine = create_machine({EOR_IND_Y, 0x41}); + machine->get_cpu().get_y().set_value(0x22); + machine->get_cpu().get_a().set_value(0x35); + machine->get_memory().set_at(0x41, 0x34); + machine->get_memory().set_at(0x42, 0x12); + machine->get_memory().set_at(0x1256, 0x23); + machine->execute(); + + ASSERT_EQ(0x16, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, BIT_ZPG) { + auto machine = create_machine({BIT_ZPG, 0x41}); + machine->get_cpu().get_a().set_value(0x23); + machine->get_memory().set_at(0x41, 0x35); + machine->execute(); + + ASSERT_EQ(0x23, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0x35, machine->get_memory().get_at(0x41)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, BIT_ZPG_ZeroFlag) { + auto machine = create_machine({BIT_ZPG, 0x41}); + machine->get_cpu().get_a().set_value(0x11); + machine->get_memory().set_at(0x41, 0x22); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0x22, machine->get_memory().get_at(0x41)); + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, BIT_ZPG_NegativeFlag) { + auto machine = create_machine({BIT_ZPG, 0x41}); + machine->get_cpu().get_a().set_value(0x23); + machine->get_memory().set_at(0x41, 0xa5); + machine->execute(); + + ASSERT_EQ(0x23, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0xa5, machine->get_memory().get_at(0x41)); + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, BIT_ZPG_OverflowFlag) { + auto machine = create_machine({BIT_ZPG, 0x41}); + machine->get_cpu().get_a().set_value(0x23); + machine->get_memory().set_at(0x41, 0x45); + machine->execute(); + + ASSERT_EQ(0x23, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0x45, machine->get_memory().get_at(0x41)); + RegisterFlagSet flags{}; + flags.overflow = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, BIT_ZPG_ZeroNegativeAndOverflowFlag) { + auto machine = create_machine({BIT_ZPG, 0x41}); + machine->get_cpu().get_a().set_value(0x02); + machine->get_memory().set_at(0x41, 0xc5); + machine->execute(); + + ASSERT_EQ(0x02, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0xc5, machine->get_memory().get_at(0x41)); + RegisterFlagSet flags{}; + flags.overflow = true; + flags.negative = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, BIT_ABS) { + auto machine = create_machine({BIT_ABS, 0x41, 0x90}); + machine->get_cpu().get_a().set_value(0x23); + machine->get_memory().set_at(0x9041, 0x35); + machine->execute(); + + ASSERT_EQ(0x23, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0x35, machine->get_memory().get_at(0x9041)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ACC) { + auto machine = create_machine({ASL_ACC}); + machine->get_cpu().get_a().set_value(0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ACC_CarryFlag) { + auto machine = create_machine({ASL_ACC}); + machine->get_cpu().get_a().set_value(0x99); + machine->execute(); + + ASSERT_EQ(0x32, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ACC_ZeroFlag) { + auto machine = create_machine({ASL_ACC}); + machine->get_cpu().get_a().set_value(0x80); + machine->execute(); + + ASSERT_EQ(0x0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ACC_NegativeFlag) { + auto machine = create_machine({ASL_ACC}); + machine->get_cpu().get_a().set_value(0xc0); + machine->execute(); + + ASSERT_EQ(0x80, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ZPG) { + auto machine = create_machine({ASL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_memory().get_at(0x10)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ZPG_CarryFlag) { + auto machine = create_machine({ASL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x99); + machine->execute(); + + ASSERT_EQ(0x32, machine->get_memory().get_at(0x10)); + RegisterFlagSet flags{}; + flags.carry = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ZPG_ZeroFlag) { + auto machine = create_machine({ASL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x80); + machine->execute(); + + ASSERT_EQ(0x0, machine->get_memory().get_at(0x10)); + RegisterFlagSet flags{}; + flags.carry = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ZPG_NegativeFlag) { + auto machine = create_machine({ASL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0xc0); + machine->execute(); + + ASSERT_EQ(0x80, machine->get_memory().get_at(0x10)); + RegisterFlagSet flags{}; + flags.carry = true; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ZPG_X) { + auto machine = create_machine({ASL_ZPG_X, 0x10}); + machine->get_cpu().get_x().set_value(0x5); + machine->get_memory().set_at(0x15, 0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_memory().get_at(0x15)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ABS) { + auto machine = create_machine({ASL_ABS, 0x10, 0x85}); + machine->get_memory().set_at(0x8510, 0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_memory().get_at(0x8510)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ASL_ABS_X) { + auto machine = create_machine({ASL_ABS_X, 0x10, 0x85}); + machine->get_cpu().get_x().set_value(0x5); + machine->get_memory().set_at(0x8515, 0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_memory().get_at(0x8515)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ACC) { + auto machine = create_machine({LSR_ACC}); + machine->get_cpu().get_a().set_value(0x8); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ACC_CarryFlag) { + auto machine = create_machine({LSR_ACC}); + machine->get_cpu().get_a().set_value(0x9); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ACC_ZeroFlag) { + auto machine = create_machine({LSR_ACC}); + machine->get_cpu().get_a().set_value(1); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ZPG) { + auto machine = create_machine({LSR_ZPG, 0x5}); + machine->get_memory().set_at(0x5, 0x8); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_memory().get_at(0x5)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ZPG_CarryFlag) { + auto machine = create_machine({LSR_ZPG, 0x5}); + machine->get_memory().set_at(0x5, 0x9); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_memory().get_at(0x5)); + RegisterFlagSet flags{}; + flags.carry = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ZPG_ZeroFlag) { + auto machine = create_machine({LSR_ZPG, 0x5}); + machine->get_memory().set_at(0x5, 1); + machine->execute(); + + ASSERT_EQ(0, machine->get_memory().get_at(0x5)); + RegisterFlagSet flags{}; + flags.carry = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ZPG_X) { + auto machine = create_machine({LSR_ZPG_X, 0x5}); + machine->get_cpu().get_x().set_value(0x5); + machine->get_memory().set_at(0x0a, 0x8); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_memory().get_at(0xa)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ABS) { + auto machine = create_machine({LSR_ABS, 0x5, 0x8}); + machine->get_memory().set_at(0x805, 0x8); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_memory().get_at(0x805)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, LSR_ABS_X) { + auto machine = create_machine({LSR_ABS_X, 0x5, 0x8}); + machine->get_cpu().get_x().set_value(0x5); + machine->get_memory().set_at(0x80a, 0x8); + machine->execute(); + + ASSERT_EQ(0x4, machine->get_memory().get_at(0x80a)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ACC) { + auto machine = create_machine({ROL_ACC}); + machine->get_cpu().get_a().set_value(0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ACC_OldCarry) { + auto machine = create_machine({ROL_ACC}); + machine->get_cpu().get_a().set_value(0x09); + machine->get_cpu().get_ps().set_carry(true); + machine->execute(); + + ASSERT_EQ(0x13, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ACC_CarryFlag) { + auto machine = create_machine({ROL_ACC}); + machine->get_cpu().get_a().set_value(0x89); + machine->get_cpu().get_ps().set_carry(true); + machine->execute(); + + ASSERT_EQ(0x13, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ACC_NegativeFlag) { + auto machine = create_machine({ROL_ACC}); + machine->get_cpu().get_a().set_value(0xc9); + machine->get_cpu().get_ps().set_carry(true); + machine->execute(); + + ASSERT_EQ(0x93, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ACC_ZeroFlag) { + auto machine = create_machine({ROL_ACC}); + machine->get_cpu().get_a().set_value(0x80); + machine->execute(); + + ASSERT_EQ(0x0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.carry = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ZPG) { + auto machine = create_machine({ROL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x09); + machine->execute(); + + ASSERT_EQ(0x12, machine->get_memory().get_at(0x10)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ZPG_OldCarry) { + auto machine = create_machine({ROL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x09); + machine->get_cpu().get_ps().set_carry(true); + machine->execute(); + + ASSERT_EQ(0x13, machine->get_memory().get_at(0x10)); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ZPG_CarryFlag) { + auto machine = create_machine({ROL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x89); + machine->get_cpu().get_ps().set_carry(true); + machine->execute(); + + ASSERT_EQ(0x13, machine->get_memory().get_at(0x10)); + RegisterFlagSet flags{}; + flags.carry = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ZPG_NegativeFlag) { + auto machine = create_machine({ROL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0xc9); + machine->get_cpu().get_ps().set_carry(true); + machine->execute(); + + ASSERT_EQ(0x93, machine->get_memory().get_at(0x10)); + RegisterFlagSet flags{}; + flags.carry = true; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(LoadOpcodeHandlerContainer, ROL_ZPG_ZeroFlag) { + auto machine = create_machine({ROL_ZPG, 0x10}); + machine->get_memory().set_at(0x10, 0x80); + machine->execute(); + + ASSERT_EQ(0x0, machine->get_memory().get_at(0x10)); + RegisterFlagSet flags{}; + flags.carry = true; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +}