Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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 $<$<BOOL:${UNIX}>:m>)

install(TARGETS nes-tools )

file(GENERATE OUTPUT .gitignore CONTENT "*")
46 changes: 40 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand All @@ -29,12 +67,8 @@ Build and install
make install
```

Run the emulator
```
nes-tools help
```
Uninstall

### Uninstall
```
make uninstall
```
Expand Down
8 changes: 8 additions & 0 deletions cmake/config.cmake
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 14 additions & 0 deletions cmake/config.h.in
Original file line number Diff line number Diff line change
@@ -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@"
20 changes: 20 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
9 changes: 9 additions & 0 deletions src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
target_sources(nes-tools PRIVATE
apu.c
audio.c
biquad.c
dmc.c
noise.c
pulse.c
triangle.c
)
39 changes: 39 additions & 0 deletions src/nanosleep.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <time.h>

#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;
}
6 changes: 6 additions & 0 deletions src/nanosleep.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions src/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h> // for memset()
#include <math.h>
#include "log.h"

Expand Down
38 changes: 34 additions & 4 deletions src/timerx.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
#include "timerx.h"

#define G 1000000000L
#if defined(_MSC_VER)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#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;
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand Down