Merge branch 'master' into port/psp2

This commit is contained in:
Jeffrey Pfau 2015-07-07 00:30:29 -07:00
commit 33ca1e2e9c
17 changed files with 146 additions and 1 deletions

View File

@ -57,6 +57,7 @@ Bugfixes:
- ARM7: ARMHotplugDetach should call deinit
- Qt: Fix window being too tall after exiting fullscreen
- Qt: Fix a missing va_end call in the log handler lambda within the GameController constructor
- GBA Cheats: Fix Pro Action Replay and GameShark issues when used together
Misc:
- Qt: Handle saving input settings better
- Debugger: Free watchpoints in addition to breakpoints
@ -97,6 +98,8 @@ Misc:
- GBA Hardware: Backport generic RTC source into core
- All: Proper handling of Unicode file paths
- GBA Video: Slightly optimize mode 0 mosaic rendering
- VFS: Add sync method to force syncing with backing
- GBA: Savedata is now synced shortly after data finishes being written
0.2.1: (2015-05-13)
Bugfixes:

View File

@ -197,6 +197,7 @@ bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
switch (set->gsaVersion) {
case 0:
case 3:
GBACheatSetGameSharkVersion(set, 1);
// Fall through
case 1:

View File

@ -297,9 +297,10 @@ bool GBACheatAddProActionReplay(struct GBACheatSet* set, uint32_t op1, uint32_t
switch (set->gsaVersion) {
case 0:
case 1:
GBACheatSetGameSharkVersion(set, 3);
// Fall through
case 1:
case 3:
GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
return GBACheatAddProActionReplayRaw(set, o1, o2);
}

View File

@ -756,6 +756,8 @@ void GBAFrameStarted(struct GBA* gba) {
}
void GBAFrameEnded(struct GBA* gba) {
GBASavedataClean(&gba->memory.savedata, gba->video.frameCounter);
if (gba->rr) {
gba->rr->nextFrame(gba->rr);
}

View File

@ -818,6 +818,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
GBASavedataWriteFlash(&memory->savedata, address, value);
} else if (memory->savedata.type == SAVEDATA_SRAM) {
memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
memory->savedata.dirty |= SAVEDATA_DIRT_NEW;
} else if (memory->hw.devices & HW_TILT) {
GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value);
} else {

View File

@ -20,6 +20,7 @@
// Other games vary from very little, with a fairly solid 20500 cycle count. (Observed on a SST (D4BF) chip).
// An average estimation is as follows.
#define FLASH_SETTLE_CYCLES 18000
#define CLEANUP_THRESHOLD 15
static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
static void _flashErase(struct GBASavedata* savedata);
@ -33,6 +34,8 @@ void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
savedata->vf = vf;
savedata->realVf = vf;
savedata->mapMode = MAP_WRITE;
savedata->dirty = 0;
savedata->dirtAge = 0;
}
void GBASavedataDeinit(struct GBASavedata* savedata) {
@ -252,6 +255,7 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
case FLASH_STATE_RAW:
switch (savedata->command) {
case FLASH_COMMAND_PROGRAM:
savedata->dirty |= SAVEDATA_DIRT_NEW;
savedata->currentBank[address] = value;
savedata->command = FLASH_COMMAND_NONE;
break;
@ -359,6 +363,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32
uint8_t current = savedata->data[savedata->writeAddress >> 3];
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
savedata->dirty |= SAVEDATA_DIRT_NEW;
savedata->data[savedata->writeAddress >> 3] = current;
++savedata->writeAddress;
} else {
@ -401,6 +406,38 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
return 0;
}
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
if (savedata->dirty & SAVEDATA_DIRT_NEW) {
savedata->dirty &= ~SAVEDATA_DIRT_NEW;
if (!(savedata->dirty & SAVEDATA_DIRT_SEEN)) {
savedata->dirtAge = frameCount;
savedata->dirty |= SAVEDATA_DIRT_SEEN;
}
} else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
size_t size;
switch (savedata->type) {
case SAVEDATA_EEPROM:
size = SIZE_CART_EEPROM;
break;
case SAVEDATA_SRAM:
size = SIZE_CART_SRAM;
break;
case SAVEDATA_FLASH512:
size = SIZE_CART_FLASH512;
break;
case SAVEDATA_FLASH1M:
size = SIZE_CART_FLASH1M;
break;
default:
size = 0;
break;
}
savedata->vf->sync(savedata->vf, savedata->data, size);
savedata->dirty = 0;
GBALog(0, GBA_LOG_INFO, "Savedata synced");
}
}
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) {
state->savedata.type = savedata->type;
state->savedata.command = savedata->command;
@ -451,6 +488,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
void _flashErase(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
savedata->dirty |= SAVEDATA_DIRT_NEW;
size_t size = SIZE_CART_FLASH512;
if (savedata->type == SAVEDATA_FLASH1M) {
size = SIZE_CART_FLASH1M;
@ -460,6 +498,7 @@ void _flashErase(struct GBASavedata* savedata) {
void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
savedata->dirty |= SAVEDATA_DIRT_NEW;
size_t size = 0x1000;
if (savedata->type == SAVEDATA_FLASH1M) {
GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);

View File

@ -51,6 +51,11 @@ enum FlashManufacturer {
FLASH_MFG_SANYO = 0x1362
};
enum SavedataDirty {
SAVEDATA_DIRT_NEW = 1,
SAVEDATA_DIRT_SEEN = 2
};
enum {
SAVEDATA_FLASH_BASE = 0x0E005555,
@ -77,6 +82,9 @@ struct GBASavedata {
unsigned settling;
int dust;
enum SavedataDirty dirty;
uint32_t dirtAge;
enum FlashStateMachine flashState;
};
@ -98,6 +106,8 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata);
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize);
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount);
struct GBASerializedState;
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData);
void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData);

View File

@ -126,6 +126,31 @@ bool GBAConfigSave(const struct GBAConfig* config) {
return ConfigurationWrite(&config->configTable, path);
}
void GBAConfigMakePortable(const struct GBAConfig* config) {
struct VFile* portable;
#ifndef _WIN32
char out[PATH_MAX];
getcwd(out, PATH_MAX);
strncat(out, PATH_SEP "portable.ini", PATH_MAX - strlen(out));
portable = VFileOpen(out, O_WRONLY | O_CREAT);
#else
char out[MAX_PATH];
wchar_t wpath[MAX_PATH];
wchar_t wprojectName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, projectName, -1, wprojectName, MAX_PATH);
HMODULE hModule = GetModuleHandleW(NULL);
GetModuleFileNameW(hModule, wpath, MAX_PATH);
PathRemoveFileSpecW(wpath);
WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, MAX_PATH, 0, 0);
StringCchCatA(out, MAX_PATH, "\\portable.ini");
portable = VFileOpen(out, O_WRONLY | O_CREAT);
#endif
if (portable) {
portable->close(portable);
GBAConfigSave(config);
}
}
void GBAConfigDirectory(char* out, size_t outLength) {
struct VFile* portable;
#ifndef _WIN32

View File

@ -52,6 +52,7 @@ void GBAConfigDeinit(struct GBAConfig*);
bool GBAConfigLoad(struct GBAConfig*);
bool GBAConfigSave(const struct GBAConfig*);
void GBAConfigMakePortable(const struct GBAConfig*);
void GBAConfigDirectory(char* out, size_t outLength);
const char* GBAConfigGetValue(const struct GBAConfig*, const char* key);

View File

@ -258,3 +258,19 @@ void ConfigController::write() {
GBAConfigSave(&m_config);
m_settings->sync();
}
void ConfigController::makePortable() {
GBAConfigMakePortable(&m_config);
char path[PATH_MAX];
GBAConfigDirectory(path, sizeof(path));
QString fileName(path);
fileName.append(QDir::separator());
fileName.append("qt.ini");
QSettings* settings2 = new QSettings(fileName, QSettings::IniFormat, this);
for (const auto& key : m_settings->allKeys()) {
settings2->setValue(key, m_settings->value(key));
}
delete m_settings;
m_settings = settings2;
}

View File

@ -89,6 +89,7 @@ public slots:
void setOption(const char* key, const QVariant& value);
void setQtOption(const QString& key, const QVariant& value, const QString& group = QString());
void makePortable();
void write();
private:

View File

@ -642,6 +642,10 @@ void Window::setupMenu(QMenuBar* menubar) {
fileMenu->addSeparator();
addControlledAction(fileMenu, fileMenu->addAction(tr("Make portable"), m_config, SLOT(makePortable())), "makePortable");
fileMenu->addSeparator();
QAction* loadState = new QAction(tr("&Load state"), fileMenu);
loadState->setShortcut(tr("F10"));
connect(loadState, &QAction::triggered, [this]() { this->openStateWindow(LoadSave::LOAD); });

View File

@ -39,6 +39,7 @@ struct VFile {
void (*unmap)(struct VFile* vf, void* memory, size_t size);
void (*truncate)(struct VFile* vf, size_t size);
ssize_t (*size)(struct VFile* vf);
bool (*sync)(struct VFile* vf, const void* buffer, size_t size);
};
struct VDirEntry {

View File

@ -30,6 +30,7 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags);
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
static void _vfdTruncate(struct VFile* vf, size_t size);
static ssize_t _vfdSize(struct VFile* vf);
static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size);
struct VFile* VFileOpenFD(const char* path, int flags) {
if (!path) {
@ -66,6 +67,7 @@ struct VFile* VFileFromFD(int fd) {
vfd->d.unmap = _vfdUnmap;
vfd->d.truncate = _vfdTruncate;
vfd->d.size = _vfdSize;
vfd->d.sync = _vfdSync;
return &vfd->d;
}
@ -166,3 +168,10 @@ static ssize_t _vfdSize(struct VFile* vf) {
}
return stat.st_size;
}
static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size) {
UNUSED(buffer);
UNUSED(size);
struct VFileFD* vfd = (struct VFileFD*) vf;
return fsync(vfd->fd) == 0;
}

View File

@ -24,6 +24,7 @@ static void* _vffMap(struct VFile* vf, size_t size, int flags);
static void _vffUnmap(struct VFile* vf, void* memory, size_t size);
static void _vffTruncate(struct VFile* vf, size_t size);
static ssize_t _vffSize(struct VFile* vf);
static bool _vffSync(struct VFile* vf, const void* buffer, size_t size);
struct VFile* VFileFOpen(const char* path, const char* mode) {
if (!path && !mode) {
@ -57,6 +58,7 @@ struct VFile* VFileFromFILE(FILE* file) {
vff->d.unmap = _vffUnmap;
vff->d.truncate = _vffTruncate;
vff->d.size = _vffSize;
vff->d.sync = _vffSync;
return &vff->d;
}
@ -140,3 +142,14 @@ static ssize_t _vffSize(struct VFile* vf) {
fseek(vff->file, pos, SEEK_SET);
return size;
}
static bool _vffSync(struct VFile* vf, const void* buffer, size_t size) {
struct VFileFILE* vff = (struct VFileFILE*) vf;
if (buffer && size) {
long pos = ftell(vff->file);
fseek(vff->file, 0, SEEK_SET);
fwrite(buffer, size, 1, vff->file);
fseek(vff->file, pos, SEEK_SET);
}
return fflush(vff->file) == 0;
}

View File

@ -56,6 +56,7 @@ static void* _vf7zMap(struct VFile* vf, size_t size, int flags);
static void _vf7zUnmap(struct VFile* vf, void* memory, size_t size);
static void _vf7zTruncate(struct VFile* vf, size_t size);
static ssize_t _vf7zSize(struct VFile* vf);
static bool _vf7zSync(struct VFile* vf, const void* buffer, size_t size);
static bool _vd7zClose(struct VDir* vd);
static void _vd7zRewind(struct VDir* vd);
@ -291,6 +292,7 @@ struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode) {
vf->d.unmap = _vf7zUnmap;
vf->d.truncate = _vf7zTruncate;
vf->d.size = _vf7zSize;
vf->d.sync = _vf7zSync;
return &vf->d;
}
@ -308,4 +310,11 @@ const char* _vde7zName(struct VDirEntry* vde) {
return vde7z->utf8;
}
bool _vf7zSync(struct VFile* vf, const void* memory, size_t size) {
UNUSED(vf);
UNUSED(memory);
UNUSED(size);
return false;
}
#endif

View File

@ -43,6 +43,7 @@ static void* _vfzMap(struct VFile* vf, size_t size, int flags);
static void _vfzUnmap(struct VFile* vf, void* memory, size_t size);
static void _vfzTruncate(struct VFile* vf, size_t size);
static ssize_t _vfzSize(struct VFile* vf);
static bool _vfzSync(struct VFile* vf, const void* buffer, size_t size);
static bool _vdzClose(struct VDir* vd);
static void _vdzRewind(struct VDir* vd);
@ -289,6 +290,7 @@ struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode) {
vfz->d.unmap = _vfzUnmap;
vfz->d.truncate = _vfzTruncate;
vfz->d.size = _vfzSize;
vfz->d.sync = _vfzSync;
return &vfz->d;
}
@ -302,4 +304,11 @@ const char* _vdezName(struct VDirEntry* vde) {
return s.name;
}
bool _vfzSync(struct VFile* vf, const void* memory, size_t size) {
UNUSED(vf);
UNUSED(memory);
UNUSED(size);
return false;
}
#endif