Initial Windows support

This commit is contained in:
Lior Halphon 2016-08-20 17:51:17 +03:00
parent 0734e990b3
commit e7626535a8
11 changed files with 242 additions and 66 deletions

2
Core/apu.c Normal file → Executable file
View File

@ -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); \

48
Core/display.c Normal file → Executable file
View File

@ -6,6 +6,10 @@
#include <string.h>
#include "gb.h"
#include "display.h"
#ifdef _WIN32
#define _WIN32_WINNT 0x0500
#include <Windows.h>
#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 {

14
Core/gb.c Normal file → Executable file
View File

@ -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 */

3
Core/symbol_hash.c Normal file → Executable file
View File

@ -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)
{

128
Makefile Normal file → Executable file
View File

@ -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
rm -rf build

View File

@ -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];

28
SDL/main.c Normal file → Executable file
View File

@ -5,6 +5,15 @@
#include <assert.h>
#include <signal.h>
#include <SDL/SDL.h>
#ifndef _WIN32
#define AUDIO_FREQUENCY 96000
#else
/* Windows (well, at least my VM) can't handle 96KHz sound well :( */
#define AUDIO_FREQUENCY 44100
#include <direct.h>
#include <windows.h>
#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);

69
Windows/stdio.h Executable file
View File

@ -0,0 +1,69 @@
#pragma once
#include_next <stdio.h>
#include <stdlib.h>
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;
}

0
Windows/sys/select.h Executable file
View File

0
Windows/sys/time.h Executable file
View File

0
Windows/unistd.h Executable file
View File