mirror of https://github.com/mgba-emu/mgba.git
Rebase branch bizhawk-0.11
This commit is contained in:
parent
fde15b6e7d
commit
ff542cbb07
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
BASEDIR=$(dirname $0)
|
||||
if [ "$(uname -s)" = "Linux" ]; then
|
||||
cd "$BASEDIR/src/platform/bizhawk/linux"
|
||||
else
|
||||
cd "$BASEDIR/src/platform/bizhawk/mingw"
|
||||
fi
|
||||
make clean
|
||||
make -j4
|
||||
make install
|
|
@ -0,0 +1,2 @@
|
|||
codeblocks/*
|
||||
mingw/obj/*
|
|
@ -0,0 +1,130 @@
|
|||
CCFLAGS = \
|
||||
-O3 -fomit-frame-pointer -fexpensive-optimizations -flto \
|
||||
-I../../../../include -I../../.. -std=gnu11 \
|
||||
-Wall -Wno-stringop-overflow -Wno-lto-type-mismatch \
|
||||
-Wno-ignored-optimization-argument -Wno-unknown-warning-option \
|
||||
-DMINIMAL_CORE=2 -DDISABLE_THREADING -DM_CORE_GBA \
|
||||
-DCOLOR_16_BIT -DMGBA_STANDALONE -DENABLE_DEBUGGERS \
|
||||
$(PLAT_FLAGS)
|
||||
|
||||
DEST_64 = ../../../../../../Assets/dll
|
||||
DESTCOPY_64 = ../../../../../../output/dll
|
||||
|
||||
SRCS = \
|
||||
$(ROOT_DIR)/core/bitmap-cache.c \
|
||||
$(ROOT_DIR)/core/cache-set.c \
|
||||
$(ROOT_DIR)/core/cheats.c \
|
||||
$(ROOT_DIR)/core/config.c \
|
||||
$(ROOT_DIR)/core/core.c \
|
||||
$(ROOT_DIR)/core/directories.c \
|
||||
$(ROOT_DIR)/core/input.c \
|
||||
$(ROOT_DIR)/core/interface.c \
|
||||
$(ROOT_DIR)/core/library.c \
|
||||
$(ROOT_DIR)/core/lockstep.c \
|
||||
$(ROOT_DIR)/core/log.c \
|
||||
$(ROOT_DIR)/core/map-cache.c \
|
||||
$(ROOT_DIR)/core/mem-search.c \
|
||||
$(ROOT_DIR)/core/rewind.c \
|
||||
$(ROOT_DIR)/core/serialize.c \
|
||||
$(ROOT_DIR)/core/sync.c \
|
||||
$(ROOT_DIR)/core/thread.c \
|
||||
$(ROOT_DIR)/core/tile-cache.c \
|
||||
$(ROOT_DIR)/core/timing.c \
|
||||
$(ROOT_DIR)/arm/arm.c \
|
||||
$(ROOT_DIR)/arm/decoder-arm.c \
|
||||
$(ROOT_DIR)/arm/decoder-thumb.c \
|
||||
$(ROOT_DIR)/arm/decoder.c \
|
||||
$(ROOT_DIR)/arm/isa-arm.c \
|
||||
$(ROOT_DIR)/arm/isa-thumb.c \
|
||||
$(ROOT_DIR)/arm/debugger/cli-debugger.c \
|
||||
$(ROOT_DIR)/arm/debugger/memory-debugger.c \
|
||||
$(ROOT_DIR)/arm/debugger/debugger.c \
|
||||
$(ROOT_DIR)/gb/audio.c \
|
||||
$(ROOT_DIR)/gba/audio.c \
|
||||
$(ROOT_DIR)/gba/bios.c \
|
||||
$(ROOT_DIR)/gba/cheats.c \
|
||||
$(ROOT_DIR)/gba/core.c \
|
||||
$(ROOT_DIR)/gba/dma.c \
|
||||
$(ROOT_DIR)/gba/gba.c \
|
||||
$(ROOT_DIR)/gba/hle-bios.c \
|
||||
$(ROOT_DIR)/gba/input.c \
|
||||
$(ROOT_DIR)/gba/io.c \
|
||||
$(ROOT_DIR)/gba/memory.c \
|
||||
$(ROOT_DIR)/gba/overrides.c \
|
||||
$(ROOT_DIR)/gba/savedata.c \
|
||||
$(ROOT_DIR)/gba/serialize.c \
|
||||
$(ROOT_DIR)/gba/sharkport.c \
|
||||
$(ROOT_DIR)/gba/sio.c \
|
||||
$(ROOT_DIR)/gba/timer.c \
|
||||
$(ROOT_DIR)/gba/video.c \
|
||||
$(ROOT_DIR)/gba/cart/ereader.c \
|
||||
$(ROOT_DIR)/gba/cart/gpio.c \
|
||||
$(ROOT_DIR)/gba/cart/matrix.c \
|
||||
$(ROOT_DIR)/gba/cart/vfame.c \
|
||||
$(ROOT_DIR)/gba/cheats/codebreaker.c \
|
||||
$(ROOT_DIR)/gba/cheats/gameshark.c \
|
||||
$(ROOT_DIR)/gba/cheats/parv3.c \
|
||||
$(ROOT_DIR)/gba/debugger/cli.c \
|
||||
$(ROOT_DIR)/gba/renderers/cache-set.c \
|
||||
$(ROOT_DIR)/gba/renderers/common.c \
|
||||
$(ROOT_DIR)/gba/renderers/software-bg.c \
|
||||
$(ROOT_DIR)/gba/renderers/software-mode0.c \
|
||||
$(ROOT_DIR)/gba/renderers/software-obj.c \
|
||||
$(ROOT_DIR)/gba/renderers/video-software.c \
|
||||
$(ROOT_DIR)/gba/sio/gbp.c \
|
||||
$(ROOT_DIR)/gba/sio/joybus.c \
|
||||
$(ROOT_DIR)/gba/sio/lockstep.c \
|
||||
$(ROOT_DIR)/debugger/debugger.c \
|
||||
$(ROOT_DIR)/debugger/stack-trace.c \
|
||||
$(ROOT_DIR)/debugger/cli-debugger.c \
|
||||
$(ROOT_DIR)/debugger/symbols.c \
|
||||
$(ROOT_DIR)/debugger/parser.c \
|
||||
$(ROOT_DIR)/third-party/inih/ini.c \
|
||||
$(ROOT_DIR)/util/circle-buffer.c \
|
||||
$(ROOT_DIR)/util/configuration.c \
|
||||
$(ROOT_DIR)/util/crc32.c \
|
||||
$(ROOT_DIR)/util/elf-read.c \
|
||||
$(ROOT_DIR)/util/formatting.c \
|
||||
$(ROOT_DIR)/util/gbk-table.c \
|
||||
$(ROOT_DIR)/util/gui.c \
|
||||
$(ROOT_DIR)/util/hash.c \
|
||||
$(ROOT_DIR)/util/image/png-io.c \
|
||||
$(ROOT_DIR)/util/patch-fast.c \
|
||||
$(ROOT_DIR)/util/patch-ips.c \
|
||||
$(ROOT_DIR)/util/patch-ups.c \
|
||||
$(ROOT_DIR)/util/patch.c \
|
||||
$(ROOT_DIR)/util/ring-fifo.c \
|
||||
$(ROOT_DIR)/util/string.c \
|
||||
$(ROOT_DIR)/util/table.c \
|
||||
$(ROOT_DIR)/util/text-codec.c \
|
||||
$(ROOT_DIR)/util/vector.c \
|
||||
$(ROOT_DIR)/util/vfs.c \
|
||||
$(ROOT_DIR)/util/vfs/vfs-mem.c \
|
||||
$(ROOT_DIR)/platform/bizhawk/bizinterface.c \
|
||||
$(ROOT_DIR)/platform/bizhawk/localtime_r.c \
|
||||
$(PLAT_SRCS)
|
||||
|
||||
_OBJS:=$(SRCS:.c=.o)
|
||||
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(OBJ_DIR)/%.o: $(ROOT_DIR)/%.c
|
||||
@mkdir -p $(@D)
|
||||
@$(CC) -c -o $@ $< $(CCFLAGS)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
@$(CC) -o $@ $(OBJS) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
@$(RM) -rf $(OBJ_DIR)
|
||||
@$(RM) -f $(TARGET)
|
||||
|
||||
install: $(TARGET)
|
||||
$(CP) $(TARGET) $(DEST_$(ARCH))
|
||||
ifneq ("$(wildcard $(DESTCOPY_$(ARCH)))", "")
|
||||
$(CP) $(TARGET) $(DESTCOPY_$(ARCH))
|
||||
endif
|
||||
|
||||
print-%:
|
||||
@echo $* = $($*)
|
|
@ -0,0 +1,623 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "mgba/core/core.h"
|
||||
#include "mgba/core/log.h"
|
||||
#include "mgba/core/timing.h"
|
||||
#include "mgba/core/serialize.h"
|
||||
#include "mgba/core/blip_buf.h"
|
||||
#include "mgba/gba/core.h"
|
||||
#include "mgba/gba/interface.h"
|
||||
#include "mgba/internal/gba/gba.h"
|
||||
#include "mgba/internal/gba/video.h"
|
||||
#include "mgba/internal/gba/overrides.h"
|
||||
#include "mgba/internal/arm/isa-inlines.h"
|
||||
#include "mgba/debugger/debugger.h"
|
||||
#include "mgba-util/common.h"
|
||||
#include "mgba-util/vfs.h"
|
||||
|
||||
// interop sanity checks
|
||||
static_assert(sizeof(bool) == 1, "Wrong bool size!");
|
||||
static_assert(sizeof(color_t) == 2, "Wrong color_t size!");
|
||||
static_assert(sizeof(enum mWatchpointType) == 4, "Wrong mWatchpointType size!");
|
||||
static_assert(sizeof(enum GBASavedataType) == 4, "Wrong GBASavedataType size!");
|
||||
static_assert(sizeof(enum GBAHardwareDevice) == 4, "Wrong GBAHardwareDevice size!");
|
||||
static_assert(sizeof(ssize_t) == 8, "Wrong ssize_t size!");
|
||||
static_assert(sizeof(void*) == 8, "Wrong pointer size!");
|
||||
|
||||
const char* const binaryName = "mgba";
|
||||
const char* const projectName = "mGBA BizHawk";
|
||||
const char* const projectVersion = "(unknown)";
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EXP __declspec(dllexport)
|
||||
#else
|
||||
#define EXP __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
* @type: the type of the container struct this is embedded in.
|
||||
* @member: the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
struct VFile* VFileOpenFD(const char* path, int flags) { return NULL; }
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct mCore* core;
|
||||
struct mLogger logger;
|
||||
struct GBA* gba; // anything that uses this will be deprecated eventually
|
||||
color_t vbuff[GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS];
|
||||
void* rom;
|
||||
struct VFile* romvf;
|
||||
uint8_t bios[0x4000];
|
||||
struct VFile* biosvf;
|
||||
uint8_t sram[0x20000 + 16];
|
||||
struct VFile* sramvf;
|
||||
struct mKeyCallback keysource;
|
||||
struct mRotationSource rotsource;
|
||||
struct mRTCSource rtcsource;
|
||||
struct GBALuminanceSource lumasource;
|
||||
struct mDebugger debugger;
|
||||
struct mDebuggerModule module;
|
||||
bool attached;
|
||||
struct GBACartridgeOverride override;
|
||||
int16_t tiltx;
|
||||
int16_t tilty;
|
||||
int16_t tiltz;
|
||||
int64_t time;
|
||||
uint8_t light;
|
||||
uint16_t keys;
|
||||
bool lagged;
|
||||
bool skipbios;
|
||||
uint32_t palette[0x10000];
|
||||
void (*input_callback)(void);
|
||||
void (*trace_callback)(const char *buffer);
|
||||
void (*exec_callback)(uint32_t pc);
|
||||
void (*mem_callback)(uint32_t addr, enum mWatchpointType type, uint32_t oldValue, uint32_t newValue);
|
||||
} bizctx;
|
||||
|
||||
static int32_t GetX(struct mRotationSource* rotationSource)
|
||||
{
|
||||
return container_of(rotationSource, bizctx, rotsource)->tiltx << 16;
|
||||
}
|
||||
static int32_t GetY(struct mRotationSource* rotationSource)
|
||||
{
|
||||
return container_of(rotationSource, bizctx, rotsource)->tilty << 16;
|
||||
}
|
||||
static int32_t GetZ(struct mRotationSource* rotationSource)
|
||||
{
|
||||
return container_of(rotationSource, bizctx, rotsource)->tiltz << 16;
|
||||
}
|
||||
static uint8_t GetLight(struct GBALuminanceSource* luminanceSource)
|
||||
{
|
||||
return container_of(luminanceSource, bizctx, lumasource)->light;
|
||||
}
|
||||
static time_t GetTime(struct mRTCSource* rtcSource)
|
||||
{
|
||||
return container_of(rtcSource, bizctx, rtcsource)->time;
|
||||
}
|
||||
static uint16_t GetKeys(struct mKeyCallback* keypadSource)
|
||||
{
|
||||
bizctx *ctx = container_of(keypadSource, bizctx, keysource);
|
||||
ctx->input_callback();
|
||||
ctx->lagged = false;
|
||||
return ctx->keys;
|
||||
}
|
||||
static void RotationCB(struct mRotationSource* rotationSource)
|
||||
{
|
||||
bizctx* ctx = container_of(rotationSource, bizctx, rotsource);
|
||||
ctx->input_callback();
|
||||
ctx->lagged = false;
|
||||
}
|
||||
static void LightCB(struct GBALuminanceSource* luminanceSource)
|
||||
{
|
||||
bizctx* ctx = container_of(luminanceSource, bizctx, lumasource);
|
||||
ctx->input_callback();
|
||||
ctx->lagged = false;
|
||||
}
|
||||
static void TimeCB(struct mRTCSource* rtcSource)
|
||||
{
|
||||
// no, reading the rtc registers should not unset the lagged flag
|
||||
// bizctx* ctx = container_of(rtcSource, bizctx, rtcsource);
|
||||
// ctx->lagged = false;
|
||||
}
|
||||
static void logdebug(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void resetinternal(bizctx* ctx)
|
||||
{
|
||||
// RTC will be reinit on GBAOverrideApply
|
||||
// The RTC data contents in the sramvf are also read back
|
||||
// This is done so RTC data is up to date
|
||||
// note reset internally calls GBAOverrideApply potentially, so we do this now
|
||||
GBASavedataRTCWrite(&ctx->gba->memory.savedata);
|
||||
|
||||
ctx->core->reset(ctx->core);
|
||||
if (ctx->skipbios)
|
||||
GBASkipBIOS(ctx->gba);
|
||||
|
||||
if (ctx->gba->memory.rom)
|
||||
{
|
||||
GBASavedataRTCWrite(&ctx->gba->memory.savedata); // again to be safe (not sure if needed?)
|
||||
GBAOverrideApply(ctx->gba, &ctx->override);
|
||||
}
|
||||
}
|
||||
|
||||
EXP void BizDestroy(bizctx* ctx)
|
||||
{
|
||||
if (ctx->attached)
|
||||
{
|
||||
ctx->core->detachDebugger(ctx->core);
|
||||
mDebuggerDetachModule(&ctx->debugger, &ctx->module);
|
||||
mDebuggerDeinit(&ctx->debugger);
|
||||
}
|
||||
|
||||
ctx->core->deinit(ctx->core);
|
||||
free(ctx->rom);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum GBASavedataType savetype;
|
||||
enum GBAHardwareDevice hardware;
|
||||
uint32_t idleLoop;
|
||||
bool vbaBugCompat;
|
||||
bool detectPokemonRomHacks;
|
||||
} overrideinfo;
|
||||
|
||||
void exec_hook(struct mDebuggerModule* module)
|
||||
{
|
||||
bizctx* ctx = container_of(module, bizctx, module);
|
||||
if (ctx->trace_callback)
|
||||
{
|
||||
char trace[1024];
|
||||
trace[sizeof(trace) - 1] = '\0';
|
||||
size_t traceSize = sizeof(trace) - 2;
|
||||
ctx->debugger.platform->trace(ctx->debugger.platform, trace, &traceSize);
|
||||
if (traceSize + 1 <= sizeof(trace)) {
|
||||
trace[traceSize] = '\n';
|
||||
trace[traceSize + 1] = '\0';
|
||||
}
|
||||
ctx->trace_callback(trace);
|
||||
}
|
||||
if (ctx->exec_callback)
|
||||
ctx->exec_callback(_ARMPCAddress(ctx->core->cpu));
|
||||
}
|
||||
|
||||
EXP void BizSetInputCallback(bizctx* ctx, void(*callback)(void))
|
||||
{
|
||||
ctx->input_callback = callback;
|
||||
}
|
||||
|
||||
EXP void BizSetTraceCallback(bizctx* ctx, void(*callback)(const char *buffer))
|
||||
{
|
||||
ctx->trace_callback = callback;
|
||||
}
|
||||
|
||||
EXP void BizSetExecCallback(bizctx* ctx, void(*callback)(uint32_t pc))
|
||||
{
|
||||
ctx->exec_callback = callback;
|
||||
}
|
||||
|
||||
EXP void BizSetMemCallback(bizctx* ctx, void(*callback)(uint32_t addr, enum mWatchpointType type, uint32_t oldValue, uint32_t newValue))
|
||||
{
|
||||
ctx->mem_callback = callback;
|
||||
}
|
||||
|
||||
static void watchpoint_entry(struct mDebuggerModule* module, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info)
|
||||
{
|
||||
bizctx* ctx = container_of(module, bizctx, module);
|
||||
if (reason == DEBUGGER_ENTER_WATCHPOINT && info && ctx->mem_callback)
|
||||
{
|
||||
module->entered = NULL; // don't allow this callback to be re-entered
|
||||
ctx->mem_callback(info->address, info->type.wp.accessType, info->type.wp.oldValue, info->type.wp.newValue);
|
||||
module->entered = watchpoint_entry;
|
||||
}
|
||||
|
||||
module->isPaused = false;
|
||||
module->needsCallback = ctx->trace_callback || ctx->exec_callback;
|
||||
}
|
||||
|
||||
EXP ssize_t BizSetWatchpoint(bizctx* ctx, uint32_t addr, enum mWatchpointType type)
|
||||
{
|
||||
struct mWatchpoint watchpoint = {
|
||||
.minAddress = addr,
|
||||
.maxAddress = addr + 1,
|
||||
.segment = -1,
|
||||
.type = type
|
||||
};
|
||||
return ctx->debugger.platform->setWatchpoint(ctx->debugger.platform, &ctx->module, &watchpoint);
|
||||
}
|
||||
|
||||
EXP bool BizClearWatchpoint(bizctx* ctx, ssize_t id)
|
||||
{
|
||||
return ctx->debugger.platform->clearBreakpoint(ctx->debugger.platform, id);
|
||||
}
|
||||
|
||||
EXP bizctx* BizCreate(const void* bios, const void* data, uint32_t length, const overrideinfo* overrides, bool skipbios)
|
||||
{
|
||||
bizctx* ctx = calloc(1, sizeof(*ctx));
|
||||
if (!ctx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->rom = malloc(length);
|
||||
if (!ctx->rom)
|
||||
{
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->logger.log = logdebug;
|
||||
mLogSetDefaultLogger(&ctx->logger);
|
||||
ctx->skipbios = skipbios;
|
||||
|
||||
memcpy(ctx->rom, data, length);
|
||||
ctx->romvf = VFileFromMemory(ctx->rom, length);
|
||||
if (!ctx->romvf)
|
||||
{
|
||||
free(ctx->rom);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->core = GBACoreCreate();
|
||||
if (!ctx->core)
|
||||
{
|
||||
ctx->romvf->close(ctx->romvf);
|
||||
free(ctx->rom);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mCoreInitConfig(ctx->core, NULL);
|
||||
|
||||
if (!ctx->core->init(ctx->core))
|
||||
{
|
||||
BizDestroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->gba = ctx->core->board;
|
||||
|
||||
ctx->core->setVideoBuffer(ctx->core, ctx->vbuff, GBA_VIDEO_HORIZONTAL_PIXELS);
|
||||
ctx->core->setAudioBufferSize(ctx->core, 1024);
|
||||
|
||||
blip_set_rates(ctx->core->getAudioChannel(ctx->core, 0), ctx->core->frequency(ctx->core), 44100);
|
||||
blip_set_rates(ctx->core->getAudioChannel(ctx->core, 1), ctx->core->frequency(ctx->core), 44100);
|
||||
|
||||
if (!ctx->core->loadROM(ctx->core, ctx->romvf))
|
||||
{
|
||||
BizDestroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ctx->sram, 0xff, sizeof(ctx->sram));
|
||||
ctx->sramvf = VFileFromMemory(ctx->sram, sizeof(ctx->sram));
|
||||
if (!ctx->sramvf)
|
||||
{
|
||||
BizDestroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->core->loadSave(ctx->core, ctx->sramvf);
|
||||
|
||||
mCoreSetRTC(ctx->core, &ctx->rtcsource);
|
||||
|
||||
ctx->gba->idleOptimization = IDLE_LOOP_IGNORE; // Don't do "idle skipping"
|
||||
ctx->gba->keyCallback = &ctx->keysource; // Callback for key reading
|
||||
|
||||
ctx->keysource.readKeys = GetKeys;
|
||||
ctx->rotsource.sample = RotationCB;
|
||||
ctx->rotsource.readTiltX = GetX;
|
||||
ctx->rotsource.readTiltY = GetY;
|
||||
ctx->rotsource.readGyroZ = GetZ;
|
||||
ctx->lumasource.sample = LightCB;
|
||||
ctx->lumasource.readLuminance = GetLight;
|
||||
ctx->rtcsource.sample = TimeCB;
|
||||
ctx->rtcsource.unixTime = GetTime;
|
||||
|
||||
ctx->core->setPeripheral(ctx->core, mPERIPH_ROTATION, &ctx->rotsource);
|
||||
ctx->core->setPeripheral(ctx->core, mPERIPH_GBA_LUMINANCE, &ctx->lumasource);
|
||||
|
||||
if (bios)
|
||||
{
|
||||
memcpy(ctx->bios, bios, sizeof(ctx->bios));
|
||||
ctx->biosvf = VFileFromMemory(ctx->bios, sizeof(ctx->bios));
|
||||
/*if (!GBAIsBIOS(ctx->biosvf))
|
||||
{
|
||||
ctx->biosvf->close(ctx->biosvf);
|
||||
GBADestroy(&ctx->gba);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}*/
|
||||
ctx->core->loadBIOS(ctx->core, ctx->biosvf, 0);
|
||||
}
|
||||
|
||||
// setup overrides (largely copy paste from GBAOverrideApplyDefaults, with minor changes for our wants)
|
||||
const struct GBACartridge* cart = (const struct GBACartridge*) ctx->gba->memory.rom;
|
||||
if (cart)
|
||||
{
|
||||
memcpy(ctx->override.id, &cart->id, sizeof(ctx->override.id));
|
||||
bool isPokemon = false, isKnownPokemon = false;
|
||||
|
||||
if (overrides->detectPokemonRomHacks)
|
||||
{
|
||||
static const uint32_t pokemonTable[] =
|
||||
{
|
||||
// Emerald
|
||||
0x4881F3F8, // BPEJ
|
||||
0x8C4D3108, // BPES
|
||||
0x1F1C08FB, // BPEE
|
||||
0x34C9DF89, // BPED
|
||||
0xA3FDCCB1, // BPEF
|
||||
0xA0AEC80A, // BPEI
|
||||
|
||||
// FireRed
|
||||
0x1A81EEDF, // BPRD
|
||||
0x3B2056E9, // BPRJ
|
||||
0x5DC668F6, // BPRF
|
||||
0x73A72167, // BPRI
|
||||
0x84EE4776, // BPRE rev 1
|
||||
0x9F08064E, // BPRS
|
||||
0xBB640DF7, // BPRJ rev 1
|
||||
0xDD88761C, // BPRE
|
||||
|
||||
// Ruby
|
||||
0x61641576, // AXVE rev 1
|
||||
0xAEAC73E6, // AXVE rev 2
|
||||
0xF0815EE7, // AXVE
|
||||
};
|
||||
|
||||
isPokemon = isPokemon || !strncmp("pokemon red version", &((const char*) ctx->gba->memory.rom)[0x108], 20);
|
||||
isPokemon = isPokemon || !strncmp("pokemon emerald version", &((const char*) ctx->gba->memory.rom)[0x108], 24);
|
||||
isPokemon = isPokemon || !strncmp("AXVE", &((const char*) ctx->gba->memory.rom)[0xAC], 4);
|
||||
|
||||
if (isPokemon)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; !isKnownPokemon && i < sizeof(pokemonTable) / sizeof(*pokemonTable); ++i)
|
||||
{
|
||||
isKnownPokemon = ctx->gba->romCrc32 == pokemonTable[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isPokemon && !isKnownPokemon)
|
||||
{
|
||||
ctx->override.savetype = GBA_SAVEDATA_FLASH1M;
|
||||
ctx->override.hardware = HW_RTC;
|
||||
ctx->override.vbaBugCompat = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GBAOverrideFind(NULL, &ctx->override); // apply defaults
|
||||
if (overrides->savetype != GBA_SAVEDATA_AUTODETECT)
|
||||
{
|
||||
ctx->override.savetype = overrides->savetype;
|
||||
}
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (!(overrides->hardware & (128 << i)))
|
||||
{
|
||||
if (overrides->hardware & (1 << i))
|
||||
{
|
||||
ctx->override.hardware |= (1 << i);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->override.hardware &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx->override.hardware |= overrides->hardware & 64; // gb player detect
|
||||
ctx->override.vbaBugCompat = overrides->vbaBugCompat;
|
||||
}
|
||||
|
||||
ctx->override.idleLoop = overrides->idleLoop;
|
||||
}
|
||||
|
||||
mDebuggerInit(&ctx->debugger);
|
||||
ctx->module.type = DEBUGGER_CUSTOM;
|
||||
ctx->module.custom = exec_hook;
|
||||
ctx->module.entered = watchpoint_entry;
|
||||
mDebuggerAttachModule(&ctx->debugger, &ctx->module);
|
||||
mDebuggerAttach(&ctx->debugger, ctx->core);
|
||||
ctx->attached = true;
|
||||
|
||||
resetinternal(ctx);
|
||||
|
||||
// proper init RTC, our buffer would have trashed it
|
||||
if (ctx->override.hardware & HW_RTC)
|
||||
{
|
||||
GBAHardwareInitRTC(&ctx->gba->memory.hw);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
EXP void BizReset(bizctx* ctx)
|
||||
{
|
||||
resetinternal(ctx);
|
||||
}
|
||||
|
||||
static void blit(uint32_t* dst, const color_t* src, const uint32_t* palette)
|
||||
{
|
||||
uint32_t* dst_end = dst + GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS;
|
||||
|
||||
while (dst < dst_end)
|
||||
{
|
||||
*dst++ = palette[*src++];
|
||||
}
|
||||
}
|
||||
|
||||
EXP bool BizAdvance(bizctx* ctx, uint16_t keys, uint32_t* vbuff, uint32_t* nsamp, int16_t* sbuff,
|
||||
int64_t time, int16_t gyrox, int16_t gyroy, int16_t gyroz, uint8_t luma)
|
||||
{
|
||||
ctx->core->setKeys(ctx->core, keys);
|
||||
ctx->keys = keys;
|
||||
ctx->light = luma;
|
||||
ctx->time = time;
|
||||
ctx->tiltx = gyrox;
|
||||
ctx->tilty = gyroy;
|
||||
ctx->tiltz = gyroz;
|
||||
ctx->lagged = true;
|
||||
|
||||
ctx->module.needsCallback = ctx->trace_callback || ctx->exec_callback;
|
||||
ctx->debugger.state = ctx->module.needsCallback ? DEBUGGER_CALLBACK : DEBUGGER_RUNNING;
|
||||
mDebuggerRunFrame(&ctx->debugger);
|
||||
|
||||
blit(vbuff, ctx->vbuff, ctx->palette);
|
||||
*nsamp = blip_samples_avail(ctx->core->getAudioChannel(ctx->core, 0));
|
||||
if (*nsamp > 1024)
|
||||
*nsamp = 1024;
|
||||
blip_read_samples(ctx->core->getAudioChannel(ctx->core, 0), sbuff, 1024, true);
|
||||
blip_read_samples(ctx->core->getAudioChannel(ctx->core, 1), sbuff + 1, 1024, true);
|
||||
return ctx->lagged;
|
||||
}
|
||||
|
||||
EXP void BizSetPalette(bizctx* ctx, const uint32_t* palette)
|
||||
{
|
||||
memcpy(ctx->palette, palette, sizeof(ctx->palette));
|
||||
}
|
||||
|
||||
struct MemoryAreas
|
||||
{
|
||||
const void* bios;
|
||||
const void* wram;
|
||||
const void* iwram;
|
||||
const void* mmio;
|
||||
const void* palram;
|
||||
const void* vram;
|
||||
const void* oam;
|
||||
const void* rom;
|
||||
const void* sram;
|
||||
};
|
||||
|
||||
EXP void BizGetMemoryAreas(bizctx* ctx, struct MemoryAreas* dst)
|
||||
{
|
||||
size_t sizeOut;
|
||||
dst->bios = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_BIOS, &sizeOut);
|
||||
dst->wram = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_EWRAM, &sizeOut);
|
||||
dst->iwram = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_IWRAM, &sizeOut);
|
||||
dst->mmio = ctx->gba->memory.io;
|
||||
dst->palram = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_PALETTE_RAM, &sizeOut);
|
||||
dst->vram = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_VRAM, &sizeOut);
|
||||
dst->oam = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_OAM, &sizeOut);
|
||||
dst->rom = ctx->core->getMemoryBlock(ctx->core, GBA_REGION_ROM0, &sizeOut);
|
||||
// Return the buffer that BizHawk hands to mGBA for storing savedata.
|
||||
// getMemoryBlock is avoided because mGBA doesn't always know save type at startup,
|
||||
// so getMemoryBlock may return nothing until the save type is detected.
|
||||
// (returning the buffer directly avoids 0-size and variable-size savedata)
|
||||
dst->sram = ctx->sram;
|
||||
// If ROM is not present (due to multiboot), send our raw buffer over
|
||||
if (!dst->rom)
|
||||
{
|
||||
dst->rom = ctx->rom;
|
||||
}
|
||||
}
|
||||
|
||||
EXP uint32_t BizGetSaveRam(bizctx* ctx, void* data, uint32_t size)
|
||||
{
|
||||
GBASavedataRTCWrite(&ctx->gba->memory.savedata); // make sure RTC data is up to date
|
||||
ctx->sramvf->seek(ctx->sramvf, 0, SEEK_SET);
|
||||
return ctx->sramvf->read(ctx->sramvf, data, size);
|
||||
}
|
||||
|
||||
EXP void BizPutSaveRam(bizctx* ctx, const void* data, uint32_t size)
|
||||
{
|
||||
ctx->sramvf->seek(ctx->sramvf, 0, SEEK_SET);
|
||||
ctx->sramvf->write(ctx->sramvf, data, size);
|
||||
if ((ctx->override.hardware & HW_RTC) && (size & 0xff)) // RTC data is in the save, read it out
|
||||
{
|
||||
GBASavedataRTCRead(&ctx->gba->memory.savedata);
|
||||
}
|
||||
}
|
||||
|
||||
// state sizes can vary!
|
||||
EXP bool BizStartGetState(bizctx* ctx, struct VFile** file, uint32_t* size)
|
||||
{
|
||||
struct VFile* vf = VFileMemChunk(NULL, 0);
|
||||
if (!mCoreSaveStateNamed(ctx->core, vf, SAVESTATE_SAVEDATA))
|
||||
{
|
||||
vf->close(vf);
|
||||
return false;
|
||||
}
|
||||
*file = vf;
|
||||
*size = vf->seek(vf, 0, SEEK_END);
|
||||
return true;
|
||||
}
|
||||
|
||||
EXP void BizFinishGetState(struct VFile* file, void* data, uint32_t size)
|
||||
{
|
||||
file->seek(file, 0, SEEK_SET);
|
||||
file->read(file, data, size);
|
||||
file->close(file);
|
||||
}
|
||||
|
||||
EXP bool BizPutState(bizctx* ctx, const void* data, uint32_t size)
|
||||
{
|
||||
struct VFile* vf = VFileFromConstMemory(data, size);
|
||||
bool ret = mCoreLoadStateNamed(ctx->core, vf, SAVESTATE_SAVEDATA);
|
||||
vf->close(vf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXP void BizSetLayerMask(bizctx *ctx, uint32_t mask)
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
ctx->core->enableVideoLayer(ctx->core, i, mask & 1 << i);
|
||||
}
|
||||
|
||||
EXP void BizSetSoundMask(bizctx* ctx, uint32_t mask)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
ctx->core->enableAudioChannel(ctx->core, i, mask & 1 << i);
|
||||
}
|
||||
|
||||
EXP void BizGetRegisters(bizctx* ctx, int32_t* dest)
|
||||
{
|
||||
memcpy(dest, ctx->gba->cpu, 18 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
EXP void BizSetRegister(bizctx* ctx, int32_t index, int32_t value)
|
||||
{
|
||||
if (index >= 0 && index < 16)
|
||||
{
|
||||
ctx->gba->cpu->gprs[index] = value;
|
||||
}
|
||||
|
||||
if (index == 16)
|
||||
{
|
||||
memcpy(&ctx->gba->cpu->cpsr, &value, sizeof(int32_t));
|
||||
}
|
||||
|
||||
if (index == 17)
|
||||
{
|
||||
memcpy(&ctx->gba->cpu->spsr, &value, sizeof(int32_t));
|
||||
}
|
||||
}
|
||||
|
||||
EXP uint64_t BizGetGlobalTime(bizctx* ctx)
|
||||
{
|
||||
return mTimingGlobalTime(ctx->debugger.core->timing);
|
||||
}
|
||||
|
||||
EXP void BizWriteBus(bizctx* ctx, uint32_t addr, uint8_t val)
|
||||
{
|
||||
ctx->core->rawWrite8(ctx->core, addr, -1, val);
|
||||
}
|
||||
|
||||
EXP uint8_t BizReadBus(bizctx* ctx, uint32_t addr)
|
||||
{
|
||||
return ctx->core->busRead8(ctx->core, addr);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
CC ?= gcc
|
||||
RM ?= rm
|
||||
CP ?= cp
|
||||
|
||||
MACHINE = $(shell $(CC) -dumpmachine)
|
||||
|
||||
ifneq (,$(findstring i686,$(MACHINE)))
|
||||
$(error 32 bit build no longer supported)
|
||||
else ifneq (,$(findstring x86_64,$(MACHINE)))
|
||||
ARCH = 64
|
||||
else
|
||||
$(error Unknown arch)
|
||||
endif
|
||||
|
||||
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
ROOT_DIR := $(MAKEFILE_DIR)/../../..
|
||||
OBJ_DIR := $(MAKEFILE_DIR)/obj
|
||||
|
||||
LDFLAGS_64 =
|
||||
LDFLAGS = -shared -s $(LDFLAGS_$(ARCH)) $(CCFLAGS)
|
||||
|
||||
PLAT_SRCS += \
|
||||
$(ROOT_DIR)/platform/posix/memory.c
|
||||
|
||||
PLAT_FLAGS += \
|
||||
-DHAVE_LOCALE -DHAVE_LOCALTIME_R -fvisibility=hidden -fPIC
|
||||
|
||||
TARGET = libmgba.dll.so
|
||||
|
||||
include ../base.mak
|
|
@ -0,0 +1,179 @@
|
|||
|
||||
//
|
||||
// time.c
|
||||
//
|
||||
// Time routines
|
||||
//
|
||||
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// 3. Neither the name of the project nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
// SUCH DAMAGE.
|
||||
//
|
||||
#include <time.h>
|
||||
|
||||
#define YEAR0 1900
|
||||
#define EPOCH_YR 1970
|
||||
#define SECS_DAY (24L * 60L * 60L)
|
||||
#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
|
||||
#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
|
||||
#define FIRSTSUNDAY(timp) (((timp)->tm_yday - (timp)->tm_wday + 420) % 7)
|
||||
#define FIRSTDAYOF(timp) (((timp)->tm_wday - (timp)->tm_yday + 420) % 7)
|
||||
|
||||
#define TIME_MAX 2147483647L
|
||||
|
||||
static const int _ytab[2][12] = {
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
errno_t _localtime64_s(struct tm *tmbuf, const time_t *timer) {
|
||||
#else
|
||||
struct tm *localtime_r(const time_t *timer, struct tm *tmbuf) {
|
||||
#endif
|
||||
time_t time = *timer;
|
||||
unsigned long dayclock, dayno;
|
||||
int year = EPOCH_YR;
|
||||
|
||||
dayclock = (unsigned long) time % SECS_DAY;
|
||||
dayno = (unsigned long) time / SECS_DAY;
|
||||
|
||||
tmbuf->tm_sec = dayclock % 60;
|
||||
tmbuf->tm_min = (dayclock % 3600) / 60;
|
||||
tmbuf->tm_hour = dayclock / 3600;
|
||||
tmbuf->tm_wday = (dayno + 4) % 7; // Day 0 was a thursday
|
||||
while (dayno >= (unsigned long) YEARSIZE(year)) {
|
||||
dayno -= YEARSIZE(year);
|
||||
year++;
|
||||
}
|
||||
tmbuf->tm_year = year - YEAR0;
|
||||
tmbuf->tm_yday = dayno;
|
||||
tmbuf->tm_mon = 0;
|
||||
while (dayno >= (unsigned long) _ytab[LEAPYEAR(year)][tmbuf->tm_mon]) {
|
||||
dayno -= _ytab[LEAPYEAR(year)][tmbuf->tm_mon];
|
||||
tmbuf->tm_mon++;
|
||||
}
|
||||
tmbuf->tm_mday = dayno + 1;
|
||||
tmbuf->tm_isdst = 0;
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
return tmbuf;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
time_t _mktime64(struct tm *tmbuf) {
|
||||
#else
|
||||
time_t mktime(struct tm *tmbuf) {
|
||||
#endif
|
||||
long day, year;
|
||||
int tm_year;
|
||||
int yday, month;
|
||||
/*unsigned*/ long seconds;
|
||||
int overflow;
|
||||
|
||||
tmbuf->tm_min += tmbuf->tm_sec / 60;
|
||||
tmbuf->tm_sec %= 60;
|
||||
if (tmbuf->tm_sec < 0) {
|
||||
tmbuf->tm_sec += 60;
|
||||
tmbuf->tm_min--;
|
||||
}
|
||||
tmbuf->tm_hour += tmbuf->tm_min / 60;
|
||||
tmbuf->tm_min = tmbuf->tm_min % 60;
|
||||
if (tmbuf->tm_min < 0) {
|
||||
tmbuf->tm_min += 60;
|
||||
tmbuf->tm_hour--;
|
||||
}
|
||||
day = tmbuf->tm_hour / 24;
|
||||
tmbuf->tm_hour= tmbuf->tm_hour % 24;
|
||||
if (tmbuf->tm_hour < 0) {
|
||||
tmbuf->tm_hour += 24;
|
||||
day--;
|
||||
}
|
||||
tmbuf->tm_year += tmbuf->tm_mon / 12;
|
||||
tmbuf->tm_mon %= 12;
|
||||
if (tmbuf->tm_mon < 0) {
|
||||
tmbuf->tm_mon += 12;
|
||||
tmbuf->tm_year--;
|
||||
}
|
||||
day += (tmbuf->tm_mday - 1);
|
||||
while (day < 0) {
|
||||
if(--tmbuf->tm_mon < 0) {
|
||||
tmbuf->tm_year--;
|
||||
tmbuf->tm_mon = 11;
|
||||
}
|
||||
day += _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
|
||||
}
|
||||
while (day >= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon]) {
|
||||
day -= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
|
||||
if (++(tmbuf->tm_mon) == 12) {
|
||||
tmbuf->tm_mon = 0;
|
||||
tmbuf->tm_year++;
|
||||
}
|
||||
}
|
||||
tmbuf->tm_mday = day + 1;
|
||||
year = EPOCH_YR;
|
||||
if (tmbuf->tm_year < year - YEAR0) return (time_t) -1;
|
||||
seconds = 0;
|
||||
day = 0; // Means days since day 0 now
|
||||
overflow = 0;
|
||||
|
||||
// Assume that when day becomes negative, there will certainly
|
||||
// be overflow on seconds.
|
||||
// The check for overflow needs not to be done for leapyears
|
||||
// divisible by 400.
|
||||
// The code only works when year (1970) is not a leapyear.
|
||||
tm_year = tmbuf->tm_year + YEAR0;
|
||||
|
||||
if (TIME_MAX / 365 < tm_year - year) overflow++;
|
||||
day = (tm_year - year) * 365;
|
||||
if (TIME_MAX - day < (tm_year - year) / 4 + 1) overflow++;
|
||||
day += (tm_year - year) / 4 + ((tm_year % 4) && tm_year % 4 < year % 4);
|
||||
day -= (tm_year - year) / 100 + ((tm_year % 100) && tm_year % 100 < year % 100);
|
||||
day += (tm_year - year) / 400 + ((tm_year % 400) && tm_year % 400 < year % 400);
|
||||
|
||||
yday = month = 0;
|
||||
while (month < tmbuf->tm_mon) {
|
||||
yday += _ytab[LEAPYEAR(tm_year)][month];
|
||||
month++;
|
||||
}
|
||||
yday += (tmbuf->tm_mday - 1);
|
||||
if (day + yday < 0) overflow++;
|
||||
day += yday;
|
||||
|
||||
tmbuf->tm_yday = yday;
|
||||
tmbuf->tm_wday = (day + 4) % 7; // Day 0 was thursday (4)
|
||||
|
||||
seconds = ((tmbuf->tm_hour * 60L) + tmbuf->tm_min) * 60L + tmbuf->tm_sec;
|
||||
|
||||
if ((TIME_MAX - seconds) / SECS_DAY < day) overflow++;
|
||||
seconds += day * SECS_DAY;
|
||||
|
||||
if (overflow) return (time_t) -1;
|
||||
|
||||
if ((time_t) seconds != seconds) return (time_t) -1;
|
||||
return (time_t) seconds;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
CC ?= gcc
|
||||
RM ?= rm
|
||||
CP ?= cp
|
||||
|
||||
MACHINE = $(shell $(CC) -dumpmachine)
|
||||
|
||||
ifneq (,$(findstring i686,$(MACHINE)))
|
||||
$(error 32 bit build no longer supported)
|
||||
else ifneq (,$(findstring x86_64,$(MACHINE)))
|
||||
ARCH = 64
|
||||
else
|
||||
$(error Unknown arch)
|
||||
endif
|
||||
|
||||
MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
ROOT_DIR := $(MAKEFILE_DIR)/../../..
|
||||
OBJ_DIR := $(MAKEFILE_DIR)/obj
|
||||
|
||||
LDFLAGS_32 = -static-libgcc
|
||||
LDFLAGS_64 =
|
||||
LDFLAGS = -shared -s $(LDFLAGS_$(ARCH)) $(CCFLAGS) -lshlwapi
|
||||
|
||||
PLAT_SRCS += \
|
||||
$(ROOT_DIR)/platform/windows/memory.c
|
||||
|
||||
PLAT_FLAGS += \
|
||||
-Wno-format -Wno-inconsistent-dllimport -D_mktime64=biz_mktime64 -D_localtime64_s=biz_localtime64_s
|
||||
|
||||
TARGET = mgba.dll
|
||||
|
||||
include ../base.mak
|
Loading…
Reference in New Issue