Merge branch 'master' into feature/input-revamp

This commit is contained in:
Vicki Pfau 2017-07-06 15:16:53 -07:00
commit 97e2004fd3
35 changed files with 5165 additions and 472 deletions

33
CHANGES
View File

@ -1,3 +1,7 @@
0.7.0: (Future)
Misc:
- GBA Timer: Use global cycles for timers
0.6.0: (Future)
Features:
- GBA: Support printing debug strings from inside a game
@ -25,6 +29,7 @@ Features:
- LR35902: Watchpoints
- Memory search
- Debugger: Execution tracing
- Qt: Italian translation (by theheroGAC)
Bugfixes:
- LR35902: Fix core never exiting with certain event patterns
- GB Timer: Improve DIV reset behavior
@ -73,6 +78,10 @@ Bugfixes:
- OpenGL: Fix some shaders causing offset graphics
- Qt: Fix game unpausing after frame advancing and refocusing
- GB Timer: Fix sub-M-cycle DIV reset timing and edge triggering
- Core: Fix interrupting a thread while on the thread (fixes mgba.io/i/692)
- Core: Fix directory sets crashing on close if base isn't properly detached
- Qt: Fix window icon being stretched
- Qt: Fix data directory path
Misc:
- SDL: Remove scancode key input
- GBA Video: Clean up unused timers
@ -142,6 +151,30 @@ Misc:
- GB: Reset with initial state of DIV register
- GB MBC: New MBC7 implementation
- Qt: Better highlight active key in control binding
- Core: Improved threading interrupted detection
- GBA Timer: Improve accuracy of timers
0.6 beta 2: (Future)
Features:
- Qt: Italian translation (by theheroGAC)
- Qt: Updated German translation
Bugfixes:
- Qt: Fix memory search close button (fixes mgba.io/i/769)
- Qt: Fix window icon being stretched
- Qt: Fix initial window size (fixes mgba.io/i/766)
- Qt: Fix data directory path
- Qt: Fix controls not saving on non-SDL builds
- GB Video: Fix LYC regression
- Qt: Fix translation initialization (fixes mgba.io/i/776)
- PSP2: Use custom localtime_r since newlib version is broken (fixes mgba.io/i/560)
Misc:
- Qt: Add language selector
- GBA Timer: Improve accuracy of timers
- Qt: Minor test fixes
- PSP2: Update toolchain to use vita.cmake
0.6 beta 1: (2017-06-29)
- Initial beta for 0.6
0.5.2: (2016-12-31)
Bugfixes:

View File

@ -275,7 +275,9 @@ endif()
include(CheckFunctionExists)
check_function_exists(strdup HAVE_STRDUP)
check_function_exists(strndup HAVE_STRNDUP)
check_function_exists(localtime_r HAVE_LOCALTIME_R)
if(NOT DEFINED PSP2)
check_function_exists(localtime_r HAVE_LOCALTIME_R)
endif()
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
check_function_exists(snprintf_l HAVE_SNPRINTF_L)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@ -843,7 +845,6 @@ if(BUILD_EXAMPLE)
endif()
endif()
message(STATUS ${USE_PTHREADS})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/flags.h.in ${CMAKE_CURRENT_BINARY_DIR}/flags.h)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/flags.h DESTINATION include/mgba COMPONENT lib${BINARY_NAME})
@ -897,6 +898,7 @@ else()
endif()
if(NOT QUIET)
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Platforms:")
message(STATUS " Game Boy Advance: ${M_CORE_GBA}")
message(STATUS " Game Boy: ${M_CORE_GB}")

View File

@ -264,10 +264,10 @@ struct GBASerializedState {
struct {
uint16_t reload;
uint16_t oldReload;
uint16_t reserved;
uint32_t lastEvent;
uint32_t nextEvent;
int32_t overflowInterval;
uint32_t nextIrq;
GBATimerFlags flags;
} timers[4];

View File

@ -17,19 +17,19 @@ DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4);
DECL_BIT(GBATimerFlags, CountUp, 4);
DECL_BIT(GBATimerFlags, DoIrq, 5);
DECL_BIT(GBATimerFlags, Enable, 6);
DECL_BIT(GBATimerFlags, IrqPending, 7);
struct GBA;
struct GBATimer {
uint16_t reload;
uint16_t oldReload;
uint32_t lastEvent;
int32_t lastEvent;
struct mTimingEvent event;
int32_t overflowInterval;
struct mTimingEvent irq;
GBATimerFlags flags;
};
void GBATimerInit(struct GBA* gba);
void GBATimerUpdateRegister(struct GBA* gba, int timer);
void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate);
void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t value);
void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t value);

View File

@ -3,6 +3,7 @@ Fog
Reilly Grant
Philip Horton
Jordan Jorgensen
mars
Rohit Nirmal
Rhys Powell
rootfather

View File

@ -22,7 +22,7 @@
#include <mgba/feature/video-logger.h>
#endif
const static struct mCoreFilter {
static const struct mCoreFilter {
bool (*filter)(struct VFile*);
struct mCore* (*open)(void);
enum mPlatform platform;

View File

@ -22,28 +22,58 @@ void mDirectorySetDeinit(struct mDirectorySet* dirs) {
mDirectorySetDetachBase(dirs);
if (dirs->archive) {
if (dirs->archive == dirs->save) {
dirs->save = NULL;
}
if (dirs->archive == dirs->patch) {
dirs->patch = NULL;
}
if (dirs->archive == dirs->state) {
dirs->state = NULL;
}
if (dirs->archive == dirs->screenshot) {
dirs->screenshot = NULL;
}
dirs->archive->close(dirs->archive);
dirs->archive = 0;
dirs->archive = NULL;
}
if (dirs->save) {
if (dirs->save == dirs->patch) {
dirs->patch = NULL;
}
if (dirs->save == dirs->state) {
dirs->state = NULL;
}
if (dirs->save == dirs->screenshot) {
dirs->screenshot = NULL;
}
dirs->save->close(dirs->save);
dirs->save = 0;
dirs->save = NULL;
}
if (dirs->patch) {
if (dirs->patch == dirs->state) {
dirs->state = NULL;
}
if (dirs->patch == dirs->screenshot) {
dirs->screenshot = NULL;
}
dirs->patch->close(dirs->patch);
dirs->patch = 0;
dirs->patch = NULL;
}
if (dirs->state) {
if (dirs->state == dirs->screenshot) {
dirs->state = NULL;
}
dirs->state->close(dirs->state);
dirs->state = 0;
dirs->state = NULL;
}
if (dirs->screenshot) {
dirs->screenshot->close(dirs->screenshot);
dirs->screenshot = 0;
dirs->screenshot = NULL;
}
}
@ -65,21 +95,21 @@ void mDirectorySetAttachBase(struct mDirectorySet* dirs, struct VDir* base) {
void mDirectorySetDetachBase(struct mDirectorySet* dirs) {
if (dirs->save == dirs->base) {
dirs->save = 0;
dirs->save = NULL;
}
if (dirs->patch == dirs->base) {
dirs->patch = 0;
dirs->patch = NULL;
}
if (dirs->state == dirs->base) {
dirs->state = 0;
dirs->state = NULL;
}
if (dirs->screenshot == dirs->base) {
dirs->screenshot = 0;
dirs->screenshot = NULL;
}
if (dirs->base) {
dirs->base->close(dirs->base);
dirs->base = 0;
dirs->base = NULL;
}
}

View File

@ -401,11 +401,14 @@ void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex);
++threadContext->interruptDepth;
if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) {
if (threadContext->state == THREAD_INTERRUPTING) {
threadContext->state = THREAD_INTERRUPTED;
}
MutexUnlock(&threadContext->stateMutex);
return;
}
threadContext->savedState = threadContext->state;
threadContext->state = THREAD_INTERRUPTING;
threadContext->state = THREAD_INTERRUPTED;
ConditionWake(&threadContext->stateCond);
MutexUnlock(&threadContext->stateMutex);
}
@ -465,7 +468,7 @@ void mCoreThreadUnpause(struct mCoreThread* threadContext) {
bool mCoreThreadIsPaused(struct mCoreThread* threadContext) {
bool isPaused;
MutexLock(&threadContext->stateMutex);
if (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) {
if (threadContext->interruptDepth) {
isPaused = threadContext->savedState == THREAD_PAUSED;
} else {
isPaused = threadContext->state == THREAD_PAUSED;
@ -495,7 +498,7 @@ void mCoreThreadTogglePause(struct mCoreThread* threadContext) {
void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) {
bool frameOn = true;
MutexLock(&threadContext->stateMutex);
if (threadContext->state == THREAD_RUNNING || (threadContext->state == THREAD_INTERRUPTING && threadContext->savedState == THREAD_RUNNING)) {
if (threadContext->state == THREAD_RUNNING || (threadContext->interruptDepth && threadContext->savedState == THREAD_RUNNING)) {
threadContext->state = THREAD_PAUSING;
frameOn = false;
}
@ -506,11 +509,11 @@ void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) {
void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding) {
MutexLock(&threadContext->stateMutex);
if (rewinding && (threadContext->state == THREAD_REWINDING || (threadContext->state == THREAD_INTERRUPTING && threadContext->savedState == THREAD_REWINDING))) {
if (rewinding && (threadContext->state == THREAD_REWINDING || (threadContext->interruptDepth && threadContext->savedState == THREAD_REWINDING))) {
MutexUnlock(&threadContext->stateMutex);
return;
}
if (!rewinding && (threadContext->state == THREAD_RUNNING || (threadContext->state == THREAD_INTERRUPTING && threadContext->savedState == THREAD_RUNNING))) {
if (!rewinding && ((!threadContext->interruptDepth && threadContext->state != THREAD_REWINDING) || (threadContext->interruptDepth && threadContext->savedState != THREAD_REWINDING))) {
MutexUnlock(&threadContext->stateMutex);
return;
}
@ -526,7 +529,7 @@ void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding)
void mCoreThreadWaitFromThread(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex);
if ((threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) && threadContext->savedState == THREAD_RUNNING) {
if (threadContext->interruptDepth && threadContext->savedState == THREAD_RUNNING) {
threadContext->savedState = THREAD_WAITING;
} else if (threadContext->state == THREAD_RUNNING) {
threadContext->state = THREAD_WAITING;
@ -536,7 +539,7 @@ void mCoreThreadWaitFromThread(struct mCoreThread* threadContext) {
void mCoreThreadStopWaiting(struct mCoreThread* threadContext) {
MutexLock(&threadContext->stateMutex);
if ((threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) && threadContext->savedState == THREAD_WAITING) {
if (threadContext->interruptDepth && threadContext->savedState == THREAD_WAITING) {
threadContext->savedState = THREAD_RUNNING;
} else if (threadContext->state == THREAD_WAITING) {
threadContext->state = THREAD_RUNNING;

View File

@ -26,7 +26,7 @@
const char mVL_MAGIC[] = "mVL\0";
const static struct mVLDescriptor {
static const struct mVLDescriptor {
enum mPlatform platform;
struct mCore* (*open)(void);
} _descriptors[] = {

View File

@ -29,26 +29,26 @@
#include <mgba/internal/gba/input.h>
#endif
const static struct mCoreChannelInfo _GBVideoLayers[] = {
static const struct mCoreChannelInfo _GBVideoLayers[] = {
{ 0, "bg", "Background", NULL },
{ 1, "obj", "Objects", NULL },
{ 2, "win", "Window", NULL },
};
const static struct mCoreChannelInfo _GBAudioChannels[] = {
{ 0, "ch0", "Channel 0", "Square/Sweep" },
{ 1, "ch1", "Channel 1", "Square" },
{ 2, "ch2", "Channel 2", "PCM" },
{ 3, "ch3", "Channel 3", "Noise" },
static const struct mCoreChannelInfo _GBAudioChannels[] = {
{ 0, "ch1", "Channel 1", "Square/Sweep" },
{ 1, "ch2", "Channel 2", "Square" },
{ 2, "ch3", "Channel 3", "PCM" },
{ 3, "ch4", "Channel 4", "Noise" },
};
const static struct LR35902Segment _GBSegments[] = {
static const struct LR35902Segment _GBSegments[] = {
{ .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
{ .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
{ 0 }
};
const static struct LR35902Segment _GBCSegments[] = {
static const struct LR35902Segment _GBCSegments[] = {
{ .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
{ .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
{ .name = "WRAM", .start = GB_BASE_WORKING_RAM_BANK1, .end = 0xE000 },
@ -56,7 +56,7 @@ const static struct LR35902Segment _GBCSegments[] = {
{ 0 }
};
const static struct mCoreMemoryBlock _GBMemoryBlocks[] = {
static const struct mCoreMemoryBlock _GBMemoryBlocks[] = {
{ -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
{ GB_REGION_VRAM, "vram", "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_BASE_VRAM + GB_SIZE_VRAM, GB_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
@ -67,7 +67,7 @@ const static struct mCoreMemoryBlock _GBMemoryBlocks[] = {
{ GB_BASE_HRAM, "hram", "HRAM", "High RAM", GB_BASE_HRAM, GB_BASE_HRAM + GB_SIZE_HRAM, GB_SIZE_HRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
};
const static struct mCoreMemoryBlock _GBCMemoryBlocks[] = {
static const struct mCoreMemoryBlock _GBCMemoryBlocks[] = {
{ -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
{ GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
{ GB_REGION_VRAM, "vram", "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_BASE_VRAM + GB_SIZE_VRAM, GB_SIZE_VRAM * 2, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },

View File

@ -558,7 +558,7 @@ void GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
return;
case 0x10:
mbc7->latch |= (value & 0xAA);
if (mbc7->latch == 0xFF && memory->rotation && memory->rotation->sample) {
if (mbc7->latch == 0xAB && memory->rotation && memory->rotation->sample) {
memory->rotation->sample(memory->rotation);
}
mbc7->latch = 0;

View File

@ -74,7 +74,7 @@ void GBTimerDivReset(struct GBTimer* timer) {
if (timer->internalDiv & (timer->timaPeriod >> 1)) {
++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, 4 - ((timer->p->cpu->executionState + 1) & 3));
}
}
timer->p->memory.io[REG_DIV] = 0;

View File

@ -386,6 +386,7 @@ void GBVideoWriteLYC(struct GBVideo* video, uint8_t value) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
GBUpdateIRQs(video->p);
}
video->p->memory.io[REG_STAT] = video->stat;
}
void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) {

View File

@ -28,7 +28,7 @@
#include <mgba/internal/gba/input.h>
#endif
const static struct mCoreChannelInfo _GBAVideoLayers[] = {
static const struct mCoreChannelInfo _GBAVideoLayers[] = {
{ 0, "bg0", "Background 0", NULL },
{ 1, "bg1", "Background 1", NULL },
{ 2, "bg2", "Background 2", NULL },
@ -36,16 +36,16 @@ const static struct mCoreChannelInfo _GBAVideoLayers[] = {
{ 4, "obj", "Objects", NULL },
};
const static struct mCoreChannelInfo _GBAAudioChannels[] = {
{ 0, "ch0", "PSG Channel 0", "Square/Sweep" },
{ 1, "ch1", "PSG Channel 1", "Square" },
{ 2, "ch2", "PSG Channel 2", "PCM" },
{ 3, "ch3", "PSG Channel 3", "Noise" },
static const struct mCoreChannelInfo _GBAAudioChannels[] = {
{ 0, "ch1", "PSG Channel 1", "Square/Sweep" },
{ 1, "ch2", "PSG Channel 2", "Square" },
{ 2, "ch3", "PSG Channel 3", "PCM" },
{ 3, "ch4", "PSG Channel 4", "Noise" },
{ 4, "chA", "FIFO Channel A", NULL },
{ 5, "chB", "FIFO Channel B", NULL },
};
const static struct mCoreMemoryBlock _GBAMemoryBlocks[] = {
static const struct mCoreMemoryBlock _GBAMemoryBlocks[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
@ -59,7 +59,7 @@ const static struct mCoreMemoryBlock _GBAMemoryBlocks[] = {
{ REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
};
const static struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
@ -74,7 +74,7 @@ const static struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
{ REGION_CART_SRAM, "sram", "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_SRAM, SIZE_CART_SRAM, true },
};
const static struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = {
static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
@ -89,7 +89,7 @@ const static struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = {
{ REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
};
const static struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = {
static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
@ -104,7 +104,7 @@ const static struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = {
{ REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
};
const static struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = {
static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = {
{ -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
{ REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
{ REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },

View File

@ -707,17 +707,18 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
}
switch (address) {
// Reading this takes two cycles (1N+1I), so let's remove them preemptively
case REG_TM0CNT_LO:
GBATimerUpdateRegister(gba, 0);
GBATimerUpdateRegister(gba, 0, 2);
break;
case REG_TM1CNT_LO:
GBATimerUpdateRegister(gba, 1);
GBATimerUpdateRegister(gba, 1, 2);
break;
case REG_TM2CNT_LO:
GBATimerUpdateRegister(gba, 2);
GBATimerUpdateRegister(gba, 2, 2);
break;
case REG_TM3CNT_LO:
GBATimerUpdateRegister(gba, 3);
GBATimerUpdateRegister(gba, 3, 2);
break;
case REG_KEYINPUT:
@ -925,10 +926,9 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
for (i = 0; i < 4; ++i) {
STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io);
STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload);
STORE_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload);
STORE_32(gba->timers[i].lastEvent - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].lastEvent);
STORE_32(gba->timers[i].event.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextEvent);
STORE_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval);
STORE_32(gba->timers[i].irq.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextIrq);
STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags);
STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);
STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
@ -954,8 +954,6 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
uint32_t when;
for (i = 0; i < 4; ++i) {
LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload);
LOAD_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload);
LOAD_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval);
LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags);
if (i > 0 && GBATimerFlagsIsCountUp(gba->timers[i].flags)) {
// Overwrite invalid values in savestate
@ -968,6 +966,10 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
if (GBATimerFlagsIsEnable(gba->timers[i].flags)) {
mTimingSchedule(&gba->timing, &gba->timers[i].event, when);
}
LOAD_32(when, 0, &state->timers[i].nextIrq);
if (GBATimerFlagsIsIrqPending(gba->timers[i].flags)) {
mTimingSchedule(&gba->timing, &gba->timers[i].irq, when);
}
LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io);
LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);

View File

@ -8,14 +8,56 @@
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>
static void GBATimerUpdate(struct mTiming* timing, struct GBA* gba, int timerId, uint32_t cyclesLate) {
#define TIMER_IRQ_DELAY 7
#define TIMER_RELOAD_DELAY 0
#define TIMER_STARTUP_DELAY 2
static void GBATimerIrq(struct GBA* gba, int timerId) {
struct GBATimer* timer = &gba->timers[timerId];
if (GBATimerFlagsIsIrqPending(timer->flags)) {
timer->flags = GBATimerFlagsClearIrqPending(timer->flags);
GBARaiseIRQ(gba, IRQ_TIMER0 + timerId);
}
}
static void GBATimerIrq0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
GBATimerIrq(context, 0);
}
static void GBATimerIrq1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
GBATimerIrq(context, 1);
}
static void GBATimerIrq2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
GBATimerIrq(context, 2);
}
static void GBATimerIrq3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
GBATimerIrq(context, 3);
}
static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) {
struct GBATimer* timer = &gba->timers[timerId];
gba->memory.io[(REG_TM0CNT_LO >> 1) + (timerId << 1)] = timer->reload;
timer->oldReload = timer->reload;
timer->lastEvent = timing->masterCycles - cyclesLate;
int32_t currentTime = mTimingCurrentTime(&gba->timing) - cyclesLate;
int32_t tickMask = (1 << GBATimerFlagsGetPrescaleBits(timer->flags)) - 1;
currentTime &= ~tickMask;
timer->lastEvent = currentTime;
GBATimerUpdateRegister(gba, timerId, 0);
if (GBATimerFlagsIsDoIrq(timer->flags)) {
GBARaiseIRQ(gba, IRQ_TIMER0 + timerId);
timer->flags = GBATimerFlagsFillIrqPending(timer->flags);
if (!mTimingIsScheduled(&gba->timing, &timer->irq)) {
mTimingSchedule(&gba->timing, &timer->irq, TIMER_IRQ_DELAY - cyclesLate);
}
}
if (gba->audio.enable && timerId < 2) {
@ -33,31 +75,30 @@ static void GBATimerUpdate(struct mTiming* timing, struct GBA* gba, int timerId,
if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled?
++gba->memory.io[(REG_TM1CNT_LO >> 1) + (timerId << 1)];
if (!gba->memory.io[(REG_TM1CNT_LO >> 1) + (timerId << 1)] && GBATimerFlagsIsEnable(nextTimer->flags)) {
mTimingSchedule(timing, &nextTimer->event, -cyclesLate);
GBATimerUpdate(gba, timerId + 1, cyclesLate);
}
}
}
if (!GBATimerFlagsIsCountUp(timer->flags)) {
uint32_t nextEvent = timer->overflowInterval - cyclesLate;
mTimingSchedule(timing, &timer->event, nextEvent);
}
}
static void GBATimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
GBATimerUpdate(timing, context, 0, cyclesLate);
UNUSED(timing);
GBATimerUpdate(context, 0, cyclesLate);
}
static void GBATimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
GBATimerUpdate(timing, context, 1, cyclesLate);
UNUSED(timing);
GBATimerUpdate(context, 1, cyclesLate);
}
static void GBATimerUpdate2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
GBATimerUpdate(timing, context, 2, cyclesLate);
UNUSED(timing);
GBATimerUpdate(context, 2, cyclesLate);
}
static void GBATimerUpdate3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
GBATimerUpdate(timing, context, 3, cyclesLate);
UNUSED(timing);
GBATimerUpdate(context, 3, cyclesLate);
}
void GBATimerInit(struct GBA* gba) {
@ -78,62 +119,91 @@ void GBATimerInit(struct GBA* gba) {
gba->timers[3].event.callback = GBATimerUpdate3;
gba->timers[3].event.context = gba;
gba->timers[3].event.priority = 0x23;
gba->timers[0].irq.name = "GBA Timer 0 IRQ";
gba->timers[0].irq.callback = GBATimerIrq0;
gba->timers[0].irq.context = gba;
gba->timers[0].irq.priority = 0x28;
gba->timers[1].irq.name = "GBA Timer 1 IRQ";
gba->timers[1].irq.callback = GBATimerIrq1;
gba->timers[1].irq.context = gba;
gba->timers[1].irq.priority = 0x29;
gba->timers[2].irq.name = "GBA Timer 2 IRQ";
gba->timers[2].irq.callback = GBATimerIrq2;
gba->timers[2].irq.context = gba;
gba->timers[2].irq.priority = 0x2A;
gba->timers[3].irq.name = "GBA Timer 3 IRQ";
gba->timers[3].irq.callback = GBATimerIrq3;
gba->timers[3].irq.context = gba;
gba->timers[3].irq.priority = 0x2B;
}
void GBATimerUpdateRegister(struct GBA* gba, int timer) {
void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate) {
struct GBATimer* currentTimer = &gba->timers[timer];
if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
int32_t prefetchSkew = -2;
if (gba->memory.lastPrefetchedPc > (uint32_t) gba->cpu->gprs[ARM_PC]) {
prefetchSkew += ((gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * gba->cpu->memory.activeSeqCycles16) / WORD_SIZE_THUMB;
}
// Reading this takes two cycles (1N+1I), so let's remove them preemptively
int32_t diff = gba->cpu->cycles - (currentTimer->lastEvent - gba->timing.masterCycles);
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((diff + prefetchSkew) >> GBATimerFlagsGetPrescaleBits(currentTimer->flags));
if (!GBATimerFlagsIsEnable(currentTimer->flags) || GBATimerFlagsIsCountUp(currentTimer->flags)) {
return;
}
if (gba->memory.lastPrefetchedPc > (uint32_t) gba->cpu->gprs[ARM_PC]) {
cyclesLate -= ((gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * gba->cpu->memory.activeSeqCycles16) / WORD_SIZE_THUMB;
}
int prescaleBits = GBATimerFlagsGetPrescaleBits(currentTimer->flags);
int32_t currentTime = mTimingCurrentTime(&gba->timing) - cyclesLate;
int32_t tickMask = (1 << prescaleBits) - 1;
currentTime &= ~tickMask;
int32_t tickIncrement = currentTime - currentTimer->lastEvent;
currentTimer->lastEvent = currentTime;
tickIncrement >>= prescaleBits;
tickIncrement += gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1];
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = tickIncrement;
if (!mTimingIsScheduled(&gba->timing, &currentTimer->event)) {
tickIncrement = (0x10000 - tickIncrement) << prescaleBits;
currentTime -= mTimingCurrentTime(&gba->timing) - cyclesLate;
mTimingSchedule(&gba->timing, &currentTimer->event, TIMER_RELOAD_DELAY + tickIncrement + currentTime);
}
}
void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
gba->timers[timer].reload = reload;
gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << GBATimerFlagsGetPrescaleBits(gba->timers[timer].flags);
}
void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
struct GBATimer* currentTimer = &gba->timers[timer];
GBATimerUpdateRegister(gba, timer);
GBATimerUpdateRegister(gba, timer, 0);
unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(currentTimer->flags);
unsigned prescaleBits;
switch (control & 0x0003) {
case 0x0000:
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 0);
prescaleBits = 0;
break;
case 0x0001:
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 6);
prescaleBits = 6;
break;
case 0x0002:
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 8);
prescaleBits = 8;
break;
case 0x0003:
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 10);
prescaleBits = 10;
break;
}
currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, prescaleBits);
currentTimer->flags = GBATimerFlagsTestFillCountUp(currentTimer->flags, timer > 0 && (control & 0x0004));
currentTimer->flags = GBATimerFlagsTestFillDoIrq(currentTimer->flags, control & 0x0040);
currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << GBATimerFlagsGetPrescaleBits(currentTimer->flags);
bool wasEnabled = GBATimerFlagsIsEnable(currentTimer->flags);
currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080);
if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) {
mTimingDeschedule(&gba->timing, &currentTimer->event);
if (!GBATimerFlagsIsCountUp(currentTimer->flags)) {
mTimingSchedule(&gba->timing, &currentTimer->event, currentTimer->overflowInterval);
}
gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
currentTimer->oldReload = currentTimer->reload;
currentTimer->lastEvent = gba->timing.masterCycles + gba->cpu->cycles;
int32_t tickMask = (1 << prescaleBits) - 1;
currentTimer->lastEvent = (mTimingCurrentTime(&gba->timing) - TIMER_STARTUP_DELAY) & ~tickMask;
GBATimerUpdateRegister(gba, timer, TIMER_STARTUP_DELAY);
} else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) {
mTimingDeschedule(&gba->timing, &currentTimer->event);
} else if (GBATimerFlagsIsEnable(currentTimer->flags) && GBATimerFlagsGetPrescaleBits(currentTimer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(currentTimer->flags)) {
mTimingDeschedule(&gba->timing, &currentTimer->event);
mTimingSchedule(&gba->timing, &currentTimer->event, currentTimer->overflowInterval - currentTimer->lastEvent);
int32_t tickMask = (1 << prescaleBits) - 1;
currentTimer->lastEvent = (mTimingCurrentTime(&gba->timing) - TIMER_STARTUP_DELAY) & ~tickMask;
GBATimerUpdateRegister(gba, timer, TIMER_STARTUP_DELAY);
}
}

View File

@ -315,24 +315,24 @@ DEFINE_POPPUSH_DECODER_LR35902(HL);
DEFINE_POPPUSH_DECODER_LR35902(AF);
#define DEFINE_CB_2_DECODER_LR35902(NAME, BODY) \
DEFINE_DECODER_LR35902(NAME ## B, info->op1.reg = LR35902_REG_B; BODY) \
DEFINE_DECODER_LR35902(NAME ## C, info->op1.reg = LR35902_REG_C; BODY) \
DEFINE_DECODER_LR35902(NAME ## D, info->op1.reg = LR35902_REG_D; BODY) \
DEFINE_DECODER_LR35902(NAME ## E, info->op1.reg = LR35902_REG_E; BODY) \
DEFINE_DECODER_LR35902(NAME ## H, info->op1.reg = LR35902_REG_H; BODY) \
DEFINE_DECODER_LR35902(NAME ## L, info->op1.reg = LR35902_REG_L; BODY) \
DEFINE_DECODER_LR35902(NAME ## HL, info->op1.reg = LR35902_REG_HL; BODY) \
DEFINE_DECODER_LR35902(NAME ## A, info->op1.reg = LR35902_REG_A; BODY)
DEFINE_DECODER_LR35902(NAME ## B, info->op2.reg = LR35902_REG_B; BODY) \
DEFINE_DECODER_LR35902(NAME ## C, info->op2.reg = LR35902_REG_C; BODY) \
DEFINE_DECODER_LR35902(NAME ## D, info->op2.reg = LR35902_REG_D; BODY) \
DEFINE_DECODER_LR35902(NAME ## E, info->op2.reg = LR35902_REG_E; BODY) \
DEFINE_DECODER_LR35902(NAME ## H, info->op2.reg = LR35902_REG_H; BODY) \
DEFINE_DECODER_LR35902(NAME ## L, info->op2.reg = LR35902_REG_L; BODY) \
DEFINE_DECODER_LR35902(NAME ## HL, info->op2.reg = LR35902_REG_HL; info->op2.flags = LR35902_OP_FLAG_MEMORY; BODY) \
DEFINE_DECODER_LR35902(NAME ## A, info->op2.reg = LR35902_REG_A; BODY)
#define DEFINE_CB_DECODER_LR35902(NAME, BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 0, info->op2.immediate = 1; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 1, info->op2.immediate = 2; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 2, info->op2.immediate = 4; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 3, info->op2.immediate = 8; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 4, info->op2.immediate = 16; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 5, info->op2.immediate = 32; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 6, info->op2.immediate = 64; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 7, info->op2.immediate = 128; BODY)
DEFINE_CB_2_DECODER_LR35902(NAME ## 0, info->op1.immediate = 0; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 1, info->op1.immediate = 1; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 2, info->op1.immediate = 2; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 3, info->op1.immediate = 3; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 4, info->op1.immediate = 4; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 5, info->op1.immediate = 5; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 6, info->op1.immediate = 6; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 7, info->op1.immediate = 7; BODY)
DEFINE_CB_DECODER_LR35902(BIT, info->mnemonic = LR35902_MN_BIT)
DEFINE_CB_DECODER_LR35902(RES, info->mnemonic = LR35902_MN_RES)
@ -496,7 +496,7 @@ static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
}
if (op.flags & LR35902_OP_FLAG_MEMORY) {
strncpy(buffer, "(", blen - 1);
strncpy(buffer, "[", blen - 1);
ADVANCE(1);
}
if (op.reg) {
@ -519,7 +519,7 @@ static int _decodeOperand(struct LR35902Operand op, char* buffer, int blen) {
ADVANCE(1);
}
if (op.flags & LR35902_OP_FLAG_MEMORY) {
strncpy(buffer, ")", blen - 1);
strncpy(buffer, "]", blen - 1);
ADVANCE(1);
}
return total;
@ -544,7 +544,7 @@ int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int bl
}
}
if (info->op1.reg || info->op1.immediate) {
if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) {
written = _decodeOperand(info->op1, buffer, blen);
ADVANCE(written);
}

View File

@ -1,9 +1,7 @@
find_program(FIXUP vita-elf-create)
find_program(MAKE_FSELF vita-make-fself)
find_program(MAKE_SFO vita-mksfoex)
include("${VITASDK}/share/vita.cmake" REQUIRED)
find_program(OBJCOPY ${cross_prefix}objcopy)
find_file(NIDDB db.json PATHS ${VITASDK} ${VITASDK}/bin ${VITASDK}/share)
find_program(STRIP ${cross_prefix}strip)
set(OS_DEFINES IOAPI_NO_64)
set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE)
@ -37,34 +35,16 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o
COMMAND ${OBJCOPY_CMD} backdrop.png ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(${BINARY_NAME}.velf ALL
${STRIP} --strip-unneeded -go ${BINARY_NAME}-stripped.elf ${BINARY_NAME}.elf
COMMAND ${FIXUP} ${BINARY_NAME}-stripped.elf ${BINARY_NAME}.velf ${NIDDB}
DEPENDS ${BINARY_NAME}.elf)
add_custom_target(sce_sys ${CMAKE_COMMAND} -E make_directory sce_sys)
add_custom_target(param.sfo
${MAKE_SFO} ${PROJECT_NAME} -s TITLE_ID=MGBA00001 sce_sys/param.sfo
DEPENDS sce_sys)
add_custom_target(eboot.bin
${MAKE_FSELF} -s ${BINARY_NAME}.velf eboot.bin
DEPENDS ${BINARY_NAME}.velf)
vita_create_self(${BINARY_NAME}.self ${BINARY_NAME}.elf)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/template.xml.in ${CMAKE_CURRENT_BINARY_DIR}/template.xml)
add_custom_target(livearea
${CMAKE_COMMAND} -E make_directory sce_sys/livearea/contents
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/icon0.png sce_sys
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/pic0.png sce_sys
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/template.xml sce_sys/livearea/contents
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bg.png sce_sys/livearea/contents
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/startup.png sce_sys/livearea/contents
DEPENDS sce_sys)
add_custom_target(${BINARY_NAME}.vpk ALL
zip -qr ${BINARY_NAME}.vpk sce_sys eboot.bin
DEPENDS livearea eboot.bin param.sfo)
vita_create_vpk(${BINARY_NAME}.vpk MGBA00001 ${BINARY_NAME}.self
NAME ${PROJECT_NAME}
FILE ${CMAKE_CURRENT_SOURCE_DIR}/icon0.png sce_sys/icon0.png
FILE ${CMAKE_CURRENT_SOURCE_DIR}/pic0.png sce_sys/pic0.png
FILE ${CMAKE_CURRENT_SOURCE_DIR}/bg.png sce_sys/livearea/contents/bg.png
FILE ${CMAKE_CURRENT_SOURCE_DIR}/startup.png sce_sys/livearea/contents/startup.png
FILE ${CMAKE_CURRENT_BINARY_DIR}/template.xml sce_sys/livearea/contents/template.xml)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.vpk DESTINATION . COMPONENT ${BINARY_NAME}-psp2)

View File

@ -14,7 +14,7 @@ set(CMAKE_PROGRAM_PATH ${toolchain_dir}/bin)
set(cross_prefix arm-vita-eabi-)
set(inc_flags -I${toolchain_dir}/include)
set(link_flags "-L${toolchain_dir}/lib -Wl,-q")
set(link_flags "-L${toolchain_dir}/lib -Wl,-z,nocopyreloc")
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR armv7-a CACHE INTERNAL "processor")
@ -26,9 +26,9 @@ find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension})
find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_LINKER ${cross_prefix}ld${extension})
set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_C_FLAGS "${inc_flags} -Wl,-q" CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags")
set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags")
set(CMAKE_CXX_FLAGS "${inc_flags} -Wl,-q" CACHE INTERNAL "cxx compiler flags")
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
@ -41,6 +41,13 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "")
set(ENV{PKG_CONFIG_PATH} ${VITASDK}/arm-vita-eabi/lib/pkgconfig)
set(ENV{PKG_CONFIG_LIBDIR} ${VITASDK}/arm-vita-eabi/lib/pkgconfig)
set(VITA_ELF_CREATE "${VITASDK}/bin/vita-elf-create${TOOL_OS_SUFFIX}" CACHE PATH "vita-elf-create")
set(VITA_ELF_EXPORT "${VITASDK}/bin/vita-elf-export${TOOL_OS_SUFFIX}" CACHE PATH "vita-elf-export")
set(VITA_LIBS_GEN "${VITASDK}/bin/vita-libs-gen${TOOL_OS_SUFFIX}" CACHE PATH "vita-libs-gen")
set(VITA_MAKE_FSELF "${VITASDK}/bin/vita-make-fself${TOOL_OS_SUFFIX}" CACHE PATH "vita-make-fself")
set(VITA_MKSFOEX "${VITASDK}/bin/vita-mksfoex${TOOL_OS_SUFFIX}" CACHE PATH "vita-mksfoex")
set(VITA_PACK_VPK "${VITASDK}/bin/vita-pack-vpk${TOOL_OS_SUFFIX}" CACHE PATH "vita-pack-vpk")
set(PSP2 ON)
add_definitions(-DPSP2)
set(M_LIBRARY m)

View File

@ -35,6 +35,10 @@ class GB(Core):
self._native.video.renderer.cache = ffi.NULL
lib.mTileCacheDeinit(cache)
def reset(self):
super(GB, self).reset()
self.memory = GBMemory(self._core)
def attachSIO(self, link):
lib.GBSIOSetDriver(ffi.addressof(self._native.sio), link._native)
@ -61,21 +65,46 @@ class GBSIODriver(object):
return value
class GBSIOSimpleDriver(GBSIODriver):
def __init__(self):
def __init__(self, period=0x100):
super(GBSIOSimpleDriver, self).__init__()
self.tx = 0xFF
self.rx = 0xFF
self.rx = 0x00
self._period = period
def init(self):
self._native.p.period = self._period
return True
def writeSB(self, value):
self.rx = value
def schedule(self, period=0x100, when=0):
def writeSC(self, value):
self._native.p.period = self._period
if value & 0x80:
lib.mTimingDeschedule(ffi.addressof(self._native.p.p.timing), ffi.addressof(self._native.p.event))
lib.mTimingSchedule(ffi.addressof(self._native.p.p.timing), ffi.addressof(self._native.p.event), self._native.p.period)
return value
def isReady(self):
return not self._native.p.remainingBits
@property
def tx(self):
self._native.p.pendingSB
@property
def period(self):
return self._native.p.period
@tx.setter
def tx(self, newTx):
self._native.p.pendingSB = newTx
self._native.p.remainingBits = 8
self._native.p.period = period
self._native.p.pendingSB = self.tx
self.tx = 0xFF
lib.mTimingDeschedule(ffi.addressof(self._native.p.p.timing), ffi.addressof(self._native.p.event))
lib.mTimingSchedule(ffi.addressof(self._native.p.p.timing), ffi.addressof(self._native.p.event), when)
@period.setter
def period(self, newPeriod):
self._period = newPeriod
if self._native.p:
self._native.p.period = newPeriod
class GBMemory(Memory):
def __init__(self, core):

View File

@ -83,7 +83,7 @@
</font>
</property>
<property name="text">
<string>© 2013 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0
<string>© 2013 2017 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0
Game Boy Advance is a registered trademark of Nintendo Co., Ltd.</string>
</property>
<property name="alignment">

View File

@ -217,7 +217,7 @@ endif()
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt)
install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt)
if(NOT WIN32 AND NOT APPLE)
list(APPEND QT_DEFINES DATADIR="${DATADIR}")
list(APPEND QT_DEFINES DATADIR="${CMAKE_INSTALL_PREFIX}/${DATADIR}")
endif()
find_package(Qt5LinguistTools)
@ -255,7 +255,7 @@ install(TARGETS ${BINARY_NAME}-qt
if(UNIX AND NOT APPLE)
find_program(DESKTOP_FILE_INSTALL desktop-file-install)
if(DESKTOP_FILE_INSTALL)
install(CODE "execute_process(COMMAND ${DESKTOP_FILE_INSTALL} \"${CMAKE_SOURCE_DIR}/res/mgba-qt.desktop\" --dir \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/applications/\")")
install(CODE "execute_process(COMMAND ${DESKTOP_FILE_INSTALL} \"${CMAKE_SOURCE_DIR}/res/mgba-qt.desktop\" --dir \"\$ENV{DESTDIR}\${CMAKE_INSTALL_FULL_DATADIR}/applications/\")")
endif()
endif()
if(UNIX)

View File

@ -6,6 +6,7 @@
#include "GBAApp.h"
#include "AudioProcessor.h"
#include "ConfigController.h"
#include "Display.h"
#include "GameController.h"
#include "Window.h"
@ -14,10 +15,8 @@
#include <QFileInfo>
#include <QFileOpenEvent>
#include <QIcon>
#include <QTranslator>
#include <mgba/core/version.h>
#include <mgba/internal/gba/video.h>
#include <mgba-util/socket.h>
#include <mgba-util/vfs.h>
@ -31,8 +30,9 @@ static GBAApp* g_app = nullptr;
mLOG_DEFINE_CATEGORY(QT, "Qt", "platform.qt");
GBAApp::GBAApp(int& argc, char* argv[])
GBAApp::GBAApp(int& argc, char* argv[], ConfigController* config)
: QApplication(argc, argv)
, m_configController(config)
{
g_app = this;
@ -41,15 +41,9 @@ GBAApp::GBAApp(int& argc, char* argv[])
#endif
#ifndef Q_OS_MAC
setWindowIcon(QIcon(":/res/mgba-1024.png"));
setWindowIcon(QIcon(":/res/mgba-512.png"));
#endif
QTranslator* translator = new QTranslator(this);
if (translator->load(QLocale(), QLatin1String(binaryName), QLatin1String("-"), QLatin1String(":/translations"))) {
installTranslator(translator);
}
SocketSubsystemInit();
qRegisterMetaType<const uint32_t*>("const uint32_t*");
qRegisterMetaType<mCoreThread*>("mCoreThread*");
@ -57,50 +51,15 @@ GBAApp::GBAApp(int& argc, char* argv[])
QApplication::setApplicationName(projectName);
QApplication::setApplicationVersion(projectVersion);
if (!m_configController.getQtOption("displayDriver").isNull()) {
Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt()));
}
mArguments args;
mGraphicsOpts graphicsOpts;
mSubParser subparser;
initParserForGraphics(&subparser, &graphicsOpts);
bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser);
if (loaded && args.showHelp) {
usage(argv[0], subparser.usage);
::exit(0);
return;
if (!m_configController->getQtOption("displayDriver").isNull()) {
Display::setDriver(static_cast<Display::Driver>(m_configController->getQtOption("displayDriver").toInt()));
}
reloadGameDB();
if (!m_configController.getQtOption("audioDriver").isNull()) {
AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
if (!m_configController->getQtOption("audioDriver").isNull()) {
AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController->getQtOption("audioDriver").toInt()));
}
Window* w = new Window(&m_configController);
connect(w, &Window::destroyed, [this, w]() {
m_windows.removeAll(w);
});
m_windows.append(w);
if (loaded) {
w->argumentsPassed(&args);
} else {
w->loadConfig();
}
freeArguments(&args);
if (graphicsOpts.multiplier) {
w->resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
}
if (graphicsOpts.fullscreen) {
w->enterFullScreen();
}
w->show();
w->controller()->setMultiplayerController(&m_multiplayer);
w->multiplayerChanged();
}
GBAApp::~GBAApp() {
@ -122,7 +81,7 @@ Window* GBAApp::newWindow() {
if (m_windows.count() >= MAX_GBAS) {
return nullptr;
}
Window* w = new Window(&m_configController, m_multiplayer.attached());
Window* w = new Window(m_configController, m_multiplayer.attached());
int windowId = m_multiplayer.attached();
connect(w, &Window::destroyed, [this, w]() {
m_windows.removeAll(w);
@ -165,10 +124,10 @@ void GBAApp::continueAll(const QList<Window*>& paused) {
QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
QList<Window*> paused;
pauseAll(&paused);
QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getOption("lastDirectory"), filter);
QString filename = QFileDialog::getOpenFileName(owner, title, m_configController->getOption("lastDirectory"), filter);
continueAll(paused);
if (!filename.isEmpty()) {
m_configController.setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
m_configController->setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
}
return filename;
}
@ -176,10 +135,10 @@ QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QStr
QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
QList<Window*> paused;
pauseAll(&paused);
QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getOption("lastDirectory"), filter);
QString filename = QFileDialog::getSaveFileName(owner, title, m_configController->getOption("lastDirectory"), filter);
continueAll(paused);
if (!filename.isEmpty()) {
m_configController.setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
m_configController->setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
}
return filename;
}
@ -187,10 +146,10 @@ QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QStr
QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) {
QList<Window*> paused;
pauseAll(&paused);
QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getOption("lastDirectory"));
QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController->getOption("lastDirectory"));
continueAll(paused);
if (!filename.isEmpty()) {
m_configController.setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
m_configController->setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
}
return filename;
}

View File

@ -10,7 +10,6 @@
#include <QFileDialog>
#include <QThread>
#include "ConfigController.h"
#include "MultiplayerController.h"
struct NoIntroDB;
@ -21,6 +20,7 @@ mLOG_DECLARE_CATEGORY(QT);
namespace QGBA {
class ConfigController;
class GameController;
class Window;
@ -43,7 +43,7 @@ class GBAApp : public QApplication {
Q_OBJECT
public:
GBAApp(int& argc, char* argv[]);
GBAApp(int& argc, char* argv[], ConfigController*);
~GBAApp();
static GBAApp* app();
@ -67,7 +67,7 @@ private:
void pauseAll(QList<Window*>* paused);
void continueAll(const QList<Window*>& paused);
ConfigController m_configController;
ConfigController* m_configController;
QList<Window*> m_windows;
MultiplayerController m_multiplayer;

View File

@ -9,6 +9,7 @@
#include "InputController.h"
#include "LogController.h"
#include "MultiplayerController.h"
#include "Override.h"
#include "VFileDevice.h"
#include <QCoreApplication>

View File

@ -151,6 +151,7 @@ void MemorySearch::refresh() {
mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i);
QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0')));
m_ui.results->setItem(i, 0, item);
QTableWidgetItem* type;
if (m_ui.numHex->isChecked()) {
switch (result->type) {
case mCORE_MEMORY_SEARCH_8:
@ -182,9 +183,30 @@ void MemorySearch::refresh() {
item = new QTableWidgetItem("?"); // TODO
}
}
QString divisor;
if (result->guessDivisor > 1) {
divisor = tr(" (⅟%0×)").arg(result->guessDivisor);
}
switch (result->type) {
case mCORE_MEMORY_SEARCH_8:
type = new QTableWidgetItem(tr("1 byte%0").arg(divisor));
break;
case mCORE_MEMORY_SEARCH_16:
type = new QTableWidgetItem(tr("2 bytes%0").arg(divisor));
break;
case mCORE_MEMORY_SEARCH_GUESS:
case mCORE_MEMORY_SEARCH_32:
type = new QTableWidgetItem(tr("4 bytes%0").arg(divisor));
break;
case mCORE_MEMORY_SEARCH_STRING:
item = new QTableWidgetItem("?"); // TODO
}
m_ui.results->setItem(i, 1, item);
m_ui.results->setItem(i, 2, type);
}
m_ui.results->sortItems(0);
m_ui.results->resizeColumnsToContents();
m_ui.results->resizeRowsToContents();
}
void MemorySearch::openMemory() {

View File

@ -17,7 +17,7 @@
</size>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Memory Search</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
@ -214,10 +214,26 @@
</layout>
</widget>
<resources/>
<connections/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MemorySearch</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>315</x>
<y>357</y>
</hint>
<hint type="destinationlabel">
<x>315</x>
<y>188</y>
</hint>
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="type"/>
<buttongroup name="width"/>
<buttongroup name="numType"/>
<buttongroup name="type"/>
</buttongroups>
</ui>

View File

@ -13,6 +13,7 @@
#include "ShortcutView.h"
#include <mgba/core/serialize.h>
#include <mgba/core/version.h>
#include <mgba/internal/gba/gba.h>
using namespace QGBA;
@ -145,6 +146,19 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
}
});
m_ui.languages->setItemData(0, QLocale("en"));
QDir ts(":/translations/");
for (auto name : ts.entryList()) {
if (!name.endsWith(".qm")) {
continue;
}
QLocale locale(name.remove(QString("%0-").arg(binaryName)).remove(".qm"));
m_ui.languages->addItem(locale.nativeLanguageName(), locale);
if (locale == QLocale()) {
m_ui.languages->setCurrentIndex(m_ui.languages->count() - 1);
}
}
m_keyView = new ShortcutView();
m_keyView->setModel(inputController->keyIndex());
m_keyView->setInputController(inputController);
@ -239,6 +253,12 @@ void SettingsView::updateConfig() {
emit displayDriverChanged();
}
QLocale language = m_ui.languages->itemData(m_ui.languages->currentIndex()).toLocale();
if (language != m_controller->getQtOption("language").toLocale() && !(language.bcp47Name() == QLocale::system().bcp47Name() && m_controller->getQtOption("language").isNull())) {
m_controller->setQtOption("language", language.bcp47Name());
emit languageChanged();
}
m_controller->write();
m_input->rebuildIndex(m_shortcutView->root());

View File

@ -30,6 +30,7 @@ signals:
void audioDriverChanged();
void displayDriverChanged();
void pathsChanged();
void languageChanged();
void libraryCleared();
private slots:

View File

@ -398,17 +398,30 @@
</widget>
<widget class="QWidget" name="interface_2">
<layout class="QFormLayout" name="formLayout_4">
<item row="1" column="1">
<widget class="QCheckBox" name="showLibrary">
<item row="0" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Show when no game open</string>
</property>
<property name="checked">
<bool>true</bool>
<string>Language</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="languages">
<item>
<property name="text">
<string>English</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Library:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="libraryStyle">
<item>
<property name="text">
@ -422,35 +435,38 @@
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<item row="3" column="1">
<widget class="QCheckBox" name="showLibrary">
<property name="text">
<string>Library:</string>
<string>Show when no game open</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="4" column="1">
<widget class="QPushButton" name="clearCache">
<property name="text">
<string>Clear cache</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="6" column="1">
<widget class="QCheckBox" name="allowOpposingDirections">
<property name="text">
<string>Allow opposing input directions</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="7" column="1">
<widget class="QCheckBox" name="suspendScreensaver">
<property name="text">
<string>Suspend screensaver</string>
@ -460,13 +476,20 @@
</property>
</widget>
</item>
<item row="6" column="1">
<item row="8" column="1">
<widget class="QCheckBox" name="pauseOnFocusLost">
<property name="text">
<string>Pause when inactive</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="emulation">

View File

@ -86,7 +86,11 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
m_screenWidget->setMinimumSize(m_display->minimumSize());
m_screenWidget->setSizePolicy(m_display->sizePolicy());
int i = 2;
#if defined(M_CORE_GBA)
float i = 2;
#elif defined(M_CORE_GB)
float i = 3;
#endif
QVariant multiplier = m_config->getOption("scaleMultiplier");
if (!multiplier.isNull()) {
m_savedScale = multiplier.toInt();
@ -120,8 +124,11 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
m_controller->loadGame(output, path.second, path.first);
}
});
#elif defined(M_CORE_GBA)
m_screenWidget->setSizeHint(QSize(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i));
#endif
#if defined(M_CORE_GBA)
resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i));
#elif defined(M_CORE_GB)
resizeFrame(QSize(GB_VIDEO_HORIZONTAL_PIXELS * i, GB_VIDEO_VERTICAL_PIXELS * i));
#endif
m_screenWidget->setPixmap(m_logo);
m_screenWidget->setLockAspectRatio(m_logo.width(), m_logo.height());
@ -242,9 +249,6 @@ void Window::argumentsPassed(mArguments* args) {
void Window::resizeFrame(const QSize& size) {
QSize newSize(size);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
newSize /= m_screenWidget->devicePixelRatioF();
#endif
m_screenWidget->setSizeHint(newSize);
newSize -= m_screenWidget->size();
newSize += this->size();
@ -468,6 +472,7 @@ void Window::openSettingsWindow() {
connect(settingsWindow, &SettingsView::biosLoaded, m_controller, &GameController::loadBIOS);
connect(settingsWindow, &SettingsView::audioDriverChanged, m_controller, &GameController::reloadAudioDriver);
connect(settingsWindow, &SettingsView::displayDriverChanged, this, &Window::mustRestart);
connect(settingsWindow, &SettingsView::languageChanged, this, &Window::mustRestart);
connect(settingsWindow, &SettingsView::pathsChanged, this, &Window::reloadConfig);
connect(settingsWindow, &SettingsView::libraryCleared, m_libraryView, &LibraryController::clear);
openView(settingsWindow);

View File

@ -5,7 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LibraryController.h"
#include "../GBAApp.h"
#include "ConfigController.h"
#include "GBAApp.h"
#include "LibraryGrid.h"
#include "LibraryTree.h"
@ -45,8 +46,10 @@ LibraryController::LibraryController(QWidget* parent, const QString& path, Confi
mLibraryListingInit(&m_listing, 0);
if (!path.isNull()) {
// This can return NULL if the library is already open
m_library = mLibraryLoad(path.toUtf8().constData());
} else {
}
if (!m_library) {
m_library = mLibraryCreateEmpty();
}

View File

@ -7,14 +7,16 @@
// This must be defined before anything else is included.
#define SDL_MAIN_HANDLED
#include "ConfigController.h"
#include "GBAApp.h"
#include "Window.h"
#include <mgba/core/version.h>
#include <mgba/internal/gba/video.h>
#include <QLibraryInfo>
#include <QTranslator>
#include <mgba/core/version.h>
#ifdef QT_STATIC
#include <QtPlugin>
#ifdef _WIN32
@ -25,13 +27,32 @@ Q_IMPORT_PLUGIN(QWindowsAudioPlugin);
#endif
#endif
using namespace QGBA;
int main(int argc, char* argv[]) {
#ifdef BUILD_SDL
SDL_SetMainReady();
#endif
QGBA::GBAApp application(argc, argv);
QLocale locale = QLocale::system();
ConfigController configController;
QLocale locale;
if (!configController.getQtOption("language").isNull()) {
locale = QLocale(configController.getQtOption("language").toString());
QLocale::setDefault(locale);
}
mArguments args;
mGraphicsOpts graphicsOpts;
mSubParser subparser;
initParserForGraphics(&subparser, &graphicsOpts);
bool loaded = configController.parseArguments(&args, argc, argv, &subparser);
if (loaded && args.showHelp) {
usage(argv[0], subparser.usage);
return 0;
}
GBAApp application(argc, argv, &configController);
QTranslator qtTranslator;
qtTranslator.load(locale, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath));
@ -41,5 +62,22 @@ int main(int argc, char* argv[]) {
langTranslator.load(locale, binaryName, "-", ":/translations/");
application.installTranslator(&langTranslator);
Window* w = application.newWindow();
if (loaded) {
w->argumentsPassed(&args);
} else {
w->loadConfig();
}
freeArguments(&args);
if (graphicsOpts.multiplier) {
w->resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
}
if (graphicsOpts.fullscreen) {
w->enterFullScreen();
}
w->show();
return application.exec();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff