View
@@ -103,6 +103,9 @@ void GBMemoryInit(struct GB* gb) {
gb->memory.mbcWrite = NULL;
gb->memory.rtc = NULL;
+ gb->memory.rotation = NULL;
+ gb->memory.rumble = NULL;
+ gb->memory.cam = NULL;
GBIOInit(gb);
}
@@ -204,10 +207,14 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
case GB_REGION_CART_BANK0 + 2:
case GB_REGION_CART_BANK0 + 3:
return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
- case GB_REGION_CART_BANK1:
- case GB_REGION_CART_BANK1 + 1:
case GB_REGION_CART_BANK1 + 2:
case GB_REGION_CART_BANK1 + 3:
+ if (memory->mbcType == GB_MBC6) {
+ return memory->mbcState.mbc6.romBank1[address & (GB_SIZE_CART_HALFBANK - 1)];
+ }
+ // Fall through
+ case GB_REGION_CART_BANK1:
+ case GB_REGION_CART_BANK1 + 1:
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
case GB_REGION_VRAM:
case GB_REGION_VRAM + 1:
@@ -218,7 +225,7 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
return memory->rtcRegs[memory->activeRtcReg];
} else if (memory->mbcRead) {
return memory->mbcRead(memory, address);
- } else if (memory->sramAccess) {
+ } else if (memory->sramAccess && memory->sram) {
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
} else if (memory->mbcType == GB_HuC3) {
return 0x01; // TODO: Is this supposed to be the current SRAM bank?
@@ -287,10 +294,10 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
case GB_REGION_EXTERNAL_RAM + 1:
if (memory->rtcAccess) {
memory->rtcRegs[memory->activeRtcReg] = value;
- } else if (memory->sramAccess) {
+ } else if (memory->sramAccess && memory->sram) {
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
- } else if (memory->mbcType == GB_MBC7) {
- GBMBC7Write(memory, address, value);
+ } else {
+ memory->mbcWrite(gb, address, value);
}
gb->sramDirty |= GB_SRAM_DIRT_NEW;
return;
@@ -385,7 +392,7 @@ uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment) {
if (memory->rtcAccess) {
return memory->rtcRegs[memory->activeRtcReg];
} else if (memory->sramAccess) {
- if (segment < 0) {
+ if (segment < 0 && memory->sram) {
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
} else if ((size_t) segment * GB_SIZE_EXTERNAL_RAM < gb->sramSize) {
return memory->sram[(address & (GB_SIZE_EXTERNAL_RAM - 1)) + segment *GB_SIZE_EXTERNAL_RAM];
@@ -462,10 +469,13 @@ void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
bool wasHdma = gb->memory.isHdma;
gb->memory.isHdma = value & 0x80;
if ((!wasHdma && !gb->memory.isHdma) || gb->video.mode == 0) {
- gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10;
+ if (gb->memory.isHdma) {
+ gb->memory.hdmaRemaining = 0x10;
+ } else {
+ gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10;
+ }
gb->cpuBlocked = true;
mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0);
- gb->cpu->nextEvent = gb->cpu->cycles;
}
}
@@ -703,8 +713,7 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
}
break;
case GB_MBC3_RTC:
- // TODO?
- //LOAD_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch);
+ LOAD_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch);
break;
case GB_MBC7:
memory->mbcState.mbc7.state = state->memory.mbc7.state;
View
@@ -19,6 +19,7 @@ static const struct GBCartridgeOverride _overrides[] = {
bool GBOverrideFind(const struct Configuration* config, struct GBCartridgeOverride* override) {
override->model = GB_MODEL_AUTODETECT;
override->mbc = GB_MBC_AUTODETECT;
+ memset(override->gbColors, 0, sizeof(override->gbColors));
bool found = false;
int i;
@@ -35,30 +36,24 @@ bool GBOverrideFind(const struct Configuration* config, struct GBCartridgeOverri
snprintf(sectionName, sizeof(sectionName), "gb.override.%08X", override->headerCrc32);
const char* model = ConfigurationGetValue(config, sectionName, "model");
const char* mbc = ConfigurationGetValue(config, sectionName, "mbc");
- const char* pal[4] = {
+ const char* pal[12] = {
ConfigurationGetValue(config, sectionName, "pal[0]"),
ConfigurationGetValue(config, sectionName, "pal[1]"),
ConfigurationGetValue(config, sectionName, "pal[2]"),
- ConfigurationGetValue(config, sectionName, "pal[3]")
+ ConfigurationGetValue(config, sectionName, "pal[3]"),
+ ConfigurationGetValue(config, sectionName, "pal[4]"),
+ ConfigurationGetValue(config, sectionName, "pal[5]"),
+ ConfigurationGetValue(config, sectionName, "pal[6]"),
+ ConfigurationGetValue(config, sectionName, "pal[7]"),
+ ConfigurationGetValue(config, sectionName, "pal[8]"),
+ ConfigurationGetValue(config, sectionName, "pal[9]"),
+ ConfigurationGetValue(config, sectionName, "pal[10]"),
+ ConfigurationGetValue(config, sectionName, "pal[11]")
};
if (model) {
- if (strcasecmp(model, "DMG") == 0) {
- found = true;
- override->model = GB_MODEL_DMG;
- } else if (strcasecmp(model, "CGB") == 0) {
- found = true;
- override->model = GB_MODEL_CGB;
- } else if (strcasecmp(model, "AGB") == 0) {
- found = true;
- override->model = GB_MODEL_AGB;
- } else if (strcasecmp(model, "SGB") == 0) {
- found = true;
- override->model = GB_MODEL_DMG; // TODO
- } else if (strcasecmp(model, "MGB") == 0) {
- found = true;
- override->model = GB_MODEL_DMG; // TODO
- }
+ override->model = GBNameToModel(model);
+ found = override->model != GB_MODEL_AUTODETECT;
}
if (mbc) {
@@ -70,18 +65,25 @@ bool GBOverrideFind(const struct Configuration* config, struct GBCartridgeOverri
}
}
- if (pal[0] && pal[1] && pal[2] && pal[3]) {
- int i;
- for (i = 0; i < 4; ++i) {
- char* end;
- unsigned long value = strtoul(pal[i], &end, 10);
- if (end == &pal[i][1] && *end == 'x') {
- value = strtoul(pal[i], &end, 16);
- }
- if (*end) {
- continue;
- }
- override->gbColors[i] = value;
+ for (i = 0; i < 12; ++i) {
+ if (!pal[i]) {
+ continue;
+ }
+ char* end;
+ unsigned long value = strtoul(pal[i], &end, 10);
+ if (end == &pal[i][1] && *end == 'x') {
+ value = strtoul(pal[i], &end, 16);
+ }
+ if (*end) {
+ continue;
+ }
+ value |= 0xFF000000;
+ override->gbColors[i] = value;
+ if (i < 8) {
+ override->gbColors[i + 4] = value;
+ }
+ if (i < 4) {
+ override->gbColors[i + 8] = value;
}
}
}
@@ -91,31 +93,46 @@ bool GBOverrideFind(const struct Configuration* config, struct GBCartridgeOverri
void GBOverrideSave(struct Configuration* config, const struct GBCartridgeOverride* override) {
char sectionName[24] = "";
snprintf(sectionName, sizeof(sectionName), "gb.override.%08X", override->headerCrc32);
- const char* model = 0;
- switch (override->model) {
- case GB_MODEL_DMG:
- model = "DMG";
- break;
- case GB_MODEL_SGB:
- model = "SGB";
- break;
- case GB_MODEL_CGB:
- model = "CGB";
- break;
- case GB_MODEL_AGB:
- model = "AGB";
- break;
- case GB_MODEL_AUTODETECT:
- break;
- }
+ const char* model = GBModelToName(override->model);
ConfigurationSetValue(config, sectionName, "model", model);
- if (override->gbColors[0] | override->gbColors[1] | override->gbColors[2] | override->gbColors[3]) {
- ConfigurationSetIntValue(config, sectionName, "pal[0]", override->gbColors[0]);
- ConfigurationSetIntValue(config, sectionName, "pal[1]", override->gbColors[1]);
- ConfigurationSetIntValue(config, sectionName, "pal[2]", override->gbColors[2]);
- ConfigurationSetIntValue(config, sectionName, "pal[3]", override->gbColors[3]);
+ if (override->gbColors[0] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[0]", override->gbColors[0] & ~0xFF000000);
+ }
+ if (override->gbColors[1] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[1]", override->gbColors[1] & ~0xFF000000);
+ }
+ if (override->gbColors[2] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[2]", override->gbColors[2] & ~0xFF000000);
}
+ if (override->gbColors[3] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[3]", override->gbColors[3] & ~0xFF000000);
+ }
+ if (override->gbColors[4] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[4]", override->gbColors[4] & ~0xFF000000);
+ }
+ if (override->gbColors[5] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[5]", override->gbColors[5] & ~0xFF000000);
+ }
+ if (override->gbColors[6] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[6]", override->gbColors[6] & ~0xFF000000);
+ }
+ if (override->gbColors[7] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[7]", override->gbColors[7] & ~0xFF000000);
+ }
+ if (override->gbColors[8] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[8]", override->gbColors[8] & ~0xFF000000);
+ }
+ if (override->gbColors[9] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[9]", override->gbColors[9] & ~0xFF000000);
+ }
+ if (override->gbColors[10] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[10]", override->gbColors[10] & ~0xFF000000);
+ }
+ if (override->gbColors[11] & 0xFF000000) {
+ ConfigurationSetIntValue(config, sectionName, "pal[11]", override->gbColors[11] & ~0xFF000000);
+ }
+
if (override->mbc != GB_MBC_AUTODETECT) {
ConfigurationSetIntValue(config, sectionName, "mbc", override->mbc);
} else {
@@ -133,11 +150,18 @@ void GBOverrideApply(struct GB* gb, const struct GBCartridgeOverride* override)
GBMBCInit(gb);
}
- if (override->gbColors[0] | override->gbColors[1] | override->gbColors[2] | override->gbColors[3]) {
- GBVideoSetPalette(&gb->video, 0, override->gbColors[0]);
- GBVideoSetPalette(&gb->video, 1, override->gbColors[1]);
- GBVideoSetPalette(&gb->video, 2, override->gbColors[2]);
- GBVideoSetPalette(&gb->video, 3, override->gbColors[3]);
+ int i;
+ for (i = 0; i < 12; ++i) {
+ if (!(override->gbColors[i] & 0xFF000000)) {
+ continue;
+ }
+ GBVideoSetPalette(&gb->video, i, override->gbColors[i]);
+ if (i < 8) {
+ GBVideoSetPalette(&gb->video, i + 4, override->gbColors[i]);
+ }
+ if (i < 4) {
+ GBVideoSetPalette(&gb->video, i + 8, override->gbColors[i]);
+ }
}
}
View
@@ -0,0 +1,129 @@
+/* Copyright (c) 2013-2017 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
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <mgba/internal/gb/renderers/cache-set.h>
+
+#include <mgba/core/cache-set.h>
+#include <mgba/internal/gb/gb.h>
+#include <mgba/internal/gb/io.h>
+#include <mgba/internal/gb/video.h>
+
+void GBVideoCacheInit(struct mCacheSet* cache) {
+ mCacheSetInit(cache, 2, 1);
+ mTileCacheConfiguration config = 0;
+ config = mTileCacheSystemInfoSetPaletteBPP(config, 1); // 2^(2^1) = 4 entries
+ config = mTileCacheSystemInfoSetPaletteCount(config, 4); // 16 palettes
+ config = mTileCacheSystemInfoSetMaxTiles(config, 1024);
+ mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 0));
+ mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), config, 0, 0);
+
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 0));
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 1));
+ mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+}
+
+void GBVideoCacheAssociate(struct mCacheSet* cache, struct GBVideo* video) {
+ mCacheSetAssignVRAM(cache, video->vram);
+ video->renderer->cache = cache;
+ size_t i;
+ for (i = 0; i < 64; ++i) {
+ mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i]));
+ }
+ mMapCacheSystemInfo sysconfig = mMapCacheSystemInfoSetPaletteCount(0, 0);
+ if (video->p->model >= GB_MODEL_CGB) {
+ sysconfig = mMapCacheSystemInfoSetPaletteCount(0, 2);
+ }
+ mMapCacheConfigureSystem(mMapCacheSetGetPointer(&cache->maps, 0), sysconfig);
+ mMapCacheConfigureSystem(mMapCacheSetGetPointer(&cache->maps, 1), sysconfig);
+
+ GBVideoCacheWriteVideoRegister(cache, REG_LCDC, video->p->memory.io[REG_LCDC]);
+}
+
+static void mapParserDMG0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
+ UNUSED(cache);
+ int map = *(uint8_t*) vram;
+ entry->tileId = map;
+ entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags);
+ entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags);
+ entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, 0);
+}
+
+static void mapParserDMG1(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
+ UNUSED(cache);
+ int map = *(int8_t*) vram;
+ entry->tileId = map + 128;
+ entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags);
+ entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags);
+ entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, 0);
+}
+
+static void mapParserCGB0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
+ UNUSED(cache);
+ int map = *(uint8_t*) vram;
+ uint8_t attr = ((uint8_t*) vram)[0x2000];
+ entry->tileId = map + GBObjAttributesGetBank(attr) * 512;
+ entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, GBObjAttributesGetXFlip(attr));
+ entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, GBObjAttributesGetYFlip(attr));
+ entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBObjAttributesGetCGBPalette(attr));
+}
+
+static void mapParserCGB1(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
+ UNUSED(cache);
+ int map = *(int8_t*) vram;
+ uint8_t attr = ((uint8_t*) vram)[0x2000];
+ entry->tileId = map + 128 + GBObjAttributesGetBank(attr) * 512;
+ entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, GBObjAttributesGetXFlip(attr));
+ entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, GBObjAttributesGetYFlip(attr));
+ entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBObjAttributesGetCGBPalette(attr));
+}
+
+void GBVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint16_t address, uint8_t value) {
+ if (address != REG_LCDC) {
+ return;
+ }
+ struct mMapCache* map = mMapCacheSetGetPointer(&cache->maps, 0);
+ struct mMapCache* window = mMapCacheSetGetPointer(&cache->maps, 1);
+
+ mMapCacheSystemInfo sysconfig = mMapCacheSystemInfoIsPaletteCount(map->sysConfig);
+ int tileStart = 0;
+ int mapStart = GB_BASE_MAP;
+ int windowStart = GB_BASE_MAP;
+ if (GBRegisterLCDCIsTileMap(value)) {
+ mapStart += GB_SIZE_MAP;
+ }
+ if (GBRegisterLCDCIsWindowTileMap(value)) {
+ windowStart += GB_SIZE_MAP;
+ }
+ if (GBRegisterLCDCIsTileData(value)) {
+ if (!sysconfig) {
+ map->mapParser = mapParserDMG0;
+ window->mapParser = mapParserDMG0;
+ } else {
+ map->mapParser = mapParserCGB0;
+ window->mapParser = mapParserCGB0;
+ }
+ } else {
+ if (!sysconfig) {
+ map->mapParser = mapParserDMG1;
+ window->mapParser = mapParserDMG1;
+ } else {
+ map->mapParser = mapParserCGB1;
+ window->mapParser = mapParserCGB1;
+ }
+ tileStart = 0x80;
+ }
+ map->tileStart = tileStart;
+ window->tileStart = tileStart;
+ sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5);
+ sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 1);
+ sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 0);
+ sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, 5);
+ sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, 5);
+ mMapCacheConfigureSystem(map, sysconfig);
+ mMapCacheConfigureSystem(window, sysconfig);
+ mMapCacheConfigureMap(map, mapStart);
+ mMapCacheConfigureMap(window, windowStart);
+}
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -1,27 +0,0 @@
-/* Copyright (c) 2013-2016 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
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include <mgba/internal/gb/renderers/tile-cache.h>
-
-#include <mgba/core/tile-cache.h>
-#include <mgba/internal/gb/video.h>
-#include <mgba/internal/gb/renderers/tile-cache.h>
-
-void GBVideoTileCacheInit(struct mTileCache* cache) {
- mTileCacheInit(cache);
- mTileCacheConfiguration config = 0;
- config = mTileCacheSystemInfoSetPalette0BPP(config, 1); // 2^(2^2) = 4 entries
- config = mTileCacheSystemInfoSetPalette0Count(config, 4); // 16 palettes
- config = mTileCacheSystemInfoSetPalette1BPP(config, 0); // Disable
- config = mTileCacheSystemInfoSetPalette1Count(config, 0); // Disable
- config = mTileCacheSystemInfoSetMaxTiles(config, 1024);
- mTileCacheConfigureSystem(cache, config);
-}
-
-void GBVideoTileCacheAssociate(struct mTileCache* cache, struct GBVideo* video) {
- cache->vram = (uint16_t*) video->vram;
- cache->palette = video->palette;
- video->renderer->cache = cache;
-}
View
@@ -12,15 +12,18 @@
mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate", "gb.serialize");
const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
-const uint32_t GB_SAVESTATE_VERSION = 0x00000001;
+const uint32_t GB_SAVESTATE_VERSION = 0x00000002;
+
+static void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state);
+static void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state);
void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
if (gb->memory.rom) {
- memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title));
+ memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title));
} else {
memset(state->title, 0, sizeof(state->title));
}
@@ -44,7 +47,6 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
STORE_16LE(gb->cpu->index, 0, &state->cpu.index);
state->cpu.bus = gb->cpu->bus;
state->cpu.executionState = gb->cpu->executionState;
- STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
GBSerializedCpuFlags flags = 0;
flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
@@ -59,6 +61,10 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
GBVideoSerialize(&gb->video, state);
GBTimerSerialize(&gb->timer, state);
GBAudioSerialize(&gb->audio, state);
+
+ if (gb->model == GB_MODEL_SGB) {
+ GBSGBSerialize(gb, state);
+ }
}
bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
@@ -77,10 +83,15 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
} else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
}
+ bool canSgb = ucheck >= GB_SAVESTATE_MAGIC + 2;
- if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
- mLOG(GB_STATE, WARN, "Savestate is for a different game");
- error = true;
+ if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title))) {
+ LOAD_32LE(ucheck, 0, &state->versionMagic);
+ if (ucheck > GB_SAVESTATE_MAGIC + 2 || memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
+ // There was a bug in previous versions where the memory address being compared was wrong
+ mLOG(GB_STATE, WARN, "Savestate is for a different game");
+ error = true;
+ }
}
LOAD_32LE(ucheck, 0, &state->romCrc32);
if (ucheck != gb->romCrc32) {
@@ -126,6 +137,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
return false;
}
gb->timing.root = NULL;
+ LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
gb->cpu->a = state->cpu.a;
gb->cpu->f.packed = state->cpu.f;
@@ -141,7 +153,6 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
gb->cpu->bus = state->cpu.bus;
gb->cpu->executionState = state->cpu.executionState;
- LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
GBSerializedCpuFlags flags;
LOAD_32LE(flags, 0, &state->cpu.flags);
@@ -150,16 +161,16 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
gb->audio.timingFactor = gb->doubleSpeed + 1;
+ LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
+ LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
+ gb->timing.root = NULL;
+
uint32_t when;
LOAD_32LE(when, 0, &state->cpu.eiPending);
if (GBSerializedCpuFlagsIsEiPending(flags)) {
mTimingSchedule(&gb->timing, &gb->eiPending, when);
}
- LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
- LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
- gb->timing.root = NULL;
-
gb->model = state->model;
if (gb->model < GB_MODEL_CGB) {
@@ -174,7 +185,74 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
GBTimerDeserialize(&gb->timer, state);
GBAudioDeserialize(&gb->audio, state);
+ if (gb->model == GB_MODEL_SGB && canSgb) {
+ GBSGBDeserialize(gb, state);
+ }
+
gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
+ gb->timing.reroot = gb->timing.root;
+ gb->timing.root = NULL;
+
return true;
}
+
+// TODO: Reorganize SGB into its own file
+void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) {
+ state->sgb.command = gb->video.sgbCommandHeader;
+ state->sgb.bits = gb->sgbBit;
+
+ GBSerializedSGBFlags flags = 0;
+ flags = GBSerializedSGBFlagsSetP1Bits(flags, gb->currentSgbBits);
+ flags = GBSerializedSGBFlagsSetRenderMode(flags, gb->video.renderer->sgbRenderMode);
+ STORE_32LE(flags, 0, &state->sgb.flags);
+
+ memcpy(state->sgb.packet, gb->sgbPacket, sizeof(state->sgb.packet));
+
+ if (gb->video.renderer->sgbCharRam) {
+ memcpy(state->sgb.charRam, gb->video.renderer->sgbCharRam, sizeof(state->sgb.charRam));
+ }
+ if (gb->video.renderer->sgbMapRam) {
+ memcpy(state->sgb.mapRam, gb->video.renderer->sgbMapRam, sizeof(state->sgb.mapRam));
+ }
+ if (gb->video.renderer->sgbPalRam) {
+ memcpy(state->sgb.palRam, gb->video.renderer->sgbPalRam, sizeof(state->sgb.palRam));
+ }
+ if (gb->video.renderer->sgbAttributeFiles) {
+ memcpy(state->sgb.atfRam, gb->video.renderer->sgbAttributeFiles, sizeof(state->sgb.atfRam));
+ }
+ if (gb->video.renderer->sgbAttributes) {
+ memcpy(state->sgb.attributes, gb->video.renderer->sgbAttributes, sizeof(state->sgb.attributes));
+ }
+}
+
+void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
+ gb->video.sgbCommandHeader = state->sgb.command;
+ gb->sgbBit = state->sgb.bits;
+
+ GBSerializedSGBFlags flags;
+ LOAD_32LE(flags, 0, &state->sgb.flags);
+ gb->currentSgbBits = GBSerializedSGBFlagsGetP1Bits(flags);
+ gb->video.renderer->sgbRenderMode = GBSerializedSGBFlagsGetRenderMode(flags);
+
+ memcpy(gb->sgbPacket, state->sgb.packet, sizeof(state->sgb.packet));
+
+ if (gb->video.renderer->sgbCharRam) {
+ memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
+ }
+ if (gb->video.renderer->sgbMapRam) {
+ memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
+ }
+ if (gb->video.renderer->sgbPalRam) {
+ memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
+ }
+ if (gb->video.renderer->sgbAttributeFiles) {
+ memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
+ }
+ if (gb->video.renderer->sgbAttributes) {
+ memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));
+ }
+
+ GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 });
+ GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
+}
View
@@ -0,0 +1,233 @@
+/* Copyright (c) 2013-2017 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
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <mgba/internal/gb/sio/printer.h>
+
+#include <mgba/internal/gb/gb.h>
+#include <mgba/internal/gb/io.h>
+
+
+static bool GBPrinterInit(struct GBSIODriver* driver);
+static void GBPrinterDeinit(struct GBSIODriver* driver);
+static void GBPrinterWriteSB(struct GBSIODriver* driver, uint8_t value);
+static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value);
+
+void GBPrinterCreate(struct GBPrinter* printer) {
+ printer->d.init = GBPrinterInit;
+ printer->d.deinit = GBPrinterDeinit;
+ printer->d.writeSB = GBPrinterWriteSB;
+ printer->d.writeSC = GBPrinterWriteSC;
+ printer->print = NULL;
+}
+
+bool GBPrinterInit(struct GBSIODriver* driver) {
+ struct GBPrinter* printer = (struct GBPrinter*) driver;
+
+ printer->checksum = 0;
+ printer->command = 0;
+ printer->remainingBytes = 0;
+ printer->currentIndex = 0;
+ printer->compression = false;
+ printer->byte = 0;
+ printer->next = GB_PRINTER_BYTE_MAGIC_0;
+ printer->status = 0;
+ printer->printWait = -1;
+
+ printer->buffer = malloc(GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS / 2);
+
+ return true;
+}
+
+void GBPrinterDeinit(struct GBSIODriver* driver) {
+ struct GBPrinter* printer = (struct GBPrinter*) driver;
+ free(printer->buffer);
+}
+
+static void GBPrinterWriteSB(struct GBSIODriver* driver, uint8_t value) {
+ struct GBPrinter* printer = (struct GBPrinter*) driver;
+ printer->byte = value;
+}
+
+static void _processByte(struct GBPrinter* printer) {
+ switch (printer->command) {
+ case GB_PRINTER_COMMAND_DATA:
+ if (printer->currentIndex < GB_VIDEO_VERTICAL_PIXELS * GB_VIDEO_HORIZONTAL_PIXELS / 2) {
+ printer->buffer[printer->currentIndex] = printer->byte;
+ ++printer->currentIndex;
+ }
+ break;
+ case GB_PRINTER_COMMAND_PRINT:
+ // TODO
+ break;
+ default:
+ break;
+ }
+}
+
+static uint8_t GBPrinterWriteSC(struct GBSIODriver* driver, uint8_t value) {
+ struct GBPrinter* printer = (struct GBPrinter*) driver;
+ if ((value & 0x81) == 0x81) {
+ switch (printer->next) {
+ driver->p->pendingSB = 0;
+ case GB_PRINTER_BYTE_MAGIC_0:
+ if (printer->byte == 0x88) {
+ printer->next = GB_PRINTER_BYTE_MAGIC_1;
+ } else {
+ printer->next = GB_PRINTER_BYTE_MAGIC_0;
+ }
+ break;
+ case GB_PRINTER_BYTE_MAGIC_1:
+ if (printer->byte == 0x33) {
+ printer->next = GB_PRINTER_BYTE_COMMAND;
+ } else {
+ printer->next = GB_PRINTER_BYTE_MAGIC_0;
+ }
+ break;
+ case GB_PRINTER_BYTE_COMMAND:
+ printer->checksum = printer->byte;
+ printer->command = printer->byte;
+ printer->next = GB_PRINTER_BYTE_COMPRESSION;
+ break;
+ case GB_PRINTER_BYTE_COMPRESSION:
+ printer->checksum += printer->byte;
+ printer->compression = printer->byte;
+ printer->next = GB_PRINTER_BYTE_LENGTH_0;
+ break;
+ case GB_PRINTER_BYTE_LENGTH_0:
+ printer->checksum += printer->byte;
+ printer->remainingBytes = printer->byte;
+ printer->next = GB_PRINTER_BYTE_LENGTH_1;
+ break;
+ case GB_PRINTER_BYTE_LENGTH_1:
+ printer->checksum += printer->byte;
+ printer->remainingBytes |= printer->byte << 8;
+ if (printer->remainingBytes) {
+ printer->next = GB_PRINTER_BYTE_DATA;
+ } else {
+ printer->next = GB_PRINTER_BYTE_CHECKSUM_0;
+ }
+ switch (printer->command) {
+ case GB_PRINTER_COMMAND_INIT:
+ printer->currentIndex = 0;
+ printer->status &= ~(GB_PRINTER_STATUS_PRINT_REQ | GB_PRINTER_STATUS_READY);
+ break;
+ default:
+ break;
+ }
+ break;
+ case GB_PRINTER_BYTE_DATA:
+ printer->checksum += printer->byte;
+ if (!printer->compression) {
+ _processByte(printer);
+ } else {
+ printer->next = printer->byte & 0x80 ? GB_PRINTER_BYTE_COMPRESSED_DATUM : GB_PRINTER_BYTE_UNCOMPRESSED_DATA;
+ printer->remainingCmpBytes = (printer->byte & 0x7F) + 1;
+ if (printer->byte & 0x80) {
+ ++printer->remainingCmpBytes;
+ }
+ }
+ --printer->remainingBytes;
+ if (!printer->remainingBytes) {
+ printer->next = GB_PRINTER_BYTE_CHECKSUM_0;
+ }
+ break;
+ case GB_PRINTER_BYTE_UNCOMPRESSED_DATA:
+ printer->checksum += printer->byte;
+ _processByte(printer);
+ --printer->remainingCmpBytes;
+ if (!printer->remainingCmpBytes) {
+ printer->next = GB_PRINTER_BYTE_DATA;
+ }
+ --printer->remainingBytes;
+ if (!printer->remainingBytes) {
+ printer->next = GB_PRINTER_BYTE_CHECKSUM_0;
+ }
+ break;
+ case GB_PRINTER_BYTE_COMPRESSED_DATUM:
+ printer->checksum += printer->byte;
+ while (printer->remainingCmpBytes) {
+ _processByte(printer);
+ --printer->remainingCmpBytes;
+ }
+ --printer->remainingBytes;
+ if (!printer->remainingBytes) {
+ printer->next = GB_PRINTER_BYTE_CHECKSUM_0;
+ } else {
+ printer->next = GB_PRINTER_BYTE_DATA;
+ }
+ break;
+ case GB_PRINTER_BYTE_CHECKSUM_0:
+ printer->checksum ^= printer->byte;
+ printer->next = GB_PRINTER_BYTE_CHECKSUM_1;
+ break;
+ case GB_PRINTER_BYTE_CHECKSUM_1:
+ printer->checksum ^= printer->byte << 8;
+ printer->next = GB_PRINTER_BYTE_KEEPALIVE;
+ break;
+ case GB_PRINTER_BYTE_KEEPALIVE:
+ driver->p->pendingSB = 0x81;
+ printer->next = GB_PRINTER_BYTE_STATUS;
+ break;
+ case GB_PRINTER_BYTE_STATUS:
+ switch (printer->command) {
+ case GB_PRINTER_COMMAND_DATA:
+ if (printer->currentIndex >= 0x280 && !(printer->status & GB_PRINTER_STATUS_CHECKSUM_ERROR)) {
+ printer->status |= GB_PRINTER_STATUS_READY;
+ }
+ break;
+ case GB_PRINTER_COMMAND_PRINT:
+ if (printer->currentIndex >= GB_VIDEO_HORIZONTAL_PIXELS * 2) {
+ printer->printWait = 0;
+ }
+ break;
+ case GB_PRINTER_COMMAND_STATUS:
+ if (!printer->printWait) {
+ printer->status &= ~GB_PRINTER_STATUS_READY;
+ printer->status |= GB_PRINTER_STATUS_PRINTING | GB_PRINTER_STATUS_PRINT_REQ;
+ if (printer->print) {
+ size_t y;
+ for (y = 0; y < printer->currentIndex / (2 * GB_VIDEO_HORIZONTAL_PIXELS); ++y) {
+ uint8_t lineBuffer[GB_VIDEO_HORIZONTAL_PIXELS * 2];
+ uint8_t* buffer = &printer->buffer[sizeof(lineBuffer) * y];
+ size_t i;
+ for (i = 0; i < sizeof(lineBuffer); i += 2) {
+ uint8_t ilo = buffer[i + 0x0];
+ uint8_t ihi = buffer[i + 0x1];
+ uint8_t olo = 0;
+ uint8_t ohi = 0;
+ olo |= ((ihi & 0x80) >> 0) | ((ilo & 0x80) >> 1);
+ olo |= ((ihi & 0x40) >> 1) | ((ilo & 0x40) >> 2);
+ olo |= ((ihi & 0x20) >> 2) | ((ilo & 0x20) >> 3);
+ olo |= ((ihi & 0x10) >> 3) | ((ilo & 0x10) >> 4);
+ ohi |= ((ihi & 0x08) << 4) | ((ilo & 0x08) << 3);
+ ohi |= ((ihi & 0x04) << 3) | ((ilo & 0x04) << 2);
+ ohi |= ((ihi & 0x02) << 2) | ((ilo & 0x02) << 1);
+ ohi |= ((ihi & 0x01) << 1) | ((ilo & 0x01) << 0);
+ lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) & ~1)] = olo;
+ lineBuffer[(((i >> 1) & 0x7) * GB_VIDEO_HORIZONTAL_PIXELS / 4) + ((i >> 3) | 1)] = ohi;
+ }
+ memcpy(buffer, lineBuffer, sizeof(lineBuffer));
+ }
+ printer->print(printer, printer->currentIndex * 4 / GB_VIDEO_HORIZONTAL_PIXELS, printer->buffer);
+ }
+ }
+ if (printer->printWait >= 0) {
+ --printer->printWait;
+ }
+ default:
+ break;
+ }
+ driver->p->pendingSB = printer->status;
+ printer->next = GB_PRINTER_BYTE_MAGIC_0;
+ break;
+ }
+ printer->byte = 0;
+ }
+ return value;
+}
+
+void GBPrinterDonePrinting(struct GBPrinter* printer) {
+ printer->status &= ~GB_PRINTER_STATUS_PRINTING;
+}
View
@@ -29,6 +29,7 @@ M_TEST_DEFINE(reset) {
struct mCore* core = GBCoreCreate();
assert_non_null(core);
assert_true(core->init(core));
+ mCoreInitConfig(core, NULL);
core->reset(core);
core->deinit(core);
}
@@ -37,6 +38,7 @@ M_TEST_DEFINE(loadNullROM) {
struct mCore* core = GBCoreCreate();
assert_non_null(core);
assert_true(core->init(core));
+ mCoreInitConfig(core, NULL);
assert_false(core->loadROM(core, NULL));
core->reset(core);
core->deinit(core);
View
@@ -1,20 +0,0 @@
-/* Copyright (c) 2013-2016 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
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "util/test/suite.h"
-
-M_TEST_SUITE_DECLARE(GBCore);
-M_TEST_SUITE_DECLARE(GBMBC);
-M_TEST_SUITE_DECLARE(GBMemory);
-M_TEST_SUITE_DECLARE(GBRTC);
-
-int TestRunGB(void) {
- int failures = 0;
- failures += M_TEST_SUITE_RUN(GBCore);
- failures += M_TEST_SUITE_RUN(GBMBC);
- failures += M_TEST_SUITE_RUN(GBMemory);
- failures += M_TEST_SUITE_RUN(GBRTC);
- return failures;
-}
View
@@ -1,12 +0,0 @@
-/* Copyright (c) 2013-2016 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
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef TEST_GB_H
-#define TEST_GB_H
-#include <mgba-util/common.h>
-
-int TestRunGB(void);
-
-#endif
View
@@ -16,6 +16,7 @@ M_TEST_SUITE_SETUP(GBMBC) {
GBSynthesizeROM(vf);
struct mCore* core = GBCoreCreate();
core->init(core);
+ mCoreInitConfig(core, NULL);
core->loadROM(core, vf);
*state = core;
return 0;
View
@@ -16,6 +16,7 @@ M_TEST_SUITE_SETUP(GBMemory) {
GBSynthesizeROM(vf);
struct mCore* core = GBCoreCreate();
core->init(core);
+ mCoreInitConfig(core, NULL);
core->loadROM(core, vf);
*state = core;
return 0;
View
@@ -14,7 +14,7 @@
struct GBRTCTest {
struct mRTCSource d;
struct mCore* core;
- struct VFile* fakeROM;
+ struct VFile* fakeSave;
time_t nextTime;
};
@@ -48,13 +48,17 @@ M_TEST_SUITE_SETUP(GBRTC) {
return -1;
}
test->core->init(test->core);
+ mCoreInitConfig(test->core, NULL);
struct VFile* vf = VFileMemChunk(NULL, 2048);
GBSynthesizeROM(vf);
test->core->loadROM(test->core, vf);
- test->core->setRTC(test->core, &test->d);
+ mCoreSetRTC(test->core, &test->d);
+
+ test->fakeSave = VFileMemChunk(NULL, 0);
+ test->core->loadSave(test->core, test->fakeSave);
+
struct GB* gb = test->core->board;
- struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100];
- cart->type = 0x0F;
+ gb->memory.mbcType = GB_MBC3_RTC;
*state = test;
return 0;
@@ -77,10 +81,12 @@ M_TEST_DEFINE(create) {
uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ assert_int_equal(gb->memory.mbcType, GB_MBC3_RTC);
}
M_TEST_DEFINE(tickSecond) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 1;
@@ -108,6 +114,7 @@ M_TEST_DEFINE(tickSecond) {
M_TEST_DEFINE(tick30Seconds) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 30;
@@ -142,6 +149,7 @@ M_TEST_DEFINE(tick30Seconds) {
M_TEST_DEFINE(tickMinute) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 60;
@@ -184,6 +192,7 @@ M_TEST_DEFINE(tickMinute) {
M_TEST_DEFINE(tick90Seconds) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 90;
@@ -240,6 +249,7 @@ M_TEST_DEFINE(tick90Seconds) {
M_TEST_DEFINE(tick30Minutes) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 1800;
@@ -282,6 +292,7 @@ M_TEST_DEFINE(tick30Minutes) {
M_TEST_DEFINE(tickHour) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600;
@@ -339,6 +350,7 @@ M_TEST_DEFINE(tickHour) {
M_TEST_DEFINE(tick12Hours) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600 * 12;
@@ -407,6 +419,7 @@ M_TEST_DEFINE(tick12Hours) {
M_TEST_DEFINE(tickDay) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600 * 24;
@@ -505,6 +518,7 @@ M_TEST_DEFINE(tickDay) {
M_TEST_DEFINE(wideTickDay) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600 * 24 * 2001;
@@ -611,6 +625,7 @@ M_TEST_DEFINE(wideTickDay) {
M_TEST_DEFINE(rolloverSecond) {
struct GBRTCTest* test = *state;
+ test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 1;
@@ -672,6 +687,270 @@ M_TEST_DEFINE(rolloverSecond) {
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
}
+M_TEST_DEFINE(roundtrip0) {
+ struct GBRTCTest* test = *state;
+ test->nextTime = 0;
+ test->fakeSave->truncate(test->fakeSave, 0);
+ test->core->reset(test->core);
+ struct GB* gb = test->core->board;
+
+ uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
+ memset(gb->memory.rtcRegs, 0, sizeof(expected));
+ GBMBCRTCWrite(gb);
+
+ GBMBCRTCRead(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ GBMBCRTCWrite(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ GBMBCRTCRead(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600;
+ expected[2] = 1;
+ GBMBCRTCWrite(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ GBMBCRTCWrite(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600 * 2;
+ expected[2] = 2;
+ GBMBCRTCWrite(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+}
+
+M_TEST_DEFINE(roundtripSecond) {
+ struct GBRTCTest* test = *state;
+ test->nextTime = 0;
+ test->fakeSave->truncate(test->fakeSave, 0);
+ test->core->reset(test->core);
+ struct GB* gb = test->core->board;
+
+ uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
+ memset(gb->memory.rtcRegs, 0, sizeof(expected));
+ GBMBCRTCWrite(gb);
+
+ test->nextTime = 1;
+ GBMBCRTCRead(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ expected[0] = 1;
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ GBMBCRTCWrite(gb);
+
+ test->nextTime = 2;
+ GBMBCRTCRead(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ _sampleRtcKeepLatch(gb);
+ expected[0] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->core->reset(test->core);
+ expected[0] = 1;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ _sampleRtcKeepLatch(gb);
+ expected[0] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->core->reset(test->core);
+ expected[0] = 1;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ expected[0] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3;
+ test->core->reset(test->core);
+ expected[0] = 1;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ _sampleRtcKeepLatch(gb);
+ expected[0] = 3;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 1;
+ test->core->reset(test->core);
+ expected[0] = 1;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ test->nextTime = 4;
+ _sampleRtcKeepLatch(gb);
+ expected[0] = 4;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+}
+
+M_TEST_DEFINE(roundtripDay) {
+ struct GBRTCTest* test = *state;
+ test->nextTime = 0;
+ test->fakeSave->truncate(test->fakeSave, 0);
+ test->core->reset(test->core);
+ struct GB* gb = test->core->board;
+
+ uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
+ memset(gb->memory.rtcRegs, 0, sizeof(expected));
+ GBMBCRTCWrite(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600 * 24;
+ GBMBCRTCRead(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 1;
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600 * 24 * 2;
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ GBMBCRTCWrite(gb);
+
+ test->nextTime = 3600 * 24 * 2;
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600 * 24 * 3;
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 3;
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600 * 24 * 2;
+ test->core->reset(test->core);
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 3600 * 24 * 3;
+ test->core->reset(test->core);
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 3;
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+}
+
+M_TEST_DEFINE(roundtripHuge) {
+ struct GBRTCTest* test = *state;
+ test->nextTime = 1500000000;
+ test->fakeSave->truncate(test->fakeSave, 0);
+ test->core->reset(test->core);
+ struct GB* gb = test->core->board;
+
+ uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
+ memset(gb->memory.rtcRegs, 0, sizeof(expected));
+ GBMBCRTCWrite(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 1500000000 + 3600 * 24;
+ GBMBCRTCRead(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 1;
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 1500000000 + 3600 * 24 * 2;
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ GBMBCRTCWrite(gb);
+
+ test->nextTime = 1500000000 + 3600 * 24 * 2;
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 1500000000 + 3600 * 24 * 3;
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 3;
+ GBMBCRTCRead(gb);
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 1500000000 + 3600 * 24 * 2;
+ test->core->reset(test->core);
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+
+ test->nextTime = 1500000000 + 3600 * 24 * 3;
+ test->core->reset(test->core);
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 2;
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+ expected[0] = 0;
+ expected[1] = 0;
+ expected[2] = 0;
+ expected[3] = 3;
+ _sampleRtcKeepLatch(gb);
+ assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
+}
+
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBRTC,
cmocka_unit_test(create),
cmocka_unit_test(tickSecond),
@@ -683,4 +962,8 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBRTC,
cmocka_unit_test(tick12Hours),
cmocka_unit_test(tickDay),
cmocka_unit_test(wideTickDay),
- cmocka_unit_test(rolloverSecond))
+ cmocka_unit_test(rolloverSecond),
+ cmocka_unit_test(roundtrip0),
+ cmocka_unit_test(roundtripSecond),
+ cmocka_unit_test(roundtripDay),
+ cmocka_unit_test(roundtripHuge))
View
@@ -64,7 +64,6 @@ void GBTimerReset(struct GBTimer* timer) {
timer->nextDiv = GB_DMG_DIV_PERIOD; // TODO: GBC differences
timer->timaPeriod = 1024 >> 4;
- timer->internalDiv = 0;
}
void GBTimerDivReset(struct GBTimer* timer) {
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -139,35 +139,51 @@ static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_
char line[18] = "XXXXXXXX XXXXXXXX";
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
- int gsaP, parP;
+ int gsaP, rgsaP, parP, rparP;
+ int maxProbability = INT_MIN;
switch (set->gsaVersion) {
case 0:
// Try to detect GameShark version
GBACheatDecryptGameShark(&o1, &o2, GBACheatGameSharkSeeds);
gsaP = GBACheatGameSharkProbability(o1, o2);
o1 = op1;
o2 = op2;
+ if (gsaP > maxProbability) {
+ maxProbability = gsaP;
+ GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1);
+ }
+
GBACheatDecryptGameShark(&o1, &o2, GBACheatProActionReplaySeeds);
parP = GBACheatProActionReplayProbability(o1, o2);
- o1 = op1;
- o2 = op2;
- if (gsaP > parP) {
- GBACheatSetGameSharkVersion(set, 1);
- GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
- return GBACheatAddGameSharkRaw(set, o1, o2);
+ if (parP > maxProbability) {
+ maxProbability = parP;
+ GBACheatSetGameSharkVersion(set, GBA_GS_PARV3);
+ }
+
+ rgsaP = GBACheatGameSharkProbability(op1, op1);
+ if (rgsaP > maxProbability) {
+ maxProbability = rgsaP;
+ GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1_RAW);
+ }
+
+ rparP = GBACheatProActionReplayProbability(op1, op1);
+ if (rparP > maxProbability) {
+ maxProbability = rparP;
+ GBACheatSetGameSharkVersion(set, GBA_GS_PARV3_RAW);
+ }
+
+ if (set->gsaVersion < 3) {
+ return GBACheatAddGameShark(set, op1, op2);
} else {
- // If probabilities are equal, assume PARv3
- GBACheatSetGameSharkVersion(set, 3);
- GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
- return GBACheatAddProActionReplayRaw(set, o1, o2);
+ return GBACheatAddProActionReplay(set, op1, op2);
}
break;
case 1:
- GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
- return GBACheatAddGameSharkRaw(set, o1, o2);
+ case 2:
+ return GBACheatAddGameShark(set, o1, o2);
case 3:
- GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
- return GBACheatAddProActionReplayRaw(set, o1, o2);
+ case 4:
+ return GBACheatAddProActionReplay(set, o1, o2);
}
return false;
}
@@ -288,11 +304,19 @@ static void GBACheatParseDirectives(struct mCheatSet* set, const struct StringLi
for (d = 0; d < StringListSize(directives); ++d) {
const char* directive = *StringListGetConstPointer(directives, d);
if (strcmp(directive, "GSAv1") == 0) {
- GBACheatSetGameSharkVersion(cheats, 1);
+ GBACheatSetGameSharkVersion(cheats, GBA_GS_GSAV1);
+ continue;
+ }
+ if (strcmp(directive, "GSAv1 raw") == 0) {
+ GBACheatSetGameSharkVersion(cheats, GBA_GS_GSAV1_RAW);
continue;
}
if (strcmp(directive, "PARv3") == 0) {
- GBACheatSetGameSharkVersion(cheats, 3);
+ GBACheatSetGameSharkVersion(cheats, GBA_GS_PARV3);
+ continue;
+ }
+ if (strcmp(directive, "PARv3 raw") == 0) {
+ GBACheatSetGameSharkVersion(cheats, GBA_GS_PARV3_RAW);
continue;
}
}
@@ -311,15 +335,21 @@ static void GBACheatDumpDirectives(struct mCheatSet* set, struct StringList* dir
char** directive;
switch (cheats->gsaVersion) {
case 1:
- case 2:
directive = StringListAppend(directives);
*directive = strdup("GSAv1");
break;
+ case 2:
+ directive = StringListAppend(directives);
+ *directive = strdup("GSAv1 raw");
+ break;
case 3:
- case 4:
directive = StringListAppend(directives);
*directive = strdup("PARv3");
break;
+ case 4:
+ directive = StringListAppend(directives);
+ *directive = strdup("PARv3 raw");
+ break;
}
}
@@ -367,7 +397,7 @@ int GBACheatAddressIsReal(uint32_t address) {
return -0x8;
case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR:
- if ((address & OFFSET_MASK) > SIZE_CART_SRAM) {
+ if ((address & OFFSET_MASK) > SIZE_CART_FLASH512) {
return -0x80;
}
return -0x8;
View
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gba/cheats.h>
+#include "gba/cheats/gameshark.h"
#include "gba/cheats/parv3.h"
#include <mgba/internal/gba/gba.h>
#include <mgba-util/string.h>
@@ -73,17 +74,19 @@ void GBACheatReseedGameShark(uint32_t* seeds, uint16_t params, const uint8_t* t1
}
}
-void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, int version) {
+void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, enum GBACheatGameSharkVersion version) {
cheats->gsaVersion = version;
switch (version) {
- case 1:
- case 2:
+ case GBA_GS_GSAV1:
+ case GBA_GS_GSAV1_RAW:
memcpy(cheats->gsaSeeds, GBACheatGameSharkSeeds, 4 * sizeof(uint32_t));
break;
- case 3:
- case 4:
+ case GBA_GS_PARV3:
+ case GBA_GS_PARV3_RAW:
memcpy(cheats->gsaSeeds, GBACheatProActionReplaySeeds, 4 * sizeof(uint32_t));
break;
+ default:
+ break;
}
}
@@ -197,14 +200,13 @@ bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
switch (set->gsaVersion) {
- case 0:
- case 3:
- case 4:
- GBACheatSetGameSharkVersion(set, 1);
+ default:
+ GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1);
// Fall through
- case 1:
- case 2:
+ case GBA_GS_GSAV1:
GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
+ // Fall through
+ case GBA_GS_GSAV1_RAW:
return GBACheatAddGameSharkRaw(set, o1, o2);
}
return false;
View
@@ -12,10 +12,18 @@ CXX_GUARD_START
extern const uint32_t GBACheatGameSharkSeeds[4];
+enum GBACheatGameSharkVersion {
+ GBA_GS_NOT_SET = 0,
+ GBA_GS_GSAV1 = 1,
+ GBA_GS_GSAV1_RAW = 2,
+ GBA_GS_PARV3 = 3,
+ GBA_GS_PARV3_RAW = 4
+};
+
struct GBACheatSet;
void GBACheatDecryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds);
void GBACheatReseedGameShark(uint32_t* seeds, uint16_t params, const uint8_t* t1, const uint8_t* t2);
-void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, int version);
+void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, enum GBACheatGameSharkVersion version);
bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2);
int GBACheatGameSharkProbability(uint32_t op1, uint32_t op2);
View
@@ -53,7 +53,7 @@ static uint32_t _parAddr(uint32_t x) {
}
static void _parEndBlock(struct GBACheatSet* cheats) {
- size_t size = mCheatListSize(&cheats->d.list) - cheats->currentBlock;
+ size_t size = mCheatListSize(&cheats->d.list) - cheats->currentBlock - 1;
struct mCheat* currentBlock = mCheatListGetPointer(&cheats->d.list, cheats->currentBlock);
if (currentBlock->repeat) {
currentBlock->negativeRepeat = size - currentBlock->repeat;
@@ -64,7 +64,7 @@ static void _parEndBlock(struct GBACheatSet* cheats) {
}
static void _parElseBlock(struct GBACheatSet* cheats) {
- size_t size = mCheatListSize(&cheats->d.list) - cheats->currentBlock;
+ size_t size = mCheatListSize(&cheats->d.list) - cheats->currentBlock - 1;
struct mCheat* currentBlock = mCheatListGetPointer(&cheats->d.list, cheats->currentBlock);
currentBlock->repeat = size;
}
@@ -284,6 +284,10 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin
cheat->address = BASE_IO | (op1 & OFFSET_MASK);
break;
}
+ if (op1 & 0x01000000 && (op1 & 0xFE000000) != 0xC6000000) {
+ return false;
+ }
+
cheat->width = width;
cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));
@@ -297,14 +301,13 @@ bool GBACheatAddProActionReplay(struct GBACheatSet* set, uint32_t op1, uint32_t
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
switch (set->gsaVersion) {
- case 0:
- case 1:
- case 2:
- GBACheatSetGameSharkVersion(set, 3);
+ default:
+ GBACheatSetGameSharkVersion(set, GBA_GS_PARV3);
// Fall through
- case 3:
- case 4:
+ case GBA_GS_PARV3:
GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
+ // Fall through
+ case GBA_GS_PARV3_RAW:
return GBACheatAddProActionReplayRaw(set, o1, o2);
}
return false;
@@ -370,7 +373,7 @@ int GBACheatProActionReplayProbability(uint32_t op1, uint32_t op2) {
int width = ((op1 & PAR3_WIDTH) >> (PAR3_WIDTH_BASE - 3));
if (op1 & PAR3_COND) {
probability += 0x20;
- if (width == 32) {
+ if (width >= 24) {
return 0;
}
if (op2 & ~((1 << width) - 1)) {
@@ -384,10 +387,13 @@ int GBACheatProActionReplayProbability(uint32_t op1, uint32_t op2) {
if (op2 & ~((1 << width) - 1)) {
probability -= 0x10;
}
+ // Fall through
case PAR3_BASE_ASSIGN:
case PAR3_BASE_INDIRECT:
probability += GBACheatAddressIsReal(address);
- // Fall through
+ if (op1 & 0x01000000) {
+ return 0;
+ }
break;
case PAR3_BASE_OTHER:
break;
View
@@ -266,6 +266,7 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->renderer.outputBuffer = buffer;
gbacore->renderer.outputBufferStride = stride;
+ memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty));
}
static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
@@ -405,14 +406,7 @@ static void _GBACoreReset(struct mCore* core) {
GBAVideoAssociateRenderer(&gba->video, renderer);
}
- struct GBACartridgeOverride override;
- const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
- if (cart) {
- memcpy(override.id, &cart->id, sizeof(override.id));
- if (GBAOverrideFind(gbacore->overrides, &override)) {
- GBAOverrideApply(gba, &override);
- }
- }
+ GBAOverrideApplyDefaults(gba, gbacore->overrides);
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
if (!gba->biosVf && core->opts.useBios) {
@@ -508,7 +502,6 @@ static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys &= ~keys;
- GBATestKeypadIRQ(core->board);
}
static void _GBACoreSetCursorLocation(struct mCore* core, int x, int y) {
View
@@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gba/renderers/proxy.h>
-#include <mgba/core/tile-cache.h>
+#include <mgba/core/cache-set.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>
@@ -224,7 +224,7 @@ void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t
proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
}
if (renderer->cache) {
- mTileCacheWriteVRAM(renderer->cache, address);
+ mCacheSetWriteVRAM(renderer->cache, address);
}
}
@@ -235,7 +235,7 @@ void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32
proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
}
if (renderer->cache) {
- mTileCacheWritePalette(renderer->cache, address);
+ mCacheSetWritePalette(renderer->cache, address >> 1, mColorFrom555(value));
}
}
View
@@ -526,6 +526,9 @@ bool GBAIsROM(struct VFile* vf) {
return isGBA;
}
#endif
+ if (!vf) {
+ return false;
+ }
if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
return false;
}
@@ -751,19 +754,17 @@ void GBATestKeypadIRQ(struct GBA* gba) {
return;
}
int isAnd = keycnt & 0x8000;
- uint16_t keyInput;
-
if (!gba->keySource) {
// TODO?
return;
}
keycnt &= 0x3FF;
- keyInput = *gba->keySource;
+ uint16_t keyInput = *gba->keySource & keycnt;
if (isAnd && keycnt == keyInput) {
GBARaiseIRQ(gba, IRQ_KEYPAD);
- } else if (!isAnd && keycnt & keyInput) {
+ } else if (!isAnd && keyInput) {
GBARaiseIRQ(gba, IRQ_KEYPAD);
}
}
View
@@ -890,14 +890,17 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
break;
case REG_MAX:
// Some bad interrupt libraries will read from this
- break;
- case 0x66:
- case 0x6E:
- case 0x76:
- case 0x7A:
- case 0x7E:
- case 0x86:
- case 0x8A:
+ case 0x066:
+ case 0x06E:
+ case 0x076:
+ case 0x07A:
+ case 0x07E:
+ case 0x086:
+ case 0x08A:
+ case 0x136:
+ case 0x142:
+ case 0x15A:
+ case 0x206:
mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address);
return 0;
case REG_DEBUG_ENABLE:
View
@@ -92,6 +92,7 @@ void GBAMemoryDeinit(struct GBA* gba) {
if (gba->memory.rom) {
mappedMemoryFree(gba->memory.rom, gba->memory.romSize);
}
+ gba->memory.savedata.maskWriteback = false;
GBASavedataUnmask(&gba->memory.savedata);
GBASavedataDeinit(&gba->memory.savedata);
if (gba->memory.savedata.realVf) {
@@ -683,27 +684,39 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
GBAIOWrite32(gba, address & (OFFSET_MASK - 3), value);
#define STORE_PALETTE_RAM \
- STORE_32(value, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \
- gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 4)) + 2, value >> 16); \
- wait += waitstatesRegion[REGION_PALETTE_RAM]; \
- gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 4), value);
+ LOAD_32(oldValue, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \
+ if (oldValue != value) { \
+ STORE_32(value, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \
+ gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 4)) + 2, value >> 16); \
+ gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 4), value); \
+ } \
+ wait += waitstatesRegion[REGION_PALETTE_RAM];
#define STORE_VRAM \
if ((address & 0x0001FFFF) < SIZE_VRAM) { \
- STORE_32(value, address & 0x0001FFFC, gba->video.vram); \
- gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
- gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
+ LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \
+ if (oldValue != value) { \
+ STORE_32(value, address & 0x0001FFFC, gba->video.vram); \
+ gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
+ gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
+ } \
} else { \
- STORE_32(value, address & 0x00017FFC, gba->video.vram); \
- gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \
- gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \
+ LOAD_32(oldValue, address & 0x00017FFC, gba->video.vram); \
+ if (oldValue != value) { \
+ STORE_32(value, address & 0x00017FFC, gba->video.vram); \
+ gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \
+ gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \
+ } \
} \
wait += waitstatesRegion[REGION_VRAM];
#define STORE_OAM \
- STORE_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); \
- gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 4)) >> 1); \
- gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1);
+ LOAD_32(oldValue, address & (SIZE_OAM - 4), gba->video.oam.raw); \
+ if (oldValue != value) { \
+ STORE_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); \
+ gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 4)) >> 1); \
+ gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1); \
+ }
#define STORE_CART \
wait += waitstatesRegion[address >> BASE_OFFSET]; \
@@ -726,6 +739,7 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
struct GBA* gba = (struct GBA*) cpu->master;
struct GBAMemory* memory = &gba->memory;
int wait = 0;
+ int32_t oldValue;
char* waitstatesRegion = memory->waitstatesNonseq32;
switch (address >> BASE_OFFSET) {
@@ -777,6 +791,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
struct GBA* gba = (struct GBA*) cpu->master;
struct GBAMemory* memory = &gba->memory;
int wait = 0;
+ int16_t oldValue;
switch (address >> BASE_OFFSET) {
case REGION_WORKING_RAM:
@@ -790,21 +805,33 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
GBAIOWrite(gba, address & (OFFSET_MASK - 1), value);
break;
case REGION_PALETTE_RAM:
- STORE_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette);
- gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 2), value);
+ LOAD_16(oldValue, address & (SIZE_PALETTE_RAM - 2), gba->video.palette);
+ if (oldValue != value) {
+ STORE_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette);
+ gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 2), value);
+ }
break;
case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) {
- STORE_16(value, address & 0x0001FFFE, gba->video.vram);
- gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
+ LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram);
+ if (value != oldValue) {
+ STORE_16(value, address & 0x0001FFFE, gba->video.vram);
+ gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
+ }
} else {
- STORE_16(value, address & 0x00017FFE, gba->video.vram);
- gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE);
+ LOAD_16(oldValue, address & 0x00017FFE, gba->video.vram);
+ if (value != oldValue) {
+ STORE_16(value, address & 0x00017FFE, gba->video.vram);
+ gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE);
+ }
}
break;
case REGION_OAM:
- STORE_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw);
- gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 2)) >> 1);
+ LOAD_16(oldValue, address & (SIZE_OAM - 2), gba->video.oam.raw);
+ if (value != oldValue) {
+ STORE_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw);
+ gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 2)) >> 1);
+ }
break;
case REGION_CART0:
if (memory->hw.devices != HW_NONE && IS_GPIO_REGISTER(address & 0xFFFFFE)) {
@@ -844,6 +871,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
struct GBA* gba = (struct GBA*) cpu->master;
struct GBAMemory* memory = &gba->memory;
int wait = 0;
+ uint16_t oldValue;
switch (address >> BASE_OFFSET) {
case REGION_WORKING_RAM:
@@ -865,8 +893,11 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address);
break;
}
- gba->video.vram[(address & 0x1FFFE) >> 1] = ((uint8_t) value) | (value << 8);
- gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
+ oldValue = gba->video.vram[(address & 0x1FFFE) >> 1];
+ if (oldValue != (((uint8_t) value) | (value << 8))) {
+ gba->video.vram[(address & 0x1FFFE) >> 1] = ((uint8_t) value) | (value << 8);
+ gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
+ }
break;
case REGION_OAM:
mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address);
@@ -1369,6 +1400,7 @@ uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum
struct GBA* gba = (struct GBA*) cpu->master;
struct GBAMemory* memory = &gba->memory;
uint32_t value;
+ uint32_t oldValue;
char* waitstatesRegion = memory->waitstatesSeq32;
int i;
View
@@ -338,11 +338,19 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri
}
}
-void GBAOverrideApplyDefaults(struct GBA* gba) {
- struct GBACartridgeOverride override;
+void GBAOverrideApplyDefaults(struct GBA* gba, const struct Configuration* overrides) {
+ struct GBACartridgeOverride override = { .idleLoop = IDLE_LOOP_NONE };
const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
- memcpy(override.id, &cart->id, sizeof(override.id));
- if (GBAOverrideFind(0, &override)) {
- GBAOverrideApply(gba, &override);
+ if (cart) {
+ memcpy(override.id, &cart->id, sizeof(override.id));
+
+ if (!strncmp("pokemon red version", &((const char*) gba->memory.rom)[0x108], 20) && gba->romCrc32 != 0xDD88761C) {
+ // Enable FLASH1M and RTC on Pokémon FireRed ROM hacks
+ override.savetype = SAVEDATA_FLASH1M;
+ override.hardware = HW_RTC;
+ GBAOverrideApply(gba, &override);
+ } else if (GBAOverrideFind(overrides, &override)) {
+ GBAOverrideApply(gba, &override);
+ }
}
}
View
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013-2017 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
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <mgba/internal/gba/renderers/cache-set.h>
+
+#include <mgba/core/cache-set.h>
+#include <mgba/internal/gba/gba.h>
+#include <mgba/internal/gba/io.h>
+#include <mgba/internal/gba/video.h>
+
+void GBAVideoCacheInit(struct mCacheSet* cache) {
+ mCacheSetInit(cache, 4, 4);
+ mTileCacheSystemInfo sysconfig = 0;
+ mTileCacheConfiguration config = mTileCacheConfigurationFillShouldStore(0);
+ sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 2); // 2^(2^2) = 16 entries
+ sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 4); // 16 palettes
+ sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048);
+ mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 0));
+ mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 0), config);
+ mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 0), sysconfig, 0, 0);
+ sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024);
+ mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 2));
+ mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 2), config);
+ mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 2), sysconfig, 0x10000, 0x100);
+
+ sysconfig = mTileCacheSystemInfoSetPaletteBPP(sysconfig, 3); // 2^(2^3) = 256 entries
+ sysconfig = mTileCacheSystemInfoSetPaletteCount(sysconfig, 0); // 1 palettes
+ sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 2048);
+ mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 1));
+ mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 1), config);
+ mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 1), sysconfig, 0, 0);
+ sysconfig = mTileCacheSystemInfoSetMaxTiles(sysconfig, 1024);
+ mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, 3));
+ mTileCacheConfigure(mTileCacheSetGetPointer(&cache->tiles, 3), config);
+ mTileCacheConfigureSystem(mTileCacheSetGetPointer(&cache->tiles, 3), sysconfig, 0x10000, 0x100);
+
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 0));
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 1));
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 2));
+ mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, 3));
+}
+
+void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) {
+ mCacheSetAssignVRAM(cache, video->vram);
+ video->renderer->cache = cache;
+ size_t i;
+ for (i = 0; i < SIZE_PALETTE_RAM / 2; ++i) {
+ mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i]));
+ }
+ GBAVideoCacheWriteVideoRegister(cache, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]);
+ GBAVideoCacheWriteVideoRegister(cache, REG_BG0CNT, video->p->memory.io[REG_BG0CNT >> 1]);
+ GBAVideoCacheWriteVideoRegister(cache, REG_BG1CNT, video->p->memory.io[REG_BG1CNT >> 1]);
+ GBAVideoCacheWriteVideoRegister(cache, REG_BG2CNT, video->p->memory.io[REG_BG2CNT >> 1]);
+ GBAVideoCacheWriteVideoRegister(cache, REG_BG3CNT, video->p->memory.io[REG_BG3CNT >> 1]);
+}
+
+static void mapParser0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
+ UNUSED(cache);
+ uint16_t map = *(uint16_t*) vram;
+ entry->tileId = GBA_TEXT_MAP_TILE(map);
+ entry->flags = mMapCacheEntryFlagsSetHMirror(entry->flags, !!GBA_TEXT_MAP_HFLIP(map));
+ entry->flags = mMapCacheEntryFlagsSetVMirror(entry->flags, !!GBA_TEXT_MAP_VFLIP(map));
+ entry->flags = mMapCacheEntryFlagsSetPaletteId(entry->flags, GBA_TEXT_MAP_PALETTE(map));
+}
+
+static void mapParser2(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) {
+ UNUSED(cache);
+ entry->tileId = *(uint8_t*) vram;
+ entry->flags = mMapCacheEntryFlagsClearHMirror(entry->flags);
+ entry->flags = mMapCacheEntryFlagsClearVMirror(entry->flags);
+ entry->flags = mMapCacheEntryFlagsClearPaletteId(entry->flags);
+}
+
+static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
+ switch (GBARegisterDISPCNTGetMode(value)) {
+ case 0:
+ default:
+ mMapCacheSetGetPointer(&cache->maps, 0)->mapParser = mapParser0;
+ mMapCacheSetGetPointer(&cache->maps, 1)->mapParser = mapParser0;
+ mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser0;
+ mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser0;
+
+ mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ break;
+ case 1:
+ case 2:
+ mMapCacheSetGetPointer(&cache->maps, 0)->mapParser = mapParser0;
+ mMapCacheSetGetPointer(&cache->maps, 1)->mapParser = mapParser0;
+ mMapCacheSetGetPointer(&cache->maps, 2)->mapParser = mapParser2;
+ mMapCacheSetGetPointer(&cache->maps, 3)->mapParser = mapParser2;
+
+ mMapCacheSetGetPointer(&cache->maps, 0)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 1)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 0);
+ mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
+ mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1);
+ break;
+ }
+}
+
+static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t value) {
+ struct mMapCache* map = mMapCacheSetGetPointer(&cache->maps, bg);
+ map->context = (void*) (uintptr_t) value;
+
+ int tileStart = GBARegisterBGCNTGetCharBase(value) * 256;
+ bool p = GBARegisterBGCNTGet256Color(value);
+ int size = GBARegisterBGCNTGetSize(value);
+ int tilesWide = 0;
+ int tilesHigh = 0;
+ mMapCacheSystemInfo sysconfig = 0;
+ if (map->mapParser == mapParser0) {
+ sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 2 + p);
+ sysconfig = mMapCacheSystemInfoSetPaletteCount(sysconfig, 4 * !p);
+ sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 5);
+ sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 1);
+ tilesWide = 5;
+ tilesHigh = 5;
+ if (size & 1) {
+ ++tilesWide;
+ }
+ if (size & 2) {
+ ++tilesHigh;
+ }
+ map->tileStart = tileStart * 2;
+ } else if (map->mapParser == mapParser2) {
+ sysconfig = mMapCacheSystemInfoSetPaletteBPP(sysconfig, 3);
+ sysconfig = mMapCacheSystemInfoSetPaletteCount(sysconfig, 0);
+ sysconfig = mMapCacheSystemInfoSetMacroTileSize(sysconfig, 4 + size);
+ sysconfig = mMapCacheSystemInfoSetMapAlign(sysconfig, 0);
+
+ tilesHigh = 4 + size;
+ tilesWide = 4 + size;
+ map->tileStart = tileStart;
+ }
+ sysconfig = mMapCacheSystemInfoSetTilesHigh(sysconfig, tilesHigh);
+ sysconfig = mMapCacheSystemInfoSetTilesWide(sysconfig, tilesWide);
+ mMapCacheConfigureSystem(map, sysconfig);
+ mMapCacheConfigureMap(map, GBARegisterBGCNTGetScreenBase(value) << 11);
+}
+
+void GBAVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint32_t address, uint16_t value) {
+ switch (address) {
+ case REG_DISPCNT:
+ GBAVideoCacheWriteDISPCNT(cache, value);
+ GBAVideoCacheWriteBGCNT(cache, 0, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 0)->context);
+ GBAVideoCacheWriteBGCNT(cache, 1, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 1)->context);
+ GBAVideoCacheWriteBGCNT(cache, 2, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 2)->context);
+ GBAVideoCacheWriteBGCNT(cache, 3, (uint16_t) mMapCacheSetGetPointer(&cache->maps, 3)->context);
+ break;
+ case REG_BG0CNT:
+ GBAVideoCacheWriteBGCNT(cache, 0, value);
+ break;
+ case REG_BG1CNT:
+ GBAVideoCacheWriteBGCNT(cache, 1, value);
+ break;
+ case REG_BG2CNT:
+ GBAVideoCacheWriteBGCNT(cache, 2, value);
+ break;
+ case REG_BG3CNT:
+ GBAVideoCacheWriteBGCNT(cache, 3, value);
+ break;
+
+ }
+}
View
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba/renderers/software-private.h"
+#include <mgba/core/interface.h>
#include <mgba/internal/gba/gba.h>
#define MODE_2_COORD_OVERFLOW \
@@ -96,21 +97,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer
if (!mosaicWait) {
LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
-#ifndef COLOR_16_BIT
- unsigned color32;
- color32 = 0;
- color32 |= (color << 3) & 0xF8;
- color32 |= (color << 6) & 0xF800;
- color32 |= (color << 9) & 0xF80000;
- color32 |= (color32 >> 5) & 0x070707;
- color = color32;
-#elif COLOR_5_6_5
- uint16_t color16 = 0;
- color16 |= (color & 0x001F) << 11;
- color16 |= (color & 0x03E0) << 1;
- color16 |= (color & 0x7C00) >> 10;
- color = color16;
-#endif
+ color = mColorFrom555(color);
mosaicWait = mosaicH;
} else {
--mosaicWait;
@@ -185,20 +172,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer
if (!mosaicWait) {
LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vramBG[0]);
-#ifndef COLOR_16_BIT
- unsigned color32 = 0;
- color32 |= (color << 9) & 0xF80000;
- color32 |= (color << 3) & 0xF8;
- color32 |= (color << 6) & 0xF800;
- color32 |= (color32 >> 5) & 0x070707;
- color = color32;
-#elif COLOR_5_6_5
- uint16_t color16 = 0;
- color16 |= (color & 0x001F) << 11;
- color16 |= (color & 0x03E0) << 1;
- color16 |= (color & 0x7C00) >> 10;
- color = color16;
-#endif
+ color = mColorFrom555(color);
mosaicWait = mosaicH;
} else {
--mosaicWait;
View
@@ -255,9 +255,13 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
target2 |= renderer->bg[2].target2 << (renderer->bg[2].priority);
target2 |= renderer->bg[3].target2 << (renderer->bg[3].priority);
if ((1 << GBAObjAttributesCGetPriority(sprite->c)) <= target2) {
+ flags |= FLAG_REBLEND;
variant = 0;
+ } else if (!target2) {
+ flags &= ~FLAG_TARGET_1;
}
}
+
color_t* palette = &renderer->normalPalette[0x100];
color_t* objwinPalette = palette;
int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed);
View
@@ -47,7 +47,7 @@ static inline void _compositeBlendObjwin(struct GBAVideoSoftwareRenderer* render
if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
color = _mix(renderer->alphaA[x], current, renderer->alphaB[x], color);
} else {
- color = (current & 0x00FFFFFF) | ((current << 1) & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
}
} else {
color = (color & ~FLAG_TARGET_2) | (current & FLAG_OBJWIN);
@@ -63,7 +63,7 @@ static inline void _compositeBlendNoObjwin(struct GBAVideoSoftwareRenderer* rend
if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
color = _mix(renderer->alphaA[x], current, renderer->alphaB[x], color);
} else {
- color = (current & 0x00FFFFFF) | ((current << 1) & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
}
} else {
color = color & ~FLAG_TARGET_2;
@@ -77,7 +77,7 @@ static inline void _compositeNoBlendObjwin(struct GBAVideoSoftwareRenderer* rend
if (color < current) {
color |= (current & FLAG_OBJWIN);
} else {
- color = (current & 0x00FFFFFF) | ((current << 1) & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
}
renderer->row[x] = color;
}
@@ -86,7 +86,7 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
uint32_t current) {
UNUSED(renderer);
if (color >= current) {
- color = (current & 0x00FFFFFF) | ((current << 1) & FLAG_REBLEND);
+ color = (current & 0x00FFFFFF) | (current & FLAG_REBLEND);
}
renderer->row[x] = color;
}
View
@@ -1,26 +0,0 @@
-/* Copyright (c) 2013-2016 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
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include <mgba/internal/gba/renderers/tile-cache.h>
-
-#include <mgba/core/tile-cache.h>
-#include <mgba/internal/gba/video.h>
-
-void GBAVideoTileCacheInit(struct mTileCache* cache) {
- mTileCacheInit(cache);
- mTileCacheConfiguration config = 0;
- config = mTileCacheSystemInfoSetPalette0BPP(config, 2); // 2^(2^2) = 16 entries
- config = mTileCacheSystemInfoSetPalette0Count(config, 5); // 32 palettes
- config = mTileCacheSystemInfoSetPalette1BPP(config, 3); // 2^(2^3) = 256 entries
- config = mTileCacheSystemInfoSetPalette1Count(config, 1); // 2 palettes
- config = mTileCacheSystemInfoSetMaxTiles(config, 3072);
- mTileCacheConfigureSystem(cache, config);
-}
-
-void GBAVideoTileCacheAssociate(struct mTileCache* cache, struct GBAVideo* video) {
- cache->vram = video->vram;
- cache->palette = video->palette;
- video->renderer->cache = cache;
-}
View
@@ -5,13 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba/renderers/software-private.h"
-#include <mgba/core/tile-cache.h>
+#include <mgba/core/cache-set.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/gba/io.h>
+#include <mgba/internal/gba/renderers/cache-set.h>
#include <mgba-util/arm-algo.h>
#include <mgba-util/memory.h>
+#define DIRTY_SCANLINE(R, Y) R->scanlineDirty[Y >> 5] |= (1 << (Y & 0x1F))
+#define CLEAN_SCANLINE(R, Y) R->scanlineDirty[Y >> 5] &= ~(1 << (Y & 0x1F))
+
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer);
@@ -26,10 +30,6 @@ static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer,
static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer);
static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg, uint16_t value);
-static void GBAVideoSoftwareRendererWriteBGPA(struct GBAVideoSoftwareBackground* bg, uint16_t value);
-static void GBAVideoSoftwareRendererWriteBGPB(struct GBAVideoSoftwareBackground* bg, uint16_t value);
-static void GBAVideoSoftwareRendererWriteBGPC(struct GBAVideoSoftwareBackground* bg, uint16_t value);
-static void GBAVideoSoftwareRendererWriteBGPD(struct GBAVideoSoftwareBackground* bg, uint16_t value);
static void GBAVideoSoftwareRendererWriteBGX_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value);
static void GBAVideoSoftwareRendererWriteBGX_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value);
static void GBAVideoSoftwareRendererWriteBGY_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value);
@@ -120,6 +120,11 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
softwareRenderer->oamMax = 0;
softwareRenderer->mosaic = 0;
+ softwareRenderer->nextY = 0;
+
+ memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
+ memset(softwareRenderer->cache, 0, sizeof(softwareRenderer->cache));
+ memset(softwareRenderer->nextIo, 0, sizeof(softwareRenderer->nextIo));
for (i = 0; i < 4; ++i) {
struct GBAVideoSoftwareBackground* bg = &softwareRenderer->bg[i];
@@ -156,6 +161,10 @@ static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer) {
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
+ if (renderer->cache) {
+ GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
+ }
+
switch (address) {
case REG_DISPCNT:
softwareRenderer->dispcnt = value;
@@ -210,52 +219,76 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
softwareRenderer->bg[3].y = value;
break;
case REG_BG2PA:
- GBAVideoSoftwareRendererWriteBGPA(&softwareRenderer->bg[2], value);
+ softwareRenderer->bg[2].dx = value;
break;
case REG_BG2PB:
- GBAVideoSoftwareRendererWriteBGPB(&softwareRenderer->bg[2], value);
+ softwareRenderer->bg[2].dmx = value;
break;
case REG_BG2PC:
- GBAVideoSoftwareRendererWriteBGPC(&softwareRenderer->bg[2], value);
+ softwareRenderer->bg[2].dy = value;
break;
case REG_BG2PD:
- GBAVideoSoftwareRendererWriteBGPD(&softwareRenderer->bg[2], value);
+ softwareRenderer->bg[2].dmy = value;
break;
case REG_BG2X_LO:
GBAVideoSoftwareRendererWriteBGX_LO(&softwareRenderer->bg[2], value);
+ if (softwareRenderer->bg[2].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[0][0]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG2X_HI:
GBAVideoSoftwareRendererWriteBGX_HI(&softwareRenderer->bg[2], value);
+ if (softwareRenderer->bg[2].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[0][0]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG2Y_LO:
GBAVideoSoftwareRendererWriteBGY_LO(&softwareRenderer->bg[2], value);
+ if (softwareRenderer->bg[2].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[0][1]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG2Y_HI:
GBAVideoSoftwareRendererWriteBGY_HI(&softwareRenderer->bg[2], value);
+ if (softwareRenderer->bg[2].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[0][1]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG3PA:
- GBAVideoSoftwareRendererWriteBGPA(&softwareRenderer->bg[3], value);
+ softwareRenderer->bg[3].dx = value;
break;
case REG_BG3PB:
- GBAVideoSoftwareRendererWriteBGPB(&softwareRenderer->bg[3], value);
+ softwareRenderer->bg[3].dmx = value;
break;
case REG_BG3PC:
- GBAVideoSoftwareRendererWriteBGPC(&softwareRenderer->bg[3], value);
+ softwareRenderer->bg[3].dy = value;
break;
case REG_BG3PD:
- GBAVideoSoftwareRendererWriteBGPD(&softwareRenderer->bg[3], value);
+ softwareRenderer->bg[3].dmy = value;
break;
case REG_BG3X_LO:
GBAVideoSoftwareRendererWriteBGX_LO(&softwareRenderer->bg[3], value);
+ if (softwareRenderer->bg[3].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[1][0]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG3X_HI:
GBAVideoSoftwareRendererWriteBGX_HI(&softwareRenderer->bg[3], value);
+ if (softwareRenderer->bg[3].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[1][0]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG3Y_LO:
GBAVideoSoftwareRendererWriteBGY_LO(&softwareRenderer->bg[3], value);
+ if (softwareRenderer->bg[3].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[1][1]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BG3Y_HI:
GBAVideoSoftwareRendererWriteBGY_HI(&softwareRenderer->bg[3], value);
+ if (softwareRenderer->bg[3].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[1][1]) {
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
break;
case REG_BLDCNT:
GBAVideoSoftwareRendererWriteBLDCNT(softwareRenderer, value);
@@ -360,48 +393,42 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
default:
mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
}
+ softwareRenderer->nextIo[address >> 1] = value;
+ if (softwareRenderer->cache[softwareRenderer->nextY].io[address >> 1] != value) {
+ softwareRenderer->cache[softwareRenderer->nextY].io[address >> 1] = value;
+ DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY);
+ }
return value;
}
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
+ struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
if (renderer->cache) {
- mTileCacheWriteVRAM(renderer->cache, address);
+ mCacheSetWriteVRAM(renderer->cache, address);
}
+ memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
}
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
- softwareRenderer->oamDirty = 1;
UNUSED(oam);
+ softwareRenderer->oamDirty = 1;
+ memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
}
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
-#ifdef COLOR_16_BIT
-#ifdef COLOR_5_6_5
- unsigned color = 0;
- color |= (value & 0x001F) << 11;
- color |= (value & 0x03E0) << 1;
- color |= (value & 0x7C00) >> 10;
-#else
- unsigned color = value;
-#endif
-#else
- unsigned color = 0;
- color |= (value << 3) & 0xF8;
- color |= (value << 6) & 0xF800;
- color |= (value << 9) & 0xF80000;
- color |= (color >> 5) & 0x070707;
-#endif
+ color_t color = mColorFrom555(value);
softwareRenderer->normalPalette[address >> 1] = color;
if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
softwareRenderer->variantPalette[address >> 1] = _brighten(color, softwareRenderer->bldy);
} else if (softwareRenderer->blendEffect == BLEND_DARKEN) {
softwareRenderer->variantPalette[address >> 1] = _darken(color, softwareRenderer->bldy);
}
if (renderer->cache) {
- mTileCacheWritePalette(renderer->cache, address);
+ mCacheSetWritePalette(renderer->cache, address >> 1, color);
}
+ memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
}
static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win, int y) {
@@ -515,6 +542,33 @@ static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer) {
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
+ if (y == VIDEO_VERTICAL_PIXELS - 1) {
+ softwareRenderer->nextY = 0;
+ } else {
+ softwareRenderer->nextY = y + 1;
+ }
+
+ bool dirty = softwareRenderer->scanlineDirty[y >> 5] & (1 << (y & 0x1F));
+ if (memcmp(softwareRenderer->nextIo, softwareRenderer->cache[y].io, sizeof(softwareRenderer->nextIo))) {
+ memcpy(softwareRenderer->cache[y].io, softwareRenderer->nextIo, sizeof(softwareRenderer->nextIo));
+ dirty = true;
+ }
+
+ softwareRenderer->cache[y].scale[0][0] = softwareRenderer->bg[2].sx;
+ softwareRenderer->cache[y].scale[0][1] = softwareRenderer->bg[2].sy;
+ softwareRenderer->cache[y].scale[1][0] = softwareRenderer->bg[3].sx;
+ softwareRenderer->cache[y].scale[1][1] = softwareRenderer->bg[3].sy;
+
+ if (!dirty) {
+ if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) != 0) {
+ softwareRenderer->bg[2].sx += softwareRenderer->bg[2].dmx;
+ softwareRenderer->bg[2].sy += softwareRenderer->bg[2].dmy;
+ softwareRenderer->bg[3].sx += softwareRenderer->bg[3].dmx;
+ softwareRenderer->bg[3].sy += softwareRenderer->bg[3].dmy;
+ }
+ return;
+ }
+
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
if (GBARegisterDISPCNTIsForcedBlank(softwareRenderer->dispcnt)) {
int x;
@@ -592,21 +646,23 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
#ifdef COLOR_16_BIT
-#if defined(__ARM_NEON) && !defined(__APPLE__)
- _to16Bit(row, softwareRenderer->row, softwareRenderer->masterEnd);
-#else
+ size_t x;
for (x = 0; x < softwareRenderer->masterEnd; ++x) {
row[x] = softwareRenderer->row[x];
+ row[x + 1] = softwareRenderer->row[x + 1];
+ row[x + 2] = softwareRenderer->row[x + 2];
+ row[x + 3] = softwareRenderer->row[x + 3];
}
-#endif
#else
memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row));
#endif
+ CLEAN_SCANLINE(softwareRenderer, y);
}
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
+ softwareRenderer->nextY = 0;
if (softwareRenderer->temporaryBuffer) {
mappedMemoryFree(softwareRenderer->temporaryBuffer, softwareRenderer->masterEnd * softwareRenderer->masterHeight * 4);
softwareRenderer->temporaryBuffer = 0;
@@ -654,22 +710,6 @@ static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer*
bg->control = value;
}
-static void GBAVideoSoftwareRendererWriteBGPA(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
- bg->dx = value;
-}
-
-static void GBAVideoSoftwareRendererWriteBGPB(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
- bg->dmx = value;
-}
-
-static void GBAVideoSoftwareRendererWriteBGPC(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
- bg->dy = value;
-}
-
-static void GBAVideoSoftwareRendererWriteBGPD(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
- bg->dmy = value;
-}
-
static void GBAVideoSoftwareRendererWriteBGX_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
bg->refx = (bg->refx & 0xFFFF0000) | value;
bg->sx = bg->refx;
View
@@ -147,7 +147,7 @@ size_t GBASavedataSize(struct GBASavedata* savedata) {
case SAVEDATA_FLASH1M:
return SIZE_CART_FLASH1M;
case SAVEDATA_EEPROM:
- return SIZE_CART_EEPROM;
+ return (savedata->vf && savedata->vf->size(savedata->vf) == SIZE_CART_EEPROM512) ? SIZE_CART_EEPROM512 : SIZE_CART_EEPROM;
case SAVEDATA_FORCE_NONE:
return 0;
case SAVEDATA_AUTODETECT:
@@ -257,20 +257,23 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata, bool realisticTiming) {
mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
return;
}
+ int32_t eepromSize = SIZE_CART_EEPROM512;
off_t end;
if (!savedata->vf) {
end = 0;
savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
} else {
end = savedata->vf->size(savedata->vf);
- if (end < SIZE_CART_EEPROM) {
- savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
+ if (end < SIZE_CART_EEPROM512) {
+ savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM512);
+ } else if (end > SIZE_CART_EEPROM512) {
+ eepromSize = SIZE_CART_EEPROM;
}
- savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
+ savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode);
}
savedata->realisticTiming = realisticTiming;
- if (end < SIZE_CART_EEPROM) {
- memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
+ if (end < SIZE_CART_EEPROM512) {
+ memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end);
}
}
@@ -405,6 +408,19 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
}
}
+static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) {
+ if (size < SIZE_CART_EEPROM512) {
+ return;
+ }
+ if (!savedata->vf || savedata->vf->size(savedata->vf) > SIZE_CART_EEPROM512) {
+ return;
+ }
+ savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512);
+ savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
+ savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
+ memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512);
+}
+
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
switch (savedata->command) {
// Read header
@@ -430,6 +446,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32
} else if (writeSize == 1) {
savedata->command = EEPROM_COMMAND_NULL;
} else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
+ _ensureEeprom(savedata, savedata->writeAddress >> 3);
uint8_t current = savedata->data[savedata->writeAddress >> 3];
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
@@ -471,6 +488,7 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
if (savedata->readBitsRemaining < 64) {
int step = 63 - savedata->readBitsRemaining;
uint32_t address = (savedata->readAddress + step) >> 3;
+ _ensureEeprom(savedata, address);
if (address >= SIZE_CART_EEPROM) {
mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
return 0xFF;
View
@@ -128,6 +128,8 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
return false;
}
gba->timing.root = NULL;
+ LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles);
+
size_t i;
for (i = 0; i < 16; ++i) {
LOAD_32(gba->cpu->gprs[i], i * sizeof(gba->cpu->gprs[0]), state->cpu.gprs);
@@ -185,5 +187,9 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
if (gba->rr) {
gba->rr->stateLoaded(gba->rr, state);
}
+
+ gba->timing.reroot = gba->timing.root;
+ gba->timing.root = NULL;
+
return true;
}
Oops, something went wrong.