all repos — mgba @ 751489f490727b624ac64bef614080a3e8ad1415

mGBA Game Boy Advance Emulator

Merge branch 'master' (early part) into medusa
Vicki Pfau vi@endrift.com
Fri, 28 Jun 2019 17:22:06 -0700
commit

751489f490727b624ac64bef614080a3e8ad1415

parent

7ef60af5fa4705b73c8ae1f2452372b6a65907ad

M CHANGESCHANGES

@@ -26,6 +26,8 @@ - Add Game Boy Color palettes for original Game Boy games

- Debugger: Add unary operators and memory dereferencing - GB: Expose platform information to CLI debugger - Support Discord Rich Presence + - Debugger: Add tracing to file + - Map viewer supports bitmapped GBA modes Emulation fixes: - GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208) - GBA: Reset now reloads multiboot ROMs

@@ -38,6 +40,7 @@ - GBA DMA: Fix DMA0-2 lengths (fixes mgba.io/i/1344)

- GB Video: Fix window y changing mid-window (fixes mgba.io/i/1345) - GB Video: Fix more window edge cases (fixes mgba.io/i/1346) - GB Timer: Fix timing adjustments when writing to TAC (fixes mgba.io/i/1340) + - GBA Memory: Fix writing to OBJ memory in modes 3 and 5 Other fixes: - Qt: More app metadata fixes - Qt: Fix load recent from archive (fixes mgba.io/i/1325)

@@ -48,6 +51,9 @@ - CMake: Fix .deb imagemagick dependencies

- Qt: Fix crash in sprite viewer magnification (fixes mgba.io/i/1362) - 3DS: Ensure core 2 can be used for threaded renderer (fixes mgba.io/i/1371) - GB Core: Fix toggling WIN and OBJ being swapped + - All: Fix several memory leaks + - LR35902: Fix trailing whitespace in disassembly + - Qt: Fix adjusting magnification in tile viewer when not fitting to window Misc: - GBA Savedata: EEPROM performance fixes - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash

@@ -60,6 +66,10 @@ - Qt: Improve camera initialization

- Qt: Support switching webcams - Core: Add keysRead callback - Vita: Improved frame drawing speed + - Qt: Cap window size on start to monitor size + - GBA BIOS: Add timings for HLE BIOS math functions (fixes mgba.io/i/1396) + - Debugger: Make tracing compatible with breakpoints/watchpoints + - Debugger: Print breakpoint/watchpoint number when inserting 0.7.1: (2019-02-24) Bugfixes:
A include/mgba/core/bitmap-cache.h

@@ -0,0 +1,64 @@

+/* Copyright (c) 2013-2019 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 M_BITMAP_CACHE_H +#define M_BITMAP_CACHE_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +#include <mgba/core/interface.h> + +DECL_BITFIELD(mBitmapCacheConfiguration, uint32_t); +DECL_BIT(mBitmapCacheConfiguration, ShouldStore, 0); + +DECL_BITFIELD(mBitmapCacheSystemInfo, uint32_t); +DECL_BITS(mBitmapCacheSystemInfo, EntryBPP, 0, 3); +DECL_BIT(mBitmapCacheSystemInfo, UsesPalette, 3); +DECL_BITS(mBitmapCacheSystemInfo, Width, 4, 10); +DECL_BITS(mBitmapCacheSystemInfo, Height, 14, 10); +DECL_BITS(mBitmapCacheSystemInfo, Buffers, 24, 2); + +struct mBitmapCacheEntry { + uint32_t paletteVersion; + uint32_t vramVersion; + uint8_t vramClean; +}; + +struct mBitmapCache { + color_t* cache; + struct mBitmapCacheEntry* status; + + uint32_t globalPaletteVersion; + + uint8_t* vram; + color_t* palette; + + uint32_t bitsSize; + uint32_t bitsStart[2]; + uint32_t stride; + uint8_t buffer; + + mBitmapCacheConfiguration config; + mBitmapCacheSystemInfo sysConfig; + + void* context; +}; + +void mBitmapCacheInit(struct mBitmapCache* cache); +void mBitmapCacheDeinit(struct mBitmapCache* cache); +void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config); +void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config); +void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address); +void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color); + +void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y); +bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y); +const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y); + +CXX_GUARD_END + +#endif
M include/mgba/core/cache-set.hinclude/mgba/core/cache-set.h

@@ -10,19 +10,22 @@ #include <mgba-util/common.h>

CXX_GUARD_START +#include <mgba/core/bitmap-cache.h> #include <mgba/core/map-cache.h> #include <mgba/core/tile-cache.h> #include <mgba-util/vector.h> DECLARE_VECTOR(mMapCacheSet, struct mMapCache); +DECLARE_VECTOR(mBitmapCacheSet, struct mBitmapCache); DECLARE_VECTOR(mTileCacheSet, struct mTileCache); struct mCacheSet { struct mMapCacheSet maps; + struct mBitmapCacheSet bitmaps; struct mTileCacheSet tiles; }; -void mCacheSetInit(struct mCacheSet*, size_t nMaps, size_t nTiles); +void mCacheSetInit(struct mCacheSet*, size_t nMaps, size_t nBitmaps, size_t nTiles); void mCacheSetDeinit(struct mCacheSet*); void mCacheSetAssignVRAM(struct mCacheSet*, void* vram);
M include/mgba/internal/debugger/cli-debugger.hinclude/mgba/internal/debugger/cli-debugger.h

@@ -15,8 +15,11 @@

extern const char* ERROR_MISSING_ARGS; extern const char* ERROR_OVERFLOW; extern const char* ERROR_INVALID_ARGS; +extern const char* INFO_BREAKPOINT_ADDED; +extern const char* INFO_WATCHPOINT_ADDED; struct CLIDebugger; +struct VFile; struct CLIDebugVector { struct CLIDebugVector* next;

@@ -74,6 +77,9 @@ struct mDebugger d;

struct CLIDebuggerSystem* system; struct CLIDebuggerBackend* backend; + + int traceRemaining; + struct VFile* traceVf; }; void CLIDebuggerCreate(struct CLIDebugger*);
M src/arm/debugger/cli-debugger.csrc/arm/debugger/cli-debugger.c

@@ -147,21 +147,27 @@

static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct CLIDebuggerBackend* be = debugger->backend; if (!dv || dv->type != CLIDV_INT_TYPE) { - be->printf(be, "%s\n", ERROR_MISSING_ARGS); + be->printf(be, "%s", ERROR_MISSING_ARGS); return; } uint32_t address = dv->intValue; - ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM); + ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM); + if (id > 0) { + debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id); + } } static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct CLIDebuggerBackend* be = debugger->backend; if (!dv || dv->type != CLIDV_INT_TYPE) { - be->printf(be, "%s\n", ERROR_MISSING_ARGS); + be->printf(be, "%s", ERROR_MISSING_ARGS); return; } uint32_t address = dv->intValue; - ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB); + ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB); + if (id > 0) { + debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id); + } } void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
A src/core/bitmap-cache.c

@@ -0,0 +1,182 @@

+/* Copyright (c) 2013-2019 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/core/bitmap-cache.h> + +#include <mgba-util/memory.h> + +void mBitmapCacheInit(struct mBitmapCache* cache) { + // TODO: Reconfigurable cache for space savings + cache->cache = NULL; + cache->config = mBitmapCacheConfigurationFillShouldStore(0); + cache->status = NULL; + cache->palette = NULL; + cache->buffer = 0; +} + +static void _freeCache(struct mBitmapCache* cache) { + size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); + mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t)); + mappedMemoryFree(cache->status, size * sizeof(*cache->status)); + if (cache->palette) { + free(cache->palette); + } + cache->cache = NULL; + cache->status = NULL; + cache->palette = NULL; +} + +static void _redoCacheSize(struct mBitmapCache* cache) { + if (!mBitmapCacheConfigurationIsShouldStore(cache->config)) { + return; + } + + size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); + cache->cache = anonymousMemoryMap(mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t)); + cache->status = anonymousMemoryMap(size * sizeof(*cache->status)); + if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) { + cache->palette = malloc((1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig))) * sizeof(color_t)); + } else { + cache->palette = NULL; + } +} + +void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config) { + if (config == cache->config) { + return; + } + _freeCache(cache); + cache->config = config; + _redoCacheSize(cache); +} + +void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config) { + if (config == cache->sysConfig) { + return; + } + _freeCache(cache); + cache->sysConfig = config; + _redoCacheSize(cache); + + size_t stride = mBitmapCacheSystemInfoGetWidth(cache->sysConfig); + size_t size = stride * mBitmapCacheSystemInfoGetHeight(cache->sysConfig); + size_t bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig); + if (bpe > 3) { + size <<= bpe - 3; + stride <<= bpe - 3; + } else { + size >>= 3 - bpe; + stride >>= 3 - bpe; + } + cache->bitsSize = size; + cache->stride = stride; +} + +void mBitmapCacheDeinit(struct mBitmapCache* cache) { + _freeCache(cache); +} + +void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address) { + size_t i; + for (i = 0; i < mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); ++i) { + if (address < cache->bitsStart[i]) { + continue; + } + uint32_t offset = address - cache->bitsStart[i]; + if (offset >= cache->bitsSize) { + continue; + } + offset /= cache->stride; + offset *= mBitmapCacheSystemInfoGetBuffers(cache->sysConfig); + offset += cache->buffer; + cache->status[offset].vramClean = 0; + ++cache->status[offset].vramVersion; + } +} + +void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color) { + if (!mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) { + return; + } + size_t maxEntry = 1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig)); + if (entry >= maxEntry) { + return; + } + cache->palette[entry] = color; + ++cache->globalPaletteVersion; +} + +uint32_t _lookupEntry8(void* vram, uint32_t offset) { + return ((uint8_t*) vram)[offset]; +} + +uint32_t _lookupEntry15(void* vram, uint32_t offset) { + return mColorFrom555(((uint16_t*) vram)[offset]); +} + +void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y) { + color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)]; + size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y; + struct mBitmapCacheEntry* status = &cache->status[location]; + struct mBitmapCacheEntry desiredStatus = { + .paletteVersion = cache->globalPaletteVersion, + .vramVersion = entry->vramVersion, + .vramClean = 1 + }; + + if (entry) { + entry[location] = desiredStatus; + } + + if (!mBitmapCacheConfigurationIsShouldStore(cache->config) || !memcmp(status, &desiredStatus, sizeof(*entry))) { + return; + } + + size_t offset = cache->bitsStart[cache->buffer] + y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig); + void* vram; + int bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig); + uint32_t (*lookupEntry)(void*, uint32_t); + switch (bpe) { + case 3: + lookupEntry = _lookupEntry8; + vram = &cache->vram[offset]; + break; + case 4: + lookupEntry = _lookupEntry15; + vram = &cache->vram[offset << 1]; + break; + default: + abort(); + break; + } + + size_t x; + if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) { + for (x = 0; x < mBitmapCacheSystemInfoGetWidth(cache->sysConfig); ++x) { + row[x] = cache->palette[lookupEntry(vram, x)]; + } + } else { + for (x = 0; x < mBitmapCacheSystemInfoGetWidth(cache->sysConfig); ++x) { + row[x] = lookupEntry(vram, x); + } + } + *status = desiredStatus; +} + +bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y) { + size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y; + struct mBitmapCacheEntry desiredStatus = { + .paletteVersion = cache->globalPaletteVersion, + .vramVersion = entry->vramVersion, + .vramClean = 1 + }; + + return memcmp(&entry[location], &desiredStatus, sizeof(*entry)) == 0; +} + +const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y) { + color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)]; + return row; +}
M src/core/cache-set.csrc/core/cache-set.c

@@ -6,11 +6,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <mgba/core/cache-set.h> DEFINE_VECTOR(mMapCacheSet, struct mMapCache); +DEFINE_VECTOR(mBitmapCacheSet, struct mBitmapCache); DEFINE_VECTOR(mTileCacheSet, struct mTileCache); -void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nTiles) { +void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nBitmaps, size_t nTiles) { mMapCacheSetInit(&cache->maps, nMaps); mMapCacheSetResize(&cache->maps, nMaps); + mBitmapCacheSetInit(&cache->bitmaps, nBitmaps); + mBitmapCacheSetResize(&cache->bitmaps, nBitmaps); mTileCacheSetInit(&cache->tiles, nTiles); mTileCacheSetResize(&cache->tiles, nTiles);

@@ -18,6 +21,9 @@ size_t i;

for (i = 0; i < nMaps; ++i) { mMapCacheInit(mMapCacheSetGetPointer(&cache->maps, i)); } + for (i = 0; i < nBitmaps; ++i) { + mBitmapCacheInit(mBitmapCacheSetGetPointer(&cache->bitmaps, i)); + } for (i = 0; i < nTiles; ++i) { mTileCacheInit(mTileCacheSetGetPointer(&cache->tiles, i)); }

@@ -28,6 +34,9 @@ size_t i;

for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) { mMapCacheDeinit(mMapCacheSetGetPointer(&cache->maps, i)); } + for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) { + mBitmapCacheDeinit(mBitmapCacheSetGetPointer(&cache->bitmaps, i)); + } for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) { mTileCacheDeinit(mTileCacheSetGetPointer(&cache->tiles, i)); }

@@ -38,6 +47,9 @@ size_t i;

for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) { mMapCacheSetGetPointer(&cache->maps, i)->vram = vram; } + for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) { + mBitmapCacheSetGetPointer(&cache->bitmaps, i)->vram = vram; + } for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) { struct mTileCache* tileCache = mTileCacheSetGetPointer(&cache->tiles, i); tileCache->vram = (void*) ((uintptr_t) vram + tileCache->tileBase);

@@ -49,6 +61,9 @@ size_t i;

for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) { mMapCacheWriteVRAM(mMapCacheSetGetPointer(&cache->maps, i), address); } + for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) { + mBitmapCacheWriteVRAM(mBitmapCacheSetGetPointer(&cache->bitmaps, i), address); + } for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) { mTileCacheWriteVRAM(mTileCacheSetGetPointer(&cache->tiles, i), address); }

@@ -56,6 +71,9 @@ }

void mCacheSetWritePalette(struct mCacheSet* cache, uint32_t entry, color_t color) { size_t i; + for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) { + mBitmapCacheWritePalette(mBitmapCacheSetGetPointer(&cache->bitmaps, i), entry, color); + } for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) { mTileCacheWritePalette(mTileCacheSetGetPointer(&cache->tiles, i), entry, color); }
M src/core/cheats.csrc/core/cheats.c

@@ -90,6 +90,7 @@ }

if (set->name) { free(set->name); } + StringListDeinit(&set->lines); set->deinit(set); free(set); }
M src/debugger/cli-debugger.csrc/debugger/cli-debugger.c

@@ -11,6 +11,7 @@ #include <mgba/core/core.h>

#include <mgba/core/version.h> #include <mgba/internal/debugger/parser.h> #include <mgba-util/string.h> +#include <mgba-util/vfs.h> #if ENABLE_SCRIPTING #include <mgba/core/scripting.h>

@@ -27,8 +28,11 @@

const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share const char* ERROR_OVERFLOW = "Arguments overflow"; const char* ERROR_INVALID_ARGS = "Invalid arguments"; +const char* INFO_BREAKPOINT_ADDED = "Added breakpoint #%" PRIz "i\n"; +const char* INFO_WATCHPOINT_ADDED = "Added watchpoint #%" PRIz "i\n"; static struct ParseTree* _parseTree(const char** string); +static bool _doTrace(struct CLIDebugger* debugger); #if !defined(NDEBUG) && !defined(_WIN32) static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);

@@ -99,7 +103,7 @@ { "r/1", _readByte, "I", "Read a byte from a specified offset" },

{ "r/2", _readHalfword, "I", "Read a halfword from a specified offset" }, { "r/4", _readWord, "I", "Read a word from a specified offset" }, { "status", _printStatus, "", "Print the current status" }, - { "trace", _trace, "I", "Trace a fixed number of instructions" }, + { "trace", _trace, "Is", "Trace a number of instructions" }, { "w", _setReadWriteWatchpoint, "Is", "Set a watchpoint" }, { "w/1", _writeByte, "II", "Write a byte at a specified offset" }, { "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },

@@ -147,7 +151,7 @@ #endif

static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - debugger->d.state = DEBUGGER_RUNNING; + debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CUSTOM : DEBUGGER_RUNNING; } static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {

@@ -551,7 +555,10 @@ debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);

return; } } - debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint); + ssize_t id = debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint); + if (id > 0) { + debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id); + } } static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) {

@@ -577,7 +584,10 @@ debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);

return; } } - debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint); + ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint); + if (id > 0) { + debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id); + } } static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {

@@ -645,19 +655,43 @@ debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);

return; } + debugger->traceRemaining = dv->intValue; + if (debugger->traceVf) { + debugger->traceVf->close(debugger->traceVf); + debugger->traceVf = NULL; + } + if (debugger->traceRemaining == 0) { + return; + } + if (dv->next && dv->next->charValue) { + debugger->traceVf = VFileOpen(dv->next->charValue, O_CREAT | O_WRONLY | O_APPEND); + } + if (_doTrace(debugger)) { + debugger->d.state = DEBUGGER_CUSTOM; + } else { + debugger->system->printStatus(debugger->system); + } +} + +static bool _doTrace(struct CLIDebugger* debugger) { char trace[1024]; trace[sizeof(trace) - 1] = '\0'; - - int i; - for (i = 0; i < dv->intValue; ++i) { - debugger->d.core->step(debugger->d.core); - size_t traceSize = sizeof(trace) - 1; - debugger->d.platform->trace(debugger->d.platform, trace, &traceSize); - if (traceSize + 1 < sizeof(trace)) { - trace[traceSize + 1] = '\0'; - } - debugger->backend->printf(debugger->backend, "%s\n", trace); + debugger->d.core->step(debugger->d.core); + size_t traceSize = sizeof(trace) - 2; + debugger->d.platform->trace(debugger->d.platform, trace, &traceSize); + if (traceSize + 1 <= sizeof(trace)) { + trace[traceSize] = '\n'; + trace[traceSize + 1] = '\0'; } + if (debugger->traceVf) { + debugger->traceVf->write(debugger->traceVf, trace, traceSize + 1); + } else { + debugger->backend->printf(debugger->backend, "%s", trace); + } + if (debugger->traceRemaining > 0) { + --debugger->traceRemaining; + } + return debugger->traceRemaining != 0; } static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {

@@ -889,6 +923,9 @@ }

static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; + if (cliDebugger->traceRemaining > 0) { + cliDebugger->traceRemaining = 0; + } switch (reason) { case DEBUGGER_ENTER_MANUAL: case DEBUGGER_ENTER_ATTACHED:

@@ -923,11 +960,18 @@ }

static void _cliDebuggerInit(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; + cliDebugger->traceRemaining = 0; + cliDebugger->traceVf = NULL; cliDebugger->backend->init(cliDebugger->backend); } static void _cliDebuggerDeinit(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; + if (cliDebugger->traceVf) { + cliDebugger->traceVf->close(cliDebugger->traceVf); + cliDebugger->traceVf = NULL; + } + if (cliDebugger->system) { if (cliDebugger->system->deinit) { cliDebugger->system->deinit(cliDebugger->system);

@@ -943,12 +987,17 @@ }

static void _cliDebuggerCustom(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; - bool retain = false; + bool retain = true; + enum mDebuggerState next = DEBUGGER_RUNNING; + if (cliDebugger->traceRemaining) { + retain = _doTrace(cliDebugger) && retain; + next = DEBUGGER_PAUSED; + } if (cliDebugger->system) { - retain = cliDebugger->system->custom(cliDebugger->system); + retain = cliDebugger->system->custom(cliDebugger->system) && retain; } if (!retain && debugger->state == DEBUGGER_CUSTOM) { - debugger->state = DEBUGGER_RUNNING; + debugger->state = next; } }
M src/debugger/test/parser.csrc/debugger/test/parser.c

@@ -21,16 +21,16 @@ assert_false(adjusted > strlen(STR)); \

struct ParseTree* tree = &lp->tree; \ parseLexedExpression(tree, &lp->lv) -M_TEST_SUITE_SETUP(Parser) { +static int parseSetup(void** state) { struct LPTest* lp = malloc(sizeof(struct LPTest)); LexVectorInit(&lp->lv, 0); *state = lp; return 0; } -M_TEST_SUITE_TEARDOWN(Parser) { +static int parseTeardown(void** state) { struct LPTest* lp = *state; - parseFree(&lp->tree); \ + parseFree(&lp->tree); lexFree(&lp->lv); LexVectorDeinit(&lp->lv); free(lp);

@@ -135,14 +135,14 @@ assert_int_equal(tree->rhs->rhs->token.type, TOKEN_UINT_TYPE);

assert_int_equal(tree->rhs->rhs->token.uintValue, 2); } -M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(Parser, - cmocka_unit_test(parseEmpty), - cmocka_unit_test(parseInt), - cmocka_unit_test(parseLexError), - cmocka_unit_test(parseError), - cmocka_unit_test(parseSimpleExpression), - cmocka_unit_test(parseAddMultplyExpression), - cmocka_unit_test(parseParentheticalExpression), - cmocka_unit_test(parseParentheticalAddMultplyExpression), - cmocka_unit_test(parseIsolatedOperator), - cmocka_unit_test(parseUnaryChainedOperator)) +M_TEST_SUITE_DEFINE(Parser, + cmocka_unit_test_setup_teardown(parseEmpty, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseInt, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseLexError, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseError, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseSimpleExpression, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseAddMultplyExpression, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseParentheticalExpression, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseParentheticalAddMultplyExpression, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseIsolatedOperator, parseSetup, parseTeardown), + cmocka_unit_test_setup_teardown(parseUnaryChainedOperator, parseSetup, parseTeardown))
M src/feature/gui/gui-runner.csrc/feature/gui/gui-runner.c

@@ -362,6 +362,7 @@ mInputMapInit(&runner->core->inputMap, &GBAInputInfo);

found = mCoreLoadFile(runner->core, path); if (!found) { mLOG(GUI_RUNNER, WARN, "Failed to load %s!", path); + mCoreConfigDeinit(&runner->core->config); runner->core->deinit(runner->core); } }

@@ -606,6 +607,7 @@ mCoreConfigSave(&runner->config);

} mInputMapDeinit(&runner->core->inputMap); mLOG(GUI_RUNNER, DEBUG, "Deinitializing core..."); + mCoreConfigDeinit(&runner->core->config); runner->core->deinit(runner->core); runner->core = NULL;
M src/gb/debugger/cli.csrc/gb/debugger/cli.c

@@ -60,7 +60,7 @@ }

gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1; return true; } - return false; + return true; } static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
M src/gb/renderers/cache-set.csrc/gb/renderers/cache-set.c

@@ -11,16 +11,13 @@ #include <mgba/internal/gb/io.h>

#include <mgba/internal/gb/video.h> void GBVideoCacheInit(struct mCacheSet* cache) { - mCacheSetInit(cache, 2, 1); + mCacheSetInit(cache, 2, 0, 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); }
M src/gb/test/core.csrc/gb/test/core.c

@@ -31,6 +31,7 @@ assert_non_null(core);

assert_true(core->init(core)); mCoreInitConfig(core, NULL); core->reset(core); + mCoreConfigDeinit(&core->config); core->deinit(core); }

@@ -41,6 +42,7 @@ assert_true(core->init(core));

mCoreInitConfig(core, NULL); assert_false(core->loadROM(core, NULL)); core->reset(core); + mCoreConfigDeinit(&core->config); core->deinit(core); }

@@ -51,7 +53,9 @@ assert_true(GBIsROM(vf));

struct mCore* core = mCoreFindVF(vf); assert_non_null(core); assert_int_equal(core->platform(core), PLATFORM_GB); + vf->close(vf); assert_true(core->init(core)); + core->deinit(core); }
M src/gb/test/mbc.csrc/gb/test/mbc.c

@@ -27,6 +27,7 @@ if (!*state) {

return 0; } struct mCore* core = *state; + mCoreConfigDeinit(&core->config); core->deinit(core); return 0; }
M src/gb/test/memory.csrc/gb/test/memory.c

@@ -27,6 +27,7 @@ if (!*state) {

return 0; } struct mCore* core = *state; + mCoreConfigDeinit(&core->config); core->deinit(core); return 0; }
M src/gb/test/rtc.csrc/gb/test/rtc.c

@@ -69,6 +69,7 @@ if (!*state) {

return 0; } struct GBRTCTest* test = *state; + mCoreConfigDeinit(&test->core->config); test->core->deinit(test->core); free(test); return 0;
M src/gba/bios.csrc/gba/bios.c

@@ -10,6 +10,7 @@ #include <mgba/internal/arm/macros.h>

#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/io.h> #include <mgba/internal/gba/memory.h> +#include <mgba-util/math.h> const uint32_t GBA_BIOS_CHECKSUM = 0xBAAE187F; const uint32_t GBA_DS_BIOS_CHECKSUM = 0xBAAE1880;

@@ -21,6 +22,18 @@ static void _unHuffman(struct GBA* gba);

static void _unRl(struct GBA* gba, int width); static void _unFilter(struct GBA* gba, int inwidth, int outwidth); static void _unBitPack(struct GBA* gba); + +static int _mulWait(int32_t r) { + if ((r & 0xFFFFFF00) == 0xFFFFFF00 || !(r & 0xFFFFFF00)) { + return 1; + } else if ((r & 0xFFFF0000) == 0xFFFF0000 || !(r & 0xFFFF0000)) { + return 2; + } else if ((r & 0xFF000000) == 0xFF000000 || !(r & 0xFF000000)) { + return 3; + } else { + return 4; + } +} static void _SoftReset(struct GBA* gba) { struct ARMCore* cpu = gba->cpu;

@@ -273,16 +286,30 @@ cpu->gprs[0] = INT32_MIN;

cpu->gprs[1] = 0; cpu->gprs[3] = INT32_MIN; } + int loops = clz32(denom) - clz32(num); + if (loops < 1) { + loops = 1; + } + cpu->cycles += 4 /* prologue */ + 13 * loops + 7 /* epilogue */; } -static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3) { +static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3, int32_t* cycles) { + int currentCycles = 37; + currentCycles += _mulWait(i * i); int32_t a = -((i * i) >> 14); + currentCycles += _mulWait(0xA9 * a); int32_t b = ((0xA9 * a) >> 14) + 0x390; + currentCycles += _mulWait(b * a); b = ((b * a) >> 14) + 0x91C; + currentCycles += _mulWait(b * a); b = ((b * a) >> 14) + 0xFB6; + currentCycles += _mulWait(b * a); b = ((b * a) >> 14) + 0x16AA; + currentCycles += _mulWait(b * a); b = ((b * a) >> 14) + 0x2081; + currentCycles += _mulWait(b * a); b = ((b * a) >> 14) + 0x3651; + currentCycles += _mulWait(b * a); b = ((b * a) >> 14) + 0xA2F9; if (r1) { *r1 = a;

@@ -290,10 +317,11 @@ }

if (r3) { *r3 = b; } + *cycles += currentCycles; return (i * b) >> 16; } -static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1) { +static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, int32_t* cycles) { if (!y) { if (x >= 0) { return 0;

@@ -309,24 +337,77 @@ }

if (y >= 0) { if (x >= 0) { if (x >= y) { - return _ArcTan((y << 14) / x, r1, NULL); + return _ArcTan((y << 14) / x, r1, NULL, cycles); } } else if (-x >= y) { - return _ArcTan((y << 14) / x, r1, NULL) + 0x8000; + return _ArcTan((y << 14) / x, r1, NULL, cycles) + 0x8000; } - return 0x4000 - _ArcTan((x << 14) / y, r1, NULL); + return 0x4000 - _ArcTan((x << 14) / y, r1, NULL, cycles); } else { if (x <= 0) { if (-x > -y) { - return _ArcTan((y << 14) / x, r1, NULL) + 0x8000; + return _ArcTan((y << 14) / x, r1, NULL, cycles) + 0x8000; } } else if (x >= -y) { - return _ArcTan((y << 14) / x, r1, NULL) + 0x10000; + return _ArcTan((y << 14) / x, r1, NULL, cycles) + 0x10000; } - return 0xC000 - _ArcTan((x << 14) / y, r1, NULL); + return 0xC000 - _ArcTan((x << 14) / y, r1, NULL, cycles); } } +static int32_t _Sqrt(uint32_t x, int32_t* cycles) { + if (!x) { + *cycles += 53; + return 0; + } + int32_t currentCycles = 15; + uint32_t lower; + uint32_t upper = x; + uint32_t bound = 1; + while (bound < upper) { + upper >>= 1; + bound <<= 1; + currentCycles += 6; + } + while (true) { + currentCycles += 6; + upper = x; + uint32_t accum = 0; + lower = bound; + while (true) { + currentCycles += 5; + uint32_t oldLower = lower; + if (lower <= upper >> 1) { + lower <<= 1; + } + if (oldLower >= upper >> 1) { + break; + } + } + while (true) { + currentCycles += 8; + accum <<= 1; + if (upper >= lower) { + ++accum; + upper -= lower; + } + if (lower == bound) { + break; + } + lower >>= 1; + } + uint32_t oldBound = bound; + bound += accum; + bound >>= 1; + if (bound >= oldBound) { + bound = oldBound; + break; + } + } + *cycles += currentCycles; + return bound; +} + void GBASwi16(struct ARMCore* cpu, int immediate) { struct GBA* gba = (struct GBA*) cpu->master; mLOG(GBA_BIOS, DEBUG, "SWI: %02X r0: %08X r1: %08X r2: %08X r3: %08X",

@@ -369,13 +450,13 @@ case 0x7:

_Div(gba, cpu->gprs[1], cpu->gprs[0]); break; case 0x8: - cpu->gprs[0] = sqrt((uint32_t) cpu->gprs[0]); + cpu->gprs[0] = _Sqrt(cpu->gprs[0], &cpu->cycles); break; case 0x9: - cpu->gprs[0] = _ArcTan(cpu->gprs[0], &cpu->gprs[1], &cpu->gprs[3]); + cpu->gprs[0] = _ArcTan(cpu->gprs[0], &cpu->gprs[1], &cpu->gprs[3], &cpu->cycles); break; case 0xA: - cpu->gprs[0] = (uint16_t) _ArcTan2(cpu->gprs[0], cpu->gprs[1], &cpu->gprs[1]); + cpu->gprs[0] = (uint16_t) _ArcTan2(cpu->gprs[0], cpu->gprs[1], &cpu->gprs[1], &cpu->cycles); cpu->gprs[3] = 0x170; break; case 0xB:

@@ -496,6 +577,13 @@ _MidiKey2Freq(gba);

break; default: mLOG(GBA_BIOS, STUB, "Stub software interrupt: %02X", immediate); + } + gba->cpu->cycles += 45 + cpu->memory.activeNonseqCycles16 /* 8 bit load for SWI # */; + // Return cycles + if (gba->cpu->executionMode == MODE_ARM) { + gba->cpu->cycles += cpu->memory.activeNonseqCycles32 + cpu->memory.activeSeqCycles32; + } else { + gba->cpu->cycles += cpu->memory.activeNonseqCycles16 + cpu->memory.activeSeqCycles16; } gba->memory.biosPrefetch = 0xE3A02004; }
M src/gba/debugger/cli.csrc/gba/debugger/cli.c

@@ -59,7 +59,7 @@ }

gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]); return true; } - return false; + return true; } static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
M src/gba/memory.csrc/gba/memory.c

@@ -938,7 +938,7 @@ case REGION_PALETTE_RAM:

GBAStore16(cpu, address & ~1, ((uint8_t) value) | ((uint8_t) value << 8), cycleCounter); break; case REGION_VRAM: - if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) == 4) ? 0x00014000 : 0x00010000)) { + if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) { // TODO: check BG mode mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); break;
M src/gba/renderers/cache-set.csrc/gba/renderers/cache-set.c

@@ -11,35 +11,45 @@ #include <mgba/internal/gba/io.h>

#include <mgba/internal/gba/video.h> void GBAVideoCacheInit(struct mCacheSet* cache) { - mCacheSetInit(cache, 4, 4); + mCacheSetInit(cache, 4, 2, 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)); + mBitmapCacheSystemInfo bitConfig; + bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4); + bitConfig = mBitmapCacheSystemInfoClearUsesPalette(bitConfig); + bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 160); + bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 240); + bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 1); + mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 0), bitConfig); + mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->bitsStart[0] = 0; + mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->bitsStart[1] = 0xA000; + + bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 3); + bitConfig = mBitmapCacheSystemInfoFillUsesPalette(bitConfig); + bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 160); + bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 240); + bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 2); + mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 1), bitConfig); + mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->bitsStart[0] = 0; + mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->bitsStart[1] = 0xA000; } void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) {

@@ -77,6 +87,8 @@ entry->flags = mMapCacheEntryFlagsClearPaletteId(entry->flags);

} static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) { + mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->buffer = GBARegisterDISPCNTGetFrameSelect(value); + switch (GBARegisterDISPCNTGetMode(value)) { case 0: default:

@@ -108,6 +120,28 @@ mMapCacheSystemInfoGetPaletteBPP(mMapCacheSetGetPointer(&cache->maps, 1)->sysConfig) == 3);

mMapCacheSetGetPointer(&cache->maps, 2)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1); mMapCacheSetGetPointer(&cache->maps, 3)->tileCache = mTileCacheSetGetPointer(&cache->tiles, 1); + break; + } + + mBitmapCacheSystemInfo bitConfig; + switch (GBARegisterDISPCNTGetMode(value)) { + case 3: + bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4); + bitConfig = mBitmapCacheSystemInfoClearUsesPalette(bitConfig); + bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 160); + bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 240); + bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 1); + mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 0), bitConfig); + mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->buffer = 0; + break; + case 5: + bitConfig = mBitmapCacheSystemInfoSetEntryBPP(0, 4); + bitConfig = mBitmapCacheSystemInfoClearUsesPalette(bitConfig); + bitConfig = mBitmapCacheSystemInfoSetHeight(bitConfig, 128); + bitConfig = mBitmapCacheSystemInfoSetWidth(bitConfig, 160); + bitConfig = mBitmapCacheSystemInfoSetBuffers(bitConfig, 2); + mBitmapCacheConfigureSystem(mBitmapCacheSetGetPointer(&cache->bitmaps, 0), bitConfig); + mBitmapCacheSetGetPointer(&cache->bitmaps, 0)->buffer = GBARegisterDISPCNTGetFrameSelect(value); break; } }
M src/gba/test/cheats.csrc/gba/test/cheats.c

@@ -13,7 +13,7 @@

#include "gba/cheats/parv3.h" #include "gba/cheats/gameshark.h" -M_TEST_SUITE_SETUP(GBACheats) { +static int cheatsSetup(void** state) { struct mCore* core = GBACoreCreate(); core->init(core); core->cheatDevice(core);

@@ -21,7 +21,7 @@ *state = core;

return 0; } -M_TEST_SUITE_TEARDOWN(GBACheats) { +static int cheatsTeardown(void** state) { if (!*state) { return 0; }

@@ -36,7 +36,7 @@ struct mCheatDevice* device = core->cheatDevice(core);

assert_non_null(device); struct mCheatSet* set = device->createSet(device, NULL); assert_non_null(set); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(addRawPARv3) {

@@ -48,7 +48,7 @@ assert_non_null(set);

GBACheatSetGameSharkVersion((struct GBACheatSet*) set, GBA_GS_PARV3_RAW); assert_true(set->addLine(set, "80000000 00000000", GBA_CHEAT_PRO_ACTION_REPLAY)); assert_false(set->addLine(set, "43000000 00000000", GBA_CHEAT_PRO_ACTION_REPLAY)); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3Assign) {

@@ -72,7 +72,7 @@ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x78);

assert_int_equal(core->rawRead16(core, 0x03000002, -1), 0x5678); assert_int_equal(core->rawRead32(core, 0x03000004, -1), 0x12345678); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3Slide1) {

@@ -101,7 +101,7 @@ assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0);

assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0); assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3Slide2) {

@@ -130,7 +130,7 @@ assert_int_equal(core->rawRead16(core, 0x03000006, -1), 0);

assert_int_equal(core->rawRead16(core, 0x03000008, -1), 0); assert_int_equal(core->rawRead16(core, 0x0300000A, -1), 0); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3Slide4) {

@@ -159,7 +159,7 @@ assert_int_equal(core->rawRead16(core, 0x0300000C, -1), 0);

assert_int_equal(core->rawRead16(core, 0x03000010, -1), 0); assert_int_equal(core->rawRead16(core, 0x03000014, -1), 0); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3If1) {

@@ -188,7 +188,7 @@ mCheatRefresh(device, set);

assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1); assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3If1x1) {

@@ -243,7 +243,7 @@ assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x1);

assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21); assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x31); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3If2) {

@@ -277,7 +277,7 @@ assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1);

assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11); assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3If2x2) {

@@ -345,7 +345,7 @@ assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);

assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x31); assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41); assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x51); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3If2Contain1) {

@@ -392,7 +392,7 @@ mCheatRefresh(device, set);

assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1); assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x1); assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfX) {

@@ -421,7 +421,7 @@ core->rawWrite8(core, 0x03000000, -1, 0x1);

mCheatRefresh(device, set); assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1); assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXxX) {

@@ -484,7 +484,7 @@ assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x1);

assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21); assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32); assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXElse) {

@@ -519,7 +519,7 @@ mCheatRefresh(device, set);

assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0x1); assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x11); assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x22); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXElsexX) {

@@ -590,7 +590,7 @@ assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);

assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32); assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x42); assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x51); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXElsexXElse) {

@@ -668,7 +668,7 @@ assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32);

assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x42); assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x51); assert_int_equal(core->rawRead8(core, 0x03000006, -1), 0x62); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXContain1) {

@@ -730,7 +730,7 @@ assert_int_equal(core->rawRead8(core, 0x03000001, -1), 0x1);

assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21); assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x31); assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXContain1Else) {

@@ -800,7 +800,7 @@ assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);

assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x31); assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41); assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x52); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXElseContain1) {

@@ -870,7 +870,7 @@ assert_int_equal(core->rawRead8(core, 0x03000002, -1), 0x21);

assert_int_equal(core->rawRead8(core, 0x03000003, -1), 0x32); assert_int_equal(core->rawRead8(core, 0x03000004, -1), 0x41); assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x52); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfXContain1ElseContain1) {

@@ -1016,7 +1016,7 @@ assert_int_equal(core->rawRead8(core, 0x03000005, -1), 0x51);

assert_int_equal(core->rawRead8(core, 0x03000006, -1), 0x62); assert_int_equal(core->rawRead8(core, 0x03000007, -1), 0x71); assert_int_equal(core->rawRead8(core, 0x03000008, -1), 0x82); - set->deinit(set); + mCheatSetDeinit(set); } M_TEST_DEFINE(doPARv3IfButton) {

@@ -1046,28 +1046,28 @@

core->rawWrite8(core, 0x03000000, -1, 0); mCheatRefresh(device, set); assert_int_equal(core->rawRead8(core, 0x03000000, -1), 0); - set->deinit(set); + mCheatSetDeinit(set); } -M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBACheats, - cmocka_unit_test(createSet), - cmocka_unit_test(addRawPARv3), - cmocka_unit_test(doPARv3Assign), - cmocka_unit_test(doPARv3Slide1), - cmocka_unit_test(doPARv3Slide2), - cmocka_unit_test(doPARv3Slide4), - cmocka_unit_test(doPARv3If1), - cmocka_unit_test(doPARv3If1x1), - cmocka_unit_test(doPARv3If2), - cmocka_unit_test(doPARv3If2x2), - cmocka_unit_test(doPARv3If2Contain1), - cmocka_unit_test(doPARv3IfX), - cmocka_unit_test(doPARv3IfXxX), - cmocka_unit_test(doPARv3IfXElse), - cmocka_unit_test(doPARv3IfXElsexX), - cmocka_unit_test(doPARv3IfXElsexXElse), - cmocka_unit_test(doPARv3IfXContain1), - cmocka_unit_test(doPARv3IfXContain1Else), - cmocka_unit_test(doPARv3IfXElseContain1), - cmocka_unit_test(doPARv3IfXContain1ElseContain1), - cmocka_unit_test(doPARv3IfButton)) +M_TEST_SUITE_DEFINE(GBACheats, + cmocka_unit_test_setup_teardown(createSet, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(addRawPARv3, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3Assign, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3Slide1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3Slide2, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3Slide4, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3If1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3If1x1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3If2, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3If2x2, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3If2Contain1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfX, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXxX, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXElse, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXElsexX, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXElsexXElse, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXContain1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXContain1Else, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXElseContain1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfXContain1ElseContain1, cheatsSetup, cheatsTeardown), + cmocka_unit_test_setup_teardown(doPARv3IfButton, cheatsSetup, cheatsTeardown))
M src/lr35902/decoder.csrc/lr35902/decoder.c

@@ -504,6 +504,9 @@ if (op.flags & LR35902_OP_FLAG_IMPLICIT) {

return 0; } + strncpy(buffer, " ", blen - 1); + ADVANCE(1); + if (op.flags & LR35902_OP_FLAG_MEMORY) { strncpy(buffer, "[", blen - 1); ADVANCE(1);

@@ -545,16 +548,16 @@ int written;

int total = 0; const char* cond = _lr35902Conditions[info->condition]; - written = snprintf(buffer, blen - 1, "%s ", mnemonic); + written = snprintf(buffer, blen - 1, "%s", mnemonic); ADVANCE(written); if (cond) { - written = snprintf(buffer, blen - 1, "%s", cond); + written = snprintf(buffer, blen - 1, " %s", cond); ADVANCE(written); if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) { - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); + strncpy(buffer, ",", blen - 1); + ADVANCE(1); } }

@@ -565,8 +568,8 @@ }

if (info->op2.reg || (!info->op1.immediate && info->opcodeSize > 1 && info->opcode[0] != 0xCB)) { if (written) { - strncpy(buffer, ", ", blen - 1); - ADVANCE(2); + strncpy(buffer, ",", blen - 1); + ADVANCE(1); } written = _decodeOperand(info->op2, pc, buffer, blen); ADVANCE(written);
M src/platform/libretro/libretro.csrc/platform/libretro/libretro.c

@@ -563,6 +563,7 @@ void retro_unload_game(void) {

if (!core) { return; } + mCoreConfigDeinit(&core->config); core->deinit(core); mappedMemoryFree(data, dataSize); data = 0;
M src/platform/openemu/mGBAGameCore.msrc/platform/openemu/mGBAGameCore.m

@@ -76,6 +76,7 @@ }

- (void)dealloc { + mCoreConfigDeinit(&core->config); core->deinit(core); [cheatSets release]; free(outputBuffer);
M src/platform/qt/MapView.cppsrc/platform/qt/MapView.cpp

@@ -12,7 +12,10 @@

#include <mgba-util/png-io.h> #include <mgba-util/vfs.h> #ifdef M_CORE_GBA +#include <mgba/internal/gba/gba.h> +#include <mgba/internal/gba/io.h> #include <mgba/internal/gba/memory.h> +#include <mgba/internal/gba/video.h> #endif #ifdef M_CORE_GB #include <mgba/internal/gb/memory.h>

@@ -139,17 +142,36 @@

void MapView::updateTilesGBA(bool force) { { CoreController::Interrupter interrupter(m_controller); - mMapCache* mapCache = mMapCacheSetGetPointer(&m_cacheSet->maps, m_map); - int tilesW = 1 << mMapCacheSystemInfoGetTilesWide(mapCache->sysConfig); - int tilesH = 1 << mMapCacheSystemInfoGetTilesHigh(mapCache->sysConfig); - m_rawMap = QImage(QSize(tilesW * 8, tilesH * 8), QImage::Format_ARGB32); - uchar* bgBits = m_rawMap.bits(); - for (int j = 0; j < tilesH; ++j) { - for (int i = 0; i < tilesW; ++i) { - mMapCacheCleanTile(mapCache, m_mapStatus, i, j); + int bitmap = -1; + if (m_controller->platform() == PLATFORM_GBA) { + int mode = GBARegisterDISPCNTGetMode(static_cast<GBA*>(m_controller->thread()->core->board)->memory.io[REG_DISPCNT]); + if (m_map == 2 && mode > 2) { + bitmap = mode == 4 ? 1 : 0; + } + } + if (bitmap >= 0) { + mBitmapCache* bitmapCache = mBitmapCacheSetGetPointer(&m_cacheSet->bitmaps, bitmap); + int width = mBitmapCacheSystemInfoGetWidth(bitmapCache->sysConfig); + int height = mBitmapCacheSystemInfoGetHeight(bitmapCache->sysConfig); + m_rawMap = QImage(QSize(width, height), QImage::Format_ARGB32); + uchar* bgBits = m_rawMap.bits(); + for (int j = 0; j < height; ++j) { + mBitmapCacheCleanRow(bitmapCache, m_bitmapStatus, j); + memcpy(static_cast<void*>(&bgBits[width * j * 4]), mBitmapCacheGetRow(bitmapCache, j), width * 4); } - for (int i = 0; i < 8; ++i) { - memcpy(static_cast<void*>(&bgBits[tilesW * 32 * (i + j * 8)]), mMapCacheGetRow(mapCache, i + j * 8), tilesW * 32); + } else { + mMapCache* mapCache = mMapCacheSetGetPointer(&m_cacheSet->maps, m_map); + int tilesW = 1 << mMapCacheSystemInfoGetTilesWide(mapCache->sysConfig); + int tilesH = 1 << mMapCacheSystemInfoGetTilesHigh(mapCache->sysConfig); + m_rawMap = QImage(QSize(tilesW * 8, tilesH * 8), QImage::Format_ARGB32); + uchar* bgBits = m_rawMap.bits(); + for (int j = 0; j < tilesH; ++j) { + for (int i = 0; i < tilesW; ++i) { + mMapCacheCleanTile(mapCache, m_mapStatus, i, j); + } + for (int i = 0; i < 8; ++i) { + memcpy(static_cast<void*>(&bgBits[tilesW * 32 * (i + j * 8)]), mMapCacheGetRow(mapCache, i + j * 8), tilesW * 32); + } } } }

@@ -181,7 +203,6 @@ CoreController::Interrupter interrupter(m_controller);

png_structp png = PNGWriteOpen(vf); png_infop info = PNGWriteHeaderA(png, m_rawMap.width(), m_rawMap.height()); - mMapCache* mapCache = mMapCacheSetGetPointer(&m_cacheSet->maps, m_map); QImage map = m_rawMap.rgbSwapped(); PNGWritePixelsA(png, map.width(), map.height(), map.bytesPerLine() / 4, static_cast<const void*>(map.constBits())); PNGWriteClose(png, info);
M src/platform/qt/MapView.hsrc/platform/qt/MapView.h

@@ -45,6 +45,7 @@ Ui::MapView m_ui;

std::shared_ptr<CoreController> m_controller; mMapCacheEntry m_mapStatus[128 * 128] = {}; // TODO: Correct size + mBitmapCacheEntry m_bitmapStatus[512 * 2] = {}; // TODO: Correct size int m_map = 0; QImage m_rawMap; int m_boundary;
M src/platform/qt/TileView.cppsrc/platform/qt/TileView.cpp

@@ -65,7 +65,10 @@ break;

} updateTiles(true); }); - connect(m_ui.magnification, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this]() { + connect(m_ui.magnification, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int mag) { + if (!m_ui.tileFit->isChecked()) { + m_ui.tiles->setMinimumSize(mag * 8 * m_ui.tilesPerRow->value(), m_ui.tiles->minimumSize().height()); + } updateTiles(true); });
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -5,14 +5,15 @@ * 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 "Window.h" -#include <QDesktopWidget> #include <QKeyEvent> #include <QKeySequence> #include <QMenuBar> #include <QMessageBox> #include <QMimeData> #include <QPainter> +#include <QScreen> #include <QStackedLayout> +#include <QWindow> #ifdef USE_SQLITE3 #include "ArchiveInspector.h"

@@ -230,6 +231,15 @@ }

void Window::resizeFrame(const QSize& size) { QSize newSize(size); + if (windowHandle()) { + QRect geom = windowHandle()->screen()->availableGeometry(); + if (newSize.width() > geom.width()) { + newSize.setWidth(geom.width()); + } + if (newSize.height() > geom.height()) { + newSize.setHeight(geom.height()); + } + } m_screenWidget->setSizeHint(newSize); newSize -= m_screenWidget->size(); newSize += this->size();

@@ -609,7 +619,7 @@ }

m_wasOpened = true; resizeFrame(m_screenWidget->sizeHint()); QVariant windowPos = m_config->getQtOption("windowPos"); - QRect geom = QApplication::desktop()->availableGeometry(this); + QRect geom = windowHandle()->screen()->availableGeometry(); if (!windowPos.isNull() && geom.contains(windowPos.toPoint())) { move(windowPos.toPoint()); } else {
M src/platform/sdl/main.csrc/platform/sdl/main.c

@@ -143,6 +143,7 @@ renderer.filter = renderer.core->opts.resampleVideo;

if (!mSDLInit(&renderer)) { freeArguments(&args); + mCoreConfigDeinit(&renderer.core->config); renderer.core->deinit(renderer.core); return 1; }
M src/platform/test/fuzz-main.csrc/platform/test/fuzz-main.c

@@ -165,6 +165,7 @@ freeArguments(&args);

if (outputBuffer) { free(outputBuffer); } + mCoreConfigDeinit(&core->config); core->deinit(core); return !cleanExit;