diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a98d69..5dd10f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,9 +25,9 @@ add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src file(GLOB_RECURSE test_src "test/**.h" "test/**.cpp" "src/**.h" "src/**.cpp") list(FILTER test_src EXCLUDE REGEX ".*/6502-emulator/src/main.cpp$") -add_executable(6502_emulator_test ${test_src} test/stack-opcode-handler-test.cpp test/ldx-opcode-handler-test.cpp) +add_executable(6502_emulator_test ${test_src}) target_link_libraries(6502_emulator_test gtest_main) add_test(NAME run_tests COMMAND 6502_emulator_test) file(GLOB_RECURSE emulator_src "src/**.h" "src/**.cpp") -add_executable(6502_emulator ${emulator_src} src/opcode/handler/stack-opcode-handler.cpp src/opcode/handler/stack-opcode-handler.h src/stack.cpp src/stack.h src/opcode/handler/lda-opcode-handler.cpp src/opcode/handler/lda-opcode-handler.h) +add_executable(6502_emulator ${emulator_src}) diff --git a/src/main.cpp b/src/main.cpp index 4c9421d..fa8b4e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,42 +1,10 @@ #include "register/register-manager.h" - #include -#include using namespace std; -void stack_test(string astring) { - astring.push_back('x'); -} - -void heap_test(shared_ptr astring){ - astring->push_back('y'); -} - int main() { - auto reg = unique_ptr>(new Register("PC")); - - cout << "Register: " << reg->get_name() << " " << to_string(56) << endl; - - string astr = "hello"; - shared_ptr bstr = make_shared("there"); - - cout << astr << " - " << bstr->c_str() << endl; - - stack_test(astr); - heap_test(bstr); - - cout << astr << " - " << bstr->c_str() << endl; - - auto reg_man = new RegisterManager(); - auto accum = reg_man->get_accumulator(); - - cout << "****** " << accum->get_name() << " ******" << endl; - cout << "****** " << reg_man->get_x_index()->get_name() << " ******" << endl; - cout << "****** " << reg_man->get_y_index()->get_name() << " ******" << endl; - cout << "****** " << reg_man->get_stack_pointer()->get_name() << " ******" << endl; - cout << "****** " << reg_man->get_status_register()->get_name() << " ******" << endl; - cout << "****** " << reg_man->get_program_counter()->get_name() << " ******" << endl; + cout << "Only unit tests for now" << endl; return 0; } \ No newline at end of file diff --git a/src/opcode/handler/flag-opcode-handler.cpp b/src/opcode/handler/flag-opcode-handler.cpp index f1c7c10..78d0a2c 100644 --- a/src/opcode/handler/flag-opcode-handler.cpp +++ b/src/opcode/handler/flag-opcode-handler.cpp @@ -1,8 +1,5 @@ #include "flag-opcode-handler.h" -#include -#include - const uint8_t FlagOpcodeHandler::CLC; const uint8_t FlagOpcodeHandler::SEC; const uint8_t FlagOpcodeHandler::CLI; @@ -39,9 +36,7 @@ void FlagOpcodeHandler::execute() { statusReg->set_decimal(true); break; default: - stringstream stream; - stream << "Unexpected opcode 0x" << hex << opcode; - throw runtime_error(stream.str()); + throw_unexpected_opcode(opcode); } move_program_counter(1); diff --git a/src/opcode/handler/lda-opcode-handler.cpp b/src/opcode/handler/lda-opcode-handler.cpp index f950b64..b3aed1d 100644 --- a/src/opcode/handler/lda-opcode-handler.cpp +++ b/src/opcode/handler/lda-opcode-handler.cpp @@ -1,5 +1,94 @@ -// -// Created by tony on 27/03/19. -// - #include "lda-opcode-handler.h" + +const uint8_t LdaOpcodeHandler::IMMEDIATE; +const uint8_t LdaOpcodeHandler::ZERO_PAGE; +const uint8_t LdaOpcodeHandler::ZERO_PAGE_X; +const uint8_t LdaOpcodeHandler::ABSOLUTE; +const uint8_t LdaOpcodeHandler::ABSOLUTE_X; +const uint8_t LdaOpcodeHandler::ABSOLUTE_Y; +const uint8_t LdaOpcodeHandler::INDIRECT_X; +const uint8_t LdaOpcodeHandler::INDIRECT_Y; + +void LdaOpcodeHandler::execute() { + auto instructionIndex = reg_man->get_program_counter()->get_value(); + auto opcode = program->get_byte_at(instructionIndex); + auto byte2 = program->get_byte_at(instructionIndex + 1); + auto accumulator = reg_man->get_accumulator(); + + switch (opcode) { + case IMMEDIATE: + accumulator->set_value(byte2); + move_program_counter(2); + break; + + case ZERO_PAGE: + accumulator->set_value(memory->get_byte_at(byte2)); + move_program_counter(2); + break; + + case ZERO_PAGE_X: { + // expect wrap around + uint8_t address = byte2 + reg_man->get_x_index()->get_value(); + + accumulator->set_value(memory->get_byte_at(address)); + move_program_counter(2); + break; + } + + case ABSOLUTE: { + auto low = byte2; + auto high = program->get_byte_at(instructionIndex + 2); + uint16_t address = (high << 8) + low; + + accumulator->set_value(memory->get_byte_at(address)); + move_program_counter(3); + break; + } + + case ABSOLUTE_X: { + auto low = byte2; + auto high = program->get_byte_at(instructionIndex + 2); + uint16_t address = (high << 8) + low + reg_man->get_x_index()->get_value(); + + accumulator->set_value(memory->get_byte_at(address)); + move_program_counter(3); + break; + } + + case ABSOLUTE_Y: { + auto low = byte2; + auto high = program->get_byte_at(instructionIndex + 2); + uint16_t address = (high << 8) + low + reg_man->get_y_index()->get_value(); + + accumulator->set_value(memory->get_byte_at(address)); + move_program_counter(3); + break; + } + + case INDIRECT_X: { + auto paddress = reg_man->get_x_index()->get_value() + byte2; + auto low = memory->get_byte_at(paddress); + auto high = memory->get_byte_at(paddress + 1); + uint16_t address = (high << 8) + low; + + accumulator->set_value(memory->get_byte_at(address)); + move_program_counter(2); + break; + } + + case INDIRECT_Y : { + auto initial = byte2; + auto low = memory->get_byte_at(initial); + auto high = memory->get_byte_at(initial + 1); + auto y = reg_man->get_y_index()->get_value(); + uint16_t address = (high << 8) + low + y; + + accumulator->set_value(memory->get_byte_at(address)); + move_program_counter(2); + break; + } + + default: + throw_unexpected_opcode(opcode); + } +} \ No newline at end of file diff --git a/src/opcode/handler/lda-opcode-handler.h b/src/opcode/handler/lda-opcode-handler.h index 020f51d..dae805a 100644 --- a/src/opcode/handler/lda-opcode-handler.h +++ b/src/opcode/handler/lda-opcode-handler.h @@ -1,13 +1,33 @@ -// -// Created by tony on 27/03/19. -// - #ifndef INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H #define INC_6502_EMULATOR_LDA_OPCODE_HANDLER_H +#include "../opcode-handler.h" -class LdaOpcodeHandler { +class LdaOpcodeHandler : public OpcodeHandler { +public: + static const uint8_t IMMEDIATE = 0xA9; + static const uint8_t ZERO_PAGE = 0xA5; + static const uint8_t ZERO_PAGE_X = 0xB5; + static const uint8_t ABSOLUTE = 0xAD; + static const uint8_t ABSOLUTE_X = 0xBD; + static const uint8_t ABSOLUTE_Y = 0xB9; + static const uint8_t INDIRECT_X = 0xA1; + static const uint8_t INDIRECT_Y = 0xB1; + explicit LdaOpcodeHandler(shared_ptr program, shared_ptr reg_man, + shared_ptr memory) : + OpcodeHandler(program, reg_man, memory) { + handled_opcodes->push_back(IMMEDIATE); + handled_opcodes->push_back(ZERO_PAGE); + handled_opcodes->push_back(ZERO_PAGE_X); + handled_opcodes->push_back(ABSOLUTE); + handled_opcodes->push_back(ABSOLUTE_X); + handled_opcodes->push_back(ABSOLUTE_Y); + handled_opcodes->push_back(INDIRECT_X); + handled_opcodes->push_back(INDIRECT_Y); + } + + virtual void execute() override; }; diff --git a/src/opcode/handler/ldx-opcode-handler.cpp b/src/opcode/handler/ldx-opcode-handler.cpp index c973bb4..1342904 100644 --- a/src/opcode/handler/ldx-opcode-handler.cpp +++ b/src/opcode/handler/ldx-opcode-handler.cpp @@ -1,5 +1,4 @@ #include "ldx-opcode-handler.h" -#include const uint8_t LdxOpcodeHandler::IMMEDIATE; const uint8_t LdxOpcodeHandler::ZERO_PAGE; @@ -25,7 +24,8 @@ void LdxOpcodeHandler::execute() { break; case ZERO_PAGE_Y: { - uint16_t address = byte2 + reg_man->get_y_index()->get_value(); + // expect wrap around + uint8_t address = byte2 + reg_man->get_y_index()->get_value(); x_reg->set_value(memory->get_byte_at(address)); move_program_counter(2); @@ -53,8 +53,6 @@ void LdxOpcodeHandler::execute() { } default: - stringstream stream; - stream << "Unexpected opcode 0x" << hex << opcode; - throw runtime_error(stream.str()); + throw_unexpected_opcode(opcode); } } \ No newline at end of file diff --git a/src/opcode/handler/nop-opcode-handler.cpp b/src/opcode/handler/nop-opcode-handler.cpp new file mode 100644 index 0000000..42596b0 --- /dev/null +++ b/src/opcode/handler/nop-opcode-handler.cpp @@ -0,0 +1,17 @@ +#include "nop-opcode-handler.h" + +const uint8_t NopOpcodeHandler::IMPLIED; + +void NopOpcodeHandler::execute() { + auto instructionIndex = reg_man->get_program_counter()->get_value(); + auto opcode = program->get_byte_at(instructionIndex); + + switch (opcode) { + case IMPLIED: + move_program_counter(1); + break; + + default: + throw_unexpected_opcode(opcode); + } +} \ No newline at end of file diff --git a/src/opcode/handler/nop-opcode-handler.h b/src/opcode/handler/nop-opcode-handler.h new file mode 100644 index 0000000..f007e10 --- /dev/null +++ b/src/opcode/handler/nop-opcode-handler.h @@ -0,0 +1,20 @@ +#ifndef INC_6502_EMULATOR_NOP_OPCODE_HANDLER_H +#define INC_6502_EMULATOR_NOP_OPCODE_HANDLER_H + +#include "../opcode-handler.h" + +class NopOpcodeHandler : public OpcodeHandler { +public: + static const uint8_t IMPLIED = 0xEA; + + explicit NopOpcodeHandler(shared_ptr program, shared_ptr reg_man, + shared_ptr memory) : + OpcodeHandler(program, reg_man, memory) { + handled_opcodes->push_back(IMPLIED); + } + + virtual void execute() override; +}; + + +#endif //INC_6502_EMULATOR_NOP_OPCODE_HANDLER_H diff --git a/src/opcode/handler/register-opcode-handler.cpp b/src/opcode/handler/register-opcode-handler.cpp index 0b8f61b..52ad5fd 100644 --- a/src/opcode/handler/register-opcode-handler.cpp +++ b/src/opcode/handler/register-opcode-handler.cpp @@ -1,8 +1,5 @@ #include "register-opcode-handler.h" -#include -#include - const uint8_t RegisterOpcodeHandler::TAX; const uint8_t RegisterOpcodeHandler::TXA; const uint8_t RegisterOpcodeHandler::DEX; @@ -23,31 +20,37 @@ void RegisterOpcodeHandler::execute() { case TAX: x_index->set_value(accumulator->get_value()); break; + case TXA: accumulator->set_value(x_index->get_value()); break; + case DEX: x_index->set_value(x_index->get_value() - 1); break; + case INX: x_index->set_value(x_index->get_value() + 1); break; + case TAY: y_index->set_value(accumulator->get_value()); break; + case TYA: accumulator->set_value(y_index->get_value()); break; + case DEY: y_index->set_value(y_index->get_value() - 1); break; + case INY: y_index->set_value(y_index->get_value() + 1); break; + default: - stringstream stream; - stream << "Unexpected opcode 0x" << hex << opcode; - throw runtime_error(stream.str()); + throw_unexpected_opcode(opcode); } move_program_counter(1); diff --git a/src/opcode/handler/stack-opcode-handler.cpp b/src/opcode/handler/stack-opcode-handler.cpp index e90e50f..89fd9e8 100644 --- a/src/opcode/handler/stack-opcode-handler.cpp +++ b/src/opcode/handler/stack-opcode-handler.cpp @@ -1,6 +1,4 @@ #include "stack-opcode-handler.h" -#include -#include const uint8_t StackOpcodeHandler::PHA; const uint8_t StackOpcodeHandler::PLA; @@ -34,9 +32,7 @@ void StackOpcodeHandler::execute() { } default: - stringstream stream; - stream << "Unexpected opcode 0x" << hex << opcode; - throw runtime_error(stream.str()); + throw_unexpected_opcode(opcode); } move_program_counter(1); diff --git a/src/opcode/handler/stx-opcode-handler.cpp b/src/opcode/handler/stx-opcode-handler.cpp new file mode 100644 index 0000000..90498bd --- /dev/null +++ b/src/opcode/handler/stx-opcode-handler.cpp @@ -0,0 +1,39 @@ +#include "stx-opcode-handler.h" + +const uint8_t StxOpcodeHandler::ZERO_PAGE; +const uint8_t StxOpcodeHandler::ZERO_PAGE_Y; +const uint8_t StxOpcodeHandler::ABSOLUTE; + +void StxOpcodeHandler::execute() { + auto instructionIndex = reg_man->get_program_counter()->get_value(); + auto opcode = program->get_byte_at(instructionIndex); + auto byte2 = program->get_byte_at(instructionIndex + 1); + auto x_reg = reg_man->get_x_index(); + + switch (opcode) { + case ZERO_PAGE: + memory->set_byte_at(byte2, x_reg->get_value()); + move_program_counter(2); + break; + + case ZERO_PAGE_Y: { + // expect wrap around + uint8_t address = reg_man->get_y_index()->get_value() + byte2; + memory->set_byte_at(address, x_reg->get_value()); + move_program_counter(2); + break; + } + + case ABSOLUTE: { + auto low = byte2; + auto high = program->get_byte_at(instructionIndex + 2); + uint16_t address = (high << 8) + low; + memory->set_byte_at(address, x_reg->get_value()); + move_program_counter(3); + break; + } + + default: + throw_unexpected_opcode(opcode); + } +} \ No newline at end of file diff --git a/src/opcode/handler/stx-opcode-handler.h b/src/opcode/handler/stx-opcode-handler.h new file mode 100644 index 0000000..63ab54e --- /dev/null +++ b/src/opcode/handler/stx-opcode-handler.h @@ -0,0 +1,24 @@ +#ifndef INC_6502_EMULATOR_STX_OPCODE_HANDLER_H +#define INC_6502_EMULATOR_STX_OPCODE_HANDLER_H + +#include "../opcode-handler.h" + +class StxOpcodeHandler : public OpcodeHandler { +public: + static const uint8_t ZERO_PAGE = 0x86; + static const uint8_t ZERO_PAGE_Y = 0x96; + static const uint8_t ABSOLUTE = 0x8E; + + explicit StxOpcodeHandler(shared_ptr program, shared_ptr reg_man, + shared_ptr memory) : + OpcodeHandler(program, reg_man, memory) { + handled_opcodes->push_back(ZERO_PAGE); + handled_opcodes->push_back(ZERO_PAGE_Y); + handled_opcodes->push_back(ABSOLUTE); + } + + virtual void execute() override; +}; + + +#endif //INC_6502_EMULATOR_STX_OPCODE_HANDLER_H diff --git a/src/opcode/handler/sty-opcode-handler.cpp b/src/opcode/handler/sty-opcode-handler.cpp new file mode 100644 index 0000000..a4aea81 --- /dev/null +++ b/src/opcode/handler/sty-opcode-handler.cpp @@ -0,0 +1,39 @@ +#include "sty-opcode-handler.h" + +const uint8_t StyOpcodeHandler::ZERO_PAGE; +const uint8_t StyOpcodeHandler::ZERO_PAGE_X; +const uint8_t StyOpcodeHandler::ABSOLUTE; + +void StyOpcodeHandler::execute() { + auto instructionIndex = reg_man->get_program_counter()->get_value(); + auto opcode = program->get_byte_at(instructionIndex); + auto byte2 = program->get_byte_at(instructionIndex + 1); + auto y_reg = reg_man->get_y_index(); + + switch (opcode) { + case ZERO_PAGE: + memory->set_byte_at(byte2, y_reg->get_value()); + move_program_counter(2); + break; + + case ZERO_PAGE_X: { + // expect wrap around + uint8_t address = reg_man->get_x_index()->get_value() + byte2; + memory->set_byte_at(address, y_reg->get_value()); + move_program_counter(2); + break; + } + + case ABSOLUTE: { + auto low = byte2; + auto high = program->get_byte_at(instructionIndex + 2); + uint16_t address = (high << 8) + low; + memory->set_byte_at(address, y_reg->get_value()); + move_program_counter(3); + break; + } + + default: + throw_unexpected_opcode(opcode); + } +} diff --git a/src/opcode/handler/sty-opcode-handler.h b/src/opcode/handler/sty-opcode-handler.h new file mode 100644 index 0000000..4edccc8 --- /dev/null +++ b/src/opcode/handler/sty-opcode-handler.h @@ -0,0 +1,24 @@ +#ifndef INC_6502_EMULATOR_STY_OPCODE_HANDLER_H +#define INC_6502_EMULATOR_STY_OPCODE_HANDLER_H + +#include "../opcode-handler.h" + +class StyOpcodeHandler : public OpcodeHandler { +public: + static const uint8_t ZERO_PAGE = 0x84; + static const uint8_t ZERO_PAGE_X = 0x94; + static const uint8_t ABSOLUTE = 0x8C; + + explicit StyOpcodeHandler(shared_ptr program, shared_ptr reg_man, + shared_ptr memory) : + OpcodeHandler(program, reg_man, memory) { + handled_opcodes->push_back(ZERO_PAGE); + handled_opcodes->push_back(ZERO_PAGE_X); + handled_opcodes->push_back(ABSOLUTE); + } + + virtual void execute() override; +}; + + +#endif //INC_6502_EMULATOR_STY_OPCODE_HANDLER_H diff --git a/src/opcode/opcode-handler-directory.cpp b/src/opcode/opcode-handler-directory.cpp index f531720..9ddf1a6 100644 --- a/src/opcode/opcode-handler-directory.cpp +++ b/src/opcode/opcode-handler-directory.cpp @@ -1,7 +1,10 @@ #include "opcode-handler-directory.h" #include "handler/flag-opcode-handler.h" #include "handler/register-opcode-handler.h" +#include "handler/lda-opcode-handler.h" #include "handler/ldx-opcode-handler.h" +#include "handler/stx-opcode-handler.h" +#include "handler/sty-opcode-handler.h" #include "handler/stack-opcode-handler.h" #include @@ -12,7 +15,10 @@ OpcodeHandlerDirectory::OpcodeHandlerDirectory(shared_ptr program, shar register_handler(make_shared(FlagOpcodeHandler(program, reg_man, memory))); register_handler(make_shared(RegisterOpcodeHandler(program, reg_man, memory))); + register_handler(make_shared(LdaOpcodeHandler(program, reg_man, memory))); register_handler(make_shared(LdxOpcodeHandler(program, reg_man, memory))); + register_handler(make_shared(StxOpcodeHandler(program, reg_man, memory))); + register_handler(make_shared(StyOpcodeHandler(program, reg_man, memory))); register_handler(make_shared(StackOpcodeHandler(program, reg_man, memory))); } diff --git a/src/opcode/opcode-handler.cpp b/src/opcode/opcode-handler.cpp index f686f47..2b2d5d3 100644 --- a/src/opcode/opcode-handler.cpp +++ b/src/opcode/opcode-handler.cpp @@ -1,4 +1,6 @@ #include "opcode-handler.h" +#include +#include OpcodeHandler::OpcodeHandler(shared_ptr program, shared_ptr reg_man, shared_ptr memory) { @@ -10,4 +12,10 @@ OpcodeHandler::OpcodeHandler(shared_ptr program, shared_ptrget_program_counter(); pc->set_value(pc->get_value() + forward_by); +} + +void OpcodeHandler::throw_unexpected_opcode(uint8_t opcode) { + stringstream stream; + stream << "Unexpected opcode 0x" << hex << opcode; + throw runtime_error(stream.str()); } \ No newline at end of file diff --git a/src/opcode/opcode-handler.h b/src/opcode/opcode-handler.h index 9d3afcf..3bd5a05 100644 --- a/src/opcode/opcode-handler.h +++ b/src/opcode/opcode-handler.h @@ -13,10 +13,11 @@ class OpcodeHandler { public: OpcodeHandler(shared_ptr program, shared_ptr reg_man, shared_ptr memory); - shared_ptr> get_handled_opcodes() { return handled_opcodes; } - virtual void execute() = 0; + shared_ptr> get_handled_opcodes() { return handled_opcodes; } + void throw_unexpected_opcode(uint8_t opcode); + protected: shared_ptr> handled_opcodes = make_shared>(); shared_ptr program; diff --git a/test/lda-opcode-handler-test.cpp b/test/lda-opcode-handler-test.cpp new file mode 100644 index 0000000..9b2d248 --- /dev/null +++ b/test/lda-opcode-handler-test.cpp @@ -0,0 +1,199 @@ +#include "gtest/gtest.h" +#include "../src/machine.h" +#include "../src/program.h" +#include "../src/opcode/handler/lda-opcode-handler.h" + +#include +#include + +using namespace std; + +const uint8_t IMMEDIATE = 0xA9; +const uint8_t ZERO_PAGE = 0xA5; +const uint8_t ZERO_PAGE_X = 0xB5; +const uint8_t ABSOLUTE = 0xAD; +const uint8_t ABSOLUTE_X = 0xBD; +const uint8_t ABSOLUTE_Y = 0xB9; +const uint8_t INDIRECT_X = 0xA1; +const uint8_t INDIRECT_Y = 0xB1; + +unique_ptr ldat_get_machine(shared_ptr> code) { + auto program = make_shared(Program(code)); + auto machine = make_unique(Machine(program)); + return machine; +} + +TEST(LdaOpcodeHandler, Immediate) { + auto code = make_shared>(vector{IMMEDIATE, 36}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + + ASSERT_EQ(0, accumulator->get_value()); + + machine->execute(); + + ASSERT_EQ(36, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, ZeroPage) { + auto code = make_shared>(vector{ZERO_PAGE, 123}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + + ASSERT_EQ(0, accumulator->get_value()); + + machine->get_memory()->set_byte_at(123, 78); + machine->execute(); + + ASSERT_EQ(78, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, ZeroPageX) { + auto code = make_shared>(vector{ZERO_PAGE_X, 0x50}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + auto x_reg = reg_man->get_x_index(); + + ASSERT_EQ(0, accumulator->get_value()); + ASSERT_EQ(0, x_reg->get_value()); + machine->get_memory()->set_byte_at(0x50, 0xff); + machine->execute(); + ASSERT_EQ(0xff, accumulator->get_value()); + + x_reg->set_value(0x15); + reg_man->get_program_counter()->set_value(0); + machine->execute(); + ASSERT_EQ(0, accumulator->get_value()); + + machine->get_memory()->set_byte_at(0x65, 233); + reg_man->get_program_counter()->set_value(0); + machine->execute(); + ASSERT_EQ(233, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, ZeroPageXWrap) { + auto code = make_shared>(vector{ZERO_PAGE_X, 0x80}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + auto x_reg = reg_man->get_x_index(); + + ASSERT_EQ(0, accumulator->get_value()); + ASSERT_EQ(0, x_reg->get_value()); + + x_reg->set_value(0xff); + machine->get_memory()->set_byte_at(0x7f, 0x12); + machine->execute(); + ASSERT_EQ(0x12, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, Absolute) { + auto code = make_shared>(vector{ABSOLUTE, 0xe5, 0xff}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + + ASSERT_EQ(0, accumulator->get_value()); + + machine->get_memory()->set_byte_at(0xffe5, 0xde); + machine->execute(); + + ASSERT_EQ(0xde, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, AbsoluteX) { + auto code = make_shared>(vector{ABSOLUTE_X, 0x33, 0xc2}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + auto x_reg = reg_man->get_x_index(); + + ASSERT_EQ(0, accumulator->get_value()); + ASSERT_EQ(0, x_reg->get_value()); + machine->get_memory()->set_byte_at(0xc233, 0xc8); + machine->execute(); + ASSERT_EQ(0xc8, accumulator->get_value()); + + x_reg->set_value(0x55); + machine->get_memory()->set_byte_at(0xc233 + 0x55, 0xab); + reg_man->get_program_counter()->set_value(0); + machine->execute(); + ASSERT_EQ(0xab, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, AbsoluteY) { + auto code = make_shared>(vector{ABSOLUTE_Y, 0x33, 0xc2}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, accumulator->get_value()); + ASSERT_EQ(0, y_reg->get_value()); + machine->get_memory()->set_byte_at(0xc233, 0xc8); + machine->execute(); + ASSERT_EQ(0xc8, accumulator->get_value()); + + y_reg->set_value(0x55); + machine->get_memory()->set_byte_at(0xc233 + 0x55, 0xab); + reg_man->get_program_counter()->set_value(0); + machine->execute(); + ASSERT_EQ(0xab, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, IndirectX) { + auto code = make_shared>(vector{INDIRECT_X, 0x00}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + auto x_reg = reg_man->get_x_index(); + + ASSERT_EQ(0, accumulator->get_value()); + + x_reg->set_value(0x01); + machine->get_memory()->set_byte_at(0x01, 0x05); + machine->get_memory()->set_byte_at(0x02, 0x07); + machine->get_memory()->set_byte_at(0x0705, 0xc6); + machine->execute(); + ASSERT_EQ(0xc6, accumulator->get_value()); + + code->at(1) = 0x15; + reg_man->get_program_counter()->set_value(0); + + x_reg->set_value(0x20); + machine->get_memory()->set_byte_at(0x35, 0xef); + machine->get_memory()->set_byte_at(0x36, 0xa8); + machine->get_memory()->set_byte_at(0xa8ef, 0x9d); + machine->execute(); + ASSERT_EQ(0x9d, accumulator->get_value()); +} + +TEST(LdaOpcodeHandler, IndirectY) { + auto code = make_shared>(vector{INDIRECT_Y, 0x00}); + auto machine = ldat_get_machine(code); + auto reg_man = machine->get_reg_man(); + auto accumulator = reg_man->get_accumulator(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, accumulator->get_value()); + + y_reg->set_value(0x00); + machine->get_memory()->set_byte_at(0x00, 0x25); + machine->get_memory()->set_byte_at(0x01, 0x3e); + machine->get_memory()->set_byte_at(0x3e25, 0xf0); + machine->execute(); + ASSERT_EQ(0xf0, accumulator->get_value()); + + code->at(1) = 0x15; + reg_man->get_program_counter()->set_value(0); + + y_reg->set_value(0x25); + machine->get_memory()->set_byte_at(0x15, 0x20); + machine->get_memory()->set_byte_at(0x16, 0x07); + machine->get_memory()->set_byte_at(0x0745, 0x89); + machine->execute(); + ASSERT_EQ(0x89, accumulator->get_value()); +} \ No newline at end of file diff --git a/test/ldx-opcode-handler-test.cpp b/test/ldx-opcode-handler-test.cpp index 322a446..cf3ddff 100644 --- a/test/ldx-opcode-handler-test.cpp +++ b/test/ldx-opcode-handler-test.cpp @@ -48,7 +48,7 @@ TEST(LdxOpcodeHandler, ZeroPage) { } TEST(LdxOpcodeHandler, ZeroPageY) { - auto code = make_shared>(vector{ZERO_PAGE_Y, 250}); + auto code = make_shared>(vector{ZERO_PAGE_Y, 0x50}); auto machine = ldxt_get_machine(code); auto reg_man = machine->get_reg_man(); auto x_reg = reg_man->get_x_index(); @@ -56,16 +56,16 @@ TEST(LdxOpcodeHandler, ZeroPageY) { ASSERT_EQ(0, x_reg->get_value()); ASSERT_EQ(0, y_reg->get_value()); - machine->get_memory()->set_byte_at(250, 255); + machine->get_memory()->set_byte_at(0x50, 255); machine->execute(); ASSERT_EQ(255, x_reg->get_value()); - reg_man->get_y_index()->set_value(100); + reg_man->get_y_index()->set_value(0x17); reg_man->get_program_counter()->set_value(0); machine->execute(); ASSERT_EQ(0, x_reg->get_value()); - machine->get_memory()->set_byte_at(350, 233); + machine->get_memory()->set_byte_at(0x67, 233); reg_man->get_program_counter()->set_value(0); machine->execute(); ASSERT_EQ(233, x_reg->get_value()); diff --git a/test/stx-opcode-handler-test.cpp b/test/stx-opcode-handler-test.cpp new file mode 100644 index 0000000..892a7fd --- /dev/null +++ b/test/stx-opcode-handler-test.cpp @@ -0,0 +1,71 @@ +#include "gtest/gtest.h" +#include "../src/machine.h" +#include "../src/program.h" + +#include +#include + +using namespace std; + +const uint8_t ZERO_PAGE = 0x86; +const uint8_t ZERO_PAGE_Y = 0x96; +const uint8_t ABSOLUTE = 0x8E; + +unique_ptr stxt_get_machine(shared_ptr> code) { + auto program = make_shared(Program(code)); + auto machine = make_unique(Machine(program)); + return machine; +} + +TEST(StxOpcodeHandler, ZeroPage) { + auto code = make_shared>(vector{ZERO_PAGE, 50}); + auto machine = stxt_get_machine(code); + auto memory = machine->get_memory(); + auto reg_man = machine->get_reg_man(); + auto x_reg = reg_man->get_x_index(); + + ASSERT_EQ(0, x_reg->get_value()); + ASSERT_EQ(0, memory->get_byte_at(50)); + + x_reg->set_value(0x8a); + machine->execute(); + + ASSERT_EQ(0x8a, memory->get_byte_at(50)); +} + +TEST(StxOpcodeHandler, ZeroPageY) { + auto code = make_shared>(vector{ZERO_PAGE_Y, 0x45}); + auto machine = stxt_get_machine(code); + auto memory = machine->get_memory(); + auto reg_man = machine->get_reg_man(); + auto x_reg = reg_man->get_x_index(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, x_reg->get_value()); + ASSERT_EQ(0, y_reg->get_value()); + ASSERT_EQ(0, memory->get_byte_at(0x4a)); + + x_reg->set_value(0x8b); + y_reg->set_value(0x5); + machine->execute(); + + ASSERT_EQ(0x8b, memory->get_byte_at(0x4a)); +} + +TEST(StxOpcodeHandler, Absolute) { + auto code = make_shared>(vector{ABSOLUTE, 0x33, 0x44}); + auto machine = stxt_get_machine(code); + auto memory = machine->get_memory(); + auto reg_man = machine->get_reg_man(); + auto x_reg = reg_man->get_x_index(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, x_reg->get_value()); + ASSERT_EQ(0, y_reg->get_value()); + ASSERT_EQ(0, memory->get_byte_at(0x4433)); + + x_reg->set_value(0x9f); + machine->execute(); + + ASSERT_EQ(0x9f, memory->get_byte_at(0x4433)); +} \ No newline at end of file diff --git a/test/sty-opcode-handler.cpp b/test/sty-opcode-handler.cpp new file mode 100644 index 0000000..4657b9c --- /dev/null +++ b/test/sty-opcode-handler.cpp @@ -0,0 +1,71 @@ +#include "gtest/gtest.h" +#include "../src/machine.h" +#include "../src/program.h" + +#include +#include + +using namespace std; + +const uint8_t ZERO_PAGE = 0x84; +const uint8_t ZERO_PAGE_X = 0x94; +const uint8_t ABSOLUTE = 0x8C; + +unique_ptr styt_get_machine(shared_ptr> code) { + auto program = make_shared(Program(code)); + auto machine = make_unique(Machine(program)); + return machine; +} + +TEST(StyOpcodeHandler, ZeroPage) { + auto code = make_shared>(vector{ZERO_PAGE, 50}); + auto machine = styt_get_machine(code); + auto memory = machine->get_memory(); + auto reg_man = machine->get_reg_man(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, y_reg->get_value()); + ASSERT_EQ(0, memory->get_byte_at(50)); + + y_reg->set_value(0x8a); + machine->execute(); + + ASSERT_EQ(0x8a, memory->get_byte_at(50)); +} + +TEST(StyOpcodeHandler, ZeroPageX) { + auto code = make_shared>(vector{ZERO_PAGE_X, 0x45}); + auto machine = styt_get_machine(code); + auto memory = machine->get_memory(); + auto reg_man = machine->get_reg_man(); + auto x_reg = reg_man->get_x_index(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, x_reg->get_value()); + ASSERT_EQ(0, y_reg->get_value()); + ASSERT_EQ(0, memory->get_byte_at(0x5b)); + + x_reg->set_value(0x16); + y_reg->set_value(0xe1); + machine->execute(); + + ASSERT_EQ(0xe1, memory->get_byte_at(0x5b)); +} + +TEST(StyOpcodeHandler, Absolute) { + auto code = make_shared>(vector{ABSOLUTE, 0x33, 0x44}); + auto machine = styt_get_machine(code); + auto memory = machine->get_memory(); + auto reg_man = machine->get_reg_man(); + auto x_reg = reg_man->get_x_index(); + auto y_reg = reg_man->get_y_index(); + + ASSERT_EQ(0, x_reg->get_value()); + ASSERT_EQ(0, y_reg->get_value()); + ASSERT_EQ(0, memory->get_byte_at(0x4433)); + + y_reg->set_value(0x9f); + machine->execute(); + + ASSERT_EQ(0x9f, memory->get_byte_at(0x4433)); +}