diff --git a/src/opcode/handler/jump-opcode-handler-container.cpp b/src/opcode/handler/jump-opcode-handler-container.cpp new file mode 100644 index 0000000..7598044 --- /dev/null +++ b/src/opcode/handler/jump-opcode-handler-container.cpp @@ -0,0 +1,44 @@ +#include "jump-opcode-handler-container.h" +#include "../../utils.h" + +namespace emu_6502 { + JumpOpcodeHandlerContainer::JumpOpcodeHandlerContainer() { + handlers.insert({Op::JMP_ABS, [this](Machine& machine) { jmp_abs(machine); }}); + handlers.insert({Op::JMP_IND, [this](Machine& machine) { jmp_ind(machine); }}); + + handlers.insert({Op::JSR, [this](Machine& machine) { jsr(machine); }}); + + handlers.insert({Op::RTI, [this](Machine& machine) { rti(machine); }}); + handlers.insert({Op::RTS, [this](Machine& machine) { rts(machine); }}); + } + + void JumpOpcodeHandlerContainer::jmp_abs(Machine& machine) { + auto addr = get_abs_address(machine); + machine.get_cpu().get_pc().set_value(addr); + } + + void JumpOpcodeHandlerContainer::jmp_ind(Machine& machine) { + auto addr = get_ind_address(machine); + machine.get_cpu().get_pc().set_value(addr); + } + + void JumpOpcodeHandlerContainer::jsr(Machine& machine) { + uint16_t addr = get_abs_address(machine); + + uint16_t pc_value = machine.get_cpu().get_pc().get_value(); + machine.get_stack().push(pc_value >> 8); + machine.get_stack().push(pc_value); + + machine.get_cpu().get_pc().set_value(addr); + } + + void JumpOpcodeHandlerContainer::rti(Machine& machine) {} + + void JumpOpcodeHandlerContainer::rts(Machine& machine) { + auto low_byte = machine.get_stack().pop(); + auto high_byte = machine.get_stack().pop(); + + uint16_t return_address = (high_byte << 8) + low_byte + 1; + machine.get_cpu().get_pc().set_value(return_address); + } +} \ No newline at end of file diff --git a/src/opcode/handler/jump-opcode-handler-container.h b/src/opcode/handler/jump-opcode-handler-container.h new file mode 100644 index 0000000..01395ec --- /dev/null +++ b/src/opcode/handler/jump-opcode-handler-container.h @@ -0,0 +1,35 @@ +#ifndef INC_6502_EMULATOR_JUMP_OPCODE_HANDLER_CONTAINER_H +#define INC_6502_EMULATOR_JUMP_OPCODE_HANDLER_CONTAINER_H + +#include "opcode-handler-container.h" + +namespace emu_6502 { + class JumpOpcodeHandlerContainer : public OpcodeHandlerContainer { + private: + enum Op { + JMP_ABS = 0x4C, + JMP_IND = 0x6C, + + JSR = 0x20, + + RTI = 0x40, + RTS = 0x60 + }; + + void jmp_abs(Machine& machine); + void jmp_ind(Machine& machine); + + void jsr(Machine& machine); + + void rti(Machine& machine); + void rts(Machine& machine); + + public: + JumpOpcodeHandlerContainer(); + JumpOpcodeHandlerContainer(const JumpOpcodeHandlerContainer&) = delete; + JumpOpcodeHandlerContainer& operator=(const JumpOpcodeHandlerContainer&) = delete; + }; +} + + +#endif //INC_6502_EMULATOR_JUMP_OPCODE_HANDLER_CONTAINER_H diff --git a/src/opcode/opcode-handler-directory.cpp b/src/opcode/opcode-handler-directory.cpp index accd35c..df14a6e 100644 --- a/src/opcode/opcode-handler-directory.cpp +++ b/src/opcode/opcode-handler-directory.cpp @@ -8,6 +8,7 @@ #include "handler/compare-opcode-handler-container.h" #include "handler/stack-opcode-handler-container.h" #include "handler/branch-opcode-handler-container.h" +#include "handler/jump-opcode-handler-container.h" #include "../utils.h" namespace emu_6502 { @@ -22,6 +23,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 4b2964b..3ab86e6 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -48,6 +48,18 @@ namespace emu_6502 { return address; } + uint16_t get_ind_address(Machine& machine) { + auto low_byte = machine.read_program_byte(); + auto high_byte = machine.read_program_byte(); + uint16_t paddress = (high_byte << 8) + low_byte; + + auto low = machine.get_memory().get_at(paddress); + auto high = machine.get_memory().get_at(paddress + 1); + uint16_t address = (high << 8) + low; + + return address; + } + uint16_t get_ind_x_address(Machine& machine) { uint8_t paddress = machine.get_cpu().get_x().get_value() + machine.read_program_byte(); auto low = machine.get_memory().get_at(paddress); diff --git a/src/utils.h b/src/utils.h index e6e977e..969ec0e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,11 +15,12 @@ namespace emu_6502 { uint8_t get_zpg_address(Machine& machine); uint8_t get_zpg_x_address(Machine& machine); uint8_t get_zpg_y_address(Machine& machine); + uint16_t get_abs_address(Machine& machine); uint16_t get_abs_x_address(Machine& machine); uint16_t get_abs_y_address(Machine& machine); - uint16_t get_abs_x_address(Machine& machine); - uint16_t get_abs_y_address(Machine& machine); + + uint16_t get_ind_address(Machine& machine); uint16_t get_ind_x_address(Machine& machine); uint16_t get_ind_y_address(Machine& machine); } diff --git a/test/jump-opcode-handler-test.cpp b/test/jump-opcode-handler-test.cpp new file mode 100644 index 0000000..f91ffa5 --- /dev/null +++ b/test/jump-opcode-handler-test.cpp @@ -0,0 +1,66 @@ +#include "gtest/gtest.h" +#include "test-utils.h" + +using namespace std; +using namespace emu_6502; + +const uint8_t JMP_ABS = 0x4C; +const uint8_t JMP_IND = 0x6C; + +const uint8_t JSR = 0x20; + +const uint8_t RTI = 0x40; +const uint8_t RTS = 0x60; + +const uint8_t LDA_IMM = 0xA9; + +TEST(LoadOpcodeHandlerContainer, JMP_ABS) { + auto machine = create_machine({JMP_ABS, 0x34, 0x12}); + + try { + machine->execute(); + } + catch (exception) { + } + + ASSERT_EQ(0x1234, machine->get_cpu().get_pc().get_value()); +} + +TEST(LoadOpcodeHandlerContainer, JMP_IND) { + auto machine = create_machine({JMP_IND, 0x34, 0x12}); + machine->get_memory().set_at(0x1234, 0xF6); + machine->get_memory().set_at(0x1235, 0xAB); + try { + machine->execute(); + } + catch (exception) { + } + + ASSERT_EQ(0xABF6, machine->get_cpu().get_pc().get_value()); +} + +TEST(LoadOpcodeHandlerContainer, JSR) { + auto machine = create_machine({JSR, 0x34, 0x12}); + + try { + machine->execute(); + } + catch (exception) { + } + + ASSERT_EQ(0x1234, machine->get_cpu().get_pc().get_value()); + ASSERT_EQ(3, machine->get_stack().pop()); +} + +TEST(LoadOpcodeHandlerContainer, RTS) { + auto machine = create_machine({JSR, 0x07, 0x06, 0x0, 0x0, 0x0, 0x0, LDA_IMM, 0x99, RTS}); + + try { + machine->execute(); + } + catch (exception) { + } + + ASSERT_EQ(0x99, machine->get_cpu().get_a().get_value()); + ASSERT_EQ(0x605, machine->get_cpu().get_pc().get_value()); +} \ No newline at end of file