Merge branch 'master' into medusa
7
CHANGES
|
@ -49,6 +49,7 @@ Emulation fixes:
|
||||||
- GBA BIOS: Implement dummy sound driver calls
|
- GBA BIOS: Implement dummy sound driver calls
|
||||||
- GBA BIOS: Improve HLE BIOS timing
|
- GBA BIOS: Improve HLE BIOS timing
|
||||||
- GBA BIOS: Fix reloading video registers after reset (fixes mgba.io/i/1808)
|
- GBA BIOS: Fix reloading video registers after reset (fixes mgba.io/i/1808)
|
||||||
|
- GBA BIOS: Make HLE BIOS calls interruptable (fixes mgba.io/i/1711 and mgba.io/i/1823)
|
||||||
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
|
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
|
||||||
- GBA Memory: Improve gamepak prefetch timing
|
- GBA Memory: Improve gamepak prefetch timing
|
||||||
- GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190)
|
- GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190)
|
||||||
|
@ -56,8 +57,11 @@ Emulation fixes:
|
||||||
- GBA SIO: Fix Normal mode being totally broken (fixes mgba.io/i/1800)
|
- GBA SIO: Fix Normal mode being totally broken (fixes mgba.io/i/1800)
|
||||||
- GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319)
|
- GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319)
|
||||||
- GBA Video: Fix Hblank timing
|
- GBA Video: Fix Hblank timing
|
||||||
|
- GBA Video: Invalidate map cache when modifying BGCNT (fixes mgba.io/i/1846)
|
||||||
- SM83: Emulate HALT bug
|
- SM83: Emulate HALT bug
|
||||||
Other fixes:
|
Other fixes:
|
||||||
|
- 3DS: Redo video sync to be more precise
|
||||||
|
- 3DS: Fix crash with libctru 2.0 when exiting
|
||||||
- All: Improve export headers (fixes mgba.io/i/1738)
|
- All: Improve export headers (fixes mgba.io/i/1738)
|
||||||
- Core: Ensure ELF regions can be written before trying
|
- Core: Ensure ELF regions can be written before trying
|
||||||
- Debugger: Don't skip undefined instructions when debugger attached
|
- Debugger: Don't skip undefined instructions when debugger attached
|
||||||
|
@ -66,6 +70,9 @@ Other fixes:
|
||||||
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
|
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
|
||||||
- Qt: Fix static compilation in MinGW (fixes mgba.io/i/1769)
|
- Qt: Fix static compilation in MinGW (fixes mgba.io/i/1769)
|
||||||
- Qt: Fix a race condition in the frame inspector
|
- Qt: Fix a race condition in the frame inspector
|
||||||
|
- Qt: Add dummy English translation file (fixes mgba.io/i/1469)
|
||||||
|
- mGUI: Fix closing down a game if an exit is signalled
|
||||||
|
- mVL: Fix injecting accidentally draining non-injection buffer
|
||||||
- SM83: Simplify register pair access on big endian
|
- SM83: Simplify register pair access on big endian
|
||||||
- VFS: Fix directory node listing on some filesystems
|
- VFS: Fix directory node listing on some filesystems
|
||||||
Misc:
|
Misc:
|
||||||
|
|
|
@ -654,6 +654,8 @@ endif()
|
||||||
if(USE_LIBZIP)
|
if(USE_LIBZIP)
|
||||||
if(TARGET libzip::zip)
|
if(TARGET libzip::zip)
|
||||||
list(APPEND DEPENDENCY_LIB libzip::zip)
|
list(APPEND DEPENDENCY_LIB libzip::zip)
|
||||||
|
elseif(TARGET zip)
|
||||||
|
list(APPEND DEPENDENCY_LIB zip)
|
||||||
else()
|
else()
|
||||||
include_directories(AFTER ${LIBZIP_INCLUDE_DIRS})
|
include_directories(AFTER ${LIBZIP_INCLUDE_DIRS})
|
||||||
link_directories(${LIBZIP_LIBRARY_DIRS})
|
link_directories(${LIBZIP_LIBRARY_DIRS})
|
||||||
|
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
@ -109,6 +109,8 @@ struct GBA {
|
||||||
bool cpuBlocked;
|
bool cpuBlocked;
|
||||||
bool earlyExit;
|
bool earlyExit;
|
||||||
uint32_t dmaPC;
|
uint32_t dmaPC;
|
||||||
|
uint32_t biosStall;
|
||||||
|
|
||||||
int idleDetectionStep;
|
int idleDetectionStep;
|
||||||
int idleDetectionFailures;
|
int idleDetectionFailures;
|
||||||
int32_t cachedRegisters[16];
|
int32_t cachedRegisters[16];
|
||||||
|
|
|
@ -201,7 +201,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
|
||||||
* | bit 1: POSTFLG
|
* | bit 1: POSTFLG
|
||||||
* | bit 2: Is IRQ pending?
|
* | bit 2: Is IRQ pending?
|
||||||
* 0x00320 - 0x00323: Next IRQ event
|
* 0x00320 - 0x00323: Next IRQ event
|
||||||
* 0x00324 - 0x003FF: Reserved (leave zero)
|
* 0x00324 - 0x00327: Interruptable BIOS stall cycles
|
||||||
|
* 0x00328 - 0x003FF: Reserved (leave zero)
|
||||||
* 0x00400 - 0x007FF: I/O memory
|
* 0x00400 - 0x007FF: I/O memory
|
||||||
* 0x00800 - 0x00BFF: Palette
|
* 0x00800 - 0x00BFF: Palette
|
||||||
* 0x00C00 - 0x00FFF: OAM
|
* 0x00C00 - 0x00FFF: OAM
|
||||||
|
@ -334,8 +335,9 @@ struct GBASerializedState {
|
||||||
uint32_t lastPrefetchedPc;
|
uint32_t lastPrefetchedPc;
|
||||||
GBASerializedMiscFlags miscFlags;
|
GBASerializedMiscFlags miscFlags;
|
||||||
uint32_t nextIrq;
|
uint32_t nextIrq;
|
||||||
|
int32_t biosStall;
|
||||||
|
|
||||||
uint32_t reserved[55];
|
uint32_t reserved[54];
|
||||||
|
|
||||||
uint16_t io[SIZE_IO >> 1];
|
uint16_t io[SIZE_IO >> 1];
|
||||||
uint16_t pram[SIZE_PALETTE_RAM >> 1];
|
uint16_t pram[SIZE_PALETTE_RAM >> 1];
|
||||||
|
|
|
@ -541,6 +541,9 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
||||||
++frame;
|
++frame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!running) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (runner->paused) {
|
if (runner->paused) {
|
||||||
runner->paused(runner);
|
runner->paused(runner);
|
||||||
|
@ -651,7 +654,7 @@ void mGUIRunloop(struct mGUIRunner* runner) {
|
||||||
mInputMapLoad(&runner->params.keyMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->config));
|
mInputMapLoad(&runner->params.keyMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->config));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (true) {
|
while (runner->running(runner)) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
const char* preselect = mCoreConfigGetValue(&runner->config, "lastGame");
|
const char* preselect = mCoreConfigGetValue(&runner->config, "lastGame");
|
||||||
if (preselect) {
|
if (preselect) {
|
||||||
|
|
|
@ -1000,7 +1000,7 @@ static ssize_t mVideoLoggerReadChannel(struct mVideoLogChannel* channel, void* d
|
||||||
data = (uint8_t*) data + size;
|
data = (uint8_t*) data + size;
|
||||||
length -= size;
|
length -= size;
|
||||||
}
|
}
|
||||||
if (!_fillBuffer(context, channelId, BUFFER_BASE_SIZE)) {
|
if (channel->injecting || !_fillBuffer(context, channelId, BUFFER_BASE_SIZE)) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
size += CircleBufferRead(buffer, data, length);
|
size += CircleBufferRead(buffer, data, length);
|
||||||
|
|
|
@ -298,10 +298,10 @@ static void _Div(struct GBA* gba, int32_t num, int32_t denom) {
|
||||||
if (loops < 1) {
|
if (loops < 1) {
|
||||||
loops = 1;
|
loops = 1;
|
||||||
}
|
}
|
||||||
cpu->cycles += 4 /* prologue */ + 13 * loops + 7 /* epilogue */;
|
gba->biosStall = 4 /* prologue */ + 13 * loops + 7 /* epilogue */;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3, int32_t* cycles) {
|
static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3, uint32_t* cycles) {
|
||||||
int currentCycles = 37;
|
int currentCycles = 37;
|
||||||
currentCycles += _mulWait(i * i);
|
currentCycles += _mulWait(i * i);
|
||||||
int32_t a = -((i * i) >> 14);
|
int32_t a = -((i * i) >> 14);
|
||||||
|
@ -325,11 +325,11 @@ static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3, int32_t* cycles) {
|
||||||
if (r3) {
|
if (r3) {
|
||||||
*r3 = b;
|
*r3 = b;
|
||||||
}
|
}
|
||||||
*cycles += currentCycles;
|
*cycles = currentCycles;
|
||||||
return (i * b) >> 16;
|
return (i * b) >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, int32_t* cycles) {
|
static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, uint32_t* cycles) {
|
||||||
if (!y) {
|
if (!y) {
|
||||||
if (x >= 0) {
|
if (x >= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -363,9 +363,9 @@ static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, int32_t* cycles) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t _Sqrt(uint32_t x, int32_t* cycles) {
|
static int32_t _Sqrt(uint32_t x, uint32_t* cycles) {
|
||||||
if (!x) {
|
if (!x) {
|
||||||
*cycles += 53;
|
*cycles = 53;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int32_t currentCycles = 15;
|
int32_t currentCycles = 15;
|
||||||
|
@ -412,7 +412,7 @@ static int32_t _Sqrt(uint32_t x, int32_t* cycles) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*cycles += currentCycles;
|
*cycles = currentCycles;
|
||||||
return bound;
|
return bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +422,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
||||||
immediate, cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3]);
|
immediate, cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3]);
|
||||||
|
|
||||||
switch (immediate) {
|
switch (immediate) {
|
||||||
|
case 0xF0: // Used for internal stall counting
|
||||||
|
cpu->gprs[4] = gba->biosStall;
|
||||||
|
return;
|
||||||
case 0xFA:
|
case 0xFA:
|
||||||
GBAPrintFlush(gba);
|
GBAPrintFlush(gba);
|
||||||
return;
|
return;
|
||||||
|
@ -431,6 +434,8 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
||||||
ARMRaiseSWI(cpu);
|
ARMRaiseSWI(cpu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool useStall = false;
|
||||||
switch (immediate) {
|
switch (immediate) {
|
||||||
case GBA_SWI_SOFT_RESET:
|
case GBA_SWI_SOFT_RESET:
|
||||||
_SoftReset(gba);
|
_SoftReset(gba);
|
||||||
|
@ -452,19 +457,24 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
||||||
ARMRaiseSWI(cpu);
|
ARMRaiseSWI(cpu);
|
||||||
return;
|
return;
|
||||||
case GBA_SWI_DIV:
|
case GBA_SWI_DIV:
|
||||||
|
useStall = true;
|
||||||
_Div(gba, cpu->gprs[0], cpu->gprs[1]);
|
_Div(gba, cpu->gprs[0], cpu->gprs[1]);
|
||||||
break;
|
break;
|
||||||
case GBA_SWI_DIV_ARM:
|
case GBA_SWI_DIV_ARM:
|
||||||
|
useStall = true;
|
||||||
_Div(gba, cpu->gprs[1], cpu->gprs[0]);
|
_Div(gba, cpu->gprs[1], cpu->gprs[0]);
|
||||||
break;
|
break;
|
||||||
case GBA_SWI_SQRT:
|
case GBA_SWI_SQRT:
|
||||||
cpu->gprs[0] = _Sqrt(cpu->gprs[0], &cpu->cycles);
|
useStall = true;
|
||||||
|
cpu->gprs[0] = _Sqrt(cpu->gprs[0], &gba->biosStall);
|
||||||
break;
|
break;
|
||||||
case GBA_SWI_ARCTAN:
|
case GBA_SWI_ARCTAN:
|
||||||
cpu->gprs[0] = _ArcTan(cpu->gprs[0], &cpu->gprs[1], &cpu->gprs[3], &cpu->cycles);
|
useStall = true;
|
||||||
|
cpu->gprs[0] = _ArcTan(cpu->gprs[0], &cpu->gprs[1], &cpu->gprs[3], &gba->biosStall);
|
||||||
break;
|
break;
|
||||||
case GBA_SWI_ARCTAN2:
|
case GBA_SWI_ARCTAN2:
|
||||||
cpu->gprs[0] = (uint16_t) _ArcTan2(cpu->gprs[0], cpu->gprs[1], &cpu->gprs[1], &cpu->cycles);
|
useStall = true;
|
||||||
|
cpu->gprs[0] = (uint16_t) _ArcTan2(cpu->gprs[0], cpu->gprs[1], &cpu->gprs[1], &gba->biosStall);
|
||||||
cpu->gprs[3] = 0x170;
|
cpu->gprs[3] = 0x170;
|
||||||
break;
|
break;
|
||||||
case GBA_SWI_CPU_SET:
|
case GBA_SWI_CPU_SET:
|
||||||
|
@ -589,6 +599,18 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
||||||
default:
|
default:
|
||||||
mLOG(GBA_BIOS, STUB, "Stub software interrupt: %02X", immediate);
|
mLOG(GBA_BIOS, STUB, "Stub software interrupt: %02X", immediate);
|
||||||
}
|
}
|
||||||
|
if (useStall) {
|
||||||
|
if (gba->biosStall >= 18) {
|
||||||
|
gba->biosStall -= 18;
|
||||||
|
gba->cpu->cycles += gba->biosStall & 3;
|
||||||
|
gba->biosStall &= ~3;
|
||||||
|
ARMRaiseSWI(cpu);
|
||||||
|
} else {
|
||||||
|
gba->cpu->cycles += gba->biosStall;
|
||||||
|
useStall = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!useStall) {
|
||||||
gba->cpu->cycles += 45 + cpu->memory.activeNonseqCycles16 /* 8 bit load for SWI # */;
|
gba->cpu->cycles += 45 + cpu->memory.activeNonseqCycles16 /* 8 bit load for SWI # */;
|
||||||
// Return cycles
|
// Return cycles
|
||||||
if (gba->cpu->executionMode == MODE_ARM) {
|
if (gba->cpu->executionMode == MODE_ARM) {
|
||||||
|
@ -596,6 +618,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
|
||||||
} else {
|
} else {
|
||||||
gba->cpu->cycles += cpu->memory.activeNonseqCycles16 + cpu->memory.activeSeqCycles16;
|
gba->cpu->cycles += cpu->memory.activeNonseqCycles16 + cpu->memory.activeSeqCycles16;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
gba->memory.biosPrefetch = 0xE3A02004;
|
gba->memory.biosPrefetch = 0xE3A02004;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,7 @@ void GBAReset(struct ARMCore* cpu) {
|
||||||
gba->cpuBlocked = false;
|
gba->cpuBlocked = false;
|
||||||
gba->earlyExit = false;
|
gba->earlyExit = false;
|
||||||
gba->dmaPC = 0;
|
gba->dmaPC = 0;
|
||||||
|
gba->biosStall = 0;
|
||||||
if (gba->yankedRomSize) {
|
if (gba->yankedRomSize) {
|
||||||
gba->memory.romSize = gba->yankedRomSize;
|
gba->memory.romSize = gba->yankedRomSize;
|
||||||
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
|
gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
|
||||||
|
|
|
@ -236,6 +236,7 @@ void GBARTCProcessByte(struct GBARTC* rtc, struct mRTCSource* source) {
|
||||||
|
|
||||||
rtc->bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
|
rtc->bytesRemaining = RTC_BYTES[RTCCommandDataGetCommand(command)];
|
||||||
rtc->commandActive = rtc->bytesRemaining > 0;
|
rtc->commandActive = rtc->bytesRemaining > 0;
|
||||||
|
mLOG(GBA_HW, DEBUG, "Got RTC command %x", RTCCommandDataGetCommand(command));
|
||||||
switch (RTCCommandDataGetCommand(command)) {
|
switch (RTCCommandDataGetCommand(command)) {
|
||||||
case RTC_DATETIME:
|
case RTC_DATETIME:
|
||||||
case RTC_TIME:
|
case RTC_TIME:
|
||||||
|
|
|
@ -3,28 +3,28 @@
|
||||||
#include <mgba/internal/gba/memory.h>
|
#include <mgba/internal/gba/memory.h>
|
||||||
|
|
||||||
const uint8_t hleBios[SIZE_BIOS] = {
|
const uint8_t hleBios[SIZE_BIOS] = {
|
||||||
0x06, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0b, 0x00, 0x00, 0xea,
|
0x06, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea,
|
||||||
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
|
0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1,
|
||||||
0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3,
|
0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3,
|
||||||
0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0x4c, 0x01, 0x9f, 0x15,
|
0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0x4c, 0x01, 0x9f, 0x15,
|
||||||
0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1,
|
0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1,
|
||||||
0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03,
|
||||||
0x00, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5, 0xd4, 0xc0, 0xa0, 0xe3,
|
0x20, 0xd0, 0x4d, 0x02, 0x10, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5,
|
||||||
0x0b, 0xb1, 0x9c, 0xe7, 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xc0, 0x4f, 0xe1,
|
0xd4, 0xc0, 0xa0, 0xe3, 0x0b, 0xb1, 0x9c, 0xe7, 0xd2, 0xcf, 0xa0, 0xe3,
|
||||||
|
0x0b, 0x00, 0x5c, 0xe1, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xc0, 0x4f, 0xe1,
|
||||||
0x00, 0x10, 0x2d, 0xe9, 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3,
|
0x00, 0x10, 0x2d, 0xe9, 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3,
|
||||||
0x0c, 0xf0, 0x29, 0xe1, 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0xa0, 0xe1,
|
0x0c, 0xf0, 0x21, 0xe1, 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0x5b, 0xe3,
|
||||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
|
||||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
||||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
||||||
0x0f, 0xe0, 0xa0, 0xe1, 0x1b, 0xff, 0x2f, 0x11, 0x00, 0x00, 0xa0, 0xe1,
|
0x0f, 0xe0, 0xa0, 0xe1, 0x1b, 0xff, 0x2f, 0x11, 0x00, 0x00, 0xa0, 0xe1,
|
||||||
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1,
|
0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x40, 0xbd, 0xe8,
|
||||||
0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3, 0x00, 0x10, 0xbd, 0xe8,
|
0x93, 0xf0, 0x29, 0xe3, 0x00, 0x10, 0xbd, 0xe8, 0x0c, 0xf0, 0x69, 0xe1,
|
||||||
0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8, 0x0e, 0xf0, 0xb0, 0xe1,
|
0x10, 0x58, 0xbd, 0xe8, 0x0e, 0xf0, 0xb0, 0xe1, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3, 0xb0, 0x01, 0x00, 0x00,
|
0x04, 0x20, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||||
0xb0, 0x01, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
0xb0, 0x01, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||||
0xcc, 0x01, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
0xcc, 0x01, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
|
||||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
0x48, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
|
||||||
0xb0, 0x01, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00,
|
0x48, 0x03, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00,
|
||||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||||
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00,
|
||||||
|
@ -72,5 +72,6 @@ const uint8_t hleBios[SIZE_BIOS] = {
|
||||||
0x01, 0x70, 0xa0, 0xe1, 0x01, 0x80, 0xa0, 0xe1, 0x01, 0x90, 0xa0, 0xe1,
|
0x01, 0x70, 0xa0, 0xe1, 0x01, 0x80, 0xa0, 0xe1, 0x01, 0x90, 0xa0, 0xe1,
|
||||||
0x01, 0xa0, 0xa0, 0xe1, 0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8,
|
0x01, 0xa0, 0xa0, 0xe1, 0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8,
|
||||||
0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8, 0x00, 0x10, 0xa0, 0xe3,
|
0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8, 0x00, 0x10, 0xa0, 0xe3,
|
||||||
0xf0, 0x07, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0xb0, 0x01, 0x00, 0x00
|
0xf0, 0x07, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0xb0, 0x01, 0x00, 0x00,
|
||||||
|
0x04, 0x40, 0x54, 0xe2, 0xfd, 0xff, 0xff, 0x8a, 0x1e, 0xff, 0x2f, 0xe1
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,25 +25,26 @@ bx r0
|
||||||
.word 0
|
.word 0
|
||||||
.word 0xE129F000
|
.word 0xE129F000
|
||||||
|
|
||||||
|
.word 0 @ Padding for back-compat
|
||||||
|
|
||||||
swiBase:
|
swiBase:
|
||||||
cmp sp, #0
|
cmp sp, #0
|
||||||
moveq sp, #0x04000000
|
moveq sp, #0x04000000
|
||||||
subeq sp, #0x20
|
subeq sp, #0x20
|
||||||
stmfd sp!, {r11-r12, lr}
|
stmfd sp!, {r4, r11-r12, lr}
|
||||||
ldrb r11, [lr, #-2]
|
ldrb r11, [lr, #-2]
|
||||||
mov r12, #swiTable
|
mov r12, #swiTable
|
||||||
ldr r11, [r12, r11, lsl #2]
|
ldr r11, [r12, r11, lsl #2]
|
||||||
cmp r11, #0
|
mov r12, #StallCall
|
||||||
|
cmp r12, r11
|
||||||
|
swieq 0xF00000 @ Special mGBA-internal call to load the stall count into r4
|
||||||
mrs r12, spsr
|
mrs r12, spsr
|
||||||
stmfd sp!, {r12}
|
stmfd sp!, {r12}
|
||||||
and r12, #0x80
|
and r12, #0x80
|
||||||
orr r12, #0x1F
|
orr r12, #0x1F
|
||||||
msr cpsr, r12
|
msr cpsr_c, r12
|
||||||
stmfd sp!, {lr}
|
stmfd sp!, {lr}
|
||||||
nop
|
cmp r11, #0
|
||||||
nop
|
|
||||||
nop
|
|
||||||
nop
|
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
|
@ -55,16 +56,17 @@ bxne r11
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
|
||||||
ldmfd sp!, {lr}
|
ldmfd sp!, {lr}
|
||||||
msr cpsr, #0x93
|
msr cpsr, #0x93
|
||||||
ldmfd sp!, {r12}
|
ldmfd sp!, {r12}
|
||||||
msr spsr, r12
|
msr spsr, r12
|
||||||
ldmfd sp!, {r11-r12, lr}
|
ldmfd sp!, {r4, r11-r12, lr}
|
||||||
movs pc, lr
|
movs pc, lr
|
||||||
.word 0
|
.word 0
|
||||||
.word 0xE3A02004
|
.word 0xE3A02004
|
||||||
|
|
||||||
|
.word 0 @ Padding for back-compat
|
||||||
|
|
||||||
swiTable:
|
swiTable:
|
||||||
.word SoftReset @ 0x00
|
.word SoftReset @ 0x00
|
||||||
.word RegisterRamReset @ 0x01
|
.word RegisterRamReset @ 0x01
|
||||||
|
@ -131,11 +133,6 @@ subs pc, lr, #4
|
||||||
SoftReset:
|
SoftReset:
|
||||||
RegisterRamReset:
|
RegisterRamReset:
|
||||||
Stop:
|
Stop:
|
||||||
Div:
|
|
||||||
DivArm:
|
|
||||||
Sqrt:
|
|
||||||
ArcTan:
|
|
||||||
ArcTan2:
|
|
||||||
GetBiosChecksum:
|
GetBiosChecksum:
|
||||||
BgAffineSet:
|
BgAffineSet:
|
||||||
ObjAffineSet:
|
ObjAffineSet:
|
||||||
|
@ -305,3 +302,14 @@ ldmfd sp!, {r4-r10}
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
.ltorg
|
.ltorg
|
||||||
|
|
||||||
|
Div:
|
||||||
|
DivArm:
|
||||||
|
Sqrt:
|
||||||
|
ArcTan:
|
||||||
|
ArcTan2:
|
||||||
|
|
||||||
|
StallCall:
|
||||||
|
subs r4, #4
|
||||||
|
bhi StallCall
|
||||||
|
bx lr
|
||||||
|
|
|
@ -800,6 +800,7 @@ static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer*
|
||||||
bg->overflow = GBARegisterBGCNTGetOverflow(value);
|
bg->overflow = GBARegisterBGCNTGetOverflow(value);
|
||||||
bg->size = GBARegisterBGCNTGetSize(value);
|
bg->size = GBARegisterBGCNTGetSize(value);
|
||||||
bg->control = value;
|
bg->control = value;
|
||||||
|
bg->yCache = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBAVideoSoftwareRendererWriteBGX_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
|
static void GBAVideoSoftwareRendererWriteBGX_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
|
||||||
|
|
|
@ -69,6 +69,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
||||||
}
|
}
|
||||||
miscFlags = GBASerializedMiscFlagsSetBlocked(miscFlags, gba->cpuBlocked);
|
miscFlags = GBASerializedMiscFlagsSetBlocked(miscFlags, gba->cpuBlocked);
|
||||||
STORE_32(miscFlags, 0, &state->miscFlags);
|
STORE_32(miscFlags, 0, &state->miscFlags);
|
||||||
|
STORE_32(gba->biosStall, 0, &state->nextIrq);
|
||||||
|
|
||||||
GBAMemorySerialize(&gba->memory, state);
|
GBAMemorySerialize(&gba->memory, state);
|
||||||
GBAIOSerialize(gba, state);
|
GBAIOSerialize(gba, state);
|
||||||
|
@ -187,6 +188,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
||||||
mTimingSchedule(&gba->timing, &gba->irqEvent, when);
|
mTimingSchedule(&gba->timing, &gba->irqEvent, when);
|
||||||
}
|
}
|
||||||
gba->cpuBlocked = GBASerializedMiscFlagsGetBlocked(miscFlags);
|
gba->cpuBlocked = GBASerializedMiscFlagsGetBlocked(miscFlags);
|
||||||
|
LOAD_32(gba->biosStall, 0, &state->nextIrq);
|
||||||
|
|
||||||
GBAVideoDeserialize(&gba->video, state);
|
GBAVideoDeserialize(&gba->video, state);
|
||||||
GBAMemoryDeserialize(&gba->memory, state);
|
GBAMemoryDeserialize(&gba->memory, state);
|
||||||
|
|
|
@ -95,7 +95,7 @@ static int activeOutputTexture = 0;
|
||||||
static ndspWaveBuf dspBuffer[DSP_BUFFERS];
|
static ndspWaveBuf dspBuffer[DSP_BUFFERS];
|
||||||
static int bufferId = 0;
|
static int bufferId = 0;
|
||||||
static bool frameLimiter = true;
|
static bool frameLimiter = true;
|
||||||
static u64 tickCounter;
|
static u32 frameCounter;
|
||||||
|
|
||||||
static C3D_RenderTarget* topScreen[2];
|
static C3D_RenderTarget* topScreen[2];
|
||||||
static C3D_RenderTarget* bottomScreen[2];
|
static C3D_RenderTarget* bottomScreen[2];
|
||||||
|
@ -107,7 +107,6 @@ static C3D_Tex upscaleBufferTex;
|
||||||
static bool interframeBlending = false;
|
static bool interframeBlending = false;
|
||||||
static bool sgbCrop = false;
|
static bool sgbCrop = false;
|
||||||
|
|
||||||
static aptHookCookie cookie;
|
|
||||||
static bool core2;
|
static bool core2;
|
||||||
|
|
||||||
static bool _initGpu(void) {
|
static bool _initGpu(void) {
|
||||||
|
@ -190,18 +189,6 @@ static void _cleanup(void) {
|
||||||
ptmuExit();
|
ptmuExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _aptHook(APT_HookType hook, void* user) {
|
|
||||||
UNUSED(user);
|
|
||||||
switch (hook) {
|
|
||||||
case APTHOOK_ONEXIT:
|
|
||||||
_cleanup();
|
|
||||||
exit(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _map3DSKey(struct mInputMap* map, int ctrKey, enum GBAKey key) {
|
static void _map3DSKey(struct mInputMap* map, int ctrKey, enum GBAKey key) {
|
||||||
mInputBindKey(map, _3DS_INPUT, __builtin_ctz(ctrKey), key);
|
mInputBindKey(map, _3DS_INPUT, __builtin_ctz(ctrKey), key);
|
||||||
}
|
}
|
||||||
|
@ -213,11 +200,17 @@ static void _drawStart(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
frameStarted = true;
|
frameStarted = true;
|
||||||
|
|
||||||
|
int screen = screenMode >= SM_PA_TOP ? GSP_SCREEN_TOP : GSP_SCREEN_BOTTOM;
|
||||||
if (frameLimiter) {
|
if (frameLimiter) {
|
||||||
if (tickCounter + 4481000 > svcGetSystemTick()) {
|
u32 oldFrame = frameCounter;
|
||||||
C3D_FrameSync();
|
frameCounter = C3D_FrameCounter(screen);
|
||||||
|
while (oldFrame == frameCounter) {
|
||||||
|
gspWaitForAnyEvent();
|
||||||
|
frameCounter = C3D_FrameCounter(screen);
|
||||||
}
|
}
|
||||||
tickCounter = svcGetSystemTick();
|
} else {
|
||||||
|
frameCounter = C3D_FrameCounter(screen);
|
||||||
}
|
}
|
||||||
C3D_FrameBegin(0);
|
C3D_FrameBegin(0);
|
||||||
ctrStartFrame();
|
ctrStartFrame();
|
||||||
|
@ -350,7 +343,7 @@ static void _gameLoaded(struct mGUIRunner* runner) {
|
||||||
}
|
}
|
||||||
osSetSpeedupEnable(true);
|
osSetSpeedupEnable(true);
|
||||||
|
|
||||||
double ratio = GBAAudioCalculateRatio(1, 59.8260982880808, 1);
|
double ratio = GBAAudioCalculateRatio(1, 268111856.f / 4481136.f, 1);
|
||||||
blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 32768 * ratio);
|
blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 32768 * ratio);
|
||||||
blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 32768 * ratio);
|
blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 32768 * ratio);
|
||||||
if (hasSound != NO_SOUND) {
|
if (hasSound != NO_SOUND) {
|
||||||
|
@ -659,7 +652,6 @@ static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
frameLimiter = limit;
|
frameLimiter = limit;
|
||||||
tickCounter = svcGetSystemTick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _running(struct mGUIRunner* runner) {
|
static bool _running(struct mGUIRunner* runner) {
|
||||||
|
@ -822,8 +814,6 @@ int main() {
|
||||||
camera.bufferSize = 0;
|
camera.bufferSize = 0;
|
||||||
camera.cam = SELECT_IN1;
|
camera.cam = SELECT_IN1;
|
||||||
|
|
||||||
aptHook(&cookie, _aptHook, 0);
|
|
||||||
|
|
||||||
ptmuInit();
|
ptmuInit();
|
||||||
camInit();
|
camInit();
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,9 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QLocale locale(name.remove(QString("%0-").arg(binaryName)).remove(".qm"));
|
QLocale locale(name.remove(QString("%0-").arg(binaryName)).remove(".qm"));
|
||||||
|
if (locale.language() == QLocale::English) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
m_ui.languages->addItem(locale.nativeLanguageName(), locale);
|
m_ui.languages->addItem(locale.nativeLanguageName(), locale);
|
||||||
if (locale.bcp47Name() == QLocale().bcp47Name()) {
|
if (locale.bcp47Name() == QLocale().bcp47Name()) {
|
||||||
m_ui.languages->setCurrentIndex(m_ui.languages->count() - 1);
|
m_ui.languages->setCurrentIndex(m_ui.languages->count() - 1);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1" language="en" sourcelanguage="en_US">
|
||||||
|
</TS>
|