From 0a2ff5f2bf92428bd52106511ddc6700ba720ab5 Mon Sep 17 00:00:00 2001 From: scivision Date: Wed, 8 Jan 2025 12:34:01 -0500 Subject: [PATCH 1/2] implement CMake --- CMakeLists.txt | 32 ++++++++++++++++++++++++++++ README.md | 46 ++++++++++++++++++++++++++++++++++------ cmake/config.cmake | 8 +++++++ cmake/config.h.in | 14 ++++++++++++ src/CMakeLists.txt | 20 +++++++++++++++++ src/audio/CMakeLists.txt | 9 ++++++++ 6 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/config.cmake create mode 100644 cmake/config.h.in create mode 100644 src/CMakeLists.txt create mode 100644 src/audio/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f2ae366 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.15) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-source builds are not allowed.") +endif() + +if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED ENV{CMAKE_BUILD_TYPE}) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type") +endif() + +project(nes-tools +LANGUAGES C +VERSION 0.1 +HOMEPAGE_URL https://github.com/zeim839/nes-tools +) + +find_package(SDL2 REQUIRED) +find_package(SDL2_ttf REQUIRED) +message(STATUS "SDL2: ${SDL2_DIR} ${SDL2_ttf_DIR}") + +include(cmake/config.cmake) + +add_executable(nes-tools) + +add_subdirectory(src) + +target_include_directories(nes-tools PRIVATE src ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(nes-tools PRIVATE SDL2::SDL2 SDL2_ttf::SDL2_ttf $<$:m>) + +install(TARGETS nes-tools ) + +file(GENERATE OUTPUT .gitignore CONTENT "*") diff --git a/README.md b/README.md index 03d6be7..64ccf72 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,47 @@ Clone the repository https://github.com/zeim839/nes-tools.git ``` -Navigate to the project directory and run the configuration script +Navigate to the project directory ``` cd nes-tools +``` + +Build with either Autotools or CMake, then run the emulator: + +```sh +nes-tools help +``` + +### CMake + +```sh +cmake -Bbuild +``` + +if SDL2 or SDL2_ttf is not found, you can specify the path to the libraries using the following flags: + +```sh +cmake -Bbuild -DSDL2_ROOT=/path/to/SDL2 -DSDL2_ttf_ROOT=/path/to/SDL2_ttf +``` + +Build + +``` +cmake --build build +``` + +Optionally, install the executable + +```sh +cmake --install build +``` + + +### Autotools + +run the configuration script + +``` ./configure ``` @@ -29,12 +67,8 @@ Build and install make install ``` -Run the emulator -``` -nes-tools help -``` +Uninstall -### Uninstall ``` make uninstall ``` diff --git a/cmake/config.cmake b/cmake/config.cmake new file mode 100644 index 0000000..3e28df5 --- /dev/null +++ b/cmake/config.cmake @@ -0,0 +1,8 @@ +set(PACKAGE_NAME "nes-tools") +set(PACKAGE_STRING "nes-tools ${PROJECT_VERSION}") +set(PACKAGE_TARNAME "nes-tools") +set(PACKAGE_URL "${PROJECT_HOMEPAGE_URL}") +set(PACKAGE_VERSION "${PROJECT_VERSION}") + + +configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in config.h) diff --git a/cmake/config.h.in b/cmake/config.h.in new file mode 100644 index 0000000..adadf3b --- /dev/null +++ b/cmake/config.h.in @@ -0,0 +1,14 @@ +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" + +/* Define to the home page for this package. */ +#cmakedefine PACKAGE_URL "@PACKAGE_URL@" + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..42cef71 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,20 @@ +target_sources(nes-tools PRIVATE +bus.c +cpu6502.c +emulator.c +font.c +gfx.c +joypad.c +log.c +main.c +mapper.c +ppu.c +snapshot.c +timerx.c +) + +if(MSVC) + target_sources(nes-tools PRIVATE nanosleep.c) +endif() + +add_subdirectory(audio) diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt new file mode 100644 index 0000000..22c7af7 --- /dev/null +++ b/src/audio/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(nes-tools PRIVATE +apu.c +audio.c +biquad.c +dmc.c +noise.c +pulse.c +triangle.c +) From b5653f2d28d2d4fd306c65d9ea69257f181e68bd Mon Sep 17 00:00:00 2001 From: scivision Date: Wed, 8 Jan 2025 12:40:01 -0500 Subject: [PATCH 2/2] enable Visual Studio compilers --- src/nanosleep.c | 39 +++++++++++++++++++++++++++++++++++++++ src/nanosleep.h | 6 ++++++ src/system.h | 1 + src/timerx.c | 38 ++++++++++++++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/nanosleep.c create mode 100644 src/nanosleep.h diff --git a/src/nanosleep.c b/src/nanosleep.c new file mode 100644 index 0000000..0c04471 --- /dev/null +++ b/src/nanosleep.c @@ -0,0 +1,39 @@ +#define WIN32_LEAN_AND_MEAN +#include + +#include + +#include "nanosleep.h" + +#ifndef __has_c_attribute +#define __has_c_attribute(x) 0 +#endif + +#if __has_c_attribute(maybe_unused) +#define MAYBE_UNUSED [[maybe_unused]] +#else +#define MAYBE_UNUSED +#endif + +// https://stackoverflow.com/a/13397866 +int nanosleep(const struct timespec* ts, MAYBE_UNUSED struct timespec* rem){ + HANDLE timer = CreateWaitableTimer(NULL, TRUE, NULL); + if(!timer) + return -1; + // from QueryPerformanceFrequency, interval is 100ns ticks + LONGLONG interval = (LONGLONG)(ts->tv_sec * 1000000000L + ts->tv_nsec) / 100; + + LARGE_INTEGER delay; + delay.QuadPart = -interval; + if(!SetWaitableTimer(timer, &delay, 0, NULL, NULL, FALSE)){ + CloseHandle(timer); + return -1; + } + + DWORD ret = WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); + if (ret != WAIT_OBJECT_0) + return -1; + + return 0; +} diff --git a/src/nanosleep.h b/src/nanosleep.h new file mode 100644 index 0000000..56fd1ad --- /dev/null +++ b/src/nanosleep.h @@ -0,0 +1,6 @@ +#ifndef NES_TOOLS_NANOSLEEP_H +#define NES_TOOLS_NANOSLEEP_H + +int nanosleep(const struct timespec*, struct timespec*); + +#endif // NES_TOOLS_NANOSLEEP_H diff --git a/src/system.h b/src/system.h index dfe29df..d78bb4d 100644 --- a/src/system.h +++ b/src/system.h @@ -14,6 +14,7 @@ #include #include #include +#include // for memset() #include #include "log.h" diff --git a/src/timerx.c b/src/timerx.c index e38c96d..eb18a76 100644 --- a/src/timerx.c +++ b/src/timerx.c @@ -1,16 +1,31 @@ #include "timerx.h" -#define G 1000000000L +#if defined(_MSC_VER) +#define WIN32_LEAN_AND_MEAN +#include +#include "nanosleep.h" +#endif + +#define G 1000000000LL #define M 1000000L timerx_t timerx_create(uint64_t period) { struct timespec res; +#ifdef _MSC_VER + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + timerx_t timer = { + .period_ns = period, + .clock_res = (uint64_t)(G / freq.QuadPart) + }; +#else clock_getres(CLOCK_MONOTONIC, &res); timerx_t timer = { .period_ns = period, .clock_res = res.tv_sec * G + res.tv_nsec }; +#endif return timer; } @@ -21,17 +36,33 @@ static inline void timespec_diff result->tv_nsec = a->tv_nsec - b->tv_nsec; if (result->tv_nsec < 0) { --result->tv_sec; - result->tv_nsec += 1000000000L; + result->tv_nsec += G; } } void timerx_mark_start(timerx_t* timer) -{ clock_gettime(CLOCK_MONOTONIC, &timer->start); } +{ +#if defined(_MSC_VER) + LARGE_INTEGER us; + QueryPerformanceCounter(&us); + timer->start.tv_sec = us.QuadPart / 100000 / timer->clock_res; + timer->start.tv_nsec = (us.QuadPart / 100000 % timer->clock_res) * 100000 * timer->clock_res; +#else + clock_gettime(CLOCK_MONOTONIC, &timer->start); +#endif +} void timerx_mark_end(timerx_t* timer) { struct timespec end; +#if defined(_MSC_VER) + LARGE_INTEGER us; + QueryPerformanceCounter(&us); + end.tv_sec = us.QuadPart / 100000 / timer->clock_res; + end.tv_nsec = (us.QuadPart / 100000 % timer->clock_res) * 100000 * timer->clock_res; +#else clock_gettime(CLOCK_MONOTONIC, &end); +#endif timespec_diff(&end, &timer->start, &timer->diff); } @@ -47,7 +78,6 @@ int timerx_adjusted_wait(timerx_t* timer) .tv_sec = req_period_ns / G, .tv_nsec = req_period_ns % G }; - return nanosleep(&req, NULL); }