Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2019-06-28 17:22:06 -07:00
commit 751489f490
31 changed files with 638 additions and 129 deletions

10
CHANGES
View File

@ -26,6 +26,8 @@ Features:
- 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 @@ Emulation fixes:
- 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 @@ Other fixes:
- 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 @@ Misc:
- 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:

View File

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

View File

@ -10,19 +10,22 @@
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);

View File

@ -15,8 +15,11 @@ CXX_GUARD_START
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 CLIDebugger {
struct CLIDebuggerSystem* system;
struct CLIDebuggerBackend* backend;
int traceRemaining;
struct VFile* traceVf;
};
void CLIDebuggerCreate(struct CLIDebugger*);

View File

@ -147,21 +147,27 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
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) {

182
src/core/bitmap-cache.c Normal file
View File

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

View File

@ -6,11 +6,14 @@
#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 @@ void mCacheSetInit(struct mCacheSet* cache, size_t nMaps, size_t nTiles) {
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 @@ void mCacheSetDeinit(struct mCacheSet* cache) {
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 @@ void mCacheSetAssignVRAM(struct mCacheSet* cache, void* vram) {
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 @@ void mCacheSetWriteVRAM(struct mCacheSet* cache, uint32_t address) {
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 mCacheSetWriteVRAM(struct mCacheSet* cache, uint32_t address) {
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);
}

View File

@ -90,6 +90,7 @@ void mCheatSetDeinit(struct mCheatSet* set) {
if (set->name) {
free(set->name);
}
StringListDeinit(&set->lines);
set->deinit(set);
free(set);
}

View File

@ -11,6 +11,7 @@
#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 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "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 @@ static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
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 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
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 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
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 @@ static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
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 _commandLine(struct mDebugger* debugger) {
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 _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r
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 _cliDebuggerDeinit(struct mDebugger* debugger) {
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;
}
}

View File

@ -21,16 +21,16 @@ struct LPTest {
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 @@ M_TEST_DEFINE(parseUnaryChainedOperator) {
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))

View File

@ -362,6 +362,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
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 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
}
mInputMapDeinit(&runner->core->inputMap);
mLOG(GUI_RUNNER, DEBUG, "Deinitializing core...");
mCoreConfigDeinit(&runner->core->config);
runner->core->deinit(runner->core);
runner->core = NULL;

View File

@ -60,7 +60,7 @@ static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
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) {

View File

@ -11,16 +11,13 @@
#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);
}

View File

@ -31,6 +31,7 @@ M_TEST_DEFINE(reset) {
assert_true(core->init(core));
mCoreInitConfig(core, NULL);
core->reset(core);
mCoreConfigDeinit(&core->config);
core->deinit(core);
}
@ -41,6 +42,7 @@ M_TEST_DEFINE(loadNullROM) {
mCoreInitConfig(core, NULL);
assert_false(core->loadROM(core, NULL));
core->reset(core);
mCoreConfigDeinit(&core->config);
core->deinit(core);
}
@ -51,7 +53,9 @@ M_TEST_DEFINE(isROM) {
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);
}

View File

@ -27,6 +27,7 @@ M_TEST_SUITE_TEARDOWN(GBMBC) {
return 0;
}
struct mCore* core = *state;
mCoreConfigDeinit(&core->config);
core->deinit(core);
return 0;
}

View File

@ -27,6 +27,7 @@ M_TEST_SUITE_TEARDOWN(GBMemory) {
return 0;
}
struct mCore* core = *state;
mCoreConfigDeinit(&core->config);
core->deinit(core);
return 0;
}

View File

@ -69,6 +69,7 @@ M_TEST_SUITE_TEARDOWN(GBRTC) {
return 0;
}
struct GBRTCTest* test = *state;
mCoreConfigDeinit(&test->core->config);
test->core->deinit(test->core);
free(test);
return 0;

View File

@ -10,6 +10,7 @@
#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;
@ -22,6 +23,18 @@ 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;
ARMSetPrivilegeMode(cpu, MODE_IRQ);
@ -273,16 +286,30 @@ static void _Div(struct GBA* gba, int32_t num, int32_t denom) {
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 @@ static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3) {
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 @@ static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1) {
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 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
_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:
@ -497,6 +578,13 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
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;
}

View File

@ -59,7 +59,7 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
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) {

View File

@ -938,7 +938,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
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;

View File

@ -11,35 +11,45 @@
#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 @@ static void mapParser2(struct mMapCache* cache, struct mMapCacheEntry* entry, vo
}
static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
mBitmapCacheSetGetPointer(&cache->bitmaps, 1)->buffer = GBARegisterDISPCNTGetFrameSelect(value);
switch (GBARegisterDISPCNTGetMode(value)) {
case 0:
default:
@ -110,6 +122,28 @@ static void GBAVideoCacheWriteDISPCNT(struct mCacheSet* cache, uint16_t value) {
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;
}
}
static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t value) {

View File

@ -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 @@ M_TEST_SUITE_SETUP(GBACheats) {
return 0;
}
M_TEST_SUITE_TEARDOWN(GBACheats) {
static int cheatsTeardown(void** state) {
if (!*state) {
return 0;
}
@ -36,7 +36,7 @@ M_TEST_DEFINE(createSet) {
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 @@ M_TEST_DEFINE(addRawPARv3) {
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 @@ M_TEST_DEFINE(doPARv3Assign) {
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 @@ M_TEST_DEFINE(doPARv3Slide1) {
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 @@ M_TEST_DEFINE(doPARv3Slide2) {
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 @@ M_TEST_DEFINE(doPARv3Slide4) {
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 @@ M_TEST_DEFINE(doPARv3If1) {
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 @@ M_TEST_DEFINE(doPARv3If1x1) {
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 @@ M_TEST_DEFINE(doPARv3If2) {
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 @@ M_TEST_DEFINE(doPARv3If2x2) {
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 @@ M_TEST_DEFINE(doPARv3If2Contain1) {
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 @@ M_TEST_DEFINE(doPARv3IfX) {
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 @@ M_TEST_DEFINE(doPARv3IfXxX) {
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 @@ M_TEST_DEFINE(doPARv3IfXElse) {
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 @@ M_TEST_DEFINE(doPARv3IfXElsexX) {
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 @@ M_TEST_DEFINE(doPARv3IfXElsexXElse) {
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 @@ M_TEST_DEFINE(doPARv3IfXContain1) {
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 @@ M_TEST_DEFINE(doPARv3IfXContain1Else) {
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 @@ M_TEST_DEFINE(doPARv3IfXElseContain1) {
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 @@ M_TEST_DEFINE(doPARv3IfXContain1ElseContain1) {
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 @@ M_TEST_DEFINE(doPARv3IfButton) {
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))

View File

@ -504,6 +504,9 @@ static int _decodeOperand(struct LR35902Operand op, uint16_t pc, char* buffer, i
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 LR35902Disassemble(struct LR35902InstructionInfo* info, uint16_t pc, char* b
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 @@ int LR35902Disassemble(struct LR35902InstructionInfo* info, uint16_t pc, char* b
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);

View File

@ -563,6 +563,7 @@ void retro_unload_game(void) {
if (!core) {
return;
}
mCoreConfigDeinit(&core->config);
core->deinit(core);
mappedMemoryFree(data, dataSize);
data = 0;

View File

@ -76,6 +76,7 @@
- (void)dealloc
{
mCoreConfigDeinit(&core->config);
core->deinit(core);
[cheatSets release];
free(outputBuffer);

View File

@ -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 @@ bool MapView::eventFilter(QObject* obj, QEvent* event) {
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;
}
for (int i = 0; i < 8; ++i) {
memcpy(static_cast<void*>(&bgBits[tilesW * 32 * (i + j * 8)]), mMapCacheGetRow(mapCache, i + j * 8), tilesW * 32);
}
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);
}
} 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 @@ void MapView::exportMap() {
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);

View File

@ -45,6 +45,7 @@ private:
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;

View File

@ -65,7 +65,10 @@ TileView::TileView(std::shared_ptr<CoreController> controller, QWidget* parent)
}
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);
});

View File

@ -5,14 +5,15 @@
* 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::argumentsPassed(mArguments* args) {
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 @@ void Window::showEvent(QShowEvent* event) {
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 {

View File

@ -143,6 +143,7 @@ int main(int argc, char** argv) {
if (!mSDLInit(&renderer)) {
freeArguments(&args);
mCoreConfigDeinit(&renderer.core->config);
renderer.core->deinit(renderer.core);
return 1;
}

View File

@ -165,6 +165,7 @@ loadError:
if (outputBuffer) {
free(outputBuffer);
}
mCoreConfigDeinit(&core->config);
core->deinit(core);
return !cleanExit;