| @@ -1,24 +1,42 @@ | |||||
| CC = gcc | |||||
| SHORT_PLATFORM = linux | |||||
| ifeq ($(PLATFORM),win64) | |||||
| CROSS_COMPILE = x86_64-w64-mingw32- | |||||
| EXTENSION = .exe | |||||
| SHORT_PLATFORM = win | |||||
| else ifeq ($(PLATFORM),win32) | |||||
| CROSS_COMPILE = i686-w64-mingw32- | |||||
| EXTENSION = .exe | |||||
| SHORT_PLATFORM = win | |||||
| endif | |||||
| ifneq ($(PLATFORM),) | |||||
| DIR_SUFFIX=-$(PLATFORM) | |||||
| endif | |||||
| CC = $(CROSS_COMPILE)gcc | |||||
| LD = $(CC) | LD = $(CC) | ||||
| PFLAGS = -g | PFLAGS = -g | ||||
| #PFLAGS += -O3 | |||||
| #PFLAGS += -O3 -s | |||||
| #PFLAGS += -DDEBUG_MAPPER | #PFLAGS += -DDEBUG_MAPPER | ||||
| #PFLAGS += -DDEBUG_RENDER | #PFLAGS += -DDEBUG_RENDER | ||||
| #PFLAGS += -DDEBUG_PPU -DDEBUG_VRAM -DDEBUG_OAM | #PFLAGS += -DDEBUG_PPU -DDEBUG_VRAM -DDEBUG_OAM | ||||
| PFLAGS += -DDEBUG_APU | |||||
| #PFLAGS += -DDEBUG_APU | |||||
| #PFLAGS += -DE6502_DEBUG | #PFLAGS += -DE6502_DEBUG | ||||
| PFLAGS += -DE6502_ILLEGAL | PFLAGS += -DE6502_ILLEGAL | ||||
| CFLAGS = $(PFLAGS) -Wall -Werror -Wshadow -Wunused -I.. | |||||
| CFLAGS = $(PFLAGS) -Wall -Werror -Wshadow -Wunused -I../ -Isrc/ | |||||
| CFLAGS += -Iinc/$(PLATFORM) -I../inc/$(PLATFORM) | |||||
| LDFLAGS = $(PFLAGS) | LDFLAGS = $(PFLAGS) | ||||
| LDFLAGS += -Llib/$(PLATFORM) | |||||
| OBJDIR = obj | |||||
| OBJDIR = obj$(DIR_SUFFIX) | |||||
| SRCDIR = src | SRCDIR = src | ||||
| BINDIR = bin | |||||
| BINDIR = bin$(DIR_SUFFIX) | |||||
| # nese | # nese | ||||
| TARGET_1 = nese | |||||
| TARGET_1 = nese$(EXTENSION) | |||||
| LDLIBS_1 = -lSDL2 | LDLIBS_1 = -lSDL2 | ||||
| SRC_SRCS_1 = nese.c ines.c | SRC_SRCS_1 = nese.c ines.c | ||||
| @@ -26,22 +44,25 @@ SRC_SRCS_1 += nes.c ppu.c input.c | |||||
| SRC_SRCS_1 += cart.c mapper.c | SRC_SRCS_1 += cart.c mapper.c | ||||
| SRC_SRCS_1 += apu.c audio.c | SRC_SRCS_1 += apu.c audio.c | ||||
| SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c | SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c | ||||
| SRC_SRCS_1 += sdl_timer.c | |||||
| PLAT_SRCS_1 = filemap.c | |||||
| MAPDIR = src/map | MAPDIR = src/map | ||||
| MAP_SRCS_1 = nrom.c mmc1.c uxrom.c cnrom.c mmc3.c | MAP_SRCS_1 = nrom.c mmc1.c uxrom.c cnrom.c mmc3.c | ||||
| EXT_SRCS_1 = e6502/e6502.c e6502/opcodes.c blip-buf/blip_buf.c | EXT_SRCS_1 = e6502/e6502.c e6502/opcodes.c blip-buf/blip_buf.c | ||||
| SRCS_1 = $(SRC_SRCS_1:%=$(SRCDIR)/%) | SRCS_1 = $(SRC_SRCS_1:%=$(SRCDIR)/%) | ||||
| SRCS_1 += $(MAP_SRCS_1:%=$(MAPDIR)/%) | SRCS_1 += $(MAP_SRCS_1:%=$(MAPDIR)/%) | ||||
| SRCS_1 += $(PLAT_SRCS_1:%=src/$(SHORT_PLATFORM)/%) | |||||
| SRCS_1 += $(EXT_SRCS_1) | SRCS_1 += $(EXT_SRCS_1) | ||||
| OBJS_1 = $(SRCS_1:%.c=$(OBJDIR)/%.o) | OBJS_1 = $(SRCS_1:%.c=$(OBJDIR)/%.o) | ||||
| all: $(BINDIR)/$(TARGET_1) | all: $(BINDIR)/$(TARGET_1) | ||||
| clean: ; rm -rf $(OBJDIR) $(BINDIR) | |||||
| clean: ; rm -rf obj*/ bin*/ | |||||
| $(BINDIR)/$(TARGET_1): $(OBJS_1) | $(BINDIR)/$(TARGET_1): $(OBJS_1) | ||||
| @mkdir -p $(@D) | @mkdir -p $(@D) | ||||
| @@ -0,0 +1 @@ | |||||
| ../../../SDL2-devel-2.30.11-mingw/i686-w64-mingw32/include/SDL2 | |||||
| @@ -0,0 +1 @@ | |||||
| ../../../SDL2-devel-2.30.11-mingw/x86_64-w64-mingw32/include/SDL2 | |||||
| @@ -0,0 +1 @@ | |||||
| ../../../SDL2-devel-2.30.11-mingw/i686-w64-mingw32/bin/SDL2.dll | |||||
| @@ -0,0 +1 @@ | |||||
| ../../../SDL2-devel-2.30.11-mingw/x86_64-w64-mingw32/bin/SDL2.dll | |||||
| @@ -1,6 +1,5 @@ | |||||
| #include <sys/mman.h> | |||||
| #include "cart.h" | #include "cart.h" | ||||
| #include "filemap.h" | |||||
| #include "ines.h" | #include "ines.h" | ||||
| #include "mapper.h" | #include "mapper.h" | ||||
| @@ -67,7 +66,7 @@ int nes_cart_init_mem(nes_cart* cart, void* mem, int len) { | |||||
| void nes_cart_done(nes_cart* cart) { | void nes_cart_done(nes_cart* cart) { | ||||
| if (NULL != cart->ines_mem) { | if (NULL != cart->ines_mem) { | ||||
| munmap(cart->ines_mem, cart->ines_size); | |||||
| unmap_file(cart->ines_mem, cart->ines_size); | |||||
| cart->ines_mem = NULL; | cart->ines_mem = NULL; | ||||
| } | } | ||||
| } | } | ||||
| @@ -87,8 +86,7 @@ int nes_cart_init_file(nes_cart* cart, FILE* file) { | |||||
| // Map file | // Map file | ||||
| if (0 == status) { | if (0 == status) { | ||||
| mem = mmap(NULL, size, PROT_READ, MAP_PRIVATE, | |||||
| fileno(file), 0); | |||||
| mem = map_file(file, size); | |||||
| if (NULL == mem) { | if (NULL == mem) { | ||||
| INES_ERR("Failed to map file (%d bytes)", size); | INES_ERR("Failed to map file (%d bytes)", size); | ||||
| status = -1; | status = -1; | ||||
| @@ -99,7 +97,7 @@ int nes_cart_init_file(nes_cart* cart, FILE* file) { | |||||
| if (0 == status) { | if (0 == status) { | ||||
| status = nes_cart_init_mem(cart, mem, size); | status = nes_cart_init_mem(cart, mem, size); | ||||
| if (0 != status) { | if (0 != status) { | ||||
| munmap(mem, size); | |||||
| unmap_file(file, size); | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,10 @@ | |||||
| #ifndef NESE_FILEMAP_H_ | |||||
| #define NESE_FILEMAP_H_ | |||||
| void* map_file(FILE* file, int size); | |||||
| void unmap_file(void* mem, int size); | |||||
| #endif // NESE_FILEMAP_H_ | |||||
| @@ -0,0 +1,15 @@ | |||||
| #include <stdio.h> | |||||
| #include <sys/mman.h> | |||||
| #include "filemap.h" | |||||
| void* map_file(FILE* file, int size) { | |||||
| return mmap(NULL, size, PROT_READ, MAP_PRIVATE, | |||||
| fileno(file), 0); | |||||
| } | |||||
| void unmap_file(void* mem, int size) { | |||||
| munmap(mem, size); | |||||
| } | |||||
| @@ -1,9 +1,9 @@ | |||||
| #include <inttypes.h> | #include <inttypes.h> | ||||
| #include <limits.h> | #include <limits.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <time.h> | |||||
| #include "nes.h" | #include "nes.h" | ||||
| #include "timer.h" | |||||
| #include "render.h" | #include "render.h" | ||||
| #include "input.h" | #include "input.h" | ||||
| #include "audio.h" | #include "audio.h" | ||||
| @@ -12,24 +12,6 @@ | |||||
| #define audio_freq (44100U) | #define audio_freq (44100U) | ||||
| #define NS_PER_S (1000U * 1000U * 1000U) | |||||
| static inline int t_diff_ns(const struct timespec* b, | |||||
| const struct timespec* a) { | |||||
| int sec = (b->tv_sec - a->tv_sec); | |||||
| int nsec = (b->tv_nsec - a->tv_nsec); | |||||
| return ((sec * NS_PER_S) + nsec); | |||||
| } | |||||
| static inline void t_add_ns(struct timespec* s, | |||||
| const struct timespec* a, | |||||
| int b) { | |||||
| int nsec = a->tv_nsec + b; | |||||
| s->tv_sec = a->tv_sec + (nsec / NS_PER_S); | |||||
| s->tv_nsec = nsec % NS_PER_S; | |||||
| } | |||||
| extern nes_Renderer sdl_renderer; | extern nes_Renderer sdl_renderer; | ||||
| extern nes_Input_Reader sdl_input; | extern nes_Input_Reader sdl_input; | ||||
| @@ -79,7 +61,7 @@ int main(int argc, char* argv[]) { | |||||
| nes_render(rend, &sys.ppu); | nes_render(rend, &sys.ppu); | ||||
| struct timespec t_target = {0}; | struct timespec t_target = {0}; | ||||
| clock_gettime(CLOCK_MONOTONIC, &t_target); | |||||
| time_get(&t_target); | |||||
| uint64_t cycle_last_frame = 0; | uint64_t cycle_last_frame = 0; | ||||
| uint64_t total_cycles = 0; | uint64_t total_cycles = 0; | ||||
| @@ -103,8 +85,7 @@ int main(int argc, char* argv[]) { | |||||
| t_add_ns(&t_target, &t_target, elapsed_ns); | t_add_ns(&t_target, &t_target, elapsed_ns); | ||||
| clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, | |||||
| &t_target, NULL); | |||||
| time_sleep_until(&t_target); | |||||
| cycle_last_frame = total_cycles; | cycle_last_frame = total_cycles; | ||||
| @@ -1,3 +1,5 @@ | |||||
| #include <stdio.h> | |||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||
| #include "render.h" | #include "render.h" | ||||
| @@ -0,0 +1,21 @@ | |||||
| #include <time.h> | |||||
| #include "time.h" | |||||
| #include <SDL2/SDL.h> | |||||
| void time_get(struct timespec* ts) { | |||||
| uint64_t time = SDL_GetTicks64(); | |||||
| ts->tv_sec = time / 1000U; | |||||
| ts->tv_nsec = (time % 1000U) * 1000U * 1000U; | |||||
| } | |||||
| void time_sleep_until(const struct timespec* ts) { | |||||
| uint64_t t_target = ( (ts->tv_sec * 1000ULL) + | |||||
| (ts->tv_nsec / (1000U * 1000U))); | |||||
| uint64_t t_now = SDL_GetTicks64(); | |||||
| if (t_target > t_now) { | |||||
| SDL_Delay(t_target - t_now); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| #ifndef NESE_TIMER_H_ | |||||
| #define NESE_TIMER_H_ | |||||
| #include <time.h> | |||||
| #define NS_PER_S (1000U * 1000U * 1000U) | |||||
| static inline int t_diff_ns(const struct timespec* b, | |||||
| const struct timespec* a) { | |||||
| int sec = (b->tv_sec - a->tv_sec); | |||||
| int nsec = (b->tv_nsec - a->tv_nsec); | |||||
| return ((sec * NS_PER_S) + nsec); | |||||
| } | |||||
| static inline void t_add_ns(struct timespec* s, | |||||
| const struct timespec* a, | |||||
| int b) { | |||||
| int nsec = a->tv_nsec + b; | |||||
| s->tv_sec = a->tv_sec + (nsec / NS_PER_S); | |||||
| s->tv_nsec = nsec % NS_PER_S; | |||||
| } | |||||
| void time_get(struct timespec*); | |||||
| void time_sleep_until(const struct timespec*); | |||||
| #endif // NESE_TIME_H_ | |||||
| @@ -0,0 +1,29 @@ | |||||
| #include <stdio.h> | |||||
| #include <windows.h> | |||||
| #include <winbase.h> | |||||
| #include <memoryapi.h> | |||||
| #include <io.h> | |||||
| #include "filemap.h" | |||||
| // TODO: Support multiple filemaps | |||||
| static HANDLE hMap; | |||||
| void* map_file(FILE* file, int size) { | |||||
| HANDLE hFile = (HANDLE)_get_osfhandle(fileno(file)); | |||||
| hMap = CreateFileMappingA( | |||||
| hFile, 0, PAGE_READONLY, 0, size, 0 | |||||
| ); | |||||
| return MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, size); | |||||
| } | |||||
| void unmap_file(void* mem, int size) { | |||||
| UnmapViewOfFile(mem); | |||||
| CloseHandle(hMap); | |||||
| } | |||||