all repos — mgba @ e5c61e0093a9219cdf95b01eb74aa0f48250d01f

mGBA Game Boy Advance Emulator

Python: Preliminary, incomplete bindings
Jeffrey Pfau jeffrey@endrift.com
Tue, 11 Oct 2016 13:13:44 -0700
commit

e5c61e0093a9219cdf95b01eb74aa0f48250d01f

parent

4ac4733cfd4c4524c6a56d0406ba138d173fad61

M CMakeLists.txtCMakeLists.txt

@@ -28,6 +28,7 @@ set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool")

set(BUILD_TEST OFF CACHE BOOL "Build testing harness") set(BUILD_SUITE OFF CACHE BOOL "Build test suite") set(BUILD_EXAMPLE OFF CACHE BOOL "Build example frontends") +set(BUILD_PYTHON OFF CACHE BOOL "Build Python bindings") set(BUILD_STATIC OFF CACHE BOOL "Build a static library") set(BUILD_SHARED ON CACHE BOOL "Build a shared library") set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)")

@@ -750,6 +751,11 @@ set_target_properties(${BINARY_NAME}-suite PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")

add_test(${BINARY_NAME}-suite ${BINARY_NAME}-suite) endif() +if(BUILD_PYTHON) + enable_testing() + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/python ${CMAKE_CURRENT_BINARY_DIR}/python) +endif() + if(BUILD_EXAMPLE) add_executable(${BINARY_NAME}-example-server ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/example/client-server/server.c) target_link_libraries(${BINARY_NAME}-example-server ${BINARY_NAME})

@@ -833,6 +839,7 @@ message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}")

message(STATUS " Profiling: ${BUILD_PERF}") message(STATUS " Test harness: ${BUILD_TEST}") message(STATUS " Test suite: ${BUILD_SUITE}") + message(STATUS " Python bindings: ${BUILD_PYTHON}") message(STATUS " Examples: ${BUILD_EXAMPLE}") message(STATUS "Cores:") message(STATUS " Libretro core: ${BUILD_LIBRETRO}")
M src/arm/arm.hsrc/arm/arm.h

@@ -73,7 +73,7 @@ unsigned n : 1;

unsigned z : 1; unsigned c : 1; unsigned v : 1; - unsigned : 20; + unsigned unused : 20; unsigned i : 1; unsigned f : 1; unsigned t : 1;

@@ -83,7 +83,7 @@ unsigned priv : 5;

unsigned t : 1; unsigned f : 1; unsigned i : 1; - unsigned : 20; + unsigned unused : 20; unsigned v : 1; unsigned c : 1; unsigned z : 1;
M src/core/log.csrc/core/log.c

@@ -44,4 +44,18 @@ }

return 0; } +void mLog(int category, enum mLogLevel level, const char* format, ...) { + struct mLogger* context = mLogGetContext(); + va_list args; + va_start(args, format); + if (context) { + context->log(context, category, level, format, args); + } else { + printf("%s: ", mLogCategoryName(category)); + vprintf(format, args); + printf("\n"); + } + va_end(args); +} + mLOG_DEFINE_CATEGORY(STATUS, "Status")
M src/core/log.hsrc/core/log.h

@@ -30,6 +30,7 @@ int mLogGenerateCategory(const char*);

const char* mLogCategoryName(int); ATTRIBUTE_FORMAT(printf, 3, 4) +#ifndef __NO_INLINE__ static inline void mLog(int category, enum mLogLevel level, const char* format, ...) { struct mLogger* context = mLogGetContext(); va_list args;

@@ -43,6 +44,9 @@ printf("\n");

} va_end(args); } +#else +void mLog(int category, enum mLogLevel level, const char* format, ...); +#endif #define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY (), mLOG_ ## LEVEL, __VA_ARGS__)
M src/debugger/debugger.hsrc/debugger/debugger.h

@@ -35,7 +35,7 @@

enum mWatchpointType { WATCHPOINT_WRITE = 1, WATCHPOINT_READ = 2, - WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ + WATCHPOINT_RW = 3 }; enum mBreakpointType {
A src/platform/python/CMakeLists.txt

@@ -0,0 +1,20 @@

+set(PY_INCLUDE_DIRS -I${CMAKE_SOURCE_DIR}/src) +get_property(INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) +get_property(COMPILE_DEFINITIONS DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS) +foreach(INCLUDE_DIR IN LISTS INCLUDE_DIRECTORIES) + list(APPEND PY_INCLUDE_DIRS -I${INCLUDE_DIR}) +endforeach() +foreach(COMPILE_DEF IN LISTS COMPILE_DEFINITIONS) + list(APPEND PY_COMPILE_DEFS -D${COMPILE_DEF}) +endforeach() + +add_custom_command(OUTPUT _builder.h + COMMAND ${CMAKE_C_COMPILER} ${PY_COMPILE_DEFS} ${PY_INCLUDE_DIRS} -fno-inline -E -P -c ${CMAKE_CURRENT_SOURCE_DIR}/_builder.h -o _builder.h + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.h) +add_custom_target(_builder.h ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_builder.h) + +add_custom_command(OUTPUT ${BINARY_NAME}/_pylib.so + COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py ${PY_COMPILE_DEFS} ${PY_INCLUDE_DIRS} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_builder.h) +add_custom_target(_pylib.so ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}/_pylib.so)
A src/platform/python/_builder.h

@@ -0,0 +1,6 @@

+#define COMMON_H +#define ATTRIBUTE_FORMAT(X, Y, Z) +typedef long time_t; +typedef ... va_list; +#include <limits.h> +#include "core/core.h"
A src/platform/python/_builder.py

@@ -0,0 +1,20 @@

+import cffi +import os.path +import subprocess +import sys + +ffi = cffi.FFI() +src = os.path.join(os.path.dirname(__file__), "..", "..") + +ffi.set_source("mgba._pylib", """ +#include "util/common.h" +#include "core/core.h" +""", include_dirs=[src], + extra_compile_args=sys.argv[1:], + libraries=["mgba"], + library_dirs=[os.path.join(os.getcwd(), "..")]) + +with open(os.path.join(os.getcwd(), "_builder.h")) as core: + ffi.cdef(core.read()) + +ffi.compile()
A src/platform/python/mCore.py

@@ -0,0 +1,47 @@

+from _pylib import ffi, lib + +def find(path): + core = lib.mCoreFind(path.encode('UTF-8')) + if core == ffi.NULL: + return None + return mCore(core) + +class mCore: + def __init__(self, native): + self._core = ffi.gc(native, self._deinit) + + def init(self): + return bool(self._core.init(self._core)) + + def _deinit(self): + self._core.deinit(self._core) + + def loadFile(self, path): + return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8'))) + + def autoloadSave(self): + return bool(lib.mCoreAutoloadSave(self._core)) + + def autoloadPatch(self): + return bool(lib.mCoreAutoloadPatch(self._core)) + + def platform(self): + return self._core.platform(self._core) + + def desiredVideoDimensions(self): + width = ffi.new("unsigned*") + height = ffi.new("unsigned*") + self._core.desiredVideoDimensions(self._core, width, height) + return width[0], height[0] + + def reset(self): + self._core.reset(self._core) + + def runFrame(self): + self._core.runFrame(self._core) + + def runLoop(self): + self._core.runLoop(self._core) + + def step(self): + self._core.step(self._core)
M src/util/table.csrc/util/table.c

@@ -163,6 +163,14 @@ size_t TableSize(const struct Table* table) {

return table->size; } +void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) { + TableInit(table, initialSize, deinitializer); +} + +void HashTableDeinit(struct Table* table) { + TableDeinit(table); +} + void* HashTableLookup(const struct Table* table, const char* key) { uint32_t hash = hash32(key, strlen(key), 0); const struct TableList* list;
M src/util/table.hsrc/util/table.h

@@ -29,6 +29,7 @@

void TableEnumerate(const struct Table*, void (handler(uint32_t key, void* value, void* user)), void* user); size_t TableSize(const struct Table*); +#ifndef __NO_INLINE__ static inline void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) { TableInit(table, initialSize, deinitializer); }

@@ -36,6 +37,10 @@

static inline void HashTableDeinit(struct Table* table) { TableDeinit(table); } +#else +void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))); +void HashTableDeinit(struct Table* table); +#endif void* HashTableLookup(const struct Table*, const char* key); void HashTableInsert(struct Table*, const char* key, void* value);