diff --git a/Info.plist b/Info.plist
index 4c0b80f..3ae5a7b 100644
--- a/Info.plist
+++ b/Info.plist
@@ -17,7 +17,7 @@
CFBundleSignature
????
CFBundleVersion
- 0.8.0
+ 0.8.1
NSPrincipalClass
OEGameCoreController
OEGameCoreClass
diff --git a/src/core/core.c b/src/core/core.c
index 0a79eab..79723c4 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -370,7 +370,7 @@ bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
Elf32_Phdr* phdr = ELFProgramHeadersGetPointer(&ph, i);
void* block = mCoreGetMemoryBlock(core, phdr->p_paddr, &bsize);
char* bytes = ELFBytes(elf, &esize);
- if (block && bsize >= phdr->p_filesz && esize >= phdr->p_filesz + phdr->p_offset) {
+ if (block && bsize >= phdr->p_filesz && bsize > phdr->p_offset && esize >= phdr->p_filesz + phdr->p_offset) {
memcpy(block, &bytes[phdr->p_offset], phdr->p_filesz);
} else {
return false;
diff --git a/src/gb/audio.c b/src/gb/audio.c
index 63af6bc..4bc5fa3 100644
--- a/src/gb/audio.c
+++ b/src/gb/audio.c
@@ -1078,9 +1078,13 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
LOAD_32LE(audio->ch4.lastEvent, 0, &state->ch4.lastEvent);
LOAD_32LE(when, 0, &state->ch4.nextEvent);
if (audio->ch4.envelope.dead < 2 && audio->playingCh4) {
- if (when - audio->ch4.lastEvent > (uint32_t) audio->sampleInterval) {
+ if (!audio->ch4.lastEvent) {
// Back-compat: fake this value
- audio->ch4.lastEvent = when - audio->sampleInterval;
+ uint32_t currentTime = mTimingCurrentTime(audio->timing);
+ int32_t cycles = audio->ch4.ratio ? 2 * audio->ch4.ratio : 1;
+ cycles <<= audio->ch4.frequency;
+ cycles *= 8 * audio->timingFactor;
+ audio->ch4.lastEvent = currentTime + (when & (cycles - 1)) - cycles;
}
mTimingSchedule(audio->timing, &audio->ch4Event, when);
}
diff --git a/src/gb/debugger/cli.c b/src/gb/debugger/cli.c
index 9ad6cdd..cba9f4a 100644
--- a/src/gb/debugger/cli.c
+++ b/src/gb/debugger/cli.c
@@ -16,13 +16,17 @@ static void _GBCLIDebuggerInit(struct CLIDebuggerSystem*);
static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem*);
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
+#endif
struct CLIDebuggerCommandSummary _GBCLIDebuggerCommands[] = {
{ "frame", _frame, "", "Frame advance" },
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
{ "load", _load, "*", "Load a savestate" },
{ "save", _save, "*", "Save a savestate" },
+#endif
{ 0, 0, 0, 0 }
};
@@ -73,6 +77,7 @@ static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1;
}
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct CLIDebuggerBackend* be = debugger->backend;
if (!dv || dv->type != CLIDV_INT_TYPE) {
@@ -106,3 +111,4 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
mCoreSaveState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC | SAVESTATE_METADATA);
}
+#endif
diff --git a/src/gba/audio.c b/src/gba/audio.c
index d2650d6..72f49b7 100644
--- a/src/gba/audio.c
+++ b/src/gba/audio.c
@@ -104,6 +104,8 @@ void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) {
}
void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
+ info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
+ info->reg = GBADMARegisterSetWidth(info->reg, 1);
switch (info->dest) {
case BASE_IO | REG_FIFO_A_LO:
audio->chA.dmaSource = number;
@@ -129,8 +131,6 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA*
audio->externalMixing = false;
}
}
- info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
- info->reg = GBADMARegisterSetWidth(info->reg, 1);
}
void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
diff --git a/src/gba/core.c b/src/gba/core.c
index 3c1ba6d..5d027c0 100644
--- a/src/gba/core.c
+++ b/src/gba/core.c
@@ -608,7 +608,7 @@ static void _GBACoreReset(struct mCore* core) {
#endif
ARMReset(core->cpu);
- if (core->opts.skipBios && (gba->romVf || gba->memory.rom)) {
+ if ((core->opts.skipBios && (gba->romVf || gba->memory.rom)) || (gba->romVf && GBAIsMB(gba->romVf))) {
GBASkipBIOS(core->board);
}
}
diff --git a/src/gba/debugger/cli.c b/src/gba/debugger/cli.c
index 643a12b..5349911 100644
--- a/src/gba/debugger/cli.c
+++ b/src/gba/debugger/cli.c
@@ -16,13 +16,17 @@ static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
+#endif
struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
{ "frame", _frame, "", "Frame advance" },
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
{ "load", _load, "*", "Load a savestate" },
{ "save", _save, "*", "Save a savestate" },
+#endif
{ 0, 0, 0, 0 }
};
@@ -72,6 +76,7 @@ static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
}
+#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct CLIDebuggerBackend* be = debugger->backend;
if (!dv || dv->type != CLIDV_INT_TYPE) {
@@ -107,3 +112,4 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC | SAVESTATE_METADATA);
}
+#endif
diff --git a/src/gba/gba.c b/src/gba/gba.c
index 7c00151..769e85b 100644
--- a/src/gba/gba.c
+++ b/src/gba/gba.c
@@ -257,7 +257,7 @@ void GBASkipBIOS(struct GBA* gba) {
if (gba->memory.rom) {
cpu->gprs[ARM_PC] = BASE_CART0;
} else {
- cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
+ cpu->gprs[ARM_PC] = BASE_WORKING_RAM + 0xC0;
}
gba->video.vcount = 0x7D;
gba->memory.io[REG_VCOUNT >> 1] = 0x7D;
diff --git a/src/gba/hle-bios.c b/src/gba/hle-bios.c
index 776c3d5..8903ca0 100644
--- a/src/gba/hle-bios.c
+++ b/src/gba/hle-bios.c
@@ -3,10 +3,10 @@
#include
const uint8_t hleBios[SIZE_BIOS] = {
- 0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x0b, 0x00, 0x00, 0xea,
+ 0x06, 0x00, 0x00, 0xea, 0x88, 0x00, 0x00, 0xea, 0x0b, 0x00, 0x00, 0xea,
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
0x2c, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3,
- 0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0xf8, 0x01, 0x9f, 0x15,
+ 0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0x04, 0x02, 0x9f, 0x15,
0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1,
0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02,
0x00, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5, 0x9c, 0xc0, 0xa0, 0xe3,
@@ -49,5 +49,6 @@ const uint8_t hleBios[SIZE_BIOS] = {
0x03, 0xa0, 0xa0, 0xe1, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xa1, 0xb8,
0xfc, 0xff, 0xff, 0xba, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x51, 0xe1,
0xf8, 0x07, 0xb0, 0xb8, 0xf8, 0x07, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba,
- 0xf0, 0x87, 0xbd, 0xe8, 0xc0, 0x00, 0x00, 0x02
+ 0xf0, 0x87, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0xe0, 0xa0, 0x03, 0xc0, 0x00, 0x00, 0x02
};
diff --git a/src/gba/hle-bios.s b/src/gba/hle-bios.s
index 96de3ad..bb7eb0c 100644
--- a/src/gba/hle-bios.s
+++ b/src/gba/hle-bios.s
@@ -187,4 +187,9 @@ blt 0b
2:
ldmfd sp!, {r4-r10, pc}
+undefBase:
+subs pc, lr, #4
+.word 0
+.word 0x03A0E004
+
.ltorg
diff --git a/src/gba/io.c b/src/gba/io.c
index 2b74dd9..65cf1e6 100644
--- a/src/gba/io.c
+++ b/src/gba/io.c
@@ -950,7 +950,7 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
}
- state->dmaTransferRegister = gba->memory.dmaTransferRegister;
+ STORE_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister);
GBAHardwareSerialize(&gba->memory.hw, state);
}
@@ -988,12 +988,11 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
- if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != GBA_DMA_TIMING_NOW) {
- GBADMASchedule(gba, i, &gba->memory.dma[i]);
- }
}
GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]);
- gba->memory.dmaTransferRegister = state->dmaTransferRegister;
+
+ LOAD_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister);
+
GBADMAUpdate(gba);
GBAHardwareDeserialize(&gba->memory.hw, state);
}
diff --git a/src/gba/memory.c b/src/gba/memory.c
index 091bfa1..d2ba5a4 100644
--- a/src/gba/memory.c
+++ b/src/gba/memory.c
@@ -772,12 +772,12 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
#define STORE_SRAM \
if (address & 0x3) { \
mLOG(GBA_MEM, GAME_ERROR, "Unaligned SRAM Store32: 0x%08X", address); \
- value = 0; \
- } \
- GBAStore8(cpu, address & ~0x3, value, cycleCounter); \
- GBAStore8(cpu, (address & ~0x3) | 1, value, cycleCounter); \
- GBAStore8(cpu, (address & ~0x3) | 2, value, cycleCounter); \
- GBAStore8(cpu, (address & ~0x3) | 3, value, cycleCounter);
+ } else { \
+ GBAStore8(cpu, address, value, cycleCounter); \
+ GBAStore8(cpu, address | 1, value, cycleCounter); \
+ GBAStore8(cpu, address | 2, value, cycleCounter); \
+ GBAStore8(cpu, address | 3, value, cycleCounter); \
+ }
#define STORE_BAD \
mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store32: 0x%08X", address);
@@ -923,8 +923,12 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
break;
case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR:
- GBAStore8(cpu, (address & ~0x1), value, cycleCounter);
- GBAStore8(cpu, (address & ~0x1) | 1, value, cycleCounter);
+ if (address & 1) {
+ mLOG(GBA_MEM, GAME_ERROR, "Unaligned SRAM Store16: 0x%08X", address);
+ break;
+ }
+ GBAStore8(cpu, address, value, cycleCounter);
+ GBAStore8(cpu, address | 1, value, cycleCounter);
break;
default:
mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store16: 0x%08X", address);
diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c
index 3c433e8..7f55333 100644
--- a/src/gba/renderers/gl.c
+++ b/src/gba/renderers/gl.c
@@ -931,6 +931,7 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
+ glRenderer->oamDirty = true;
glRenderer->paletteDirty = true;
glRenderer->vramDirty = 0xFFFFFF;
glRenderer->firstAffine = -1;
@@ -1727,13 +1728,13 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
glStencilFunc(GL_EQUAL, 1, 1);
glUseProgram(shader->program);
glDrawBuffers(2, (GLenum[]) { GL_NONE, GL_COLOR_ATTACHMENT1 });
- glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
glBindVertexArray(shader->vao);
glUniform2i(uniforms[GBA_GL_VS_LOC], totalHeight, 0);
glUniform2i(uniforms[GBA_GL_VS_MAXPOS], totalWidth, totalHeight);
- glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c), 0, 0, 0);
+ glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c),
+ (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (renderer->blendEffect * 4),
+ renderer->blda, GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
}
diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c
index 666baa5..00a76cf 100644
--- a/src/gba/renderers/video-software.c
+++ b/src/gba/renderers/video-software.c
@@ -623,7 +623,7 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
_drawScanline(softwareRenderer, y);
- if (softwareRenderer->forceTarget1 && softwareRenderer->target2Bd) {
+ if ((softwareRenderer->forceTarget1 || softwareRenderer->bg[0].target1 || softwareRenderer->bg[1].target1 || softwareRenderer->bg[2].target1 || softwareRenderer->bg[3].target1) && softwareRenderer->target2Bd) {
x = 0;
for (w = 0; w < softwareRenderer->nWindows; ++w) {
uint32_t backdrop = 0;
diff --git a/src/util/elf-read.c b/src/util/elf-read.c
index 8ac3877..520c01c 100644
--- a/src/util/elf-read.c
+++ b/src/util/elf-read.c
@@ -84,6 +84,9 @@ void ELFGetProgramHeaders(struct ELF* elf, struct ELFProgramHeaders* ph) {
ELFProgramHeadersClear(ph);
Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
Elf32_Phdr* phdr = elf32_getphdr(elf->e);
+ if (!hdr || !phdr) {
+ return;
+ }
ELFProgramHeadersResize(ph, hdr->e_phnum);
memcpy(ELFProgramHeadersGetPointer(ph, 0), phdr, sizeof(*phdr) * hdr->e_phnum);
}
diff --git a/src/util/vfs/vfs-fd.c b/src/util/vfs/vfs-fd.c
index ed22225..dde2397 100644
--- a/src/util/vfs/vfs-fd.c
+++ b/src/util/vfs/vfs-fd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau
+/* Copyright (c) 2013-2020 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -14,11 +14,23 @@
#include
#endif
+#include
+
+#ifdef _WIN32
+struct HandleMappingTuple {
+ HANDLE handle;
+ void* mapping;
+};
+
+DECLARE_VECTOR(HandleMappingList, struct HandleMappingTuple);
+DEFINE_VECTOR(HandleMappingList, struct HandleMappingTuple);
+#endif
+
struct VFileFD {
struct VFile d;
int fd;
#ifdef _WIN32
- HANDLE hMap;
+ struct HandleMappingList handles;
#endif
};
@@ -74,12 +86,23 @@ struct VFile* VFileFromFD(int fd) {
vfd->d.truncate = _vfdTruncate;
vfd->d.size = _vfdSize;
vfd->d.sync = _vfdSync;
+#ifdef _WIN32
+ HandleMappingListInit(&vfd->handles, 4);
+#endif
return &vfd->d;
}
bool _vfdClose(struct VFile* vf) {
struct VFileFD* vfd = (struct VFileFD*) vf;
+#ifdef _WIN32
+ size_t i;
+ for (i = 0; i < HandleMappingListSize(&vfd->handles); ++i) {
+ UnmapViewOfFile(HandleMappingListGetPointer(&vfd->handles, i)->mapping);
+ CloseHandle(HandleMappingListGetPointer(&vfd->handles, i)->handle);
+ }
+ HandleMappingListDeinit(&vfd->handles);
+#endif
if (close(vfd->fd) < 0) {
return false;
}
@@ -134,16 +157,25 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags) {
if (size > fileSize) {
size = fileSize;
}
- vfd->hMap = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
- return MapViewOfFile(vfd->hMap, mapFiles, 0, 0, size);
+ struct HandleMappingTuple tuple = {0};
+ tuple.handle = CreateFileMapping((HANDLE) _get_osfhandle(vfd->fd), 0, createFlags, 0, size & 0xFFFFFFFF, 0);
+ tuple.mapping = MapViewOfFile(tuple.handle, mapFiles, 0, 0, size);
+ *HandleMappingListAppend(&vfd->handles) = tuple;
+ return tuple.mapping;
}
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size) {
UNUSED(size);
struct VFileFD* vfd = (struct VFileFD*) vf;
- UnmapViewOfFile(memory);
- CloseHandle(vfd->hMap);
- vfd->hMap = 0;
+ size_t i;
+ for (i = 0; i < HandleMappingListSize(&vfd->handles); ++i) {
+ if (HandleMappingListGetPointer(&vfd->handles, i)->mapping == memory) {
+ UnmapViewOfFile(memory);
+ CloseHandle(HandleMappingListGetPointer(&vfd->handles, i)->handle);
+ HandleMappingListShift(&vfd->handles, i, 1);
+ break;
+ }
+ }
}
#endif