Merge branch 'master' into medusa

This commit is contained in:
Vicki Pfau 2020-07-30 19:09:52 -07:00
commit 5135756ec4
28 changed files with 751 additions and 187 deletions

View File

@ -88,6 +88,8 @@ Other fixes:
- SM83: Simplify register pair access on big endian
- Wii: Fix pixelated filtering on interframe blending (fixes mgba.io/i/1830)
Misc:
- GB: Allow pausing event loop while CPU is blocked
- GBA: Allow pausing event loop while CPU is blocked
- Debugger: Keep track of global cycle count
- FFmpeg: Add looping option for GIF/APNG
- FFmpeg: Use range coder for FFV1 to reduce output size

View File

@ -13,7 +13,7 @@ set(CMAKE_C_STANDARD 99)
if(NOT MSVC)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(SWITCH)
if(SWITCH OR 3DS)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS ON)
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.3")
@ -297,6 +297,7 @@ include(CheckIncludeFiles)
check_function_exists(strdup HAVE_STRDUP)
check_function_exists(strndup HAVE_STRNDUP)
check_function_exists(strlcpy HAVE_STRLCPY)
check_function_exists(vasprintf HAVE_VASPRINTF)
if(NOT DEFINED PSP2)
check_function_exists(localtime_r HAVE_LOCALTIME_R)
endif()
@ -379,6 +380,10 @@ if(HAVE_STRLCPY)
list(APPEND FUNCTION_DEFINES HAVE_STRLCPY)
endif()
if(HAVE_VASPRINTF)
list(APPEND FUNCTION_DEFINES HAVE_VASPRINTF)
endif()
if(HAVE_LOCALTIME_R)
list(APPEND FUNCTION_DEFINES HAVE_LOCALTIME_R)
endif()
@ -988,6 +993,9 @@ endif()
if(NOT USE_CMOCKA)
set(BUILD_SUITE OFF)
endif()
if(BUILD_TEST OR BUILD_SUITE OR BUILD_CINEMA)
enable_testing()
endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/test ${CMAKE_CURRENT_BINARY_DIR}/test)
if(BUILD_EXAMPLE)

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

View File

@ -24,6 +24,7 @@ typedef THREAD_ENTRY (*ThreadEntry)(void*);
typedef pthread_t Thread;
typedef pthread_mutex_t Mutex;
typedef pthread_cond_t Condition;
typedef pthread_key_t ThreadLocal;
static inline int MutexInit(Mutex* mutex) {
return pthread_mutex_init(mutex, 0);
@ -101,6 +102,18 @@ static inline int ThreadSetName(const char* name) {
#endif
}
static inline void ThreadLocalInitKey(ThreadLocal* key) {
pthread_key_create(key, 0);
}
static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
pthread_setspecific(key, value);
}
static inline void* ThreadLocalGetValue(ThreadLocal key) {
return pthread_getspecific(key);
}
CXX_GUARD_END
#endif

View File

@ -17,6 +17,7 @@ typedef struct {
} Condition;
#define THREAD_ENTRY int
typedef THREAD_ENTRY (*ThreadEntry)(void*);
typedef int ThreadLocal;
static inline int MutexInit(Mutex* mutex) {
Mutex id = sceKernelCreateMutex("mutex", 0, 0, 0);
@ -143,4 +144,19 @@ static inline int ThreadSetName(const char* name) {
UNUSED(name);
return -1;
}
static inline void ThreadLocalInitKey(ThreadLocal* key) {
static int base = 0x90;
*key = __atomic_fetch_add(&base, 1, __ATOMIC_SEQ_CST);
}
static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
void** tls = sceKernelGetTLSAddr(key);
*tls = value;
}
static inline void* ThreadLocalGetValue(ThreadLocal key) {
void** tls = sceKernelGetTLSAddr(key);
return *tls;
}
#endif

View File

@ -16,6 +16,7 @@ typedef THREAD_ENTRY ThreadEntry(LPVOID);
typedef HANDLE Thread;
typedef CRITICAL_SECTION Mutex;
typedef CONDITION_VARIABLE Condition;
typedef DWORD ThreadLocal;
static inline int MutexInit(Mutex* mutex) {
InitializeCriticalSection(mutex);
@ -88,4 +89,16 @@ static inline int ThreadSetName(const char* name) {
return -1;
}
static inline void ThreadLocalInitKey(ThreadLocal* key) {
*key = TlsAlloc();
}
static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
TlsSetValue(key, value);
}
static inline void* ThreadLocalGetValue(ThreadLocal key) {
return TlsGetValue(key);
}
#endif

View File

@ -45,6 +45,7 @@ const char* hex4(const char* line, uint8_t* out);
void rtrim(char* string);
ssize_t parseQuotedString(const char* unparsed, ssize_t unparsedLen, char* parsed, ssize_t parsedLen);
bool wildcard(const char* search, const char* string);
CXX_GUARD_END

View File

@ -11,6 +11,12 @@
CXX_GUARD_START
#ifndef DISABLE_THREADING
#if __STDC_VERSION__ >= 201112L
#define ThreadLocal _Thread_local void*
#define ThreadLocalInitKey(X)
#define ThreadLocalSetKey(K, V) K = V
#define ThreadLocalGetValue(K) K
#endif
#ifdef USE_PTHREADS
#include <mgba-util/platform/posix/threading.h>
#elif defined(_WIN32)
@ -40,6 +46,7 @@ typedef void* Thread;
typedef void* Mutex;
#endif
typedef void* Condition;
typedef int ThreadLocal;
static inline int MutexInit(Mutex* mutex) {
UNUSED(mutex);
@ -93,6 +100,20 @@ static inline int ConditionWake(Condition* cond) {
UNUSED(cond);
return 0;
}
static inline void ThreadLocalInitKey(ThreadLocal* key) {
UNUSED(key);
}
static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
UNUSED(key);
UNUSED(value);
}
static inline void* ThreadLocalGetValue(ThreadLocal key) {
UNUSED(key);
return NULL;
}
#endif
CXX_GUARD_END

View File

@ -235,6 +235,8 @@ DECL_BIT(GBSerializedCpuFlags, Condition, 0);
DECL_BIT(GBSerializedCpuFlags, IrqPending, 1);
DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2);
DECL_BIT(GBSerializedCpuFlags, EiPending, 3);
DECL_BIT(GBSerializedCpuFlags, Halted, 4);
DECL_BIT(GBSerializedCpuFlags, Blocked, 5);
DECL_BITFIELD(GBSerializedTimerFlags, uint8_t);
DECL_BIT(GBSerializedTimerFlags, IrqPending, 0);

View File

@ -236,6 +236,7 @@ DECL_BITFIELD(GBASerializedMiscFlags, uint32_t);
DECL_BIT(GBASerializedMiscFlags, Halted, 0);
DECL_BIT(GBASerializedMiscFlags, POSTFLG, 1);
DECL_BIT(GBASerializedMiscFlags, IrqPending, 2);
DECL_BIT(GBASerializedMiscFlags, Blocked, 3);
struct GBASerializedState {
uint32_t versionMagic;

View File

@ -16,23 +16,22 @@
#ifndef DISABLE_THREADING
static const float _defaultFPSTarget = 60.f;
static ThreadLocal _contextKey;
#ifdef USE_PTHREADS
static pthread_key_t _contextKey;
static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT;
static void _createTLS(void) {
pthread_key_create(&_contextKey, 0);
ThreadLocalInitKey(&_contextKey);
}
#elif _WIN32
static DWORD _contextKey;
static INIT_ONCE _contextOnce = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) {
UNUSED(once);
UNUSED(param);
UNUSED(context);
_contextKey = TlsAlloc();
ThreadLocalInitKey(&_contextKey);
return TRUE;
}
#endif
@ -144,12 +143,11 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
struct mCoreThread* threadContext = context;
#ifdef USE_PTHREADS
pthread_once(&_contextOnce, _createTLS);
pthread_setspecific(_contextKey, threadContext);
#elif _WIN32
InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0);
TlsSetValue(_contextKey, threadContext);
#endif
ThreadLocalSetKey(_contextKey, threadContext);
ThreadSetName("CPU Thread");
#if !defined(_WIN32) && defined(USE_PTHREADS)
@ -620,21 +618,14 @@ void mCoreThreadStopWaiting(struct mCoreThread* threadContext) {
MutexUnlock(&threadContext->impl->stateMutex);
}
struct mCoreThread* mCoreThreadGet(void) {
#ifdef USE_PTHREADS
struct mCoreThread* mCoreThreadGet(void) {
pthread_once(&_contextOnce, _createTLS);
return pthread_getspecific(_contextKey);
}
#elif _WIN32
struct mCoreThread* mCoreThreadGet(void) {
InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0);
return TlsGetValue(_contextKey);
}
#else
struct mCoreThread* mCoreThreadGet(void) {
return NULL;
}
#endif
return ThreadLocalGetValue(_contextKey);
}
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
UNUSED(logger);

View File

@ -681,7 +681,7 @@ void GBProcessEvents(struct SM83Core* cpu) {
nextEvent = cycles;
do {
nextEvent = mTimingTick(&gb->timing, nextEvent);
} while (gb->cpuBlocked);
} while (gb->cpuBlocked && !gb->earlyExit);
cpu->nextEvent = nextEvent;
if (cpu->halted) {
@ -695,6 +695,9 @@ void GBProcessEvents(struct SM83Core* cpu) {
}
} while (cpu->cycles >= cpu->nextEvent);
gb->earlyExit = false;
if (gb->cpuBlocked) {
cpu->cycles = cpu->nextEvent;
}
}
void GBSetInterrupts(struct SM83Core* cpu, bool enable) {

View File

@ -56,6 +56,8 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending);
flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed);
flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending));
flags = GBSerializedCpuFlagsSetHalted(flags, gb->cpu->halted);
flags = GBSerializedCpuFlagsSetBlocked(flags, gb->cpuBlocked);
STORE_32LE(flags, 0, &state->cpu.flags);
STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending);
@ -173,6 +175,9 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
gb->cpu->halted = GBSerializedCpuFlagsGetHalted(flags);
gb->cpuBlocked = GBSerializedCpuFlagsGetBlocked(flags);
gb->audio.timingFactor = gb->doubleSpeed + 1;
LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);

View File

@ -379,6 +379,7 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat
GBFrameEnded(video->p);
mCoreSyncPostFrame(video->p->sync);
++video->frameCounter;
video->p->earlyExit = true;
GBFrameStarted(video->p);
}

View File

@ -286,7 +286,7 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
}
#endif
nextEvent = mTimingTick(&gba->timing, cycles < nextEvent ? nextEvent : cycles);
} while (gba->cpuBlocked);
} while (gba->cpuBlocked && !gba->earlyExit);
cpu->nextEvent = nextEvent;
if (cpu->halted) {
@ -305,11 +305,9 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
}
}
gba->earlyExit = false;
#ifndef NDEBUG
if (gba->cpuBlocked) {
mLOG(GBA, FATAL, "CPU is blocked!");
cpu->cycles = cpu->nextEvent;
}
#endif
}
#ifdef USE_DEBUGGERS

View File

@ -67,6 +67,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
miscFlags = GBASerializedMiscFlagsFillIrqPending(miscFlags);
STORE_32(gba->irqEvent.when - mTimingCurrentTime(&gba->timing), 0, &state->nextIrq);
}
miscFlags = GBASerializedMiscFlagsSetBlocked(miscFlags, gba->cpuBlocked);
STORE_32(miscFlags, 0, &state->miscFlags);
GBAMemorySerialize(&gba->memory, state);
@ -185,6 +186,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
LOAD_32(when, 0, &state->nextIrq);
mTimingSchedule(&gba->timing, &gba->irqEvent, when);
}
gba->cpuBlocked = GBASerializedMiscFlagsGetBlocked(miscFlags);
GBAVideoDeserialize(&gba->video, state);
GBAMemoryDeserialize(&gba->memory, state);

View File

@ -196,6 +196,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
video->frameskipCounter = video->frameskip;
}
++video->frameCounter;
video->p->earlyExit = true;
break;
case VIDEO_VERTICAL_TOTAL_PIXELS - 1:
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);

View File

@ -54,9 +54,8 @@ add_custom_target(${BINARY_NAME}-py-bdist
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${BINARY_NAME}-py)
file(GLOB BASE_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/test_*.py)
file(GLOB SUBTESTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/*/test_*.py)
foreach(TEST IN LISTS BASE_TESTS SUBTESTS)
file(GLOB TESTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/*/test_*.py)
foreach(TEST IN LISTS TESTS)
if(APPLE)
set(PATH DYLD_LIBRARY_PATH)
elseif(WIN32)
@ -64,7 +63,7 @@ foreach(TEST IN LISTS BASE_TESTS SUBTESTS)
else()
set(PATH LD_LIBRARY_PATH)
endif()
string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/(tests/.*/)?test_" "" TEST_NAME "${TEST}")
string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/tests/(.*/)?test_" "" TEST_NAME "${TEST}")
string(REPLACE ".py" "" TEST_NAME "${TEST_NAME}")
add_test(NAME python-${TEST_NAME}
COMMAND ${PYTHON_EXECUTABLE} setup.py build -b ${CMAKE_CURRENT_BINARY_DIR} pytest --extras --addopts ${TEST}

View File

@ -43,4 +43,5 @@ if(BUILD_CINEMA)
add_executable(${BINARY_NAME}-cinema ${CMAKE_CURRENT_SOURCE_DIR}/cinema-main.c)
target_link_libraries(${BINARY_NAME}-cinema ${BINARY_NAME} ${PLATFORM_LIBRARY})
set_target_properties(${BINARY_NAME}-cinema PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
add_test(cinema ${BINARY_NAME}-cinema -v)
endif()

File diff suppressed because it is too large Load Diff

View File

@ -518,4 +518,34 @@ ssize_t parseQuotedString(const char* unparsed, ssize_t unparsedLen, char* parse
}
}
return -1;
}
bool wildcard(const char* search, const char* string) {
while (true) {
if (search[0] == '*') {
while (search[0] == '*') {
++search;
}
if (!search[0]) {
return true;
}
while (string[0]) {
if (string[0] == search[0] && wildcard(search, string)) {
return true;
}
++string;
}
return false;
} else if (!search[0]) {
return !string[0];
} else if (!string[0]) {
return false;
} else if (string[0] != search[0]) {
return false;
} else {
++search;
++string;
}
}
return false;
}