diff --git a/Core/apu.c b/Core/apu.c old mode 100644 new mode 100755 index 2db8c36..c4085ee --- a/Core/apu.c +++ b/Core/apu.c @@ -4,11 +4,13 @@ #include "apu.h" #include "gb.h" +#undef max #define max(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a > _b ? _a : _b; }) +#undef min #define min(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ diff --git a/Core/display.c b/Core/display.c old mode 100644 new mode 100755 index 06ff945..5355ca3 --- a/Core/display.c +++ b/Core/display.c @@ -6,6 +6,10 @@ #include #include "gb.h" #include "display.h" +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include +#endif #pragma pack(push, 1) typedef struct { @@ -161,17 +165,42 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) return gb->background_palletes_rgb[(attributes & 7) * 4 + background_pixel]; } +static int64_t get_nanoseconds(void) +{ +#ifndef _WIN32 + struct timeval now; + gettimeofday(&now, NULL); + return (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; +#else + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((int64_t)time.dwHighDateTime << 32) | time.dwLowDateTime) * 100L; +#endif +} + +static void nsleep(uint64_t nanoseconds) +{ +#ifndef _WIN32 + struct timespec sleep = {0, nanoseconds}; + nanosleep(&sleep, NULL); +#else + HANDLE timer; + LARGE_INTEGER time; + timer = CreateWaitableTimer(NULL, true, NULL); + time.QuadPart = -(nanoseconds / 100L); + SetWaitableTimer(timer, &time, 0, NULL, NULL, false); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); +#endif +} + // Todo: FPS capping should not be related to vblank, as the display is not always on, and this causes "jumps" // when switching the display on and off. void display_vblank(GB_gameboy_t *gb) { - _Static_assert(CLOCKS_PER_SEC == 1000000, "CLOCKS_PER_SEC != 1000000"); - /* Called every Gameboy vblank. Does FPS-capping and calls user's vblank callback if Turbo Mode allows. */ if (gb->turbo) { - struct timeval now; - gettimeofday(&now, NULL); - int64_t nanoseconds = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; + int64_t nanoseconds = get_nanoseconds(); if (nanoseconds <= gb->last_vblank + FRAME_LENGTH) { return; } @@ -205,14 +234,9 @@ void display_vblank(GB_gameboy_t *gb) gb->vblank_callback(gb); if (!gb->turbo) { - struct timeval now; - struct timespec sleep = {0,}; - gettimeofday(&now, NULL); - signed long nanoseconds = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; + int64_t nanoseconds = get_nanoseconds(); if (labs((signed long)(nanoseconds - gb->last_vblank)) < FRAME_LENGTH ) { - sleep.tv_nsec = (FRAME_LENGTH + gb->last_vblank - nanoseconds); - nanosleep(&sleep, NULL); - + nsleep(FRAME_LENGTH + gb->last_vblank - nanoseconds); gb->last_vblank += FRAME_LENGTH; } else { diff --git a/Core/gb.c b/Core/gb.c old mode 100644 new mode 100755 index 1ec611b..8e83532 --- a/Core/gb.c +++ b/Core/gb.c @@ -73,6 +73,7 @@ static char *default_input_callback(GB_gameboy_t *gb) static char *default_async_input_callback(GB_gameboy_t *gb) { +#ifndef _WIN32 fd_set set; FD_ZERO(&set); FD_SET(STDIN_FILENO, &set); @@ -84,6 +85,7 @@ static char *default_async_input_callback(GB_gameboy_t *gb) } return default_input_callback(gb); } +#endif return NULL; } @@ -95,10 +97,6 @@ void GB_init(GB_gameboy_t *gb) gb->ram = malloc(gb->ram_size = 0x2000); gb->vram = malloc(gb->vram_size = 0x2000); - struct timeval now; - gettimeofday(&now, NULL); - gb->last_vblank = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;; - gb->mbc_rom_bank = 1; gb->last_rtc_second = time(NULL); gb->last_vblank = clock(); @@ -127,10 +125,6 @@ void GB_init_cgb(GB_gameboy_t *gb) gb->is_cgb = true; gb->cgb_mode = true; - struct timeval now; - gettimeofday(&now, NULL); - gb->last_vblank = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; - gb->mbc_rom_bank = 1; gb->last_rtc_second = time(NULL); gb->last_vblank = clock(); @@ -180,7 +174,7 @@ void GB_free(GB_gameboy_t *gb) int GB_load_boot_rom(GB_gameboy_t *gb, const char *path) { - FILE *f = fopen(path, "r"); + FILE *f = fopen(path, "rb"); if (!f) return errno; fread(gb->boot_rom, sizeof(gb->boot_rom), 1, f); fclose(f); @@ -189,7 +183,7 @@ int GB_load_boot_rom(GB_gameboy_t *gb, const char *path) int GB_load_rom(GB_gameboy_t *gb, const char *path) { - FILE *f = fopen(path, "r"); + FILE *f = fopen(path, "rb"); if (!f) return errno; fseek(f, 0, SEEK_END); gb->rom_size = (ftell(f) + 0x3FFF) & ~0x3FFF; /* Round to bank */ diff --git a/Core/symbol_hash.c b/Core/symbol_hash.c old mode 100644 new mode 100755 index 5af04f0..37664e1 --- a/Core/symbol_hash.c +++ b/Core/symbol_hash.c @@ -1,4 +1,7 @@ #include "gb.h" +#ifdef _WIN32 +typedef intptr_t ssize_t; +#endif static size_t GB_map_find_symbol_index(GB_symbol_map_t *map, uint16_t addr) { diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index 7ad7c87..6f77421 --- a/Makefile +++ b/Makefile @@ -1,4 +1,8 @@ -ifeq ($(shell uname -s),Darwin) +# Set target, configuration, version and destination folders + +PLATFORM := $(shell uname -s) + +ifeq ($(PLATFORM),Darwin) DEFAULT := cocoa else DEFAULT := sdl @@ -11,43 +15,79 @@ MAKECMDGOALS := $(DEFAULT) endif VERSION := 0.6 +CONF ?= debug BIN := build/bin OBJ := build/obj +# Set tools + CC := clang +ifeq ($(PLATFORM),windows32) +# To force use of the Unix version instead of the Windows version +MKDIR := $(shell which mkdir) +else +MKDIR := mkdir +endif -CFLAGS += -Werror -Wall -std=gnu11 -ICore -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. +# Set compilation and linkage flags based on target, platform and configuration + +CFLAGS += -Werror -Wall -std=gnu11 -ICore -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES SDL_LDFLAGS := -lSDL +ifeq ($(PLATFORM),windows32) +CFLAGS += -IWindows +LDFLAGS += -lmsvcrt -lSDLmain +else LDFLAGS += -lc -lm -CONF ?= debug +endif -ifeq ($(shell uname -s),Darwin) +ifeq ($(PLATFORM),Darwin) CFLAGS += -F/Library/Frameworks OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(shell xcode-select -p)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -mmacosx-version-min=10.9 LDFLAGS += -framework AppKit -framework Carbon SDL_LDFLAGS := -framework SDL endif +ifeq ($(PLATFORM),windows32) +CFLAGS += -Wno-deprecated-declarations # Seems like Microsoft deprecated every single LIBC function +LDFLAGS += -Wl,/NODEFAULTLIB:libcmt +endif + ifeq ($(CONF),debug) CFLAGS += -g +ifeq ($(PLATFORM),windows32) +LDFLAGS += -Wl,/debug +endif else ifeq ($(CONF), release) -CFLAGS += -O3 -flto -DNDEBUG +CFLAGS += -O3 -DNDEBUG +ifneq ($(PLATFORM),windows32) LDFLAGS += -flto +CFLAGS += -flto +endif else $(error Invalid value for CONF: $(CONF). Use "debug" or "release") endif +# Define our targets + +ifeq ($(PLATFORM),windows32) +SDL_TARGET := $(BIN)/sdl/sameboy.exe $(BIN)/sdl/sameboy_debugger.exe $(BIN)/sdl/SDL.dll +else +SDL_TARGET := $(BIN)/sdl/sameboy +endif + cocoa: $(BIN)/Sameboy.app -sdl: $(BIN)/sdl/sameboy $(BIN)/sdl/dmg_boot.bin $(BIN)/sdl/cgb_boot.bin $(BIN)/sdl/LICENSE +sdl: $(SDL_TARGET) $(BIN)/sdl/dmg_boot.bin $(BIN)/sdl/cgb_boot.bin $(BIN)/sdl/LICENSE bootroms: $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin -CORE_SOURCES := $(shell echo Core/*.c) -SDL_SOURCES := $(shell echo SDL/*.c) +# Get a list of our source files and their respective object file targets -ifeq ($(shell uname -s),Darwin) -COCOA_SOURCES := $(shell echo Cocoa/*.m) $(shell echo HexFiend/*.m) -SDL_SOURCES += $(shell echo SDL/*.m) +CORE_SOURCES := $(shell ls Core/*.c) +SDL_SOURCES := $(shell ls SDL/*.c) + +ifeq ($(PLATFORM),Darwin) +COCOA_SOURCES := $(shell ls Cocoa/*.m) $(shell ls HexFiend/*.m) +SDL_SOURCES += $(shell ls SDL/*.m) endif CORE_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(CORE_SOURCES)) @@ -57,6 +97,7 @@ SDL_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(SDL_SOURCES)) ALL_OBJECTS := $(CORE_OBJECTS) $(COCOA_OBJECTS) $(SDL_OBJECTS) # Automatic dependency generation + ifneq ($(MAKECMDGOALS),clean) -include $(CORE_OBJECTS:.o=.dep) ifneq ($(filter $(MAKECMDGOALS),sdl),) @@ -68,28 +109,30 @@ endif endif $(OBJ)/%.dep: % - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) $(CC) $(CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@ +# Compilation rules + $(OBJ)/%.c.o: %.c - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) $(CC) $(CFLAGS) -c $< -o $@ # HexFiend requires more flags $(OBJ)/HexFiend/%.m.o: HexFiend/%.m - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) $(CC) $(CFLAGS) $(OCFLAGS) -c $< -o $@ -fno-objc-arc -include HexFiend/HexFiend_2_Framework_Prefix.pch $(OBJ)/%.m.o: %.m - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) $(CC) $(CFLAGS) $(OCFLAGS) -c $< -o $@ # Cocoa Port -Shaders:$(shell echo Shaders/*.fsh) +Shaders:$(shell ls Shaders/*.fsh) $(BIN)/Sameboy.app: $(BIN)/Sameboy.app/Contents/MacOS/Sameboy \ - $(shell echo Cocoa/*.icns) \ + $(shell ls Cocoa/*.icns) \ Cocoa/License.html \ Cocoa/info.plist \ $(BIN)/BootROMs/dmg_boot.bin \ @@ -98,15 +141,15 @@ $(BIN)/Sameboy.app: $(BIN)/Sameboy.app/Contents/MacOS/Sameboy \ $(BIN)/Sameboy.app/Contents/Resources/Base.lproj/MainMenu.nib \ $(BIN)/Sameboy.app/Contents/Resources/Base.lproj/Preferences.nib \ Shaders - mkdir -p $(BIN)/Sameboy.app/Contents/Resources + $(MKDIR) -p $(BIN)/Sameboy.app/Contents/Resources cp Cocoa/*.icns $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/Sameboy.app/Contents/Resources/ sed s/@VERSION/$(VERSION)/ < Cocoa/info.plist > $(BIN)/Sameboy.app/Contents/info.plist cp Cocoa/License.html $(BIN)/Sameboy.app/Contents/Resources/Credits.html - mkdir -p $(BIN)/Sameboy.app/Contents/Resources/Shaders + $(MKDIR) -p $(BIN)/Sameboy.app/Contents/Resources/Shaders cp Shaders/*.fsh $(BIN)/Sameboy.app/Contents/Resources/Shaders $(BIN)/Sameboy.app/Contents/MacOS/Sameboy: $(CORE_OBJECTS) $(COCOA_OBJECTS) - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) $(CC) $^ -o $@ $(LDFLAGS) -framework OpenGL -framework AudioUnit ifeq ($(CONF), release) strip $@ @@ -115,27 +158,50 @@ endif $(BIN)/Sameboy.app/Contents/Resources/Base.lproj/%.nib: Cocoa/%.xib ibtool --compile $@ $^ +# SDL Port + +# Unix versions build only one binary $(BIN)/sdl/sameboy: $(CORE_OBJECTS) $(SDL_OBJECTS) - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) ifeq ($(CONF), release) strip $@ endif - -$(BIN)/BootROMs/%.bin: BootROMs/%.asm - -@mkdir -p $(dir $@) - cd BootROMs && rgbasm -o ../$@.tmp ../$< - rgblink -o $@.tmp2 $@.tmp - head -c $(if $(findstring dmg,$@), 256, 2304) $@.tmp2 > $@ - @rm $@.tmp $@.tmp2 + +# Windows version builds two, one with a conole and one without it +$(BIN)/sdl/sameboy.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) + -@$(MKDIR) -p $(dir $@) + $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) -Wl,/subsystem:windows + +$(BIN)/sdl/sameboy_debugger.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) + -@$(MKDIR) -p $(dir $@) + $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) -Wl,/subsystem:console + +# We must provide SDL.dll with the Windows port. This is an AWFUL HACK to find it. +SPACE := +SPACE += +$(BIN)/sdl/SDL.dll: + @$(eval POTENTIAL_MATCHES := $(subst @@@," ",$(patsubst %,%/SDL.dll,$(subst ;,$(SPACE),$(subst $(SPACE),@@@,$(lib)))))) + @$(eval MATCH := $(shell ls $(POTENTIAL_MATCHES) 2> NUL | head -n 1)) + cp "$(MATCH)" $@ $(BIN)/sdl/%.bin: $(BIN)/BootROMs/%.bin - -@mkdir -p $(dir $@) + -@$(MKDIR) -p $(dir $@) cp -f $^ $@ $(BIN)/sdl/LICENSE: LICENSE cp -f $^ $@ +# Boot ROMs + +$(BIN)/BootROMs/%.bin: BootROMs/%.asm + -@$(MKDIR) -p $(dir $@) + cd BootROMs && rgbasm -o ../$@.tmp ../$< + rgblink -o $@.tmp2 $@.tmp + head -c $(if $(findstring dmg,$@), 256, 2304) $@.tmp2 > $@ + @rm $@.tmp $@.tmp2 + +# Clean + clean: - rm -rf build - \ No newline at end of file + rm -rf build \ No newline at end of file diff --git a/SDL/SDLMain.m b/SDL/SDLMain.m index 535e4c7..d8aadf5 100644 --- a/SDL/SDLMain.m +++ b/SDL/SDLMain.m @@ -19,21 +19,21 @@ @end /* Use this flag to determine whether we use SDLMain.nib or not */ -#define SDL_USE_NIB_FILE 0 +#define SDL_USE_NIB_FILE 0 /* Use this flag to determine whether we use CPS (docking) or not */ -#define SDL_USE_CPS 1 +#define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { - UInt32 lo; - UInt32 hi; + UInt32 lo; + UInt32 hi; } CPSProcessSerNum; -extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); -extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); -extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ @@ -200,7 +200,7 @@ static void setupWindowMenu(void) /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { - SDLMain *sdlMain; + SDLMain *sdlMain; /* Ensure the application object is initialised */ [NSApplication sharedApplication]; diff --git a/SDL/main.c b/SDL/main.c old mode 100644 new mode 100755 index da00977..1d15972 --- a/SDL/main.c +++ b/SDL/main.c @@ -5,6 +5,15 @@ #include #include #include +#ifndef _WIN32 +#define AUDIO_FREQUENCY 96000 +#else +/* Windows (well, at least my VM) can't handle 96KHz sound well :( */ +#define AUDIO_FREQUENCY 44100 +#include +#include +#define snprintf _snprintf +#endif #include "gb.h" #include "debugger.h" @@ -14,7 +23,7 @@ static char *filename; static void replace_extension(const char *src, size_t length, char *dest, const char *ext); GB_gameboy_t gb; -void GB_update_keys_status(GB_gameboy_t *gb) +static void GB_update_keys_status(GB_gameboy_t *gb) { static bool ctrl = false; static bool shift = false; @@ -111,7 +120,7 @@ void GB_update_keys_status(GB_gameboy_t *gb) } } -void vblank(GB_gameboy_t *gb) +static void vblank(GB_gameboy_t *gb) { SDL_Surface *screen = gb->user_data; SDL_Flip(screen); @@ -139,16 +148,24 @@ static const char *executable_folder(void) ssize_t length = readlink("/proc/self/exe", &path[0], sizeof(path) - 1); assert (length != -1); #else -#warning Unsupported OS: sameboy will only run from CWD +#ifdef _WIN32 + HMODULE hModule = GetModuleHandle(NULL); + GetModuleFileName(hModule, path, sizeof(path) - 1); +#else /* No OS-specific way, assume running from CWD */ getcwd(&path[0], sizeof(path) - 1); return path; #endif +#endif #endif size_t pos = strlen(path); while (pos) { pos--; +#ifdef _WIN32 + if (path[pos] == '\\') { +#else if (path[pos] == '/') { +#endif path[pos] = 0; break; } @@ -256,6 +273,7 @@ usage: SDL_Init( SDL_INIT_EVERYTHING ); screen = SDL_SetVideoMode(160, 144, 32, SDL_SWSURFACE ); + SDL_WM_SetCaption("SameBoy v" xstr(VERSION), "SameBoy v" xstr(VERSION)); #ifdef __APPLE__ cocoa_disable_filtering(); #endif @@ -281,14 +299,14 @@ usage: /* Configure Audio */ SDL_AudioSpec want, have; SDL_memset(&want, 0, sizeof(want)); - want.freq = 96000; + want.freq = AUDIO_FREQUENCY; want.format = AUDIO_S16SYS; want.channels = 2; want.samples = 512; want.callback = audio_callback; want.userdata = &gb; SDL_OpenAudio(&want, &have); - GB_set_sample_rate(&gb, 96000); + GB_set_sample_rate(&gb, AUDIO_FREQUENCY); /* Start Audio */ SDL_PauseAudio(0); diff --git a/Windows/stdio.h b/Windows/stdio.h new file mode 100755 index 0000000..8ff90e4 --- /dev/null +++ b/Windows/stdio.h @@ -0,0 +1,69 @@ +#pragma once +#include_next +#include + +static inline int vasprintf(char **str, const char *fmt, va_list args) +{ + size_t size = _vscprintf(fmt, args) + 1; + *str = malloc(size); + int ret = vsprintf(*str, fmt, args); + if (ret != size - 1) { + free(*str); + *str = NULL; + return -1; + } + return ret; +} + +/* This code is public domain -- Will Hartung 4/9/09 */ +static inline size_t getline(char **lineptr, size_t *n, FILE *stream) { + char *bufptr = NULL; + char *p = bufptr; + size_t size; + int c; + + if (lineptr == NULL) { + return -1; + } + if (stream == NULL) { + return -1; + } + if (n == NULL) { + return -1; + } + bufptr = *lineptr; + size = *n; + + c = fgetc(stream); + if (c == EOF) { + return -1; + } + if (bufptr == NULL) { + bufptr = malloc(128); + if (bufptr == NULL) { + return -1; + } + size = 128; + } + p = bufptr; + while (c != EOF) { + if ((p - bufptr) > (size - 1)) { + size = size + 128; + bufptr = realloc(bufptr, size); + if (bufptr == NULL) { + return -1; + } + } + *p++ = c; + if (c == '\n') { + break; + } + c = fgetc(stream); + } + + *p++ = '\0'; + *lineptr = bufptr; + *n = size; + + return p - bufptr - 1; +} \ No newline at end of file diff --git a/Windows/sys/select.h b/Windows/sys/select.h new file mode 100755 index 0000000..e69de29 diff --git a/Windows/sys/time.h b/Windows/sys/time.h new file mode 100755 index 0000000..e69de29 diff --git a/Windows/unistd.h b/Windows/unistd.h new file mode 100755 index 0000000..e69de29