From 434d810b54b3ef4e20c1ef1562e0067378f2f2b2 Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Wed, 28 Aug 2024 21:58:55 +0100 Subject: [PATCH 1/7] Coverage generating scripts --- scripts/gather_cov.sh | 49 +++++++++++++++++++++++++++++++++++++++ scripts/gcov_for_clang.sh | 2 ++ 2 files changed, 51 insertions(+) create mode 100755 scripts/gather_cov.sh create mode 100755 scripts/gcov_for_clang.sh diff --git a/scripts/gather_cov.sh b/scripts/gather_cov.sh new file mode 100755 index 0000000..da18d1d --- /dev/null +++ b/scripts/gather_cov.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +set -euo pipefail + +: ' This script will find run lcov to generate + a report and then push it to codecov. +' + +THIS_DIR=$(cd "$(dirname "$0")" && pwd) +PROJECT_DIR="$(cd "${THIS_DIR}/.." && pwd)" + +echo "Project root dir: ${PROJECT_DIR}" +lcov --capture --directory . --output-file coverage.info \ + --rc geninfo_adjust_src_path="${PROJECT_DIR}/build/unix-deb-ninja \ + => ${PROJECT_DIR}" \ + --gcov-tool "${PROJECT_DIR}/scripts/gcov_for_clang.sh" \ + --ignore-errors inconsistent \ + --ignore-errors unused + + +SYSTEM_DIR="/usr/" +CONAN_DIR="${HOME}/.conan2/" + +# Remove the system & test dirs +echo "!!!!!!1" +lcov --ignore-errors inconsistent --remove coverage.info "${SYSTEM_DIR}*" --output-file coverage.info +echo "!!!!!!2" +lcov --ignore-errors inconsistent --remove coverage.info "${CONAN_DIR}*" --output-file coverage.info +echo "!!!!!!3" +lcov --ignore-errors inconsistent --remove coverage.info "${PROJECT_DIR}/tests*" --output-file coverage.info +echo "!!!!!!4" + +# Generate HTML report into coverage/ +genhtml coverage.info --ignore-errors inconsistent --ignore-errors corrupt --output-directory coverage > coverage_stats.txt +LINES_COV="$(grep lines < coverage_stats.txt | grep -Eo "[0-9]+\.[0-9]+%" | cut -d '.' -f1)" +FUNCTIONS_COV="$(grep functions < coverage_stats.txt | grep -Eo "[0-9]+\.[0-9]+%" | cut -d '.' -f1)" + +# Make sure we fail the pipeline if coverage is less than something +LINES_COV_THRESH="98" +if [ "$LINES_COV" -lt "$LINES_COV_THRESH" ]; then + echo "Line coverage is less than threshold $LINES_COV_THRESH" + exit 1 +fi + +FUNCTIONS_COV_THRESH="100" +if [ "$FUNCTIONS_COV" -lt "$FUNCTIONS_COV_THRESH" ]; then + echo "Functions coverage is less than threshold $FUNCTIONS_COV_THRESH" + exit 1 +fi diff --git a/scripts/gcov_for_clang.sh b/scripts/gcov_for_clang.sh new file mode 100755 index 0000000..4e320d8 --- /dev/null +++ b/scripts/gcov_for_clang.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec llvm-cov gcov "$@" From 91ec124c619fca8144ddc785052718e0654eeb30 Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Thu, 29 Aug 2024 19:48:53 +0100 Subject: [PATCH 2/7] removing unecessary logs and renaming cov file to work better with vscode extension --- scripts/gather_cov.sh | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/scripts/gather_cov.sh b/scripts/gather_cov.sh index da18d1d..6c43f38 100755 --- a/scripts/gather_cov.sh +++ b/scripts/gather_cov.sh @@ -10,7 +10,7 @@ THIS_DIR=$(cd "$(dirname "$0")" && pwd) PROJECT_DIR="$(cd "${THIS_DIR}/.." && pwd)" echo "Project root dir: ${PROJECT_DIR}" -lcov --capture --directory . --output-file coverage.info \ +lcov --capture --directory . --output-file lcov.info \ --rc geninfo_adjust_src_path="${PROJECT_DIR}/build/unix-deb-ninja \ => ${PROJECT_DIR}" \ --gcov-tool "${PROJECT_DIR}/scripts/gcov_for_clang.sh" \ @@ -22,16 +22,12 @@ SYSTEM_DIR="/usr/" CONAN_DIR="${HOME}/.conan2/" # Remove the system & test dirs -echo "!!!!!!1" -lcov --ignore-errors inconsistent --remove coverage.info "${SYSTEM_DIR}*" --output-file coverage.info -echo "!!!!!!2" -lcov --ignore-errors inconsistent --remove coverage.info "${CONAN_DIR}*" --output-file coverage.info -echo "!!!!!!3" -lcov --ignore-errors inconsistent --remove coverage.info "${PROJECT_DIR}/tests*" --output-file coverage.info -echo "!!!!!!4" +lcov --ignore-errors inconsistent --remove lcov.info "${SYSTEM_DIR}*" --output-file lcov.info +lcov --ignore-errors inconsistent --remove lcov.info "${CONAN_DIR}*" --output-file lcov.info +lcov --ignore-errors inconsistent --remove lcov.info "${PROJECT_DIR}/tests*" --output-file lcov.info # Generate HTML report into coverage/ -genhtml coverage.info --ignore-errors inconsistent --ignore-errors corrupt --output-directory coverage > coverage_stats.txt +genhtml lcov.info --ignore-errors inconsistent --ignore-errors corrupt --output-directory coverage > coverage_stats.txt LINES_COV="$(grep lines < coverage_stats.txt | grep -Eo "[0-9]+\.[0-9]+%" | cut -d '.' -f1)" FUNCTIONS_COV="$(grep functions < coverage_stats.txt | grep -Eo "[0-9]+\.[0-9]+%" | cut -d '.' -f1)" From e5ced9e92a3881f7d4a93e5a7a21c429d95b18dd Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Mon, 13 May 2024 20:45:12 +0100 Subject: [PATCH 3/7] Improving the profiler classes --- CMakeLists.txt | 5 +++ conanfile.txt | 1 - emulator/CMakeLists.txt | 10 ++++-- emulator/emulator.cpp | 72 ++++++++++++++++++++++++++++++++++--- emulator_app/CMakeLists.txt | 2 -- emulator_app/main.cpp | 7 +++- 6 files changed, 85 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c884cd1..d9a81a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,14 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN On) option(CLOCK_SPEED_MHZ "The clock speed for the processor") +option(BUILD_PROFILER "Build profiling for the instruction handlers") add_subdirectory(emulator) add_subdirectory(emulator_app) +if (BUILD_PROFILER) + add_subdirectory(profiler) +endif() + enable_testing() add_subdirectory(tests) diff --git a/conanfile.txt b/conanfile.txt index ea2cdea..5e95f05 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,6 +1,5 @@ [requires] gtest/1.13.0 -fmt/10.2.1 raylib/5.0 [generators] diff --git a/emulator/CMakeLists.txt b/emulator/CMakeLists.txt index c7688d4..2cc0a9c 100644 --- a/emulator/CMakeLists.txt +++ b/emulator/CMakeLists.txt @@ -1,6 +1,3 @@ - -find_package(fmt REQUIRED) - add_library(emulator) target_sources(emulator PUBLIC @@ -14,3 +11,10 @@ if (CLOCK_SPEED_MHZ) endif() target_link_libraries(emulator PRIVATE fmt::fmt) +if(BUILD_PROFILER) + message(STATUS "Building profiler") + target_link_libraries(emulator PRIVATE profiler) + target_compile_definitions(emulator PRIVATE BUILD_PROFILER=) +else() + message(STATUS "Profiler not build") +endif() diff --git a/emulator/emulator.cpp b/emulator/emulator.cpp index 2db1b1d..2362982 100644 --- a/emulator/emulator.cpp +++ b/emulator/emulator.cpp @@ -1,5 +1,9 @@ module; +// #ifdef BUILD_PROFILER +import profiler; +// #endif // BUILD_PROFILER + #include #include #include @@ -7,6 +11,7 @@ module; #include #include #include +#include #include #include #include @@ -21,6 +26,34 @@ module; export module emulator; +// Define a macro for the profiler +#ifdef BUILD_PROFILER +struct ProfileBook +{ + std::unordered_map functions; + + bool update(std::string const& func_name, double profile) + { + auto found = functions.find(func_name); + if (found != end(functions)) + { + // update it + found->second += profile; + return true; + } + + functions[func_name] = profile; + return true; + } +}; + +#define ENABLE_PROFILER(cpu) \ + volatile auto profile_result_666 = profiler::FunctionProfiler(cpu.profiler_book) +#else +#define ENABLE_PROFILER(cpu) +#endif // BUILD_PROFILER + + export namespace emulator { @@ -84,6 +117,7 @@ Instruction ld_immediate(std::uint8_t emulator::Registers::*reg) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -102,6 +136,7 @@ Instruction ld_zeropage(std::uint8_t emulator::Registers::*reg) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -123,6 +158,8 @@ Instruction ld_zeropage_plus_reg(std::uint8_t emulator::Registers::*to, std::uin { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -143,6 +180,7 @@ Instruction ld_absolute(std::uint8_t emulator::Registers::*to) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 2) >= program.size()) { return std::nullopt; @@ -165,6 +203,7 @@ Instruction ld_absolute_plus_reg(std::uint8_t emulator::Registers::*to, std::uin { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 2) >= program.size()) { return std::nullopt; @@ -190,6 +229,7 @@ Instruction ld_index_indirect(std::uint8_t emulator::Registers::*to, std::uint8_ { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -215,6 +255,7 @@ Instruction ld_indirect_index(std::uint8_t emulator::Registers::*to, std::uint8_ { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -237,6 +278,7 @@ Instruction ld_indirect_index(std::uint8_t emulator::Registers::*to, std::uint8_ std::optional inc_zeropage(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -252,6 +294,7 @@ std::optional inc_zeropage(emulator::Cpu& cpu, std::span inc_zeropage_plus_x(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -267,6 +310,7 @@ std::optional inc_zeropage_plus_x(emulator::Cpu& cpu, std::sp std::optional inc_absolute(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 2) >= program.size()) { return std::nullopt; @@ -284,6 +328,8 @@ std::optional inc_absolute(emulator::Cpu& cpu, std::span inc_absolute_plus_x(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 2) >= program.size()) { return std::nullopt; @@ -303,6 +349,7 @@ std::optional inc_absolute_plus_x(emulator::Cpu& cpu, std::sp std::optional dec_zeropage(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -318,8 +365,9 @@ std::optional dec_zeropage(emulator::Cpu& cpu, std::span program) + return [=](emulator::Cpu& cpu, std::span /* program */) { + ENABLE_PROFILER(cpu); ((cpu.reg).*reg)++; cpu.flags.n = (cpu.reg).*reg & 0b1000'0000; cpu.flags.z = (cpu.reg).*reg == 0; @@ -329,8 +377,9 @@ Instruction inc_reg(std::uint8_t emulator::Registers::*reg) Instruction dec_reg(std::uint8_t emulator::Registers::*reg) { - return [=](emulator::Cpu& cpu, std::span program) + return [=](emulator::Cpu& cpu, std::span /* program */) { + ENABLE_PROFILER(cpu); ((cpu.reg).*reg)--; cpu.flags.n = (cpu.reg).*reg & 0b1000'0000; cpu.flags.z = (cpu.reg).*reg == 0; @@ -340,8 +389,9 @@ Instruction dec_reg(std::uint8_t emulator::Registers::*reg) Instruction transfer_regs(std::uint8_t emulator::Registers::*from, std::uint8_t emulator::Registers::*to) { - return [=](emulator::Cpu& cpu, std::span program) + return [=](emulator::Cpu& cpu, std::span /* program */) { + ENABLE_PROFILER(cpu); (cpu.reg).*to = (cpu.reg).*from; cpu.flags.z = (cpu.reg).*to == 0; cpu.flags.n = (cpu.reg).*to & 0b1000'0000; @@ -353,6 +403,7 @@ Instruction transfer_regs(std::uint8_t emulator::Registers::*from, std::uint8_t // does not set any flags. std::optional txa(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); cpu.reg.sp = cpu.reg.x; return std::make_optional(1); } @@ -361,6 +412,7 @@ Instruction st_indirect(std::uint8_t emulator::Registers::*from, std::uint8_t em { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -384,6 +436,7 @@ Instruction st_zeropage(std::uint8_t emulator::Registers::*from) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); // LOAD Value into accumulator if ((cpu.reg.pc + 1) >= program.size()) { @@ -401,6 +454,7 @@ Instruction st_absolute(std::uint8_t emulator::Registers::*from) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 2) >= program.size()) { return std::nullopt; @@ -423,6 +477,7 @@ Instruction cmp_immediate_reg(std::uint8_t emulator::Registers::*reg) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -442,6 +497,8 @@ Instruction cmp_zeropage_reg(std::uint8_t emulator::Registers::*reg) { return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -461,6 +518,7 @@ Instruction cmp_zeropage_reg(std::uint8_t emulator::Registers::*reg) // Branching functions here std::optional bne(emulator::Cpu& cpu, std::span program) { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -484,6 +542,7 @@ Instruction branch_flag_value(bool emulator::Flags::*flag) // TODO : Do we need a return here? return [=](emulator::Cpu& cpu, std::span program) -> std::optional { + ENABLE_PROFILER(cpu); if ((cpu.reg.pc + 1) >= program.size()) { return std::nullopt; @@ -496,8 +555,9 @@ Instruction branch_flag_value(bool emulator::Flags::*flag) // TODO : provide support for counting the number of cycles passed // from the start of the program -std::unordered_map get_instructions() +std::unordered_map get_instructions(emulator::Cpu& cpu) { + ENABLE_PROFILER(cpu); // Byte key indicates which function we need to call // to handle the specific instruction return {{ @@ -575,6 +635,7 @@ std::unordered_map get_instructions() std::optional execute_next(emulator::Cpu& cpu, std::span program, std::unordered_map instructions) { + ENABLE_PROFILER(cpu); // Read 1 byte for the operator if (cpu.reg.pc >= program.size()) { @@ -601,8 +662,9 @@ export namespace emulator std::size_t execute(Cpu& cpu, std::span program) { - auto const instructions = get_instructions(); std::size_t n_cycles = 0; + ENABLE_PROFILER(cpu); + auto const instructions = get_instructions(cpu); while (cpu.reg.pc < program.size()) { auto const time_now = std::chrono::high_resolution_clock::now(); diff --git a/emulator_app/CMakeLists.txt b/emulator_app/CMakeLists.txt index bb19f12..7b84406 100644 --- a/emulator_app/CMakeLists.txt +++ b/emulator_app/CMakeLists.txt @@ -1,10 +1,8 @@ -find_package(fmt REQUIRED) find_package(raylib REQUIRED) add_executable(emulator_app main.cpp) target_link_libraries(emulator_app PRIVATE emulator - fmt::fmt raylib) diff --git a/emulator_app/main.cpp b/emulator_app/main.cpp index 68f3503..60c05be 100644 --- a/emulator_app/main.cpp +++ b/emulator_app/main.cpp @@ -6,10 +6,10 @@ import emulator; #include #include #include -#include #include #include +#include namespace { @@ -83,5 +83,10 @@ int main(int argc, char** argv) emulator::execute(easy65k, {reinterpret_cast(program_contents.data()), program_contents.size()}); + for (auto const& [function, profile] : easy65k.current_profile()) + { + std::cout << std::format("{}: {:.6f}\n", function, profile); + } + draw(easy65k); } From c1fe978adc92cba06ce28d345107ba25bcf710af Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Wed, 21 Aug 2024 20:34:20 +0100 Subject: [PATCH 4/7] Adding profiler as well as improving the speed without maps --- CMakePresets.json | 6 +- conanfile.txt | 1 + emulator/CMakeLists.txt | 4 + emulator/emulator.cpp | 177 ++++++++++++++++++++++------------------ profiler/CMakeLists.txt | 4 + profiler/profiler.cpp | 56 +++++++++++++ 6 files changed, 166 insertions(+), 82 deletions(-) create mode 100644 profiler/CMakeLists.txt create mode 100644 profiler/profiler.cpp diff --git a/CMakePresets.json b/CMakePresets.json index 1144867..148e7c7 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -100,7 +100,8 @@ "binaryDir": "${sourceDir}/build/unix-rel-ninja", "inherits": ["unix-ninja", "rel", "conan-rel"], "cacheVariables": { - "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/unix-rel-ninja/install" + "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/unix-rel-ninja/install", + "BUILD_PROFILER": true } }, { @@ -130,7 +131,8 @@ "cacheVariables": { "CMAKE_CXX_FLAGS": "-O0 --coverage -g -fsanitize=address", "CMAKE_INSTALL_PREFIX": "${sourceDir}/build/unix-deb-ninja/install", - "CLOCK_SPEED_MHZ": "3.58" + "CLOCK_SPEED_MHZ": "3.58", + "BUILD_PROFILER": true } }, { diff --git a/conanfile.txt b/conanfile.txt index 5e95f05..8826c09 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,4 +1,5 @@ [requires] +fmt/11.0.2 gtest/1.13.0 raylib/5.0 diff --git a/emulator/CMakeLists.txt b/emulator/CMakeLists.txt index 2cc0a9c..5d5f5ae 100644 --- a/emulator/CMakeLists.txt +++ b/emulator/CMakeLists.txt @@ -1,3 +1,5 @@ +find_package(fmt REQUIRED) + add_library(emulator) target_sources(emulator PUBLIC @@ -18,3 +20,5 @@ if(BUILD_PROFILER) else() message(STATUS "Profiler not build") endif() + +target_link_libraries(emulator PRIVATE fmt::fmt) diff --git a/emulator/emulator.cpp b/emulator/emulator.cpp index 2362982..ab3ec73 100644 --- a/emulator/emulator.cpp +++ b/emulator/emulator.cpp @@ -5,10 +5,12 @@ import profiler; // #endif // BUILD_PROFILER #include +#include #include #include #include #include +#include #include #include #include @@ -24,6 +26,8 @@ import profiler; #define CLOCK_SPEED_MHZ 1.79 #endif // CLOCK_SPEED_MHZ +#include + export module emulator; // Define a macro for the profiler @@ -56,6 +60,22 @@ struct ProfileBook export namespace emulator { + class OpcodeNotSupported: public std::exception + { + public: + OpcodeNotSupported(std::string opcode) + : _error_msg{"opcode not supported: " + opcode} + { + } + + const char* what() const throw() override + { + return _error_msg.c_str(); + } + + private: + std::string _error_msg; + }; struct Registers { @@ -555,85 +575,81 @@ Instruction branch_flag_value(bool emulator::Flags::*flag) // TODO : provide support for counting the number of cycles passed // from the start of the program -std::unordered_map get_instructions(emulator::Cpu& cpu) +std::array get_instructions(emulator::Cpu& cpu) { ENABLE_PROFILER(cpu); // Byte key indicates which function we need to call // to handle the specific instruction - return {{ - {0x00, [](emulator::Cpu&, std::span) { return std::nullopt; }}, - - - // Transferring instrucitons here - {0x8a, transfer_regs(&emulator::Registers::x, &emulator::Registers::a)}, // TXA - {0x98, transfer_regs(&emulator::Registers::y, &emulator::Registers::a)}, // TYA - {0xa8, transfer_regs(&emulator::Registers::a, &emulator::Registers::y)}, // TAY - {0xaa, transfer_regs(&emulator::Registers::a, &emulator::Registers::x)}, // TAX - {0xba, transfer_regs(&emulator::Registers::sp, &emulator::Registers::x)}, // TSX - {0x9a, txa}, - - // Memory storing functions here - // TODO : Add more tests for these - {0x85, st_zeropage(&emulator::Registers::a)}, - {0x8d, st_absolute(&emulator::Registers::a)}, - {0x91, st_indirect(&emulator::Registers::a, &emulator::Registers::y)}, - {0x86, st_zeropage(&emulator::Registers::x)}, - {0x8e, st_absolute(&emulator::Registers::x)}, - {0x84, st_zeropage(&emulator::Registers::y)}, - {0x8c, st_absolute(&emulator::Registers::y)}, - - // TODO : Finish supporting the ld* family - // of instructions - {0xa9, ld_immediate(&emulator::Registers::a)}, - {0xa5, ld_zeropage(&emulator::Registers::a)}, - {0xb5, ld_zeropage_plus_reg(&emulator::Registers::a, &emulator::Registers::x)}, - {0xbd, ld_absolute_plus_reg(&emulator::Registers::a, &emulator::Registers::x)}, - {0xb9, ld_absolute_plus_reg(&emulator::Registers::a, &emulator::Registers::y)}, - {0xa1, ld_index_indirect(&emulator::Registers::a, &emulator::Registers::x)}, - {0xb1, ld_indirect_index(&emulator::Registers::a, &emulator::Registers::y)}, - {0xad, ld_absolute(&emulator::Registers::a)}, - {0xa2, ld_immediate(&emulator::Registers::x)}, - {0xa6, ld_zeropage(&emulator::Registers::x)}, - {0xb6, ld_zeropage_plus_reg(&emulator::Registers::x, &emulator::Registers::y)}, - {0xae, ld_absolute(&emulator::Registers::x)}, - {0xbe, ld_absolute_plus_reg(&emulator::Registers::x, &emulator::Registers::y)}, - {0xa0, ld_immediate(&emulator::Registers::y)}, - {0xa4, ld_zeropage(&emulator::Registers::y)}, - {0xb4, ld_zeropage_plus_reg(&emulator::Registers::y, &emulator::Registers::x)}, - {0xbc, ld_absolute_plus_reg(&emulator::Registers::y, &emulator::Registers::x)}, - {0xac, ld_absolute(&emulator::Registers::y)}, - - // TODO : finish support for the cmp* family - // of instructions - {0xc0, cmp_immediate_reg(&emulator::Registers::y)}, - {0xc5, cmp_zeropage_reg(&emulator::Registers::a)}, - {0xe0, cmp_immediate_reg(&emulator::Registers::x)}, - - {0xf0, branch_flag_value(&emulator::Flags::z)}, - {0xd0, branch_flag_value(&emulator::Flags::z)}, - {0x30, branch_flag_value(&emulator::Flags::n)}, - {0x10, branch_flag_value(&emulator::Flags::n)}, - {0xb0, branch_flag_value(&emulator::Flags::c)}, - {0x90, branch_flag_value(&emulator::Flags::c)}, - {0x70, branch_flag_value(&emulator::Flags::v)}, - {0x50, branch_flag_value(&emulator::Flags::v)}, - - // TODO : finish support for the inc/dec - // instructions - {0xe6, inc_zeropage}, - {0xf6, inc_zeropage_plus_x}, // TODO : Need tests for this - {0xee, inc_absolute}, - {0xfe, inc_absolute_plus_x}, // TODO : Need tests for this - {0xc8, inc_reg(&emulator::Registers::y)}, - {0xe8, inc_reg(&emulator::Registers::x)}, - {0xc6, dec_zeropage}, - {0x88, dec_reg(&emulator::Registers::y)}, - {0xca, dec_reg(&emulator::Registers::x)}, - }}; +// using Instruction = std::function(emulator::Cpu&, std::span)>; + std::array supported_instructions{}; + for (std::size_t i = 0; i < supported_instructions.size(); ++i) + { + supported_instructions[i] = [=](emulator::Cpu&, std::span) -> std::optional{ + throw emulator::OpcodeNotSupported(fmt::format("{0:#x}", i)); + }; + } + // make sure that all default elemets of supported_instructions + // are functions that will raise an error + + // Supported instructions + supported_instructions[0x00] = [](emulator::Cpu&, std::span) { return std::nullopt; }; + supported_instructions[0x8a] = transfer_regs(&emulator::Registers::x, &emulator::Registers::a); + supported_instructions[0x98] = transfer_regs(&emulator::Registers::y, &emulator::Registers::a); + supported_instructions[0xa8] = transfer_regs(&emulator::Registers::a, &emulator::Registers::y); + supported_instructions[0xaa] = transfer_regs(&emulator::Registers::a, &emulator::Registers::x); + supported_instructions[0xba] = transfer_regs(&emulator::Registers::sp, &emulator::Registers::x); + supported_instructions[0x9a] = txa; + supported_instructions[0x85] = st_zeropage(&emulator::Registers::a); + supported_instructions[0x8d] = st_absolute(&emulator::Registers::a); + supported_instructions[0x91] = st_indirect(&emulator::Registers::a, &emulator::Registers::y); + supported_instructions[0x86] = st_zeropage(&emulator::Registers::x); + supported_instructions[0x8e] = st_absolute(&emulator::Registers::x); + supported_instructions[0x84] = st_zeropage(&emulator::Registers::y); + supported_instructions[0x8c] = st_absolute(&emulator::Registers::y); + supported_instructions[0xa9] = ld_immediate(&emulator::Registers::a); + supported_instructions[0xa5] = ld_zeropage(&emulator::Registers::a); + supported_instructions[0xb5] = ld_zeropage_plus_reg(&emulator::Registers::a, &emulator::Registers::x); + supported_instructions[0xbd] = ld_absolute_plus_reg(&emulator::Registers::a, &emulator::Registers::x); + supported_instructions[0xb9] = ld_absolute_plus_reg(&emulator::Registers::a, &emulator::Registers::y); + supported_instructions[0xa1] = ld_index_indirect(&emulator::Registers::a, &emulator::Registers::x); + supported_instructions[0xb1] = ld_indirect_index(&emulator::Registers::a, &emulator::Registers::y); + supported_instructions[0xad] = ld_absolute(&emulator::Registers::a); + supported_instructions[0xa2] = ld_immediate(&emulator::Registers::x); + supported_instructions[0xa6] = ld_zeropage(&emulator::Registers::x); + supported_instructions[0xb6] = ld_zeropage_plus_reg(&emulator::Registers::x, &emulator::Registers::y); + supported_instructions[0xae] = ld_absolute(&emulator::Registers::x); + supported_instructions[0xbe] = ld_absolute_plus_reg(&emulator::Registers::x, &emulator::Registers::y); + supported_instructions[0xa0] = ld_immediate(&emulator::Registers::y); + supported_instructions[0xa4] = ld_zeropage(&emulator::Registers::y); + supported_instructions[0xb4] = ld_zeropage_plus_reg(&emulator::Registers::y, &emulator::Registers::x); + supported_instructions[0xbc] = ld_absolute_plus_reg(&emulator::Registers::y, &emulator::Registers::x); + supported_instructions[0xac] = ld_absolute(&emulator::Registers::y); + supported_instructions[0xc0] = cmp_immediate_reg(&emulator::Registers::y); + supported_instructions[0xc5] = cmp_zeropage_reg(&emulator::Registers::a); + supported_instructions[0xe0] = cmp_immediate_reg(&emulator::Registers::x); + supported_instructions[0xf0] = branch_flag_value(&emulator::Flags::z); + supported_instructions[0xd0] = branch_flag_value(&emulator::Flags::z); + supported_instructions[0x30] = branch_flag_value(&emulator::Flags::n); + supported_instructions[0x10] = branch_flag_value(&emulator::Flags::n); + supported_instructions[0xb0] = branch_flag_value(&emulator::Flags::c); + supported_instructions[0x90] = branch_flag_value(&emulator::Flags::c); + supported_instructions[0x70] = branch_flag_value(&emulator::Flags::v); + supported_instructions[0x50] = branch_flag_value(&emulator::Flags::v); + supported_instructions[0xe6] = inc_zeropage; + supported_instructions[0xf6] = inc_zeropage_plus_x; + supported_instructions[0xee] = inc_absolute; + supported_instructions[0xfe] = inc_absolute_plus_x; + supported_instructions[0xc8] = inc_reg(&emulator::Registers::y); + supported_instructions[0xe8] = inc_reg(&emulator::Registers::x); + supported_instructions[0xc6] = dec_zeropage; + supported_instructions[0x88] = dec_reg(&emulator::Registers::y); + supported_instructions[0xca] = dec_reg(&emulator::Registers::x); + + return supported_instructions; } std::optional execute_next(emulator::Cpu& cpu, std::span program, - std::unordered_map instructions) + std::array instructions) { ENABLE_PROFILER(cpu); // Read 1 byte for the operator @@ -644,17 +660,18 @@ std::optional execute_next(emulator::Cpu& cpu, std::spansecond(cpu, program); + return instruction(cpu, program); + } + catch (emulator::OpcodeNotSupported const& e) + { + std::cout << e.what() << std::endl; + return std::nullopt; } - - // Instruction not supported here - // unsupported command - return std::nullopt; } export namespace emulator diff --git a/profiler/CMakeLists.txt b/profiler/CMakeLists.txt new file mode 100644 index 0000000..39ee04b --- /dev/null +++ b/profiler/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(profiler) + +target_sources(profiler PUBLIC + FILE_SET CXX_MODULES FILES profiler.cpp) diff --git a/profiler/profiler.cpp b/profiler/profiler.cpp new file mode 100644 index 0000000..d3b08b6 --- /dev/null +++ b/profiler/profiler.cpp @@ -0,0 +1,56 @@ +module; + +#include +#include +#include +#include +#include +#include + +export module profiler; + +export namespace profiler +{ + + // Constrait for collections that can be used to store + // a profile result + template + concept Bookeper = std::convertible_to && std::convertible_to + && requires(T v, FuncName func_name, Measure measure) { + { + v.update(func_name, measure) + } -> std::same_as; + }; + + template + requires Bookeper + class FunctionProfiler + { + public: + FunctionProfiler(std::shared_ptr books, const std::source_location& sl = std::source_location::current()) + : _unit_name{sl.function_name()}, _start{std::chrono::high_resolution_clock::now()}, _books{books} + { + } + + ~FunctionProfiler() + { + using namespace std::chrono; + auto const now = std::chrono::high_resolution_clock::now(); + auto const time_diff = duration_cast>(now - _start); + + // TODO : Save the info in a map or something + if (!_books) + { + std::cout << "cannot store profile as books is null\n"; + return; + } + + _books->update(_unit_name, time_diff.count()); + } + + private: + std::string _unit_name; + std::chrono::time_point _start; + std::shared_ptr _books; + }; +} // namespace profiler From e3d971999ea3c24df7c945f905bb7fab4e96665d Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Tue, 27 Aug 2024 22:16:32 +0100 Subject: [PATCH 5/7] Support for the ORA operations and tests for immediate mode --- emulator/emulator.cpp | 216 ++++++++++++++++++++++++++++++++--- tests/CMakeLists.txt | 14 ++- tests/or_immediate_tests.cpp | 168 +++++++++++++++++++++++++++ 3 files changed, 376 insertions(+), 22 deletions(-) create mode 100644 tests/or_immediate_tests.cpp diff --git a/emulator/emulator.cpp b/emulator/emulator.cpp index ab3ec73..55989c0 100644 --- a/emulator/emulator.cpp +++ b/emulator/emulator.cpp @@ -4,8 +4,8 @@ module; import profiler; // #endif // BUILD_PROFILER -#include #include +#include #include #include #include @@ -60,13 +60,10 @@ struct ProfileBook export namespace emulator { - class OpcodeNotSupported: public std::exception + class OpcodeNotSupported : public std::exception { public: - OpcodeNotSupported(std::string opcode) - : _error_msg{"opcode not supported: " + opcode} - { - } + OpcodeNotSupported(std::string opcode) : _error_msg{"opcode not supported: " + opcode} {} const char* what() const throw() override { @@ -573,24 +570,186 @@ Instruction branch_flag_value(bool emulator::Flags::*flag) }; } +// Logical operations +std::optional or_acc_immediate(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) + { + return std::nullopt; + } + + auto const value = program[cpu.reg.pc + 1]; + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + return std::make_optional(2); +} + +std::optional or_acc_zeropage(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) + { + return std::nullopt; + } + + auto const offset = program[cpu.reg.pc + 1]; + auto const value = cpu.mem[offset]; + + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + return std::make_optional(2); +} + +std::optional or_acc_zeropage_x(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) + { + return std::nullopt; + } + + auto const zp_offset = program[cpu.reg.pc + 1]; + auto const offset = static_cast(zp_offset + cpu.reg.x); + auto const value = cpu.mem[offset]; + + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + return std::make_optional(2); +} + +std::optional or_acc_absolute(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 2) >= program.size()) + { + return std::nullopt; + } + + // (hsb << 8) + lsb convert little endian to the address + auto const lsb = program[cpu.reg.pc + 1]; + auto const hsb = program[cpu.reg.pc + 2]; + auto const addr = static_cast((hsb << 8) | lsb); + + auto const value = cpu.mem[addr]; + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + + return std::make_optional(3); +} + +// TODO : merge this with the abs y function, same code +std::optional or_acc_absolute_x(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 2) >= program.size()) + { + return std::nullopt; + } + + // (hsb << 8) + lsb convert little endian to the address + auto const lsb = program[cpu.reg.pc + 1]; + auto const hsb = program[cpu.reg.pc + 2]; + auto const abs_addr = static_cast((hsb << 8) | lsb); + auto const addr = static_cast(abs_addr + cpu.reg.x); + // TOOD : add 1 to cycle if this addr crosses page boundary + + auto const value = cpu.mem[addr]; + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + + return std::make_optional(3); +} + +// TODO : merge this with the abs x function, same code +std::optional or_acc_absolute_y(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 2) >= program.size()) + { + return std::nullopt; + } + + // (hsb << 8) + lsb convert little endian to the address + auto const lsb = program[cpu.reg.pc + 1]; + auto const hsb = program[cpu.reg.pc + 2]; + auto const abs_addr = static_cast((hsb << 8) | lsb); + auto const addr = static_cast(abs_addr + cpu.reg.y); + // TOOD : add 1 to cycle if this addr crosses page boundary + + auto const value = cpu.mem[addr]; + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + + return std::make_optional(3); +} + +std::optional or_acc_index_indirect(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) + { + return std::nullopt; + } + + // (hsb << 8) + lsb convert little endian to the address + auto const zp_addr = static_cast(program[cpu.reg.pc + 1] + cpu.reg.x); + + auto const lsb = cpu.mem[static_cast(zp_addr + 1)]; + auto const hsb = cpu.mem[static_cast(zp_addr + 2)]; + auto const abs_addr = static_cast((hsb << 8) | lsb); + + auto const value = cpu.mem[abs_addr]; + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + + return std::make_optional(2); +} + +std::optional or_acc_indirect_index(emulator::Cpu& cpu, std::span program) +{ + ENABLE_PROFILER(cpu); + if ((cpu.reg.pc + 1) >= program.size()) + { + return std::nullopt; + } + + auto const zp_addr = program[cpu.reg.pc + 1]; + auto const lsb = cpu.mem[static_cast(zp_addr + 1)]; + auto const hsb = cpu.mem[static_cast(zp_addr + 2)]; + auto const abs_addr = static_cast(((hsb << 8) | lsb) + cpu.reg.y); + + auto const value = cpu.mem[abs_addr]; + cpu.reg.a = cpu.reg.a | value; + cpu.flags.n = 0b1000'0000 & cpu.reg.a; + cpu.flags.z = !static_cast(cpu.reg.a); + + return std::make_optional(2); +} + // TODO : provide support for counting the number of cycles passed // from the start of the program -std::array get_instructions(emulator::Cpu& cpu) +std::array get_instructions() { - ENABLE_PROFILER(cpu); // Byte key indicates which function we need to call // to handle the specific instruction -// using Instruction = std::function(emulator::Cpu&, std::span)>; + // using Instruction = std::function(emulator::Cpu&, std::span)>; std::array supported_instructions{}; for (std::size_t i = 0; i < supported_instructions.size(); ++i) { - supported_instructions[i] = [=](emulator::Cpu&, std::span) -> std::optional{ - throw emulator::OpcodeNotSupported(fmt::format("{0:#x}", i)); - }; + supported_instructions[i] = [=](emulator::Cpu&, std::span) -> std::optional + { throw emulator::OpcodeNotSupported(fmt::format("{0:#x}", i)); }; } // make sure that all default elemets of supported_instructions // are functions that will raise an error - + // Supported instructions supported_instructions[0x00] = [](emulator::Cpu&, std::span) { return std::nullopt; }; supported_instructions[0x8a] = transfer_regs(&emulator::Registers::x, &emulator::Registers::a); @@ -599,6 +758,7 @@ std::array get_instructions(emulator::Cpu& cpu) supported_instructions[0xaa] = transfer_regs(&emulator::Registers::a, &emulator::Registers::x); supported_instructions[0xba] = transfer_regs(&emulator::Registers::sp, &emulator::Registers::x); supported_instructions[0x9a] = txa; + supported_instructions[0x85] = st_zeropage(&emulator::Registers::a); supported_instructions[0x8d] = st_absolute(&emulator::Registers::a); supported_instructions[0x91] = st_indirect(&emulator::Registers::a, &emulator::Registers::y); @@ -606,6 +766,7 @@ std::array get_instructions(emulator::Cpu& cpu) supported_instructions[0x8e] = st_absolute(&emulator::Registers::x); supported_instructions[0x84] = st_zeropage(&emulator::Registers::y); supported_instructions[0x8c] = st_absolute(&emulator::Registers::y); + supported_instructions[0xa9] = ld_immediate(&emulator::Registers::a); supported_instructions[0xa5] = ld_zeropage(&emulator::Registers::a); supported_instructions[0xb5] = ld_zeropage_plus_reg(&emulator::Registers::a, &emulator::Registers::x); @@ -624,9 +785,17 @@ std::array get_instructions(emulator::Cpu& cpu) supported_instructions[0xb4] = ld_zeropage_plus_reg(&emulator::Registers::y, &emulator::Registers::x); supported_instructions[0xbc] = ld_absolute_plus_reg(&emulator::Registers::y, &emulator::Registers::x); supported_instructions[0xac] = ld_absolute(&emulator::Registers::y); + + // This is the immediate mode compares to registers + supported_instructions[0xc9] = cmp_immediate_reg(&emulator::Registers::a); // TODO : test supported_instructions[0xc0] = cmp_immediate_reg(&emulator::Registers::y); - supported_instructions[0xc5] = cmp_zeropage_reg(&emulator::Registers::a); supported_instructions[0xe0] = cmp_immediate_reg(&emulator::Registers::x); + + // TODO : support for compare zeropage simple + supported_instructions[0xc5] = cmp_zeropage_reg(&emulator::Registers::a); + supported_instructions[0xe4] = cmp_zeropage_reg(&emulator::Registers::x); // TODO : test + supported_instructions[0xc4] = cmp_zeropage_reg(&emulator::Registers::y); // TODO : test + supported_instructions[0xf0] = branch_flag_value(&emulator::Flags::z); supported_instructions[0xd0] = branch_flag_value(&emulator::Flags::z); supported_instructions[0x30] = branch_flag_value(&emulator::Flags::n); @@ -635,16 +804,28 @@ std::array get_instructions(emulator::Cpu& cpu) supported_instructions[0x90] = branch_flag_value(&emulator::Flags::c); supported_instructions[0x70] = branch_flag_value(&emulator::Flags::v); supported_instructions[0x50] = branch_flag_value(&emulator::Flags::v); + supported_instructions[0xe6] = inc_zeropage; supported_instructions[0xf6] = inc_zeropage_plus_x; supported_instructions[0xee] = inc_absolute; supported_instructions[0xfe] = inc_absolute_plus_x; supported_instructions[0xc8] = inc_reg(&emulator::Registers::y); supported_instructions[0xe8] = inc_reg(&emulator::Registers::x); + supported_instructions[0xc6] = dec_zeropage; supported_instructions[0x88] = dec_reg(&emulator::Registers::y); supported_instructions[0xca] = dec_reg(&emulator::Registers::x); + // Logical operators + supported_instructions[0x05] = or_acc_zeropage; + supported_instructions[0x09] = or_acc_immediate; + supported_instructions[0x15] = or_acc_immediate; + supported_instructions[0x0d] = or_acc_absolute; + supported_instructions[0x1d] = or_acc_absolute_x; + supported_instructions[0x19] = or_acc_absolute_y; + supported_instructions[0x01] = or_acc_index_indirect; + supported_instructions[0x11] = or_acc_indirect_index; + return supported_instructions; } @@ -660,9 +841,9 @@ std::optional execute_next(emulator::Cpu& cpu, std::span execute_next(emulator::Cpu& cpu, std::span + +#include +#include + + +// NOLINTNEXTLINE +TEST(ORATests, NoFlagOperations) +{ + // test_case = {init acc, immediate value} + std::array, 3> const test_cases{{ + {0b0101'0101, 0b0010'1010}, + {0b0101'0101, 0b0101'0101}, + {0b0111'1111, 0b0000'0000}, + }}; + + for (auto const& [init_acc, im_value] : test_cases) + { + emulator::Cpu cpu; + cpu.reg.a = init_acc; + + std::array program{ + 0x09, + im_value, + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, init_acc | im_value); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_EQ(cpu.flags, make_flags(0b0000'0000)); + } +} + +// NOLINTNEXTLINE +TEST(ORATests, NegativeFlagOperation) +{ + // test_case = {init acc, immediate value} + std::array, 6> const test_cases{{ + {0b1000'0000, 0b0010'1010}, + {0b1000'0000, 0b0101'0101}, + {0b1000'0000, 0b0000'0000}, + {0b0010'1010, 0b1000'0000}, + {0b0101'0101, 0b1000'0000}, + {0b0000'0000, 0b1000'0000}, + }}; + + for (auto const& [init_acc, im_value] : test_cases) + { + emulator::Cpu cpu; + cpu.reg.a = init_acc; + + std::array program{ + 0x09, + im_value, + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, init_acc | im_value); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_EQ(cpu.flags, make_flags(0b1000'0000)); + } +} + +// NOLINTNEXTLINE +TEST(ORATests, ZeroFlagOperation) +{ + emulator::Cpu cpu; + cpu.reg.a = 0x00; + + std::array program{ + 0x09, + 0x00, + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, 0x00); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_EQ(cpu.flags, make_flags(0b0000'0010)); +} + +// NOLINTNEXTLINE +TEST(ORATests, MakeSureFlagsAreSound) +{ + // Weird testcase, we should never have both Z and N + // flags set + + for (std::int16_t acc = 0; acc < 256; ++acc) + { + for (std::int16_t val = 0; val < 256; ++val) + { + emulator::Cpu cpu; + cpu.reg.a = static_cast(acc); + + std::array program{ + 0x09, + static_cast(val), + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, val | acc); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_FALSE(cpu.flags.v); + ASSERT_FALSE(cpu.flags.b); + ASSERT_FALSE(cpu.flags.d); + ASSERT_FALSE(cpu.flags.i); + ASSERT_FALSE(cpu.flags.c); + + if (cpu.flags.z) + { + ASSERT_FALSE(cpu.flags.n); + } + if (cpu.flags.n) + { + ASSERT_FALSE(cpu.flags.z); + } + } + } +} + + + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 165341d0271d0ca57044d82bf94201d108beccef Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Wed, 28 Aug 2024 21:50:51 +0100 Subject: [PATCH 6/7] Adding zeropage tests --- emulator/emulator.cpp | 19 ++ tests/CMakeLists.txt | 5 +- ...iate_tests.cpp => ora_immediate_tests.cpp} | 10 +- tests/ora_zeropage_tests.cpp | 171 ++++++++++++++++++ 4 files changed, 196 insertions(+), 9 deletions(-) rename tests/{or_immediate_tests.cpp => ora_immediate_tests.cpp} (95%) create mode 100644 tests/ora_zeropage_tests.cpp diff --git a/emulator/emulator.cpp b/emulator/emulator.cpp index 55989c0..50f3ae1 100644 --- a/emulator/emulator.cpp +++ b/emulator/emulator.cpp @@ -114,6 +114,25 @@ export namespace emulator // Clock speed for this particular CPU double clock_speed = CLOCK_SPEED_MHZ; + +#ifdef BUILD_PROFILER + // If profiling is enabled, create space for a bookeper + std::shared_ptr profiler_book{std::make_shared()}; + + std::unordered_map current_profile() + { + if (!profiler_book) + { + return {}; + } + return profiler_book->functions; + } +#else + std::unordered_map current_profile() + { + return {}; + } +#endif // BUILD_PROFILER }; } // namespace emulator diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cb9c282..a3c3926 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,10 +17,8 @@ function(create_tests cpp_file_name) add_test(NAME ${cpp_file_name} COMMAND ${cpp_file_name}) gtest_discover_tests(${cpp_file_name}) - endfunction() - create_tests(branch_tests) create_tests(emulator_tests) create_tests(increment_tests) @@ -30,5 +28,6 @@ create_tests(ld_immediate_tests) create_tests(ld_index_indirect_tests) create_tests(ld_indirect_indexed_tests) create_tests(ld_zeropage_tests) -create_tests(or_immediate_tests) +create_tests(ora_immediate_tests) +create_tests(ora_zeropage_tests) create_tests(tx_tests) diff --git a/tests/or_immediate_tests.cpp b/tests/ora_immediate_tests.cpp similarity index 95% rename from tests/or_immediate_tests.cpp rename to tests/ora_immediate_tests.cpp index 370f723..31c4e06 100644 --- a/tests/or_immediate_tests.cpp +++ b/tests/ora_immediate_tests.cpp @@ -23,7 +23,7 @@ import emulator; // NOLINTNEXTLINE -TEST(ORATests, NoFlagOperations) +TEST(ORAImmediateTests, NoFlagOperations) { // test_case = {init acc, immediate value} std::array, 3> const test_cases{{ @@ -56,7 +56,7 @@ TEST(ORATests, NoFlagOperations) } // NOLINTNEXTLINE -TEST(ORATests, NegativeFlagOperation) +TEST(ORAImmediateTests, NegativeFlagOperation) { // test_case = {init acc, immediate value} std::array, 6> const test_cases{{ @@ -92,7 +92,7 @@ TEST(ORATests, NegativeFlagOperation) } // NOLINTNEXTLINE -TEST(ORATests, ZeroFlagOperation) +TEST(ORAImmediateTests, ZeroFlagOperation) { emulator::Cpu cpu; cpu.reg.a = 0x00; @@ -115,7 +115,7 @@ TEST(ORATests, ZeroFlagOperation) } // NOLINTNEXTLINE -TEST(ORATests, MakeSureFlagsAreSound) +TEST(ORAImmediateTests, MakeSureFlagsAreSound) { // Weird testcase, we should never have both Z and N // flags set @@ -159,8 +159,6 @@ TEST(ORATests, MakeSureFlagsAreSound) } } - - int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); diff --git a/tests/ora_zeropage_tests.cpp b/tests/ora_zeropage_tests.cpp new file mode 100644 index 0000000..77aa03d --- /dev/null +++ b/tests/ora_zeropage_tests.cpp @@ -0,0 +1,171 @@ +/* +This tests will check that the behaviour of the +"ORA" zeropage opcode 0x05 + +This instructions will OR the value at the +zeropage location given to the program to +the accumulator, then store the result in +the accumulator. + +This sets the N and Z flags depending on the value +left in the accumulator. + +This instruction takes exactly two cycles. +*/ + +import emulator; + +#include "common.h" + +#include + +#include +#include + + +// NOLINTNEXTLINE +TEST(ORAZeropageTests, NoFlagOperations) +{ + // test_case = {init acc, value, zp address} + std::array, 3> const test_cases{{ + {0b0101'0101, 0b0010'1010, 0x00}, + {0b0101'0101, 0b0101'0101, 0x88}, + {0b0111'1111, 0b0000'0000, 0xff}, + }}; + + for (auto const& [init_acc, value, address] : test_cases) + { + emulator::Cpu cpu; + cpu.reg.a = init_acc; + cpu.mem[static_cast(address)] = value; + + std::array program{ + 0x05, + static_cast(address), + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, init_acc | value); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_EQ(cpu.flags, make_flags(0b0000'0000)); + } +} + +// NOLINTNEXTLINE +TEST(ORAZeropageTests, NegativeFlagOperation) +{ + // test_case = {init acc, value, zp address} + std::array, 6> const test_cases{{ + {0b1000'0000, 0b0010'1010, 0x00}, + {0b1000'0000, 0b0101'0101, 0x88}, + {0b1000'0000, 0b0000'0000, 0xFF}, + {0b0010'1010, 0b1000'0000, 0x00}, + {0b0101'0101, 0b1000'0000, 0x88}, + {0b0000'0000, 0b1000'0000, 0xff}, + }}; + + for (auto const& [acc, value, address] : test_cases) + { + emulator::Cpu cpu; + cpu.reg.a = acc; + cpu.mem[static_cast(address)] = value; + + std::array program{ + 0x05, + static_cast(address), + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, acc | value); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_EQ(cpu.flags, make_flags(0b1000'0000)); + } +} + +// NOLINTNEXTLINE +TEST(ORAZeropageTests, ZeroFlagOperation) +{ + emulator::Cpu cpu; + cpu.reg.a = 0x00; + cpu.mem[0x88] = 0x00; + + std::array program{ + 0x05, + 0x88, + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, 0x00); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_EQ(cpu.flags, make_flags(0b0000'0010)); +} + +// NOLINTNEXTLINE +TEST(ORAZeropageTests, MakeSureFlagsAreSound) +{ + // Weird testcase, we should never have both Z and N + // flags set + + for (std::int16_t acc = 0; acc < 256; ++acc) + { + for (std::int16_t val = 0; val < 256; ++val) + { + emulator::Cpu cpu; + cpu.reg.a = static_cast(acc); + cpu.mem[0x88] = static_cast(val); + + std::array program{ + 0x05, + 0x88, + }; + emulator::execute(cpu, program); + + // Registry expect + ASSERT_EQ(cpu.reg.a, val | acc); + ASSERT_EQ(cpu.reg.x, 0x00); + ASSERT_EQ(cpu.reg.y, 0x00); + ASSERT_EQ(cpu.reg.sp, 0x00); + ASSERT_EQ(cpu.reg.pc, 0x02); + + // Flags expect + ASSERT_FALSE(cpu.flags.v); + ASSERT_FALSE(cpu.flags.b); + ASSERT_FALSE(cpu.flags.d); + ASSERT_FALSE(cpu.flags.i); + ASSERT_FALSE(cpu.flags.c); + + if (cpu.flags.z) + { + ASSERT_FALSE(cpu.flags.n); + } + if (cpu.flags.n) + { + ASSERT_FALSE(cpu.flags.z); + } + } + } +} + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From b1024aeb4393331e7756bfcc168ec15ba4952bfb Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Thu, 29 Aug 2024 21:58:37 +0100 Subject: [PATCH 7/7] Adding tests for the program size checks --- emulator/emulator.cpp | 4 +- emulator_app/main.cpp | 5 +- tests/CMakeLists.txt | 1 + tests/branch_tests.cpp | 34 ++--- tests/emulator_tests.cpp | 14 +- tests/increment_tests.cpp | 36 ++--- tests/ld_absolute_indexed_tests.cpp | 24 ++-- tests/ld_absolute_tests.cpp | 18 +-- tests/ld_immediate_tests.cpp | 18 +-- tests/ld_index_indirect_tests.cpp | 8 +- tests/ld_indirect_indexed_tests.cpp | 6 +- tests/ld_zeropage_tests.cpp | 18 +-- tests/ora_immediate_tests.cpp | 8 +- tests/ora_zeropage_tests.cpp | 10 +- tests/program_size_tests.cpp | 198 ++++++++++++++++++++++++++++ tests/tx_tests.cpp | 32 ++--- 16 files changed, 318 insertions(+), 116 deletions(-) create mode 100644 tests/program_size_tests.cpp diff --git a/emulator/emulator.cpp b/emulator/emulator.cpp index 50f3ae1..4f408a1 100644 --- a/emulator/emulator.cpp +++ b/emulator/emulator.cpp @@ -878,7 +878,7 @@ std::optional execute_next(emulator::Cpu& cpu, std::span program) + [[nodiscard]] std::optional execute(Cpu& cpu, std::span program) { std::size_t n_cycles = 0; ENABLE_PROFILER(cpu); @@ -889,7 +889,7 @@ export namespace emulator auto maybe_increment = execute_next(cpu, program, instructions); if (!maybe_increment) { - return false; + return std::nullopt; } cpu.reg.pc += maybe_increment->bytes; diff --git a/emulator_app/main.cpp b/emulator_app/main.cpp index 60c05be..d1d4dae 100644 --- a/emulator_app/main.cpp +++ b/emulator_app/main.cpp @@ -81,7 +81,10 @@ int main(int argc, char** argv) std::vector program_contents{(std::istreambuf_iterator(file)), std::istreambuf_iterator()}; - emulator::execute(easy65k, {reinterpret_cast(program_contents.data()), program_contents.size()}); + if (!emulator::execute(easy65k, {reinterpret_cast(program_contents.data()), program_contents.size()})) + { + std::cout << std::format("failed to execute the program\n"); + } for (auto const& [function, profile] : easy65k.current_profile()) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a3c3926..48fd2de 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,4 +30,5 @@ create_tests(ld_indirect_indexed_tests) create_tests(ld_zeropage_tests) create_tests(ora_immediate_tests) create_tests(ora_zeropage_tests) +create_tests(program_size_tests) create_tests(tx_tests) diff --git a/tests/branch_tests.cpp b/tests/branch_tests.cpp index c413289..f06afc6 100644 --- a/tests/branch_tests.cpp +++ b/tests/branch_tests.cpp @@ -51,7 +51,7 @@ TEST(BranchingTests, BranchOnCarrySetWhenUnset) emulator::Cpu cpu; cpu.flags.c = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -82,7 +82,7 @@ TEST(BranchingTests, BranchOnCarrySetWhenSet) emulator::Cpu cpu; cpu.flags.c = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -113,7 +113,7 @@ TEST(BranchingTests, BranchOnCarryClearWhenSet) emulator::Cpu cpu; cpu.flags.c = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -144,7 +144,7 @@ TEST(BranchingTests, BranchOnCarryClearWhenUnset) emulator::Cpu cpu; cpu.flags.c = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -175,7 +175,7 @@ TEST(BranchingTests, BranchOnZeroSetWhenUnset) emulator::Cpu cpu; cpu.flags.z = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -198,7 +198,7 @@ TEST(BranchingTests, BranchOnZeroSetWhenSet) {{0xf0, 0x00}, 0x02}, {{0xf0, 0x01}, 0x03}, {{0xf0, 0x0a}, 0x0c}, - {{0xf0, 0xff}, 0x01}, + // {{0xf0, 0xff}, 0x01}, - bad test: jump is not valid }}; for (auto& [program, expected_pc] : programs) @@ -206,7 +206,7 @@ TEST(BranchingTests, BranchOnZeroSetWhenSet) emulator::Cpu cpu; cpu.flags.z = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -237,7 +237,7 @@ TEST(BranchingTests, BranchOnZeroClearWhenSet) emulator::Cpu cpu; cpu.flags.z = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -268,7 +268,7 @@ TEST(BranchingTests, BranchOnZeroClearWhenUnset) emulator::Cpu cpu; cpu.flags.z = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -299,7 +299,7 @@ TEST(BranchingTests, BranchOnNegativeSetWhenUnset) emulator::Cpu cpu; cpu.flags.n = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -330,7 +330,7 @@ TEST(BranchingTests, BranchOnNegativeSetWhenSet) emulator::Cpu cpu; cpu.flags.n = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -361,7 +361,7 @@ TEST(BranchingTests, BranchOnNegativeClearWhenSet) emulator::Cpu cpu; cpu.flags.n = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -392,7 +392,7 @@ TEST(BranchingTests, BranchOnNegativeClearWhenUnset) emulator::Cpu cpu; cpu.flags.n = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -423,7 +423,7 @@ TEST(BranchingTests, BranchOnOverflowSetWhenUnset) emulator::Cpu cpu; cpu.flags.n = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -454,7 +454,7 @@ TEST(BranchingTests, BranchOnOverflowSetWhenSet) emulator::Cpu cpu; cpu.flags.v = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -485,7 +485,7 @@ TEST(BranchingTests, BranchOnOverflowClearWhenSet) emulator::Cpu cpu; cpu.flags.v = true; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -516,7 +516,7 @@ TEST(BranchingTests, BranchOnOverflowClearWhenUnset) emulator::Cpu cpu; cpu.flags.v = false; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); diff --git a/tests/emulator_tests.cpp b/tests/emulator_tests.cpp index 15fe1fa..a7d6ab8 100644 --- a/tests/emulator_tests.cpp +++ b/tests/emulator_tests.cpp @@ -17,7 +17,7 @@ TEST(EmulatorTests, EmulateInxNoFlag) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.x, program[1] + 1); ASSERT_EQ(cpu.reg.sp, 0x00); @@ -37,7 +37,7 @@ TEST(EmulatorTests, EmulateInyNoFlag) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.y, program[1] + 1); ASSERT_EQ(cpu.reg.sp, 0x00); @@ -59,7 +59,7 @@ TEST(EmulatorTests, EmulateDexNoFlag) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.x, program[1] - 1); ASSERT_EQ(cpu.reg.sp, 0x00); @@ -79,7 +79,7 @@ TEST(EmulatorTests, EmulateDeyNoFlag) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.y, program[1] - 1); ASSERT_EQ(cpu.reg.sp, 0x00); @@ -101,7 +101,7 @@ TEST(EmulatorTests, EmulateCpxXGreaterThanValue) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.x, program[1]); ASSERT_EQ(cpu.reg.sp, 0x00); @@ -127,7 +127,7 @@ TEST(EmulatorTests, EmulateCpxSameValues) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.x, program[1]); ASSERT_EQ(cpu.reg.sp, 0x00); @@ -152,7 +152,7 @@ TEST(EmulatorTests, EmulateCpxSetCarry) for (auto const& program : programs) { emulator::Cpu cpu; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.x, program[1]); ASSERT_EQ(cpu.reg.sp, 0x00); diff --git a/tests/increment_tests.cpp b/tests/increment_tests.cpp index ba758b1..e153615 100644 --- a/tests/increment_tests.cpp +++ b/tests/increment_tests.cpp @@ -34,7 +34,7 @@ TEST(IncrementTests, INXNoFlags) { emulator::Cpu cpu; cpu.reg.x = init_x; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, init_x + 1); @@ -62,7 +62,7 @@ TEST(IncrementTests, INYNoFlags) { emulator::Cpu cpu; cpu.reg.y = init_y; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -91,7 +91,7 @@ TEST(IncrementTests, INCZeropageNoFlags) emulator::Cpu cpu; // TODO : Set the memory to init cpu.mem[init_v] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -123,7 +123,7 @@ TEST(IncrementTests, INCZeropagePlusXNoFlags) cpu.reg.x = 0x0a; std::uint8_t const pos = cpu.reg.x + program[1]; cpu.mem[pos] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x0a); @@ -157,7 +157,7 @@ TEST(IncrementTests, INCAbsoluteNoFlags) std::uint16_t pos = (hsb << 8) | lsb; cpu.mem[pos] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -192,7 +192,7 @@ TEST(IncrementTests, INCAbsolutePluxXNoFlags) std::uint16_t pos = (hsb << 8) | lsb + cpu.reg.x; cpu.mem[pos] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x0a); @@ -212,7 +212,7 @@ TEST(IncrementTests, INXZeroFlag) emulator::Cpu cpu; cpu.reg.x = 0xff; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -230,7 +230,7 @@ TEST(IncrementTests, INYZeroFlag) emulator::Cpu cpu; cpu.reg.y = 0xff; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -248,7 +248,7 @@ TEST(IncrementTests, INCZeropageZeroFlag) emulator::Cpu cpu; cpu.mem[0x0a] = 0xff; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -268,7 +268,7 @@ TEST(IncrementTests, INCZeropagePluxXZeroFlag) emulator::Cpu cpu; cpu.reg.x = 0x0a; cpu.mem[0x14] = 0xff; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x0a); @@ -292,7 +292,7 @@ TEST(IncrementTests, INCAbsoluteZeroFlag) std::uint16_t const pos = ((hsb << 8) | lsb); cpu.mem[pos] = 0xff; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -317,7 +317,7 @@ TEST(IncrementTests, INCAbsolutePluxXZeroFlag) std::uint16_t const pos = ((hsb << 8) | lsb) + cpu.reg.x; cpu.mem[pos] = 0xff; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x0a); @@ -350,7 +350,7 @@ TEST(IncrementTests, INXNegativeFlag) { emulator::Cpu cpu; cpu.reg.x = init_x; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, init_x + 1); @@ -382,7 +382,7 @@ TEST(IncrementTests, INYNegativeFlag) { emulator::Cpu cpu; cpu.reg.y = init_y; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -416,7 +416,7 @@ TEST(IncrementTests, INCZeropageNegativeFlag) { emulator::Cpu cpu; cpu.mem[init_v] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -455,7 +455,7 @@ TEST(IncrementTests, INCZeropagePlusXNegativeFlag) cpu.mem[pos] = init_v; cpu.reg.x = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, init_v); @@ -495,7 +495,7 @@ TEST(IncrementTests, INCAbsoluteNegativeFlag) std::uint16_t const pos = (hsb << 8) | lsb; cpu.mem[pos] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -536,7 +536,7 @@ TEST(IncrementTests, INCAbsolutePluxXNegativeFlag) std::uint16_t const pos = (hsb << 8) | lsb + cpu.reg.x; cpu.mem[pos] = init_v; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x0a); diff --git a/tests/ld_absolute_indexed_tests.cpp b/tests/ld_absolute_indexed_tests.cpp index 73716f1..9d26c66 100644 --- a/tests/ld_absolute_indexed_tests.cpp +++ b/tests/ld_absolute_indexed_tests.cpp @@ -40,7 +40,7 @@ TEST(LDTests, LDAAbsolutePlusXNonZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); @@ -70,7 +70,7 @@ TEST(LDTests, LDAAbsolutePlusYNonZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); @@ -100,7 +100,7 @@ TEST(LDTests, LDXAbsolutePlusYNonZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -130,7 +130,7 @@ TEST(LDTests, LDYAbsolutePlusXNonZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -161,7 +161,7 @@ TEST(LDTests, LDAAbsolutePlusXWithZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -192,7 +192,7 @@ TEST(LDTests, LDAAbsolutePlusYWithZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -223,7 +223,7 @@ TEST(LDTests, LDXAbsolutePlusYWithZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -254,7 +254,7 @@ TEST(LDTests, LDYAbsolutePlusXWithZero) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -281,7 +281,7 @@ TEST(LDTests, LDAAbsolutePlusXWithNegative) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0xFF); @@ -308,7 +308,7 @@ TEST(LDTests, LDAAbsolutePlusYWithNegative) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0xFF); @@ -335,7 +335,7 @@ TEST(LDTests, LDXAbsolutePlusYWithNegative) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -362,7 +362,7 @@ TEST(LDTests, LDYAbsolutePlusXWithNegative) 0xed, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); diff --git a/tests/ld_absolute_tests.cpp b/tests/ld_absolute_tests.cpp index 115e3b7..4499986 100644 --- a/tests/ld_absolute_tests.cpp +++ b/tests/ld_absolute_tests.cpp @@ -36,7 +36,7 @@ TEST(LDTests, LDAAbsoluteNonZero) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); @@ -61,7 +61,7 @@ TEST(LDTests, LDXAbsoluteNonZero) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -86,7 +86,7 @@ TEST(LDTests, LDYAbsoluteNonZero) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -111,7 +111,7 @@ TEST(LDTests, LDAAbsoluteWithZero) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -136,7 +136,7 @@ TEST(LDTests, LDXAbsoluteWithZero) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -161,7 +161,7 @@ TEST(LDTests, LDYAbsoluteWithZero) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -186,7 +186,7 @@ TEST(LDTests, LDAAbsoluteWithNegative) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0xFF); @@ -211,7 +211,7 @@ TEST(LDTests, LDXAbsoluteWithNegative) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -236,7 +236,7 @@ TEST(LDTests, LDYAbsoluteWithNegative) 0x00, 0x02, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); diff --git a/tests/ld_immediate_tests.cpp b/tests/ld_immediate_tests.cpp index 66f7f6a..f196e33 100644 --- a/tests/ld_immediate_tests.cpp +++ b/tests/ld_immediate_tests.cpp @@ -29,7 +29,7 @@ TEST(LDTests, LdAImmediateWithNonZero) 0x0a, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x0a); @@ -54,7 +54,7 @@ TEST(LDTests, LdAImmediateWithZero) 0x00, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -78,7 +78,7 @@ TEST(LDTests, LdAImmediateWithNegative) 0xFF, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0xFF); ASSERT_EQ(cpu.reg.x, 0x00); @@ -98,7 +98,7 @@ TEST(LDTests, LdXImmediateWithNonZero) 0x0a, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -119,7 +119,7 @@ TEST(LDTests, LdXImmediateWithZero) 0x00, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -139,7 +139,7 @@ TEST(LDTests, LdXImmediateWithNegative) 0xFF, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0xFF); @@ -160,7 +160,7 @@ TEST(LDTests, LdYImmediateWithNonZero) 0x0a, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -181,7 +181,7 @@ TEST(LDTests, LdYImmediateWithZero) 0x00, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -201,7 +201,7 @@ TEST(LDTests, LdYImmediateWithNegative) 0xFF, }; emulator::Cpu cpu; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); diff --git a/tests/ld_index_indirect_tests.cpp b/tests/ld_index_indirect_tests.cpp index 28c3d92..a9300ff 100644 --- a/tests/ld_index_indirect_tests.cpp +++ b/tests/ld_index_indirect_tests.cpp @@ -30,7 +30,7 @@ TEST(LDTests, LDAIndexIndirectXNonZero) 0xa1, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); @@ -58,7 +58,7 @@ TEST(LDTests, LDAIndexIndirectXWithZero) 0xa1, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -85,7 +85,7 @@ TEST(LDTests, LDAIndexIndirectXNegative) 0xa1, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0xff); @@ -115,7 +115,7 @@ TEST(LDTests, LDAIndexIndirectXNonZeroPosWrap) 0xa1, 0xee, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); diff --git a/tests/ld_indirect_indexed_tests.cpp b/tests/ld_indirect_indexed_tests.cpp index 6a192fb..ae454fc 100644 --- a/tests/ld_indirect_indexed_tests.cpp +++ b/tests/ld_indirect_indexed_tests.cpp @@ -32,7 +32,7 @@ TEST(LDTests, LDAIndirectIndexYNonZero) 0xb1, 0x58, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); @@ -61,7 +61,7 @@ TEST(LDTests, LDAIndirectIndexYWithZero) 0xb1, 0x58, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -89,7 +89,7 @@ TEST(LDTests, LDAIndirectIndexYWithNegative) 0xb1, 0x58, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0xff); diff --git a/tests/ld_zeropage_tests.cpp b/tests/ld_zeropage_tests.cpp index 1c805d4..fd31b67 100644 --- a/tests/ld_zeropage_tests.cpp +++ b/tests/ld_zeropage_tests.cpp @@ -31,7 +31,7 @@ TEST(LDTests, LDAZeropageWithNonZero) 0xa5, 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x5a); @@ -57,7 +57,7 @@ TEST(LDTests, LDAZeropageWithZero) 0xa5, 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -83,7 +83,7 @@ TEST(LDTests, LDAZeropageWithNegative) 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0xff); ASSERT_EQ(cpu.reg.x, 0x00); @@ -108,7 +108,7 @@ TEST(LDTests, LDXZeropageWithNonZero) 0xa6, 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -134,7 +134,7 @@ TEST(LDTests, LDXZeropageWithZero) 0xa6, 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -160,7 +160,7 @@ TEST(LDTests, LDXZeropageWithNegative) 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0xff); @@ -185,7 +185,7 @@ TEST(LDTests, LDYZeropageWithNonZero) 0xa4, 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -211,7 +211,7 @@ TEST(LDTests, LDYZeropageWithZero) 0xa4, 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -237,7 +237,7 @@ TEST(LDTests, LDYZeropageWithNegative) 0x22, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); diff --git a/tests/ora_immediate_tests.cpp b/tests/ora_immediate_tests.cpp index 31c4e06..142763d 100644 --- a/tests/ora_immediate_tests.cpp +++ b/tests/ora_immediate_tests.cpp @@ -41,7 +41,7 @@ TEST(ORAImmediateTests, NoFlagOperations) 0x09, im_value, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, init_acc | im_value); @@ -77,7 +77,7 @@ TEST(ORAImmediateTests, NegativeFlagOperation) 0x09, im_value, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, init_acc | im_value); @@ -101,7 +101,7 @@ TEST(ORAImmediateTests, ZeroFlagOperation) 0x09, 0x00, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -131,7 +131,7 @@ TEST(ORAImmediateTests, MakeSureFlagsAreSound) 0x09, static_cast(val), }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, val | acc); diff --git a/tests/ora_zeropage_tests.cpp b/tests/ora_zeropage_tests.cpp index 77aa03d..6f1650e 100644 --- a/tests/ora_zeropage_tests.cpp +++ b/tests/ora_zeropage_tests.cpp @@ -39,11 +39,11 @@ TEST(ORAZeropageTests, NoFlagOperations) cpu.reg.a = init_acc; cpu.mem[static_cast(address)] = value; - std::array program{ + std::array program{ 0x05, static_cast(address), }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, init_acc | value); @@ -80,7 +80,7 @@ TEST(ORAZeropageTests, NegativeFlagOperation) 0x05, static_cast(address), }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, acc | value); @@ -105,7 +105,7 @@ TEST(ORAZeropageTests, ZeroFlagOperation) 0x05, 0x88, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, 0x00); @@ -136,7 +136,7 @@ TEST(ORAZeropageTests, MakeSureFlagsAreSound) 0x05, 0x88, }; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); // Registry expect ASSERT_EQ(cpu.reg.a, val | acc); diff --git a/tests/program_size_tests.cpp b/tests/program_size_tests.cpp new file mode 100644 index 0000000..9561d8d --- /dev/null +++ b/tests/program_size_tests.cpp @@ -0,0 +1,198 @@ +/* +This test file will make sure that all branches +checking for program sizes are covered. + +Essentially, we are testing that, where the program +is malformed by not having enough argument bytes, we +fail. +*/ + +import emulator; + +#include "common.h" + +#include + +#include +#include + + +// NOLINTNEXTLINE +TEST(ProgramSizeTests, LdImmediateMalformed) +{ + std::array constexpr program{0xa9}; + emulator::Cpu cpu{}; + + ASSERT_FALSE(emulator::execute(cpu, program)); +} + +// 0xa5, LdZeropageMalformed +TEST(ProgramSizeTests, LdZeropageMalformed0) +{ + std::array constexpr program{0xa5}; + emulator::Cpu cpu{}; + + ASSERT_FALSE(emulator::execute(cpu, program)); +} + +// NOLINTNEXTLINE +TEST(ProgramSizeTests, LdZeropageMalformed1) +{ + std::array constexpr program{0xa6}; + emulator::Cpu cpu{}; + + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdZeropageMalformed2) +{ + std::array constexpr program{0xa4}; + emulator::Cpu cpu{}; + + ASSERT_FALSE(emulator::execute(cpu, program)); +} +// 0xb5, LdZeropagePlusRegMalformed +TEST(ProgramSizeTests, LdZeropagePlusRegMalformed0) +{ + std::array constexpr program{0xb6}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdZeropagePlusRegMalformed1) +{ + std::array constexpr program{0xb4}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsoluteMalformed0) +{ + std::array constexpr program{0xad}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsoluteMalformed1) +{ + std::array constexpr program{0xae}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsoluteMalformed2) +{ + std::array constexpr program{0xac}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsolutePlusRegMalformed0) +{ + std::array constexpr program{0xbd}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsolutePlusRegMalformed1) +{ + std::array constexpr program{0xb9}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsolutePlusRegMalformed2) +{ + std::array constexpr program{0xbe}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdAbsolutePlusRegMalformed3) +{ + std::array constexpr program{0xbc}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdindexIndirectMalformed) +{ + std::array constexpr program{0xa1}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, LdIndirectIndexMalformed) +{ + std::array constexpr program{0xb1}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, IncZeropageMalformed0) +{ + std::array constexpr program{0xe6}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, IncZeropageMalformed1) +{ + std::array constexpr program{0xf6}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, IncAbsoluteMalformed) +{ + std::array constexpr program{0x33}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, IncAbsolutePlusXmalformed) +{ + std::array constexpr program{0xf3}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, DecZeropageMalformed) +{ + std::array constexpr program{0xc6}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StIndirectMalformed) +{ + std::array constexpr program{0x91}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StZeroPageMalformed0) +{ + std::array constexpr program{0x84}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StZeroPageMalformed1) +{ + std::array constexpr program{0x85}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StZeroPageMalformed2) +{ + std::array constexpr program{0x86}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StAbsoluteMalformed0) +{ + std::array constexpr program{0x8c}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StAbsoluteMalformed1) +{ + std::array constexpr program{0x8d}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} +TEST(ProgramSizeTests, StAbsoluteMalformed22) +{ + std::array constexpr program{0x8e}; + emulator::Cpu cpu{}; + ASSERT_FALSE(emulator::execute(cpu, program)); +} + + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/tx_tests.cpp b/tests/tx_tests.cpp index cbf8a35..3b212ff 100644 --- a/tests/tx_tests.cpp +++ b/tests/tx_tests.cpp @@ -24,7 +24,7 @@ TEST(TXTests, TXANoFlags) { emulator::Cpu cpu; cpu.reg.x = init_x; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, init_x); ASSERT_EQ(cpu.reg.x, init_x); @@ -54,7 +54,7 @@ TEST(TXTests, TAXNoFlags) { emulator::Cpu cpu; cpu.reg.a = init_a; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, init_a); ASSERT_EQ(cpu.reg.x, init_a); @@ -84,7 +84,7 @@ TEST(TXTests, TAYNoFlags) { emulator::Cpu cpu; cpu.reg.a = init_a; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, init_a); ASSERT_EQ(cpu.reg.x, 0x00); @@ -114,7 +114,7 @@ TEST(TXTests, TSXNoFlags) { emulator::Cpu cpu; cpu.reg.sp = init_sp; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, init_sp); @@ -144,7 +144,7 @@ TEST(TXTests, TYANoFlags) { emulator::Cpu cpu; cpu.reg.y = init_y; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, init_y); ASSERT_EQ(cpu.reg.x, 0x00); @@ -177,7 +177,7 @@ TEST(TXTests, TXSNoFlags) { emulator::Cpu cpu; cpu.reg.x = init_x; - emulator::execute(cpu, {program.data(), program.size()}); + ASSERT_TRUE(emulator::execute(cpu, {program.data(), program.size()})); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, init_x); @@ -198,7 +198,7 @@ TEST(TXTests, TXAZeroFlag) emulator::Cpu cpu; cpu.reg.x = 0x00; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -219,7 +219,7 @@ TEST(TXTests, TAXZeroFlag) cpu.reg.a = 0x00; cpu.reg.x = 0xFF; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -241,7 +241,7 @@ TEST(TXTests, TAYZeroFlag) cpu.reg.a = 0x00; cpu.reg.y = 0xFF; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -263,7 +263,7 @@ TEST(TXTests, TSXZeroFlag) cpu.reg.sp = 0x00; cpu.reg.x = 0xFF; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -284,7 +284,7 @@ TEST(TXTests, TYAZeroFlag) emulator::Cpu cpu; cpu.reg.y = 0x00; cpu.reg.a = 0xFF; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, 0x00); @@ -316,7 +316,7 @@ TEST(TXTests, TXANegativeFlag) { emulator::Cpu cpu; cpu.reg.x = init_x; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, init_x); ASSERT_EQ(cpu.reg.x, init_x); @@ -346,7 +346,7 @@ TEST(TXTests, TAXNegativeFlag) { emulator::Cpu cpu; cpu.reg.a = init_a; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, init_a); ASSERT_EQ(cpu.reg.x, init_a); @@ -377,7 +377,7 @@ TEST(TXTests, TAYNegativeFlag) { emulator::Cpu cpu; cpu.reg.a = init_a; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, init_a); ASSERT_EQ(cpu.reg.x, 0); @@ -408,7 +408,7 @@ TEST(TXTests, TSXNegativeFlag) { emulator::Cpu cpu; cpu.reg.sp = init_sp; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, 0x00); ASSERT_EQ(cpu.reg.x, init_sp); @@ -440,7 +440,7 @@ TEST(TXTests, TYANegativeFlag) { emulator::Cpu cpu; cpu.reg.y = init_y; - emulator::execute(cpu, program); + ASSERT_TRUE(emulator::execute(cpu, program)); ASSERT_EQ(cpu.reg.a, init_y); ASSERT_EQ(cpu.reg.x, 0x00);