From 248be24ef847d723e506d7a66d493d3b3f417f1a Mon Sep 17 00:00:00 2001 From: Tony Di Nucci Date: Sun, 21 Apr 2019 21:53:00 +0100 Subject: [PATCH] Stack opcodes --- .../stack-opcode-handler-container.cpp | 30 +++++++ .../handler/stack-opcode-handler-container.h | 30 +++++++ src/opcode/opcode-handler-directory.cpp | 2 + test/stack-opcode-handler-test.cpp | 90 +++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 src/opcode/handler/stack-opcode-handler-container.cpp create mode 100644 src/opcode/handler/stack-opcode-handler-container.h create mode 100644 test/stack-opcode-handler-test.cpp diff --git a/src/opcode/handler/stack-opcode-handler-container.cpp b/src/opcode/handler/stack-opcode-handler-container.cpp new file mode 100644 index 0000000..240bcdd --- /dev/null +++ b/src/opcode/handler/stack-opcode-handler-container.cpp @@ -0,0 +1,30 @@ +#include "stack-opcode-handler-container.h" +#include "../../utils.h" + +namespace emu_6502 { + StackOpcodeHandlerContainer::StackOpcodeHandlerContainer() { + handlers.insert({Op::PHA, [this](Machine& machine) { pha(machine); }}); + handlers.insert({Op::PHP, [this](Machine& machine) { php(machine); }}); + + handlers.insert({Op::PLA, [this](Machine& machine) { pla(machine); }}); + handlers.insert({Op::PLP, [this](Machine& machine) { plp(machine); }}); + } + + void StackOpcodeHandlerContainer::pha(Machine& machine) { + machine.get_stack().push(machine.get_cpu().get_a().get_value()); + } + + void StackOpcodeHandlerContainer::php(Machine& machine) { + machine.get_stack().push(machine.get_cpu().get_ps().get_value().to_ulong()); + } + + void StackOpcodeHandlerContainer::pla(Machine& machine) { + auto value = machine.get_stack().pop(); + machine.get_cpu().get_a().set_value(value); + set_zero_and_neg_flags(machine.get_cpu().get_ps(), value); + } + + void StackOpcodeHandlerContainer::plp(Machine& machine) { + machine.get_cpu().get_ps().set_value(machine.get_stack().pop()); + } +} \ No newline at end of file diff --git a/src/opcode/handler/stack-opcode-handler-container.h b/src/opcode/handler/stack-opcode-handler-container.h new file mode 100644 index 0000000..ba1a1f0 --- /dev/null +++ b/src/opcode/handler/stack-opcode-handler-container.h @@ -0,0 +1,30 @@ +#ifndef INC_6502_EMULATOR_STACK_OPCODE_HANDLER_CONTAINER_H +#define INC_6502_EMULATOR_STACK_OPCODE_HANDLER_CONTAINER_H + +#include "opcode-handler-container.h" + +namespace emu_6502 { + class StackOpcodeHandlerContainer : public OpcodeHandlerContainer { + private: + enum Op { + PHA = 0x48, + PHP = 0x08, + PLA = 0x68, + PLP = 0x28, + }; + + void pha(Machine& machine); + void php(Machine& machine); + + void pla(Machine& machine); + void plp(Machine& machine); + + public: + StackOpcodeHandlerContainer(); + StackOpcodeHandlerContainer(const StackOpcodeHandlerContainer&) = delete; + StackOpcodeHandlerContainer& operator=(const StackOpcodeHandlerContainer&) = delete; + }; +} + + +#endif //INC_6502_EMULATOR_STACK_OPCODE_HANDLER_CONTAINER_H diff --git a/src/opcode/opcode-handler-directory.cpp b/src/opcode/opcode-handler-directory.cpp index a4578c5..9074e30 100644 --- a/src/opcode/opcode-handler-directory.cpp +++ b/src/opcode/opcode-handler-directory.cpp @@ -6,6 +6,7 @@ #include "handler/bitwise-opcode-handler-container.h" #include "handler/status-opcode-handler-container.h" #include "handler/compare-opcode-handler-container.h" +#include "handler/stack-opcode-handler-container.h" #include "../utils.h" namespace emu_6502 { @@ -18,6 +19,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/test/stack-opcode-handler-test.cpp b/test/stack-opcode-handler-test.cpp new file mode 100644 index 0000000..d08ad2a --- /dev/null +++ b/test/stack-opcode-handler-test.cpp @@ -0,0 +1,90 @@ +#include "gtest/gtest.h" +#include "test-utils.h" + +using namespace std; +using namespace emu_6502; + +const uint8_t PHA = 0x48; +const uint8_t PHP = 0x08; +const uint8_t PLA = 0x68; +const uint8_t PLP = 0x28; + +const uint8_t CLC = 0x18; +const uint8_t CLD = 0xD8; +const uint8_t CLI = 0x58; +const uint8_t CLV = 0xB8; + +TEST(StackOpcodeHandlerContainer, PHA) { + auto machine = create_machine({PHA}); + machine->get_cpu().get_a().set_value(0x13); + machine->execute(); + + ASSERT_EQ(0x13, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0x13, machine->get_stack().pop()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(StackOpcodeHandlerContainer, PHP) { + auto machine = create_machine({PHP}); + machine->get_cpu().get_ps().set_value(0xFF); + machine->execute(); + + ASSERT_EQ(0xFF, machine->get_cpu().get_ps().get_value().to_ulong()); + ASSERT_EQ(0xFF, machine->get_stack().pop()); +} + +TEST(StackOpcodeHandlerContainer, PLA) { + auto machine = create_machine({PLA}); + machine->get_stack().push(0x05); + machine->execute(); + + ASSERT_EQ(0x05, machine->get_cpu().get_a().get_value()); + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), RegisterFlagSet{})); +} + +TEST(StackOpcodeHandlerContainer, PLA_NegativeFlag) { + auto machine = create_machine({PLA}); + machine->get_stack().push(0xf5); + 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(StackOpcodeHandlerContainer, PLA_ZeroFlag) { + auto machine = create_machine({PLA}); + machine->get_stack().push(0x0); + machine->execute(); + + ASSERT_EQ(0x0, machine->get_cpu().get_a().get_value()); + RegisterFlagSet flags{}; + flags.zero = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +} + +TEST(StackOpcodeHandlerContainer, PLP) { + auto machine = create_machine({PHP, CLC, CLD, CLI, CLV, PLP}); + + auto& ps = machine->get_cpu().get_ps(); + ps.set_zero(true); + ps.set_negative(true); + ps.set_carry(true); + ps.set_overflow(true); + ps.set_interupt_disable(true); + ps.set_decimal(true); + ps.set_break(true); + + machine->execute(); + + RegisterFlagSet flags{}; + flags.zero = true; + flags.negative = true; + flags.carry = true; + flags.overflow = true; + flags.interupt_disable = true; + flags.decimal = true; + flags.brk = true; + ASSERT_TRUE(are_flags_set(machine->get_cpu().get_ps(), flags)); +}