mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
751489f490
10
CHANGES
10
CHANGES
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ void mCheatSetDeinit(struct mCheatSet* set) {
|
|||
if (set->name) {
|
||||
free(set->name);
|
||||
}
|
||||
StringListDeinit(&set->lines);
|
||||
set->deinit(set);
|
||||
free(set);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ M_TEST_SUITE_TEARDOWN(GBMBC) {
|
|||
return 0;
|
||||
}
|
||||
struct mCore* core = *state;
|
||||
mCoreConfigDeinit(&core->config);
|
||||
core->deinit(core);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ M_TEST_SUITE_TEARDOWN(GBMemory) {
|
|||
return 0;
|
||||
}
|
||||
struct mCore* core = *state;
|
||||
mCoreConfigDeinit(&core->config);
|
||||
core->deinit(core);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
110
src/gba/bios.c
110
src/gba/bios.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -563,6 +563,7 @@ void retro_unload_game(void) {
|
|||
if (!core) {
|
||||
return;
|
||||
}
|
||||
mCoreConfigDeinit(&core->config);
|
||||
core->deinit(core);
|
||||
mappedMemoryFree(data, dataSize);
|
||||
data = 0;
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
|
||||
- (void)dealloc
|
||||
{
|
||||
mCoreConfigDeinit(&core->config);
|
||||
core->deinit(core);
|
||||
[cheatSets release];
|
||||
free(outputBuffer);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -165,6 +165,7 @@ loadError:
|
|||
if (outputBuffer) {
|
||||
free(outputBuffer);
|
||||
}
|
||||
mCoreConfigDeinit(&core->config);
|
||||
core->deinit(core);
|
||||
|
||||
return !cleanExit;
|
||||
|
|
Loading…
Reference in New Issue