diff --git a/src/machine/register.cpp b/src/machine/register.cpp index 5d3ed9c..a380978 100644 --- a/src/machine/register.cpp +++ b/src/machine/register.cpp @@ -13,12 +13,12 @@ namespace emu_6502 { } template - const T Register::get_value() { + T Register::get_value() const { return value; } template - const string& Register::get_name() { + const string& Register::get_name() const { return name; } } diff --git a/src/machine/register.h b/src/machine/register.h index 4861b5c..9c0123c 100644 --- a/src/machine/register.h +++ b/src/machine/register.h @@ -20,9 +20,9 @@ namespace emu_6502 { Register(const Register&) = delete; Register& operator=(const Register&) = delete; - const string& get_name(); + const string& get_name() const; - const T get_value(); + T get_value() const; void set_value(T value); }; } diff --git a/src/opcode/handler/load-opcode-handler-container.h b/src/opcode/handler/load-opcode-handler-container.h index f78f92f..f0961ea 100644 --- a/src/opcode/handler/load-opcode-handler-container.h +++ b/src/opcode/handler/load-opcode-handler-container.h @@ -51,7 +51,8 @@ namespace emu_6502 { public: LoadOpcodeHandlerContainer(); - LoadOpcodeHandlerContainer(const LoadOpcodeHandlerContainer& other) = delete; + LoadOpcodeHandlerContainer(const LoadOpcodeHandlerContainer&) = delete; + LoadOpcodeHandlerContainer& operator=(const LoadOpcodeHandlerContainer&) = delete; }; } diff --git a/src/opcode/handler/opcode-handler-container.h b/src/opcode/handler/opcode-handler-container.h index 3830cad..18907b1 100644 --- a/src/opcode/handler/opcode-handler-container.h +++ b/src/opcode/handler/opcode-handler-container.h @@ -15,6 +15,7 @@ namespace emu_6502 { public: OpcodeHandlerContainer(); OpcodeHandlerContainer(const OpcodeHandlerContainer& other) = delete; + OpcodeHandlerContainer operator=(const OpcodeHandlerContainer& other) = delete; virtual ~OpcodeHandlerContainer() {}; diff --git a/src/opcode/handler/store-opcode-handler-container.h b/src/opcode/handler/store-opcode-handler-container.h index 0ef1567..bd09fd5 100644 --- a/src/opcode/handler/store-opcode-handler-container.h +++ b/src/opcode/handler/store-opcode-handler-container.h @@ -45,6 +45,7 @@ namespace emu_6502 { public: StoreOpcodeHandlerContainer(); StoreOpcodeHandlerContainer(const StoreOpcodeHandlerContainer& other) = delete; + StoreOpcodeHandlerContainer operator=(const StoreOpcodeHandlerContainer& other) = delete; }; } diff --git a/src/opcode/handler/transfer-opcode-handler-container.cpp b/src/opcode/handler/transfer-opcode-handler-container.cpp new file mode 100644 index 0000000..7b0b80b --- /dev/null +++ b/src/opcode/handler/transfer-opcode-handler-container.cpp @@ -0,0 +1,42 @@ +#include "transfer-opcode-handler-container.h" + +namespace emu_6502 { + + TransferOpcodeHandlerContainer::TransferOpcodeHandlerContainer() : OpcodeHandlerContainer() { + handlers.insert({Op::TAX, [this](Machine& machine) { + transfer(machine, machine.get_cpu().get_a(), machine.get_cpu().get_x()); + }}); + + handlers.insert({Op::TAY, [this](Machine& machine) { + transfer(machine, machine.get_cpu().get_a(), machine.get_cpu().get_y()); + }}); + + handlers.insert({Op::TSX, [this](Machine& machine) { + transfer(machine, machine.get_cpu().get_sp(), machine.get_cpu().get_x()); + }}); + + handlers.insert({Op::TXA, [this](Machine& machine) { + transfer(machine, machine.get_cpu().get_x(), machine.get_cpu().get_a()); + }}); + + handlers.insert({Op::TXS, [this](Machine& machine) { + transfer(machine, machine.get_cpu().get_x(), machine.get_cpu().get_sp(), true); + }}); + + handlers.insert({Op::TYA, [this](Machine& machine) { + transfer(machine, machine.get_cpu().get_y(), machine.get_cpu().get_a()); + }}); + } + + void TransferOpcodeHandlerContainer::transfer(Machine& machine, const Register& source, + Register& dest, bool ignoreFlags) { + auto value = source.get_value(); + dest.set_value(value); + + if (!ignoreFlags) { + auto& ps = machine.get_cpu().get_ps(); + ps.set_zero(value == 0); + ps.set_negative((value & 0x80) == 0x80); + } + } +} \ No newline at end of file diff --git a/src/opcode/handler/transfer-opcode-handler-container.h b/src/opcode/handler/transfer-opcode-handler-container.h new file mode 100644 index 0000000..f3739be --- /dev/null +++ b/src/opcode/handler/transfer-opcode-handler-container.h @@ -0,0 +1,30 @@ +#ifndef INC_6502_EMULATOR_TRANSFER_OPCODE_HANDLER_CONTAINER_H +#define INC_6502_EMULATOR_TRANSFER_OPCODE_HANDLER_CONTAINER_H + +#include "opcode-handler-container.h" +#include "../../machine/register.h" + +namespace emu_6502 { + class TransferOpcodeHandlerContainer : public OpcodeHandlerContainer { + private: + enum Op { + TAX = 0xAA, + TAY = 0xA8, + TSX = 0xBA, + TXA = 0x8A, + TXS = 0x9A, + TYA = 0x98 + }; + + void transfer(Machine& machine, const Register& source, Register& dest, + bool ignoreFlags = false); + + public: + TransferOpcodeHandlerContainer(); + TransferOpcodeHandlerContainer(const TransferOpcodeHandlerContainer&) = delete; + TransferOpcodeHandlerContainer operator=(const TransferOpcodeHandlerContainer&) = delete; + }; +} + + +#endif //INC_6502_EMULATOR_TRANSFER_OPCODE_HANDLER_CONTAINER_H diff --git a/src/opcode/opcode-handler-directory.cpp b/src/opcode/opcode-handler-directory.cpp index 3edeb67..f7c200b 100644 --- a/src/opcode/opcode-handler-directory.cpp +++ b/src/opcode/opcode-handler-directory.cpp @@ -1,6 +1,7 @@ #include "opcode-handler-directory.h" #include "handler/load-opcode-handler-container.h" #include "handler/store-opcode-handler-container.h" +#include "handler/transfer-opcode-handler-container.h" #include "../utils.h" namespace emu_6502 { @@ -8,6 +9,7 @@ namespace emu_6502 { OpcodeHandlerDirectory::OpcodeHandlerDirectory() : handler_containers{}, handlers{} { handler_containers.push_back(make_unique()); handler_containers.push_back(make_unique()); + handler_containers.push_back(make_unique()); init_handlers(); } diff --git a/test/load-opcode-handler-test.cpp b/test/load-opcode-handler-test.cpp index 7a3452d..c09304c 100644 --- a/test/load-opcode-handler-test.cpp +++ b/test/load-opcode-handler-test.cpp @@ -1,9 +1,6 @@ #include "gtest/gtest.h" #include "test-utils.h" -#include -#include - using namespace std; using namespace emu_6502; diff --git a/test/store-opcode-handler-test.cpp b/test/store-opcode-handler-test.cpp index 27b376a..24bfaaf 100644 --- a/test/store-opcode-handler-test.cpp +++ b/test/store-opcode-handler-test.cpp @@ -1,9 +1,6 @@ #include "gtest/gtest.h" #include "test-utils.h" -#include -#include - using namespace std; using namespace emu_6502; diff --git a/test/transfer-opcode-handler-test.cpp b/test/transfer-opcode-handler-test.cpp new file mode 100644 index 0000000..f13d51b --- /dev/null +++ b/test/transfer-opcode-handler-test.cpp @@ -0,0 +1,207 @@ +#include "gtest/gtest.h" +#include "test-utils.h" + +using namespace std; +using namespace emu_6502; + +const uint8_t TAX = 0xAA; +const uint8_t TAY = 0xA8; +const uint8_t TSX = 0xBA; +const uint8_t TXA = 0x8A; +const uint8_t TXS = 0x9A; +const uint8_t TYA = 0x98; + +TEST(TransferOpcodeHandlerContainer, TAX) { + auto machine = create_machine({TAX}); + machine->get_cpu().get_a().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_x().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TAX_ZeroFlag) { + auto machine = create_machine({TAX}); + machine->get_cpu().get_a().set_value(0); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_x().get_value()); + + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TAX_NegativeFlag) { + auto machine = create_machine({TAX}); + machine->get_cpu().get_a().set_value(0xf0); + machine->execute(); + + ASSERT_EQ(0xf0, machine->get_cpu().get_x().get_value()); + + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TAY) { + auto machine = create_machine({TAY}); + machine->get_cpu().get_a().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_y().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TAY_ZeroFlag) { + auto machine = create_machine({TAY}); + machine->get_cpu().get_a().set_value(0); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_y().get_value()); + + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TAY_NegativeFlag) { + auto machine = create_machine({TAY}); + machine->get_cpu().get_a().set_value(0xf0); + machine->execute(); + + ASSERT_EQ(0xf0, machine->get_cpu().get_y().get_value()); + + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TSX) { + auto machine = create_machine({TSX}); + machine->get_cpu().get_sp().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_x().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TSX_ZeroFlag) { + auto machine = create_machine({TSX}); + machine->get_cpu().get_sp().set_value(0); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_x().get_value()); + + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TSX_NegativeFlag) { + auto machine = create_machine({TSX}); + machine->get_cpu().get_sp().set_value(0xf0); + machine->execute(); + + ASSERT_EQ(0xf0, machine->get_cpu().get_x().get_value()); + + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TXA) { + auto machine = create_machine({TXA}); + machine->get_cpu().get_x().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TXA_ZeroFlag) { + auto machine = create_machine({TXA}); + machine->get_cpu().get_x().set_value(0); + 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(TransferOpcodeHandlerContainer, TXA_NegativeFlag) { + auto machine = create_machine({TXA}); + machine->get_cpu().get_x().set_value(0xf0); + machine->execute(); + + ASSERT_EQ(0xf0, machine->get_cpu().get_a().get_value()); + + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(TransferOpcodeHandlerContainer, TXS) { + auto machine = create_machine({TXS}); + machine->get_cpu().get_x().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_sp().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TXS_ZeroFlag) { + auto machine = create_machine({TXS}); + machine->get_cpu().get_x().set_value(0); + machine->execute(); + + ASSERT_EQ(0, machine->get_cpu().get_sp().get_value()); + + // flags not affected with this op + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TXS_NegativeFlag) { + auto machine = create_machine({TXS}); + machine->get_cpu().get_x().set_value(0xf0); + machine->execute(); + + ASSERT_EQ(0xf0, machine->get_cpu().get_sp().get_value()); + // flags not affected with this op + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TYA) { + auto machine = create_machine({TYA}); + machine->get_cpu().get_y().set_value(0x11); + machine->execute(); + + ASSERT_EQ(0x11, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(TransferOpcodeHandlerContainer, TYA_ZeroFlag) { + auto machine = create_machine({TYA}); + machine->get_cpu().get_y().set_value(0); + 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(TransferOpcodeHandlerContainer, TYA_NegativeFlag) { + auto machine = create_machine({TYA}); + machine->get_cpu().get_y().set_value(0xf0); + machine->execute(); + + ASSERT_EQ(0xf0, machine->get_cpu().get_a().get_value()); + + RegisterFlagSet flags{}; + flags.negative = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} \ No newline at end of file