Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2019-06-28 15:41:23 -07:00
commit 3b379d7e8d
22 changed files with 147 additions and 71 deletions

View File

@ -65,6 +65,12 @@ Bugfixes:
- GBA I/O: Fix writing to DISPCNT CGB flag (fixes mgba.io/i/902)
- GBA Memory: Partially revert prefetch changes (fixes mgba.io/i/840)
- PSP2: Fix issues causing poor audio
- Wii: Fix screen tear when unpausing
- GBA: Fix some GBA ROM misdetection (fixes mgba.io/i/978)
- GBA Hardware: RTC accuracy improvements
- GB Timer: Minor accuracy improvements
- GB Audio: Clock frame events on DIV
- GBA: Fix SharkPort saves for EEPROM games
Misc:
- GBA Timer: Use global cycles for timers
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)

View File

@ -232,6 +232,8 @@ void GBAudioWriteNR50(struct GBAudio* audio, uint8_t);
void GBAudioWriteNR51(struct GBAudio* audio, uint8_t);
void GBAudioWriteNR52(struct GBAudio* audio, uint8_t);
void GBAudioUpdateFrame(struct GBAudio* audio, struct mTiming* timing);
void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right);
struct GBSerializedPSGState;

View File

@ -102,7 +102,7 @@ void GBASavedataDeinit(struct GBASavedata* savedata);
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback);
void GBASavedataUnmask(struct GBASavedata* savedata);
size_t GBASavedataSize(struct GBASavedata* savedata);
size_t GBASavedataSize(const struct GBASavedata* savedata);
bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out);
bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in);
void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming);

View File

@ -109,10 +109,12 @@ void GBAudioReset(struct GBAudio* audio) {
mTimingDeschedule(audio->timing, &audio->ch3Fade);
mTimingDeschedule(audio->timing, &audio->ch4Event);
mTimingDeschedule(audio->timing, &audio->sampleEvent);
mTimingSchedule(audio->timing, &audio->frameEvent, 0);
if (audio->style != GB_AUDIO_GBA) {
mTimingSchedule(audio->timing, &audio->sampleEvent, 0);
}
if (audio->style == GB_AUDIO_GBA) {
mTimingSchedule(audio->timing, &audio->frameEvent, 0);
}
audio->ch1 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } };
audio->ch2 = (struct GBAudioSquareChannel) { .envelope = { .dead = 2 } };
audio->ch3 = (struct GBAudioWaveChannel) { .bank = 0 };
@ -486,7 +488,13 @@ void GBAudioWriteNR52(struct GBAudio* audio, uint8_t value) {
void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct GBAudio* audio = user;
GBAudioUpdateFrame(audio, timing);
if (audio->style == GB_AUDIO_GBA) {
mTimingSchedule(timing, &audio->frameEvent, audio->timingFactor * FRAME_CYCLES - cyclesLate);
}
}
void GBAudioUpdateFrame(struct GBAudio* audio, struct mTiming* timing) {
int frame = (audio->frame + 1) & 7;
audio->frame = frame;
@ -576,8 +584,6 @@ void _updateFrame(struct mTiming* timing, void* user, uint32_t cyclesLate) {
}
break;
}
mTimingSchedule(timing, &audio->frameEvent, audio->timingFactor * FRAME_CYCLES - cyclesLate);
}
void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) {
@ -959,8 +965,10 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt
audio->playingCh4 = !!(*audio->nr52 & 0x0008);
audio->enable = GBAudioEnableGetEnable(*audio->nr52);
LOAD_32LE(when, 0, &state->ch1.nextFrame);
mTimingSchedule(audio->timing, &audio->frameEvent, when);
if (audio->style == GB_AUDIO_GBA) {
LOAD_32LE(when, 0, &state->ch1.nextFrame);
mTimingSchedule(audio->timing, &audio->frameEvent, when);
}
LOAD_32LE(flags, 0, flagsIn);
audio->frame = GBSerializedAudioFlagsGetFrame(flags);

View File

@ -380,8 +380,17 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
}
break;
case REG_TIMA:
if (value && mTimingUntil(&gb->timing, &gb->timer.irq) > 1) {
mTimingDeschedule(&gb->timing, &gb->timer.irq);
}
if (mTimingUntil(&gb->timing, &gb->timer.irq) == -1) {
return;
}
break;
case REG_TMA:
// Handled transparently by the registers
if (mTimingUntil(&gb->timing, &gb->timer.irq) == -1) {
gb->memory.io[REG_TIMA] = value;
}
break;
case REG_TAC:
value = GBTimerUpdateTAC(&gb->timer, value);

View File

@ -27,9 +27,13 @@ static void _GBTimerDivIncrement(struct GBTimer* timer, uint32_t cyclesLate) {
if (timer->timaPeriod > 0 && (timer->internalDiv & (timer->timaPeriod - 1)) == timer->timaPeriod - 1) {
++timer->p->memory.io[REG_TIMA];
if (!timer->p->memory.io[REG_TIMA]) {
mTimingSchedule(&timer->p->timing, &timer->irq, 4 - cyclesLate);
mTimingSchedule(&timer->p->timing, &timer->irq, 7 - ((timer->p->cpu->executionState - cyclesLate) & 3));
}
}
int timingFactor = 0x3FF >> !timer->p->doubleSpeed;
if ((timer->internalDiv & timingFactor) == timingFactor) {
GBAudioUpdateFrame(&timer->p->audio, &timer->p->timing);
}
++timer->internalDiv;
timer->p->memory.io[REG_DIV] = timer->internalDiv >> 4;
}
@ -69,13 +73,17 @@ void GBTimerReset(struct GBTimer* timer) {
void GBTimerDivReset(struct GBTimer* timer) {
timer->nextDiv -= mTimingUntil(&timer->p->timing, &timer->event);
mTimingDeschedule(&timer->p->timing, &timer->event);
_GBTimerDivIncrement(timer, (timer->p->cpu->executionState + 1) & 3);
if (timer->internalDiv & (timer->timaPeriod >> 1)) {
_GBTimerDivIncrement(timer, 0);
if (((timer->internalDiv << 1) | ((timer->nextDiv >> 3) & 1)) & timer->timaPeriod) {
++timer->p->memory.io[REG_TIMA];
if (!timer->p->memory.io[REG_TIMA]) {
mTimingSchedule(&timer->p->timing, &timer->irq, 4 - ((timer->p->cpu->executionState + 1) & 3));
mTimingSchedule(&timer->p->timing, &timer->irq, 7 - (timer->p->cpu->executionState & 3));
}
}
int timingFactor = 0x200 >> !timer->p->doubleSpeed;
if (timer->internalDiv & 0x200) {
GBAudioUpdateFrame(&timer->p->audio, &timer->p->timing);
}
timer->p->memory.io[REG_DIV] = 0;
timer->internalDiv = 0;
timer->nextDiv = GB_DMG_DIV_PERIOD;
@ -101,7 +109,7 @@ uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) {
timer->nextDiv -= mTimingUntil(&timer->p->timing, &timer->event);
mTimingDeschedule(&timer->p->timing, &timer->event);
_GBTimerDivIncrement(timer, (timer->p->cpu->executionState + 1) & 3);
_GBTimerDivIncrement(timer, (timer->p->cpu->executionState + 2) & 3);
timer->nextDiv += GB_DMG_DIV_PERIOD;
mTimingSchedule(&timer->p->timing, &timer->event, timer->nextDiv);
} else {

View File

@ -33,6 +33,9 @@ const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
static const size_t GBA_ROM_MAGIC_OFFSET = 3;
static const uint8_t GBA_ROM_MAGIC[] = { 0xEA };
static const size_t GBA_ROM_MAGIC_OFFSET2 = 0xB2;
static const uint8_t GBA_ROM_MAGIC2[] = { 0x96 };
static const size_t GBA_MB_MAGIC_OFFSET = 0xC0;
static void GBAInit(void* cpu, struct mCPUComponent* component);
@ -542,17 +545,48 @@ bool GBAIsROM(struct VFile* vf) {
if (!vf) {
return false;
}
uint8_t signature[sizeof(GBA_ROM_MAGIC) + sizeof(GBA_ROM_MAGIC2)];
if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
return false;
}
uint8_t signature[sizeof(GBA_ROM_MAGIC)];
if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
if (vf->read(vf, &signature, sizeof(GBA_ROM_MAGIC)) != sizeof(GBA_ROM_MAGIC)) {
return false;
}
if (memcmp(signature, GBA_ROM_MAGIC, sizeof(GBA_ROM_MAGIC)) != 0) {
return false;
}
if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET2, SEEK_SET) < 0) {
return false;
}
if (vf->read(vf, &signature, sizeof(GBA_ROM_MAGIC2)) != sizeof(GBA_ROM_MAGIC2)) {
return false;
}
if (memcmp(signature, GBA_ROM_MAGIC2, sizeof(GBA_ROM_MAGIC2)) != 0) {
// If the signature byte is missing then we must be using an unfixed ROM
uint32_t buffer[0x9C / sizeof(uint32_t)];
if (vf->seek(vf, 0x4, SEEK_SET) < 0) {
return false;
}
if (vf->read(vf, &buffer, sizeof(buffer)) != sizeof(buffer)) {
return false;
}
uint32_t bits = 0;
size_t i;
for (i = 0; i < sizeof(buffer) / sizeof(*buffer); ++i) {
bits |= buffer[i];
}
if (bits) {
return false;
}
}
if (GBAIsBIOS(vf)) {
return false;
}
return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0;
return true;
}
bool GBAIsMB(struct VFile* vf) {

View File

@ -63,7 +63,7 @@ void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
void GBAHardwareClear(struct GBACartridgeHardware* hw) {
hw->devices = HW_NONE | (hw->devices & HW_GB_PLAYER_DETECTION);
hw->direction = GPIO_WRITE_ONLY;
hw->readWrite = GPIO_WRITE_ONLY;
hw->pinState = 0;
hw->direction = 0;
@ -79,7 +79,7 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uin
switch (address) {
case GPIO_REG_DATA:
hw->pinState &= ~hw->direction;
hw->pinState |= value;
hw->pinState |= value & hw->direction;
_readPins(hw);
break;
case GPIO_REG_DIRECTION:
@ -92,13 +92,13 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uin
mLOG(GBA_HW, WARN, "Invalid GPIO address");
}
if (hw->readWrite) {
uint16_t old;
LOAD_16(old, 0, hw->gpioBase);
old &= ~hw->direction;
old |= hw->pinState;
STORE_16(old, 0, hw->gpioBase);
STORE_16(hw->pinState, 0, hw->gpioBase);
STORE_16(hw->direction, 2, hw->gpioBase);
STORE_16(hw->readWrite, 4, hw->gpioBase);
} else {
hw->gpioBase[0] = 0;
hw->gpioBase[1] = 0;
hw->gpioBase[2] = 0;
}
}
@ -165,11 +165,15 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) {
if ((hw->pinState & 5) == 1) {
hw->rtc.transferStep = 1;
}
_outputPins(hw, 1);
break;
case 1:
if ((hw->pinState & 5) == 5) {
hw->rtc.transferStep = 2;
} else {
hw->rtc.transferStep = 0;
}
_outputPins(hw, 5);
break;
case 2:
if (!(hw->pinState & 1)) {
@ -177,11 +181,7 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) {
hw->rtc.bits |= ((hw->pinState & 2) >> 1) << hw->rtc.bitsRead;
} else {
if (hw->pinState & 4) {
// GPIO direction should always != reading
if (hw->direction & 2) {
if (RTCCommandDataIsReading(hw->rtc.command)) {
mLOG(GBA_HW, GAME_ERROR, "Attempting to write to RTC while in read mode");
}
if (!RTCCommandDataIsReading(hw->rtc.command)) {
++hw->rtc.bitsRead;
if (hw->rtc.bitsRead == 8) {
GBARTCProcessByte(&hw->rtc, hw->p->rtcSource);
@ -193,7 +193,7 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) {
--hw->rtc.bytesRemaining;
if (hw->rtc.bytesRemaining <= 0) {
hw->rtc.commandActive = 0;
hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
hw->rtc.command = 0;
}
hw->rtc.bitsRead = 0;
}
@ -202,8 +202,9 @@ void _rtcReadPins(struct GBACartridgeHardware* hw) {
hw->rtc.bitsRead = 0;
hw->rtc.bytesRemaining = 0;
hw->rtc.commandActive = 0;
hw->rtc.command = RTCCommandDataClearReading(hw->rtc.command);
hw->rtc.transferStep = 0;
hw->rtc.command = 0;
hw->rtc.transferStep = hw->pinState & 1;
_outputPins(hw, 1);
}
}
break;
@ -269,6 +270,10 @@ void GBARTCProcessByte(struct GBARTC* rtc, struct mRTCSource* source) {
unsigned GBARTCOutput(struct GBARTC* rtc) {
uint8_t outputByte = 0;
if (!rtc->commandActive) {
mLOG(GBA_HW, GAME_ERROR, "Attempting to use RTC without an active command");
return 0;
}
switch (RTCCommandDataGetCommand(rtc->command)) {
case RTC_STATUS1:
outputByte = rtc->control;

View File

@ -138,7 +138,7 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
return true;
}
size_t GBASavedataSize(struct GBASavedata* savedata) {
size_t GBASavedataSize(const struct GBASavedata* savedata) {
switch (savedata->type) {
case SAVEDATA_SRAM:
return SIZE_CART_SRAM;

View File

@ -130,8 +130,21 @@ bool GBASavedataImportSharkPort(struct GBA* gba, struct VFile* vf, bool testChec
goto cleanup;
}
memcpy(gba->memory.savedata.data, &payload[0x1C], copySize);
gba->memory.savedata.vf && gba->memory.savedata.vf->sync(gba->memory.savedata.vf, gba->memory.savedata.data, size);
if (gba->memory.savedata.type == SAVEDATA_EEPROM) {
size_t i;
for (i = 0; i < copySize; i += 8) {
uint32_t lo, hi;
LOAD_32BE(lo, i + 0x1C, payload);
LOAD_32BE(hi, i + 0x20, payload);
STORE_32LE(hi, i, gba->memory.savedata.data);
STORE_32LE(lo, i + 4, gba->memory.savedata.data);
}
} else {
memcpy(gba->memory.savedata.data, &payload[0x1C], copySize);
}
if (gba->memory.savedata.vf) {
gba->memory.savedata.vf->sync(gba->memory.savedata.vf, gba->memory.savedata.data, size);
}
free(payload);
return true;
@ -146,7 +159,7 @@ bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) {
char c[0x1C];
int32_t i;
} buffer;
int32_t size = strlen(SHARKPORT_HEADER);
uint32_t size = strlen(SHARKPORT_HEADER);
STORE_32(size, 0, &buffer.i);
if (vf->write(vf, &buffer.i, 4) < 4) {
return false;
@ -187,22 +200,8 @@ bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) {
}
// Write payload
size = 0x1C;
switch (gba->memory.savedata.type) {
case SAVEDATA_SRAM:
size += SIZE_CART_SRAM;
break;
case SAVEDATA_FLASH512:
size += SIZE_CART_FLASH512;
break;
case SAVEDATA_FLASH1M:
size += SIZE_CART_FLASH1M;
break;
case SAVEDATA_EEPROM:
size += SIZE_CART_EEPROM;
break;
case SAVEDATA_FORCE_NONE:
case SAVEDATA_AUTODETECT:
size = 0x1C + GBASavedataSize(&gba->memory.savedata);
if (size == 0x1C) {
return false;
}
STORE_32(size, 0, &buffer.i);
@ -229,17 +228,24 @@ bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) {
}
uint32_t checksum = 0;
int i;
size_t i;
for (i = 0; i < 0x1C; ++i) {
checksum += buffer.c[i] << (checksum % 24);
}
if (vf->write(vf, gba->memory.savedata.data, size) < size) {
return false;
}
for (i = 0; i < size; ++i) {
checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24);
if (gba->memory.savedata.type == SAVEDATA_EEPROM) {
for (i = 0; i < size; ++i) {
char byte = gba->memory.savedata.data[i ^ 7];
checksum += byte << (checksum % 24);
vf->write(vf, &byte, 1);
}
} else if (vf->write(vf, gba->memory.savedata.data, size) < size) {
return false;
} else {
for (i = 0; i < size; ++i) {
checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24);
}
}
STORE_32(checksum, 0, &buffer.i);

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DisplayGL.h"
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
#include "CoreController.h"

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
#include "Display.h"

View File

@ -291,13 +291,13 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
}
SettingsView::~SettingsView() {
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
setShaderSelector(nullptr);
#endif
}
void SettingsView::setShaderSelector(ShaderSelector* shaderSelector) {
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
if (m_shader) {
auto items = m_ui.tabs->findItems(tr("Shaders"), Qt::MatchFixedString);
for (const auto& item : items) {

View File

@ -21,7 +21,7 @@
#include <mgba-util/vfs.h>
#include "platform/video-backend.h"
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
#if !defined(_WIN32) || defined(USE_EPOXY)
#include "platform/opengl/gles2.h"

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
#include <QDialog>

View File

@ -852,7 +852,7 @@ void Window::reloadDisplayDriver() {
detachWidget(m_display.get());
}
m_display = std::move(std::unique_ptr<Display>(Display::create(this)));
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
m_shaderView.reset();
m_shaderView = std::make_unique<ShaderSelector>(m_display.get(), m_config);
#endif
@ -871,7 +871,7 @@ void Window::reloadDisplayDriver() {
const mCoreOptions* opts = m_config->options();
m_display->lockAspectRatio(opts->lockAspectRatio);
m_display->filter(opts->resampleVideo);
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
if (opts->shader) {
struct VDir* shader = VDirOpen(opts->shader);
if (shader && m_display->supportsShaders()) {

View File

@ -187,7 +187,7 @@ private:
QMenu* m_mruMenu = nullptr;
QMenu* m_videoLayers;
QMenu* m_audioChannels;
#if defined(BUILD_GL) || defined(BUILD_GLES)
#if defined(BUILD_GL) || defined(BUILD_GLES2)
std::unique_ptr<ShaderSelector> m_shaderView;
#endif
bool m_fullscreenOnStart = false;

View File

@ -123,15 +123,15 @@ void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
SDL_Event event;
struct VideoBackend* v = &renderer->gl2.d;
while (context->state < THREAD_EXITING) {
while (mCoreThreadIsActive(context)) {
while (SDL_PollEvent(&event)) {
mSDLHandleEvent(context, &renderer->player, &event);
}
if (mCoreSyncWaitFrameStart(&context->sync)) {
if (mCoreSyncWaitFrameStart(&context->impl->sync)) {
v->postFrame(v, renderer->outputBuffer);
}
mCoreSyncWaitFrameEnd(&context->sync);
mCoreSyncWaitFrameEnd(&context->impl->sync);
v->drawFrame(v);
#ifdef BUILD_RASPI
eglSwapBuffers(renderer->display, renderer->surface);

View File

@ -733,6 +733,7 @@ void _gameLoaded(struct mGUIRunner* runner) {
void _unpaused(struct mGUIRunner* runner) {
u32 level = 0;
VIDEO_WaitVSync();
_CPU_ISR_Disable(level);
referenceRetraceCount = retraceCount;
_CPU_ISR_Restore(level);